☞梦想进大厂的一只程序猿☜
☞期望毕业前力扣刷够400题☜
☞正在复习数据结构和算法☜
☞博客地址:https://www.huangliangshuai.com/☜
建堆的过程,我们需要知道一个函数heapify()【这里的heapify不代表最终版本】
public static void heapify(int[] tree, int n, int i) {
if (i >= n) {
return;
}
int max = i;
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
if (c1 < n && tree[c1] > tree[max]) {
max = c1;
}
if (c2 < n && tree[c2] > tree[max]) {
max = c2;
}
if (max != i) {
duiSwap(tree, max, i);
}
}
这个函数用来进行3、5、6中,将最大的数与3交换
我们对于每一个结点利用heapify,这样,我们是否就得到了一个完整的堆?
我们往下看看,当3与6交换完后,我们再对结点2进行heapify(),2与7进行交换,然后对结点4进行heapify,6与4进行交换,最后1与7交换,我们看看最后的结果
我们考虑下,关于堆的定义:是一个完全二叉树、父节点全部大于等于或者全部小于等于子节点
我们看下图,可以看出明明5和3是4的子节点,为什么4还小于6呢?
同理,5和2也是1的子节点,为什么1还小于5呢?
这说明了我们对于堆的建立出现了错误,难道是我们的heapify出现了错误,我们从头开始分析一下:
首先,当我们将3和6进行交换时,这时候我们仅仅改变的是3-5-6之间的关系,也就是合理的,继而我们以2为父节点,改变2-5-7之间的关系,也是合理的,
当我们对以节点4进行heapify时,我们会将6和4的位置进行调换
这时候,聪明的你有没有看出什么错误导致的我们的建堆错误?
答案是:当我们对结点4进行heapify时,将4转变至子节点,破坏了下面这个小堆
也就是,对于交换后,我们原来排序好的堆,就失去了稳定性,有什么办法能让我们原来排序的堆也是顺序的嘛?
聪明的你可能想到了,我们再一次进行heapify不就可以了,对,我们只需要对交换完之后的节点再一次使用heapify,也就是对于上图中进行heapify,得到如下
按照上面的想法,我们对节点1再一次进行heapify
这时候聪明的你,能不能想到我们的heapify少了点什么?
对,我们一开始的heapify少了对改变的子节点进行heapify,我们怎么实现呢?
这里只需要递归就可以了,也就是对改变的子节点进行heapify
public static void heapify(int[] tree, int n, int i) {
if (i >= n) {
return;
}
int max = i;
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
if (c1 < n && tree[c1] > tree[max]) {
max = c1;
}
if (c2 < n && tree[c2] > tree[max]) {
max = c2;
}
if (max != i) {
duiSwap(tree, max, i);
heapify(tree, n, max);
}
}
这时候我们的堆就建好了,我们可以进行下一步操作,堆排序
对于堆排序,我们使用方法是:
每次将root与末尾的进行交换,然后对root进行heapify
我们看一下图示:
依次进行这种操作,我们最后得到的数组就是从小到大排序好的
注意:我们进行堆排序的时候,我们每次重新对节点使用heapify时,我们已经排序好了一个7,所以下一次进行heapify时,n(也就是heapify的范围)就可以直接除去一个7,后面也是这样
public static void duiSwap(int[] tree, int i, int j) {
int x = tree[i];
tree[i] = tree[j];
tree[j] = x;
}
public static void heapify(int[] tree, int n, int i) {
if (i >= n) {
return;
}
int max = i;
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
if (c1 < n && tree[c1] > tree[max]) {
max = c1;
}
if (c2 < n && tree[c2] > tree[max]) {
max = c2;
}
if (max != i) {
duiSwap(tree, max, i);
heapify(tree, n, max);
}
}
public static void bulidDui(int[] tree, int n) {
int last = n - 1;
int parent = (last - 1) / 2;
for (int i = parent; i >= 0; i--) {
heapify(tree, n, i);
}
}
public static void duiSort(int[] tree, int n) {
bulidDui(tree, n);
for (int i = n - 1; i >= 0; i--) {
duiSwap(tree, i, 0);
heapify(tree, i, 0);
}
}
public static void main(String[] args) {
int[] tree = new int[] { 2, 5, 3, 1, 10 };
int n = tree.length;
duiSort(tree, n);
for (int i = 0; i < n; i++) {
System.out.println(tree[i]);
}
}