堆:满足上大下小(大根堆),或下大上小的(小根堆)完全二叉树,当用一维数组存储时
父结点位置为i;
左孩子结点位置为2i + 1;
右孩子结点位置为2i + 2。
最后一个非叶结点位置为:Ln/2」- 1
初始建堆
步骤一:可按层直接填充
步骤二:将一棵普通的完全二叉树调整为堆【因为叶子节点已是堆,从最后一个非叶子节点开始调整】
堆的调整:
3号:65满足堆条件,无需调整
2号:38不满足:
将38所在的树调整成堆
1号:49不满足:
将49所在的树调整成堆
在堆调整时要先将最后一个非叶子节点38所在的树调整成堆(判断:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2] )
还要再将49所在的树调整成堆
插入:再路径上进行前后比较,比较后上移
删除:
#include <stdio.h>
void heap_adjust(int *a, int i, int size){ /*堆调整,a为堆存储数组,i为根节点的位置,size为堆的大小*/
int lchild = 2*i;
int rchild = 2*i +1;
int max = i;
int temp;
if(i <= size/2) {
if(lchild<=size && a[lchild]>a[max]){
max = lchild;
}
if(rchild<=size && a[rchild]>a[max]){
max = rchild;
}
if(max != i){/*如果需要调整*/
temp = a[i];
a[i] = a[max];
a[max] = temp;
heap_adjust(a, max, size);/*所以最多比较的次数是当前节点的高度-1*/
}
}
}
void build_bheap(int *a, int size) { /*建堆*/
int i;
for(i=(size/2)-1; i >= 1; i--){
heap_adjust(a, i, size);
}
}
void heap_sort(int *a, int size){ /*堆排序*/
int i;
int temp;
build_bheap(a, size);
for(i=size; i >= 1; i--){
temp = a[1];
a[1] = a[i];
a[i] = temp;
heap_adjust(a, 1, i-1);
}
}
int main(int argc, char *argv[]){
int a[]={10,9,8,7,6,5,4,3,2,1};
int size = 10;
int i;
heap_sort(a, size);
for(i=1;i <= size; i++)
printf("%d ", a[i]);
return 0;
}
复杂度
建堆的时间O(n):
假 如 有 N 个 节 点 , 那 么 高 度 为 H = l o g N 下 取 整 + 1 , 最 后 一 层 每 个 父 节 点 最 多 只 需 要 下 调 0 次 , 倒 数 第 二 层 最 多 只 需 要 下 调 1 次 , 顶 点 最 多 需 要 下 调 H − 1 次 所 以 总 共 的 时 间 复 杂 度 为 s = 1 ∗ 2 H − 1 + 2 ∗ 2 H − 2 + . . . + ( H − 2 ) ∗ 2 1 + ( H − 1 ) ∗ 2 0 假如有N个节点,那么高度为H=logN下取整+1,\\最后一层每个父节点最多只需要下调0次,\\倒数第二层最多只需要下调1次,顶点最多需要下调H-1次\\所以总共的时间复杂度为s = 1 * 2^{H-1} + 2 * 2^{H-2} + ... + (H-2) * 2^1 + (H-1) * 2^0 假如有N个节点,那么高度为H=logN下取整+1,最后一层每个父节点最多只需要下调0次,倒数第二层最多只需要下调1次,顶点最多需要下调H−1次所以总共的时间复杂度为s=1∗2H−1+2∗2H−2+...+(H−2)∗21+(H−1)∗20
排序的时间O(nlog n)
我们知道删除一个元素的时间复杂度是O(log n),则删除n个元素:
l
o
g
n
+
l
o
g
(
n
−
1
)
+
…
…
+
l
o
g
(
n
−
2
)
+
l
o
g
1
=
O
(
n
l
o
g
n
)
log n + log(n-1) +……+ log(n-2) + log 1=O(nlog n)
logn+log(n−1)+……+log(n−2)+log1=O(nlogn)