堆排序(附代码和注释)
堆排序就是使用完全二叉树的逻辑结构来对数据进行排序,理解堆排序主要理解三个部分内容
什么是完全二叉树,堆在逻辑结构上是一种怎样的完全二叉树堆元素的添加堆元素的删除
什么是完全二叉树,堆在逻辑结构上是一种怎样的完全二叉树
通俗来讲,完全二叉树就是在二叉树添加结点时完全按照从左到右的顺序添加结点的二叉树。
上图为完全二叉树,下图先添加右边结点所以不是 堆分为大根堆和小根堆,本文以小根堆为例,小根堆即二叉树中所有结点的值都小于子结点的值,大根堆则反之。 要构造小根堆就得理解,堆元素的添加和删除过程
堆元素的添加
堆元素的添加需遵循从左到右的添加原则,添加到二叉树的最后,添加元素后,二叉树需重新构造确保每个结点的值小于子结点值。构造方式就是添加的结点a,与a的父结点值比较,如果a值小于父结点值则将a值与父节点值互换,以此类推,直到满足小根堆的条件,整个构造过程就像a结点上浮的过程。
堆元素的删除
堆元素删除,一般遵循删除根节点,然后将小根堆的最后一个结点代替根结点,再重新构造小根堆,与堆元素的添加相反,根节点与值最小的子结点比较,如果该结点小于最小子结点,则两元素值互换,整个构造过程类似新的根结点下沉的过程。 由于小根堆的根结点值是整个二叉树中最小的值,所以不断取出根的值(也就是不断删除根结点,并重构堆的过程),则取出后的元素是一个从小到大的排序列。为了实现这一排序思想,将逻辑结构转换为数组的存储结构。 图片来源
逻辑结构与数据存储结构转换(采用数组存储逻辑完全二叉树): 当前i下标的父节点下标为:(i-1)/2 当前i下标的子结点下标为:2i+1和2i+2
代码实现堆排序(c++实现)
#include <iostream>
using namespace std
;
void Heapfixup(int a
[],int i
){
int tem
= a
[i
];
int j
= (i
-1)/2;
while(j
>= 0 && i
!= 0){
if(a
[j
] <= tem
) break;
a
[i
] = a
[j
];
i
= j
;
j
= (i
-1)/2;
}
a
[i
] = tem
;
}
void Heapfixdown(int a
[],int i
,int n
){
int tem
= a
[i
];
int j
= 2*i
+ 1;
while(i
<= n
&& j
< n
){
if( j
+1<n
&& a
[j
+1] < a
[j
]) j
++;
if(a
[j
] >= tem
) break;
a
[i
] = a
[j
];
i
= j
;
j
= 2*i
+ 1;
}
a
[i
] = tem
;
}
void printall(int a
[],int n
){
cout
<<"\n";
for(int i
=0;i
<n
;i
++){
cout
<<a
[i
]<<"\t";
}
}
int main(){
int a
[5];
cout
<<"请输入将要排序的5个数字:";
for(int i
=0;i
<5;i
++){
cin
>>a
[i
];
}
for(int i
=4;i
>=0;i
--){
Heapfixup(a
,i
);
}
printall(a
,5);
cout
<<"\n排序结果为:";
for(int i
=4;i
>=0;){
int tem
;
tem
= a
[0];
a
[0] = a
[i
];
a
[i
] = tem
;
i
--;
Heapfixdown(a
,0,i
);
}
printall(a
,5);
}
感谢你的阅读,如有疑问欢迎在下方评论。