数据结构——堆排序

堆排序总结


堆排序思想:最大堆的堆顶元素是全部数据中的最大值,输出这个值
。再将剩余元素整理成新的最大堆,此时堆顶元素有时又是剩余元素
的最大值,再输出这个值。继续这个过程,每次输出堆顶元素,并将
剩余元素整理成新的最大堆再输出...

堆排序要解决的几个问题
1:如何将数据排列成堆的形式——初始堆的建立
2:输出堆顶元素后,剩余元素如何再整理成新的堆——堆的整理
3:输出元素放在什么位置

预备知识:
1: 堆中的元素存储在一个数组中,根据堆中的各元素之间具有
有序性关系,可以使用二叉树的方式来表示一个堆。因为各元素从前
至后存放在数组的钱n 个单元中,所以所画的二叉树实际上是一颗完全
二叉树
2: 所以根据完全二叉树的性质,数组前一半的数据都是分值节点,后一半
的数据都是叶子节点
3: 即如果有七个数,分别占据数组的a[1]-a[7],那么7/2=3,所以a[1],
    a[2],a[3]为分支节点,剩下的为叶子节点
4: a[i]的左儿子为a[i*2],右儿子为a[i*2+1],如a[1]的左右儿子分别为
    a[2]与a[3]。(这有赖于数组从a[0]开始,还是从a[1]开始)

建堆的过程:
    见代码,见实例图

复制代码
1 /* ******************************************************* */
2   /* 数组从下标1开始 */
3
4 #include < iostream >
5   #define L(t) ((t)<<1)
6 #define R(t) ((t)<<1 | 1)
7 usingnamespace std;
8
9 intconst NUMBER = 1000 ;
10 int trees[NUMBER];
11 int N;
12 /* ******************************************************* */
13 void swap( int & a, int & b){
14 int temp = a;
15 a = b;
16 b = temp;
17 }
18 /* ******************************************************* */
19 // a[i]元素向下沉,此时堆中的实际元素为n,被甩在后面的元素
20 // 已经不用管了
21 void ShiftDown( int i, int n){
22 int child;
23 // i<=n/2说明trees[i]为分支结点
24 // i=child;该句在循环最后执行,即从上往下递归判断
25 // 新的位置是否已经稳定,不稳定继续下沉
26 for (;i <= n / 2 ;i = child){
27 child = i * 2 ; // 先试着将预交换的元素设为左儿子
28 if ((child != n) && trees[child + 1 ] > trees[child])
29 child = child + 1 ; // 如果右儿子比左儿子大
30 // 则将预交换儿子设置为右儿子
31 if (trees[child] > trees[i]) // 如果该节点不如较大的
32 // 儿子大,则下沉(及交换)
33 swap(trees[child],trees[i]);
34 }
35 }
36 /* ******************************************************* */
37 void HeapSort(){
38 // 该循环极为初始堆的建立,从最后一个分支结点开始
39 for ( int i = N / 2 ;i >= 1 ;i -- ){
40 ShiftDown(i,N);
41 }
42 // 每次循环首先使堆顶元素和首元素交换,再将首元素
43 // 下沉到合适的位置,记得每次实际堆中元素减1
44 for ( int i = N;i >= 1 ;i -- ){
45 swap(trees[ 1 ],trees[i]); // 最大的放到末尾
46 ShiftDown( 1 ,i - 1 ); // 所以此时的实际数量为i-1
47 }
48 }
49 /* ******************************************************* */
50 int main(){
51 while (cin >> N && N != 0 ){
52 for ( int i = 1 ;i <= N;i ++ )
53 cin >> trees[i];
54 HeapSort();
55 for ( int i = 1 ;i <= N;i ++ )
56 cout << trees[i] << " " ;
57 cout << endl;
58 }
59 return0;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值