首页 > 代码库 > 堆排序

堆排序

 1 #include <iostream>
 2 using namespace std;
 3 
 4 /*
 5     三个函数的内部实现中,大多数定义的变量表示的是 数组的下标, 注意区分!!
 6 */
 7 void max_heapify(int *, int, int);            // 调整最大堆    数组 组长 当前操作的下标(对应的就是当前操作的值)
 8 void build_max_heap(int *, int len);        // 创建最大堆    数组 组长
 9 void heapSort(int *, int len);                // 堆排序        数组 组长
10 
11 int main() {
12 
13     int Array[10] = { 4, 8, 6, 20, 7, 14, 22, 5, 32, 40 };
14     heapSort(Array, 10);
15     for (int i = 0; i < 10; ++i) {
16         cout << Array[i] << " ";
17     }
18 
19     system("pause");
20     return 0;
21 }
22 
23 /* 
24     该函数:完成以某个结点为最大堆,即父节点大于左右孩子结点,且左右孩子也满足于最大堆的特点
25 */
26 void max_heapify(int Array[], int len, int eIndex) {        
27     int left = 2 * eIndex + 1;        // 当前构成的二叉树顺序存储中当前结点(父结点)所对应的 左孩子, 即数组中对应的下标
28     int right = 2 * eIndex + 2;        // 所对应的 右孩子下标
29     int max_Index = eIndex;            // 保存最大父亲结点和两个孩子结点中最大值的下标
30     // 以下两个 if 中的 第一个逻辑判断目的:避免某个结点中没有左或右孩子,导致 后者逻辑判断中 数组下标越界!
31     if(left < len && Array[left] > Array[eIndex]) {
32         max_Index = left;            // 左孩子 比 父结点大,就保存最大的左孩子所在的数组的下标
33     }
34     if(right < len && Array[right] > Array[max_Index]) {
35         max_Index = right;            // 右孩子 比 父结点大,就保存最大的右孩子所在的数组的下标
36     }
37     if(max_Index != eIndex) {        // 如果不成立,表示父亲结点都比两个孩子结点的值要大,表示已经满足了最大堆的要求,否则就要进行递归去解决可能由于调整而产生某个结点破坏了最大堆的要求
38         int exchange = Array[eIndex];        // 执行这步表示父结点不是最大的,所以将 最大值下标的max_Index所对应的数值于当前元素交换值
39         Array[eIndex] = Array[max_Index];    
40         Array[max_Index] = exchange;
41         max_heapify(Array, len, max_Index);    // 将max_Index所在的下标元素和父结点相交换,父结点满足了最大堆,但是原来max_Index所在下标的值发生了变化,可能导致变化的值不满足最大堆(若原来的值为 10,左右为 7 3,变化值为 5,将变化的值视为父结点,那么左孩子比它大) 
42     }
43 }
44 /*
45     该函数:将一个数组,构建成一个最大堆
46 */
47 void biuld_heap(int Array[], int len) {
48     int mIndex = len / 2 - 1;
49 /*
50     mIndex: 根据二叉树的性质,K层上的结点数量为 2的K次方, K-1层是 2的K-1次方,故 len / 2所在下标(向下取整) 表示 K-1层上的最后一个根结点
51             剩下的全是 叶子结点, 可以看作: 子数组 Array[ mIndex+1 .... len-1]中的元素都是树的叶结点,每一个叶子结点都可看作只包含了一个元素的堆
52             对于已经是堆的元素,就不用再去调用 max_heapify() 函数取调整最大堆,所以 从 最后一个根结点一直调整 到 "顶根"结点 完成最大堆的创建
53 */
54     for (int i = mIndex; i >= 0; --i) {
55         max_heapify(Array, len, i);
56     }
57 }
58 /*
59     堆排序:首先第一步就是将数组中的元素构建成最大堆
60             其次根据最大堆的特点,数组中的第一个元素存放的就是 无序数列 中的最大值,将 Array[0] 与 无序数列中最后一个位置的元素进行交换(此时导致第一个元素不再是最大值)    
61             然后 将交换位置导致破坏最大堆的 数组,再一次 调用 max_heapify(),使之再次成为 最大堆,此时数组的第一个元素又是 无序数列 的最大值
62 */
63 void heapSort(int Array[], int len) {
64     biuld_heap(Array, len);        // 构建最大堆
65     int nSortSize = len;        // 无序数列的长度
66     int exchange;                // 作为变量,交换两值得桥梁
67     for (int i = len - 1; i > 0; --i) {
68         exchange = Array[0];
69         Array[0] = Array[i];
70         Array[i] = exchange;
71         nSortSize--;            // 交换了一个数值,表示对一个数排好了序,无序数列中的个数少一 (将排好序的值放入数组末尾,在下面函数的调整最大堆的时候将不会操作 已排好序的数,因为 nSortSize所对应的下标 + 1才是排好序的第一个元素的下标)
72         max_heapify(Array, nSortSize, 0);    // 已交换根结点,除根结点以外,其余的都满足最大堆,所以将 0 传递给第三个参数 eIndex(操作下标为eIndex的结点,使其满足最大堆)
73     }
74 }

 

堆排序