堆排序
1.大顶堆和小顶堆
堆是具有下列性质的完全二叉树:大顶堆和小顶堆的性质
大顶堆:每个结点的值大于等于其左右孩子结点的值 双亲结点
k
i
≥
k
2
i
k_i \geq k_{2i}
ki?≥k2i? 其左孩子结点(其中
i
i
i 代表结点在数组中的下标) 双亲结点
k
i
≥
k
2
i
+
1
k_i \geq k_{2i+1}
ki?≥k2i+1? 其右孩子结点 1
≤
i
≤
\leq i \leq
≤i≤
?
\lfloor
?
n
2
\frac{n}{2}
2n?
?
\rfloor
? (向下取整) 对于有
n
n
n个结点的二叉树,第
n
n
n个结点的双亲为二叉树中第
?
\lfloor
?
n
2
\frac{n}{2}
2n?
?
\rfloor
?个结点
小顶堆:每个结点的值小于等于其左右孩子结点的值
双亲结点
k
i
≤
k
2
i
k_i \leq k_{2i}
ki?≤k2i? 其左孩子结点(其中
i
i
i 代表结点在数组中的下标) 双亲结点
k
i
≤
k
2
i
+
1
k_i \leq k_{2i+1}
ki?≤k2i+1? 其右孩子结点 1
≤
i
≤
\leq i \leq
≤i≤
?
\lfloor
?
n
2
\frac{n}{2}
2n?
?
\rfloor
? (向下取整) 对于有
n
n
n个结点的二叉树,第
n
n
n个结点的双亲为二叉树中第
?
\lfloor
?
n
2
\frac{n}{2}
2n?
?
\rfloor
?个结点
2.堆排序算法
步骤: 1.将现在的待排序序列构建成一个大顶堆(或小顶堆) 2.逐步将每个最大值的根结点与末尾元素交换,并且再调整其成为大顶堆(或小顶堆)
堆排序算法实现
void HeapSort(SqList *L){
for(int i=L->length/2; i>0; i--)
HeapAdjust(L,i,L->length);
for(int i=L->length; i>1; i--){
swap(L,1,i);
HeapAdjust(L,1,i-1);
}
}
HeapAdjust具体实现
void HeapAdjust(SqList *L, int s, int m){
int temp;
temp=L->r[s];
for(int j=2*s; j<=m; j*=2){
if(j<m && L->r[j]<L->r[j+1])
++j;
if(temp>=L->r[j])
break;
L->r[s]=L->r[j];
s=j;
}
L->r[s]=temp;
}
小例子: 调整为大顶堆后,进行下一次序列调整
具体过程: 一、构建大顶堆(从下往上、从右到左)将每个非叶子结点当作根结点,将其和其子树调整成大顶堆
变量
i
i
i的变化:4
→
\rightarrow
→ 3
→
\rightarrow
→ 2
→
\rightarrow
→ 1,也就是结点30,90,10,50的调整过程
待排序序列{50,10,90,30,70,40,80,60,20}
for(i=9/2=4;i>0;i--)
HeadAdjust(L,4,9)
temp=r[4]=30
for(j=2*4=8; j<=9; j*=2)
if(j=8<9 && r[8]=60 < r[9]=20)
++j;
r[4]=r[8]=60
s=j=8
r[8]=30
for(i=3;i>0;i--)
HeadAdjust(L,3,9)
temp=r[3]=90
for(j=2*3=6; j<=9; j*=2)
if(90 >= r[6]=40)
break;
r[3]=90;
for(i=2;i>;i--)
HeadAdjust(L,2,9)
temp=r[2]=10
for(j=2*2=4; j<=9; j*=2)
if(j=4<9 && r[4]=60 < r[5]=70)
++j;
r[2]=r[5]=70
s=j=5
r[5]=10
二、排序过程
for(int i=L->length; i>1; i--){
swap(L,1,i);
HeapAdjust(L,1,i-1);
}
实现步骤
for(i=9; i>1; i--){
swap(L,1,9);
HeapAdjust(L,1,8);
}
temp=r[1];
for(j=2*1=2; j<=8; j*=2)
if(j=2 < m=8 && r[2]=70 < r[3]=80)
++j;
r[1]=r[3]=80
s=j=3
for(j=6; j<=8; j*=2)
if(j=6 < m=8 && r[6]=40 < r[7]=50)
++j
r[3]=r[7]=50
s=j=7
j=2*6=12
r[7]=temp=20
|