来源:https://loliwithpick.github.io/deny.github.io/2019/03/13/heapTheory/
堆(Heap)
什么是堆
堆是一种特殊的树,它必须满足以下两点要求:
- 堆是一个完全二叉树。
- 堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。
每个节点的值都大于等于其子树中每个节点的值的数,叫左**“大顶堆”。每个节点的值都小于等于其子树中每个节点的值的数,叫左“小顶堆”**。
如何实现堆
如何存储堆
用数组储存完全二叉树是非常节省空间的。因为我们不需要存储左右子节点的指针,只要用数组下标,就可以找到一个节点的左右子节点和父节点。
堆支持哪些操作
堆主要的操作有:插入元素和取出堆顶元素。
插入元素
往堆中插入一个元素后,我们需要继续满足堆的特性。如果我们直接把新插入的元素放在堆尾,它就不符合堆的特性了。所以,我们要进行调整,重新满足堆的特性,这一过程叫左**“堆化”**。
而堆化非常简单,就是顺着节点所在路径往上或往下进行对比和交换。堆化有两种方式,一是**“从上往下堆化”,二是“从下往上堆化”**。
“从下往上堆化”
以小顶堆为例,我们让新插入的节点与其父节点进行对比,如果不满足子节点都小于等于父节点的关系,就把它们两个互换。一直重复这个过程,直到父子节点之间满足关系。
“从上往下堆化”
同样以小顶堆为例,**“从上往下堆化”**通常发生在取出栈顶元素之后,我们拿出堆顶元素后,将最后一个元素放到堆顶,然后让该元素与其左右子节点进行对比,如果不满足子节点都小于等于父节点的关系,就把它与不符合要求的子节点交换。一直重复这个过程,直到父子节点之间满足关系。
由于每次我们都是对数组的最后一个元素进行操作,而且堆化进行的都是交换操作,所以不会出现数组"空洞"。
关于堆的代码实现,详细请看:https://loliwithpick.github.io/deny.github.io/2019/03/13/heap/
堆排序(HeapSort)
堆排序是基于堆实现的排序算法,它是一种原地排序算法,时间复杂度为 O(nlogn),由于涉及到数据交换,所以它是不稳定的。
如何实现堆排序
堆排序主要有两个操作:建堆和排序。
建堆
建堆有两种方法:
- 借助在堆中插入一个元素的思想。假设数组中的数据存放在下标从 1 到 n 内,堆中只包含一个数据(下标为 1 的数据)。然后调用堆的插入方法,依次把剩下的数据插入到堆中。该方法是从下往上堆化的。
- 我们直接对数组进行堆化,而这种操作是从上往下堆化的。我们首先从最后一个非叶子节点开始,分别跟其左右子节点比较和堆化,依次往前。这么说法会很难理解,我们直接从代码方面下手。
/**
* 以现有数组构建小頂堆
* @param args
*/
public void BuildMinHeap(int args[]) {
len = args.length;
for (int i = len / 2; i >= 0; i--) {
heapifly(args, i);
}
}
/**
* 从上往下堆化
* @param args
* @param index
*/
public void heapifly(int args[], int index) {
while(true) {
int left = index * 2;
int right = index * 2 + 1;
int max = index;
if (left < len && args[left] > args[index]) {
max = left;
}
if (right < len && args[right] > args[max]) {
max = right;
}
if (max == index) break;
swap(args, max, index);
index = max;
}
}
在完全二叉树中,下标为 n/2 + 1 到 n 的节点是叶子节点。所以我们从下标为 n/2 开始,依次往前进行堆化的。所以我们只需从下标为 n/2 开始,依次往前进行堆化。
排序
假设我们建的是大顶堆,那么建堆后,数组中的数据是按照大顶堆特性进行的。堆顶元素是最大的元素,我们将它与最后一个元素进行交换,那么最大的元素就放在下标为 n 的位置,然后我们将堆长度减一,重复进行前面的操作,最终就得到一个升序排序的数组。
/**
* 进行排序
* @param args
*/
public void sort(int args[]) {
//判断数组是否有效或需要排序
if (args == null || args.length < 1)
return;
BuildMinHeap(args);
for (int i = args.length - 1; i >= 0; i--) {
swap(args, 0, i);
len--;
heapifly(args, 0);
}
}
关于堆排序的代码实现,请观看:https://loliwithpick.github.io/deny.github.io/2019/03/13/heapSort/
以上均为个人学习时的笔录总结,若有错误之处,请多多指教。