当前位置:   article > 正文

[算法导论]堆排序_csdn chenhaojing

csdn chenhaojing
1: 如图所示,(二叉)堆是一个 数组,它可以被看成一个近似的 完全二叉树
表示堆的数组A有两个属性:
A.length 给出数组元素个数
A.heap-size 表示有多少个堆元素存储在该数组中
也就是说 A[1..length]可能都存放有数据,但只有A[1..A.heap-size]中存放的是堆的有效元素。

这里 0 <= A.heap-size <= A.length




2. 树的根节点是A[i],这样给定一个结点的下标i,我们很容易计算得到它的父结点、左孩子、右孩子的下标
  1. PARENT(i)
  2. return i/2;
  3. LEFT(i)
  4. return 2*i;
  5. RIGHT(i)
  6. return 2*i+1;
(可用 宏定义实现)


3. 二叉堆有两种形式: 最大堆和最小堆
最大堆: 除根结点外,所有的结点 i 都要满足:
A[PARENT[i]] >= A[i]
最小堆: 除根结点外,所有结点 i 都要满足:
A[PARENT(i)] <= A[i]

4. 维护堆的性质( 以最大堆为例
MAX_HEAPIFY 是用于维护最大堆性质的重要过程。它输入为一个数组A和一个下标i。

在调用 MAX_HEAPIFY 的时候,我们假定根结点为 LEFT(i) 和 RIGHT(i) 的二叉树都是最大堆(这个是必须的假设。也就是说,在调整堆的某个结点 i 时,

必须保证 结点 i 的孩子结点都满足最大堆性质)

  1. MAX_HEAPIFY(A,i)
  2. l = LEFT(i); //获得左孩子结点
  3. r = RIGHT(A,i); //获得右孩子结点
  4. if l<=A.heap-size and A[l]>A[i] // 如果做孩子结点是堆元素,并且左孩子结点的关键值大于父结点的关键值
  5. largest = l; //记录结点关键字最大的下标
  6. else largest = i;
  7. if r<=A.heap-size and A[r] > A[largest]
  8. largest = r;
  9. if largest ≠ i
  10. exchange A[i] width A[largest]
  11. MAX_HEAPIFY(A,largest) // 调整堆



5.  建堆
我们用自顶向上的方法利用过程 MAX_HEAPIFY 把一个大小为 A.length 的数组 A[1..n] 装换为最大堆
首先,从完全二叉树的性质可知, 子数组[n/2 + 1, ...n] 都是树的叶结点。每个叶结点可以看成是一个
堆元素,由于它们没有孩子结点,它们自然满足最大堆的性质。
所以,需要我们处理的是 子数组[1...n/2] 这些非叶结点。

算法如下:
  1. BUILD_MAX_HEAP(A)
  2. A.heap-size = A.length
  3. for i = [A.length/2] downto 1
  4. MAX_HEAPIFY(A,i);



6.  堆排序算法
初始时候,堆排序算法利用 BUILD_MAX_HEAP 将输入数组 A[1...n]建成最大堆,其中 n  = A.length.
因为数组中的最大元素总在根结点A[1]中,通过把它与A[n]进行互换,我们可以让该元素放到正确的
位置。这时候,如果我们从堆中去掉结点n(这操作可以通过减少A.heap-size的值来实现),剩余的
结点中,原来的根的孩子仍然是最大堆,而新结点可能会违背最大堆的性质。为了维护最大堆的性质,
我们要做的是调用 MAX_HEAPIFY(A,1),从而在A[1...n-1] 上构造一个新的最大堆。
堆排序会 不断重复这个过程,直到堆的大小从 n-1 降到2
  1. HEAPSORT(A)
  2. BUILD_MAX_HEAP(A) // 建堆
  3. for i = A.length downto 2
  4. exchange A[1] with A[i]
  5. A.heap-size = A.heap-size - 1;
  6. MAX_HEAPIFY(A,1)




优先队列
优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中每一个元素都有一个相关的值,称为关键字。
一个最大优先队列支持一下操作:
INSERT(S,x): 把元素X插入集合S中。这一操作等价于S=SU{X}。
MAXIMUM(S) : 返回S中具有最大关键字的元素
EXTRACT_MAX(S): 去掉并返回S中的具有最大关键字的元素。
INCREASE_KEY(S,x,k): 将元素X的关键字值增加到k,这里假设k的值不小于x的原关键字



  1. EXTRACT_MAX(S)
  2. if A.heap-size < 1
  3. error "heap underflow"
  4. max = A[1]
  5. A[1] = A[A.heap-size]
  6. A.heap-size = A.heap-size - 1
  7. MAX_HEAPIFY(A,1)
  8. return max
  9. INCREASE_KEY(S,x,k)
  10. if key < A[i]
  11. error "new key is smaller than current key"
  12. A[i] = key
  13. while i > 1 and A[PARENT(i)] < A[i]
  14. exchange A[i] with A[PARENT(i)]
  15. i = PARENT(i);
  16. INSERT(S,x)
  17. A.heap-size = A.heap-size + 1;
  18. A[A.heap-size] = -无穷
  19. INCREASE_KEY(S,A.heap-size,x)



代码实现(不包括)

  1. #include "iostream"
  2. #define PARENT(i) (i/2)
  3. #define LEFT(i) (2*i)
  4. #define RIGHT(i) (2*i+1)
  5. #define Heapswap(a,b) (a = a+b, b=a-b, a= a-b)
  6. struct Heap {
  7. int A[256] = {0}; // 0位不要,下标从1开始
  8. unsigned length = 0; // 数组有效位数
  9. unsigned heapSize = 0; // 堆元素
  10. unsigned const MaxSize = 256; //数组容量
  11. };
  12. void InitialHeap(Heap& hp, int A[], int Arrlength, int HeapLength);//初始化堆
  13. void Print(Heap hp); // 打印 堆元素
  14. void MaxHeapify( Heap &hp, int i); // 维护堆的性质
  15. void BuildMaxHeap(Heap &hp); // 建堆
  16. void HeapSort(Heap &hp); // 堆排序算法
  17. int main(void)
  18. {
  19. #if 1 //测试
  20. Heap hp;
  21. int A[] = {9,10,18,1,12,6,9,11,13,2};
  22. //初始化
  23. InitialHeap(hp, A, 10, 0);
  24. //建堆
  25. BuildMaxHeap(hp);
  26. //输出数据
  27. Print(hp);
  28. std::cout << std::endl;
  29. //堆排序
  30. HeapSort(hp);
  31. for (size_t i = 1; i <= hp.length; i++)
  32. {
  33. std::cout << hp.A[i] << " ";
  34. }
  35. std::cout << std::endl;
  36. system("pause");
  37. #endif
  38. return 0;
  39. }
  40. void InitialHeap(Heap & hp, int A[], int Arrlength, int HeapLength)
  41. {
  42. for (int i = 0; i < Arrlength; i++)
  43. hp.A[i+1] = A[i];
  44. hp.length = Arrlength;
  45. hp.heapSize = HeapLength;
  46. }
  47. void Print(Heap hp)
  48. {
  49. for (size_t i = 1; i <= hp.heapSize; i++)
  50. {
  51. std::cout << hp.A[i] << " ";
  52. }
  53. }
  54. void MaxHeapify(Heap &hp, int i)
  55. {
  56. int left = LEFT(i);
  57. int right = RIGHT(i);
  58. int largest = -1;
  59. // 是堆元素并且是孩子结点大于父子结点
  60. if (left <= hp.heapSize && hp.A[left] > hp.A[i])
  61. largest = left;
  62. else
  63. largest = i;
  64. if (right <= hp.heapSize && hp.A[right] > hp.A[largest])
  65. largest = right;
  66. if (largest != i)
  67. {
  68. Heapswap(hp.A[largest], hp.A[i]);
  69. MaxHeapify(hp, largest);
  70. }
  71. }
  72. void BuildMaxHeap(Heap &hp)
  73. {
  74. hp.heapSize = hp.length;
  75. for (int i = hp.length / 2; i >= 1; i--)
  76. MaxHeapify(hp, i);
  77. }
  78. void HeapSort(Heap & hp)
  79. {
  80. BuildMaxHeap(hp); //建堆
  81. for (int i = hp.length; i >= 2; i--)
  82. {
  83. Heapswap(hp.A[1], hp.A[i]);
  84. hp.heapSize = hp.heapSize - 1;
  85. MaxHeapify(hp, 1);
  86. }
  87. }








声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/943792
推荐阅读
相关标签
  

闽ICP备14008679号