`
rein07
  • 浏览: 21907 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

堆排序(Heap Sort)算法学习

 
阅读更多
在程序设计相关领域,堆(Heap)的概念主要涉及到两个方面:

一种数据结构,逻辑上是一颗完全二叉树,存储上是一个数组对象(二叉堆)。
垃圾收集存储区,是软件系统可以编程的内存区域。
本文所说的堆,指的是前者。

堆排序的时间复杂度是O(nlgN),与快速排序达到相同的时间复杂度。但是在实际应用中,我们往往采用快速排序而不是堆排序。这是因为快速排序的一个好的实现,往往比堆排序具有更好的表现。堆排序的主要用途,是在形成和处理优先级队列方面。另外,如果计算要求是类优先级队列(比如,只要返回最大或者最小元素,只有有限的插入要求等),堆同样是很适合的数据结构。

基础知识
堆一般用数组表示,比如数组A数组的长度Length(A),堆在数组中的元素个数HeapSize(A)。一般说来,HeapSize(A) <= Length(A),因为数组A当中可能有一些元素不在堆中。

假设节点I是数组A中下标为i的节点。

Parent(i) : return Floor(i/2); //I的父节点下标,Floor(i)表示比i小的最大整数。
Left(i) : return 2*i; //I的左子节点
Right(i) : return 2*i+1; //I的右子节点
含有n个元素的堆A的高度是: Floor(lgn)。

堆的基本操作
MaxHeapify( A, i ):
保持堆的性质。假设数组A和下标i,假定以Left(i)和Right(i)为根结点的左右两棵子树都已经是最大堆,节点i的值可能小于其子节点。调整节点i的位置。

BuildMaxHeap( A ):
从一个给定的数组建立最大堆。子数组A[ floor(n/2)+1 .... ... n]中的元素都是树的叶节点(完全二叉树的基本性质)。从索引 ceiling(n/2)开始一直到1,对每一个元素都执行MaxHeapify,最终得到一个最大堆。

堆排序 HeapSort( A ):
堆排序算法的基本思想是,将数组A创建为一个最大堆,然后交换堆的根(最大元素)和最后一个叶节点x,将x从堆中去掉形成新的堆A1,然后重复以上动作,直到堆中只有一个节点。

优先级队列算法-增加某元素的值(优先级) : HeapIncreaseKey( A, i, key )
增加某一个元素的优先级后(元素的值),该元素应该向上移动,才能保持堆的性质。

优先级队列算法-插入一个元素: Insert( S, x ) 将x元素插入到优先级队列S中。
主要思路是,将堆的最后一个叶节点之后,扩展一个为无穷小的新叶节点,然后增大它的值为x的值。

堆排序实现原理






堆排序的C语言实现
view sourceprint?01 #include <stdio.h> 

02 #include <stdlib.h> 

03   

04 void HeapSort(int num[],int size); 

05 void BuildHeap(int num[] ,int size); 

06 void PercolateDown(int num[] , int index,int size); 

07 void PrintHeap(const char* strMsg,int array[],int nLength);  

08 void Swap(int num[] , int v, int u); 

09   

10 int main(int argc, char *argv[]) 

11 { 

12   int data[13]={8,5,4,6,13,7,1,9,12,11,3,10,2}; 

13   HeapSort(data,13); 

14     

15   system("PAUSE");   

16   return 0; 

17 } 

18   

19   

20 void HeapSort(int num[] ,int size) 

21 { 

22     int i; 

23     int iLength=size; 

24       

25     PrintHeap("Befor Sort:",num,iLength); 

26       

27     BuildHeap(num,size);// 建立小顶堆    

28       

29     for (i = iLength - 1; i >= 1; i--) {    

30         Swap(num, 0, i);// 交换    

31         size--;// 每交换一次让规模减少一次    

32         PercolateDown(num, 0,size);// 将新的首元素下滤操作  

33         PrintHeap("Sort Heap:",num,iLength);   

34     } 

35 } 

36   

37 // 建堆方法,只需线性时间建好    

38 void BuildHeap(int num[] ,int size) {  

39     int i;  

40     for (i = size / 2 - 1; i >= 0; i--) {// 对前一半的节点(解释为“从最后一个非叶子节点开始,将每个父节点都调整为最小堆”更合理一些)    

41         PercolateDown(num, i,size);// 进行下滤操作 

42         PrintHeap("Build heap:",num,size); 

43     }    

44 } 

45       

46 // 对该数进行下滤操作,直到该数比左右节点都小就停止下滤    

47 void PercolateDown(int num[] , int index,int size) {    

48     int min;// 设置最小指向下标    

49     while (index * 2 + 1<size) {// 如果该数有左节点,则假设左节点最小    

50         min = index * 2 + 1;// 获取左节点的下标    

51         if (index * 2 + 2<size) {// 如果该数还有右节点    

52             if (num[min] > num[index * 2 + 2]) {// 就和左节点分出最小者    

53                 min = index * 2 + 2;// 此时右节点更小,则更新min的指向下标    

54             }    

55         }    

56         // 此时进行该数和最小者进行比较,    

57         if (num[index] < num[min]) {// 如果index最小,    

58             break;// 停止下滤操作    

59         } else {    

60             Swap(num, index, min);// 交换两个数,让大数往下沉    

61             index = min;// 更新index的指向    

62         }    

63     }// while    

64 } 

65       

66 // 给定数组交换两个数的位置    

67 void Swap(int num[] , int v, int u) {   

68     int temp = num[v];    

69     num[v] = num[u];    

70     num[u] = temp;    

71 }    

72   

73 void PrintHeap(const char* strMsg,int array[],int nLength) 

74 { 

75      int i; 

76      printf("%s",strMsg); 

77      for(i=0;i<nLength;i++) 

78      { 

79         printf("%d ",array[i]); 

80      } 

81      printf("\n"); 

82 }

下面也是C语言的实现,稍微改动了下:

view sourceprint?01 #include <stdio.h> 

02 #include <stdlib.h> 

03   

04 void HeapSort(int num[],int size); 

05 void BuildHeap(int num[] ,int size); 

06 void PercolateDown(int num[] , int index,int size); 

07 void PrintHeap(const char* strMsg,int array[],int nLength);  

08 void Swap(int num[] , int v, int u); 

09   

10 int main(int argc, char *argv[]) 

11 { 

12   /* 将数组看成完全二叉树的中序遍历结果的线性存储 */

13   int data[13]={8,5,4,6,13,7,2,9,12,11,3,10,1}; 

14   HeapSort(data,13); 

15     

16   system("PAUSE");     

17   return 0; 

18 } 

19   

20   

21 void HeapSort(int num[] ,int size) 

22 { 

23     int i; 

24     int iLength=size; 

25       

26     PrintHeap("Befor Sort:",num,iLength); 

27       

28     BuildHeap(num,size);// 建立小顶堆    

29       

30     for (i = iLength - 1; i >= 1; i--) {    

31         Swap(num, 0, i);// 交换    

32         size--;// 每交换一次让规模减少一次    

33         PercolateDown(num, 0,size);// 将新的首元素下滤操作  

34         PrintHeap("Sort Heap:",num,iLength);   

35     } 

36 } 

37   

38 /* 建堆方法,只需线性时间建好; 

39    建堆的结果:数组的第一个元素(即树根)是所有元素中的最小值,索引小于等于size/2-1的其它元素(即其它非叶子节点)的值都是其所在子树的最小值 */   

40 void BuildHeap(int num[] ,int size) {  

41     int i;  

42     //从最后一个非叶子节点开始,对每个非叶子节点进型最小根调整,保证每个根节点都是其子树中的最小值 

43     for (i = size / 2 - 1; i >= 0; i--) {    

44         PercolateDown(num, i,size);// 进行下滤操作 

45         PrintHeap("Build heap:",num,size); 

46     }    

47 } 

48       

49 /* 对该数进行下滤操作,直到该数比左右节点都小就停止下滤。 

50    即对某个根节点的值进行位置下降调整,使该值比其左右子节点都小; 

51    若该节点是叶子节点,则无法while循环 */

52 void PercolateDown(int num[] , int index,int size) {    

53     int min;// 设置最小指向下标    

54     while (index * 2 + 1<size) {// 如果该数有左节点,则假设左节点最小    

55         min = index * 2 + 1;// 获取左节点的下标    

56         if (index * 2 + 2<size) {// 如果该数还有右节点    

57             if (num[min] > num[index * 2 + 2]) {// 就和左节点分出最小者    

58                 min = index * 2 + 2;// 此时右节点更小,则更新min的指向下标    

59             }    

60         }    

61         // 此时进行该数和最小者进行比较,    

62         if (num[index] < num[min]) {// 如果index最小,    

63             break;// 停止下滤操作    

64         } else {    

65             Swap(num, index, min);// 交换两个数,让大数往下沉    

66             index = min;// 更新index的指向    

67         }    

68     }// while    

69 } 

70       

71 // 给定数组交换两个数的位置    

72 void Swap(int num[] , int v, int u) {   

73     int temp = num[v];    

74     num[v] = num[u];    

75     num[u] = temp;    

76 }    

77   

78 void PrintHeap(const char* strMsg,int array[],int nLength) 

79 { 

80      int i; 

81      printf("%s",strMsg); 

82      for(i=0;i<nLength;i++) 

83      { 

84         printf("%d ",array[i]); 

85      } 

86      printf("\n"); 

87 }
分享到:
评论

相关推荐

    C++语言的算法实现包括插入排序冒泡排序堆排序快速排序

    本文将深入探讨四种在C++中实现的常见排序算法:插入排序、冒泡排序、堆排序和快速排序。这些算法各有特点,适用于不同的场景,理解并掌握它们对于提升编程能力至关重要。 1. **插入排序**: 插入排序是一种简单的...

    堆排序算法原理

    其中,堆排序(Heap Sort)因其高效的性能和稳定性,在实际应用中占据了一席之地。本文将详细介绍堆排序的基本原理、实现步骤以及通过一个具体的例子来帮助读者理解这一算法。 #### 二、堆的概念 堆排序是基于堆的...

    基于C语言的堆排序算法(免费提供源码)

    本项目是一个基于C语言实现的堆排序(Heap Sort)算法,旨在帮助学习者理解和掌握这一高效的排序方法。堆排序是一种基于二叉堆数据结构的比较排序算法,具有时间复杂度为O(n log n)的优点。项目免费提供完整源码,...

    基数排序、堆排序、希尔排序、直接插入排序

    在`堆排序Heap_sort.cpp`中,你可以学习到如何维护堆的性质并进行相应的调整,如 sift-up 和 sift-down 操作,以实现排序。 希尔排序,又称缩小增量排序,是插入排序的一种更高效的改进版本。它通过将待排序的元素...

    MaxHeap堆排序建堆类

    **最大堆及其应用** 在计算机科学中,堆是一种特殊的树...理解和掌握堆排序及其相关算法对于学习数据结构和算法至关重要,因为它不仅在理论上有价值,也在实际应用中,如大数据处理、优先级调度等领域有着广泛的应用。

    快速排序、堆排序、归并排序、希尔排序实现

    在C++中,可以使用标准库中的`std::make_heap`、`std::push_heap`、`std::pop_heap`和`std::sort_heap`等函数来实现堆排序。 **归并排序(Merge Sort)** 归并排序同样采用分治策略。它将数组分为两个子数组,分别...

    学生成绩管理中实现堆排序

    C++作为一门强大的系统级编程语言,提供了标准模板库(STL),其中的`&lt;algorithm&gt;`头文件包含了各种排序算法,包括heap_sort()函数,可以直接用于堆排序。但在这个项目中,开发者可能选择手动实现堆排序,这样不仅...

    test_heap_sort.rar_heap

    虽然堆排序可以手动实现,但VC++提供了标准模板库(STL),其中`&lt;algorithm&gt;`头文件包含了一些排序算法如`std::make_heap`、`std::push_heap`、`std::pop_heap`和`std::sort_heap`,这些可以简化堆排序的实现。...

    8.12-8.19-冒泡-选择-插入-希尔-快速-归并-基数-堆排序-排序算法Swift代码及UI演示

    8. 堆排序(Heap Sort):堆排序利用了堆这种数据结构,构建一个大顶堆或小顶堆,然后将堆顶元素与末尾元素交换,调整堆,再将末尾元素移除,重复这个过程。时间复杂度为O(n log n)。 这些排序算法的Swift实现提供...

    c++堆排序算法

    C++中实现堆排序,我们可以利用标准库中的`&lt;algorithm&gt;`头文件中的`make_heap`,`push_heap`,`pop_heap`和`sort_heap`等函数,或者直接编写自定义的堆操作函数。下面是一个简单的C++堆排序的实现示例: ```cpp #...

    Python3实现堆排序算法(源代码)

    ### Python3实现堆排序算法详解 ...通过对堆的基本特性和堆排序的具体实现方法的学习,可以帮助我们更好地理解和应用这一算法。此外,深入理解堆排序的原理还可以帮助我们在实际问题中更灵活地运用该算法。

    排序算法(堆排序,快速排序等等)

    首先,我们来讨论堆排序(Heap Sort)。堆排序是一种基于比较的排序算法,它利用了完全二叉树的特性构建最大(或最小)堆。在最大堆中,每个父节点的值都大于或等于其子节点;在最小堆中则相反。堆排序的过程分为两...

    CSort内排序算法

    6. **堆排序(Heap Sort)**: 堆排序利用了完全二叉树的特性,通过构建最大堆(或最小堆)来进行排序。其时间复杂度为O(n log n),并且是原地排序,不需要额外空间。 7. **计数排序(Counting Sort)**: 计数...

    最小堆排序

    在C++实现中,可以使用标准库中的`&lt;algorithm&gt;`头文件,特别是`make_heap()`、`push_heap()`、`pop_heap()`和`sort_heap()`这些函数来简化最小堆排序的过程。但是,为了更好地理解和控制堆的操作,自定义一个堆类...

    堆排序的学习示例

    堆排序是一种基于比较的排序算法,它...总的来说,堆排序是一种重要的排序算法,理解其工作原理和实现细节对于深入学习数据结构和算法大有裨益。通过实践,你可以更好地掌握这种排序方法,并能在适当的场景中灵活运用。

    堆排序

    这个项目可能包含一个主文件(如`main.c`)和一个包含堆排序函数的头文件(如`heap_sort.h`)。 总的来说,堆排序是一种重要的排序算法,通过理解和掌握其原理,我们可以更好地理解和设计高效的排序算法,这对于...

    Java ArrayList实现的快排,归并排序,堆排序

    在Java编程中,排序是数据处理的一个重要...以上就是关于使用ArrayList实现快速排序、归并排序和堆排序的详细解析,这些排序算法是数据结构和算法学习中的经典内容,理解和掌握它们对于提升编程能力有着重要的作用。

    堆排序代码(C++)

    在C++中,我们可以使用标准库中的`&lt;algorithm&gt;`头文件中的`make_heap()`、`pop_heap()`和`sort_heap()`函数来实现堆排序。这些函数可以帮助我们快速构建、调整和处理堆。 下面是一个简化的C++堆排序代码示例: ```...

    各种排序算法大全排序 各种排序算法大全

    6. 堆排序(Heap Sort):堆排序利用了堆这种数据结构。将待排序的序列构造成一个大顶堆或小顶堆,然后将堆顶元素与末尾元素交换,调整堆,重复此过程。堆排序的时间复杂度为O(n log n),原地排序,但不稳定。 7. ...

    java版冒泡排序,插入排序,堆排序,快速排序,归并排序,希尔排序,桶排序

    3. **堆排序(Heap Sort)**: 堆排序利用了二叉堆的特性,将待排序的序列构造成一个大顶堆或小顶堆,然后将堆顶元素与末尾元素交换,再调整剩余元素成为新的堆,如此反复。Java中可以使用`PriorityQueue`类实现堆...

Global site tag (gtag.js) - Google Analytics