堆排序

  堆排序是一种不管最佳情况还是最糟情况,时间复杂度都是O(NlogN)的一种排序算法。

  这种算法将目标源数组抽象化成一个堆(heap),并且根据增序降序的要求再分别转化为大顶堆和小顶堆。

  是一种数据结构,可以看成一种近似的完全二叉树,只不过该二叉树必须满足左侧填充。而大顶堆的特性则是父节点必须大于等于孩子节点,也就是说大顶堆的根节点必须是当前数据中数值最大的元素。

堆排序

  上图a就是一个大顶堆。

  堆还有一个特性就是索引值与堆节点位置的互相对应。例如图a,堆中的最后一个父节点肯定是堆中节点数量 / 2(数组中的索引值就是末尾元素索引值 / 2)。

  所以,为了进行排序,我们初始化大顶堆后每次循环需要做的步骤有以下几个:

  1.将首元素与末尾元素(当前容量的末尾而不是数组的末尾)交换

  2.将堆的容量减1

  3.维护交换后的根节点,保证交换后的堆仍是大顶堆

  4.回到1,终止条件为容量为1

  这样每次都会把数组中的最大元素提取出来放到末尾,做到一个递增的效果。

  

  首先是维护大顶堆

 1 /// <summary>
 2 /// 自顶向下维护堆为大顶堆
 3 /// </summary>
 4 /// <param name="nums">数据</param>
 5 /// <param name="n">要从第n个数据开始自顶向下维护</param>
 6 /// <param name="size">目前大顶堆的容量</param>
 7 void keepMaxHeap(vector<int>& nums, int n, int size) {
 8     int left = 2 * n + 1, right = 2 * n + 2;        //当前节点的左右孩子
 9     int maxIndex = 0;                                //找出左右孩子谁的数值更大        
10     if (left <= size && nums[n] <= nums[left]) {
11         maxIndex = left;
12     }else {
13         maxIndex = n;
14     }
15     if (right <= size && nums[maxIndex] <= nums[right]) {
16         maxIndex = right;
17     }
18 
19     //如果最大节点不是本身,则自身数值和最大数值孩子交换数值
20     if (maxIndex != n) {
21         int temp = nums[n];
22         nums[n] = nums[maxIndex];
23         nums[maxIndex] = temp;
24         keepMaxHeap(nums, maxIndex, size);            //顺着刚才交换的节点继续维护
25     }
26 }

  初始化大顶堆

 1 /// <summary>
 2 /// 构造大顶堆(初始化)
 3 /// </summary>
 4 /// <param name="nums">数据</param>
 5 void buildMaxHeap(vector<int>& nums) {
 6     //数组的中间元素为最后一个有叶子节点的父节点
 7     for (int i = (nums.size() - 1) / 2; i >= 0; i--) {
 8         keepMaxHeap(nums, i, nums.size() - 1);
 9     }
10 }

  最终排序函数

 1 /// <summary>
 2 /// 堆排序
 3 /// </summary>
 4 /// <param name="nums">数据</param>
 5 void heapSort(vector<int>& nums) {
 6     buildMaxHeap(nums);            //先初始化大顶堆
 7     int count = 0;
 8     //当完成第二个元素的交换后,就没元素可以交换了
 9     for (int i = nums.size() - 1; i >= 1; i--) {
10         int temp = nums[i];        //交换首尾元素
11         nums[i] = nums[0];
12         nums[0] = temp;
13         count++;
14 
15         //每将大顶堆的首元素(最大元素)放到后面后,就将容量减1
16         //交换后维护根节点,保证更新后的堆仍为大顶堆
17         keepMaxHeap(nums, 0, nums.size() - 1 - count);
18     } 
19 }

 

堆排序

上一篇:bash字符串操作


下一篇:Ansible部署K8s集群