`

堆排序算法原理以及实例代码

 
阅读更多

1、 堆排序定义
n个关键字序列Kl,K2,…,Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质):
(1) ki≤K2i且ki≤K2i+1 或(2)Ki≥K2i且ki≥K2i+1(1≤i≤ )

若将此序列所存储的向量R[1..n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
【例】关键字序列(10,15,56,25,30,70)和(70,56,30,25,15,10)分别满足堆性质(1)和(2),故它们均是堆,其对应的完全二叉树分别如小根堆示例和大根堆示例所示。
2、大根堆和小根堆
根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最小者的堆称为小根堆。
根结点(亦称为堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆。
注意:
①堆中任一子树亦是堆。
②以上讨论的堆实际上是二叉堆(Binary Heap),类似地可定义k叉堆。
3、堆排序特点
堆排序(HeapSort)是一树形选择排序。
堆排序的特点是:在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系【参见二叉树的顺序存储结构】,在当前无序区中选择关键字最大(或最小)的记录。
4、堆排序与直接插入排序的区别
直 接选择排序中,为了从R[1..n]中选出关键字最小的记录,必须进行n-1次比较,然后在R[2..n]中选出关键字最小的记录,又需要做n-2次比 较。事实上,后面的n-2次比较中,有许多比较可能在前面的n-1次比较中已经做过,但由于前一趟排序时未保留这些比较结果,所以后一趟排序时又重复执行 了这些比较操作。
堆排序可通过树形结构保存部分比较结果,可减少比较次数。
5、堆排序
堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。

<!--</p> <p>Code highlighting produced by Actipro CodeHighlighter (freeware)</p> <p>http://www.CodeHighlighter.com/</p> <p>-->1 /*
2 堆排序
3 (1)用大根堆排序的基本思想
4 ① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
5 ② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,
6 由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
7 ③ 由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。
8 然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,
9 由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n- 2].keys≤R[n-1..n].keys,
10 同样要将R[1..n-2]调整为堆。
11 ……
12 直到无序区只有一个元素为止。
13 (2)大根堆排序算法的基本操作:
14 ① 初始化操作:将R[1..n]构造为初始堆;
15 ② 每一趟排序的基本操作:将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)。
16 注意:
17 ①只需做n-1趟排序,选出较大的n-1个关键字即可以使得文件递增有序。
18 ②用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。
19 堆排序和直接选择排序相反:在任何时刻,堆排序中无序区总是在有序区之前,
20 且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止。
21 */
22
23 //生成大根堆
24 void HeapAdjust(int SortData[],int StartIndex, int Length)
25 {
26 while(2*StartIndex+1 < Length)
27 {
28 int MinChildrenIndex = 2*StartIndex+1 ;
29 if(2*StartIndex+2 < Length )
30 {
31 //比较左子树和右子树,记录最大值的Index
32 if(SortData[2*StartIndex+1]<SortData[2*StartIndex+2])
33 {
34 MinChildrenIndex = 2*StartIndex+2;
35 }
36 }
37 if(SortData[StartIndex] < SortData[MinChildrenIndex])
38 {
39 //交换i与MinChildrenIndex的数据
40 int tmpData =SortData[StartIndex];
41 SortData[StartIndex] =SortData[MinChildrenIndex];
42 SortData[MinChildrenIndex] =tmpData;
43 //堆被破坏,需要重新调整
44 StartIndex = MinChildrenIndex ;
45 }
46 else
47 {
48 //比较左右孩子均大则堆未破坏,不再需要调整
49 break;
50 }
51 }
52
53 return;
54 }
55
56 //堆排序
57 void HeapSortData(int SortData[], int Length)
58 {
59 int i=0;
60
61 //将Hr[0,Lenght-1]建成大根堆
62 for (i=Length/2-1; i>=0; i)
63 {
64 HeapAdjust(SortData, i, Length);
65 }
66
67 for (i=Length-1; i>0; i)
68 {
69 //与最后一个记录交换
70 int tmpData =SortData[0];
71 SortData[0] =SortData[i];
72 SortData[i] =tmpData;
73 //将H.r[0..i]重新调整为大根堆
74 HeapAdjust(SortData, 0, i);
75 }
76
77 return;
78 }

 

完整的实现代码

 

public class Heap {

    public static void main(String[] args) {
     
        int[] a = { 26, 5, 77, 1, 33, 11, 34, 95, 48 };
        Sort(a);
    }
   
    public static void Sort(int[] a){
        int temp;
        int n = a.length;
        Display(a);
       
        for(int i = n/2-1;i>=0;i--)                        //从非叶子节点开始
            Adjust(a, i, n);                            //初始化堆
        for(int i = n-1;i > 0;i--){
            temp = a[0];                                //交换根节点与最后一个叶子节点,要调整的范围减1
            a[0] = a[i];
            a[i] = temp;
            Adjust(a, 0, i);                          //不断减小长度、 交换、调整
        }   
        Display(a);
    }
   
    public static void Adjust(int[] a, int i, int n){     //调整函数,参数含义 代表从哪个节点开始跳着,n代表堆的长度范围
        int j = 2*i+1;                                    //从要调整的节点的子节点开始
        int temp = a[i];                                // temp 记录要调整的节点
        while(j<n){                                        //还有叶子节点怎循环
            if(j<n-1 && a[j]<a[j+1])                    //保证不越界,选择两子重的较大者
                j++;
            if(temp >= a[j])                            //根节点较大,停止调整
                break;
            a[(j-1)/2] = a[j];                            //子节点较大,本应该交换,但覆盖即可,temp保存着交换后该节点的信息
            j = j*2+1;                                    //继续检查子节点是否需要交互,如果越界则表明没有子节点
        }
        a[(j-1)/2] = temp;                                //最后停下来的位置上赋上原始节点的值
    }
   
    public static void Display(int[] a){                 //方便展示所以定义此函数
        System.out.println("------------------------");
        for(int i=0; i<a.length;i++){
            System.out.print(a[i]+" ");
        }
        System.out.println();
    }

}

 

 

 

 

分享到:
评论

相关推荐

    Python实现的堆排序算法原理与用法实例分析

    本文实例讲述了Python实现的堆排序算法。分享给大家供大家参考,具体如下: 堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆性质:即子结点的键值或...

    Python实现的选择排序算法原理与用法实例分析

    本文实例讲述了Python实现的选择排序算法。分享给大家供大家参考,具体如下: 选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在...

    Python实现的基数排序算法原理与用法实例分析

    本文实例讲述了Python实现的基数排序算法。分享给大家供大家参考,具体如下: 基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值...

    C++选择排序算法实例

    选择排序是一种简单直观的排序算法,它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推...

    C/C++常用算法手册.秦姣华(有详细书签).rar

    4.7.2 堆排序算法示例 121 4.8 合并排序法 123 4.8.1 合并排序算法 123 4.8.2 合并排序算法示例 126 4.9 排序算法的效率 129 4.10 排序算法的其他应用 130 4.10.1 反序排序 130 4.10.2 字符串数组的排序 132...

    vc源代码合集.rar

    2012-06-11 08:36 279,706 ARM JTAG调试原理完整源代码包.rar 2012-06-11 08:46 1,691,629 Asm汇编编译器(VC++6.0源代码).rar 2012-06-11 08:57 88,576 C++ 开发中内存分配及堆和栈的区别.doc 2012-06-11 08:52 190,...

    vc源代码合集0951.rar

    2012-06-12 11:51 103,936 最大堆实现排序(从大到小输出).doc 2012-06-12 11:51 240,128 最小生成树(prim算法)贪心算法.doc 2012-06-12 12:26 772,419 最简单的c++静态链接.zip 2012-06-12 11:45 202,240 最长...

    算法导论(part2)

    6.4 堆排序算法 6.5 优先级队列 第7章 快速排序 7.1 快速排序的描述 7.2 快速排序的性能 7.3 快速排序的随机化版本 7.4 快速排序分析 7.4.1 最坏情况分析 7.4.2 期望的运行时间 第8章 线性时间...

    算法导论(part1)

    6.4 堆排序算法 6.5 优先级队列 第7章 快速排序 7.1 快速排序的描述 7.2 快速排序的性能 7.3 快速排序的随机化版本 7.4 快速排序分析 7.4.1 最坏情况分析 7.4.2 期望的运行时间 第8章 线性时间...

    编程珠玑 第二版 修订版

    14.4 一种排序算法 148 14.5 原理 150 14.6 习题 150 14.7 深入阅读 152 第15章 字符串 153 15.1 单词 153 15.2 短语 156 15.3 生成文本 158 15.4 原理 163 15.5 习题 163 15.6 深入阅读 164 第1版跋 165...

    net学习笔记及其他代码应用

    8.请编程实现一个冒泡排序算法? 答: int [] array = new int ; int temp = 0 ; for (int i = 0 ; i ; i++) { for (int j = i + 1 ; j ; j++) { if (array[j] ) { temp = array ; array = array[j] ; ...

    最新Python3.5零基础+高级+完整项目(28周全)培训视频学习资料

    最新Python3.5零基础+高级+完整项目(28周全)培训视频学习资料;本资料仅用于学习。 【课程内容】 第1周 开课介绍 python发展介绍 ...堆排序复习 归并排序 希尔排序 算法练习 栈和队列 数据结构其他

    Visual C++ 2010入门经典(第5版)--源代码及课后练习答案

    4.3.1 堆的别名—— 空闲存储器 168 4.3.2 new和delete操作符 168 4.3.3 为数组动态分配内存 169 4.3.4 多维数组的动态分配 171 4.4 使用引用 172 4.4.1 引用的概念 172 4.4.2 声明并初始化lvalue引用 172 ...

    免费下载:C语言难点分析整理.doc

    4. C/C++实现冒泡排序算法 32 5. C++中指针和引用的区别 35 6. const char*, char const*, char*const的区别 36 7. C中可变参数函数实现 38 8. C程序内存中组成部分 41 9. C编程拾粹 42 10. C语言中实现数组的动态...

    高级C语言详解

    4. C/C++实现冒泡排序算法 32 5. C++中指针和引用的区别 35 6. const char*, char const*, char*const的区别 36 7. C中可变参数函数实现 38 8. C程序内存中组成部分 41 9. C编程拾粹 42 10. C语言中实现数组的动态...

    C语言难点分析整理.doc

    4. C/C++实现冒泡排序算法 32 5. C++中指针和引用的区别 35 6. const char*, char const*, char*const的区别 36 7. C中可变参数函数实现 38 8. C程序内存中组成部分 41 9. C编程拾粹 42 10. C语言中实现数组的...

    c语言难点分析整理,C语言

    4. C/C++实现冒泡排序算法 32 5. C++中指针和引用的区别 35 6. const char*, char const*, char*const的区别 36 7. C中可变参数函数实现 38 8. C程序内存中组成部分 41 9. C编程拾粹 42 10. C语言中实现数组的动态...

    高级C语言 C 语言编程要点

    4. C/C++实现冒泡排序算法 32 5. C++中指针和引用的区别 35 6. const char*, char const*, char*const的区别 36 7. C中可变参数函数实现 38 8. C程序内存中组成部分 41 9. C编程拾粹 42 10. C语言中实现数组的动态...

    高级进阶c语言教程..doc

    4. C/C++实现冒泡排序算法 32 5. C++中指针和引用的区别 35 6. const char*, char const*, char*const的区别 36 7. C中可变参数函数实现 38 8. C程序内存中组成部分 41 9. C编程拾粹 42 10. C语言中实现数组的动态...

Global site tag (gtag.js) - Google Analytics