赞
踩
目录
堆是一个完全二叉树
假设在这个堆中高度为K层,总节点数为N
那么由 2^K-1=N 得到 log(N+1)=K
在堆插入数据时使用
- //向上调整
- void AdjustUp(int* a, int child)//从孩子的位置向上调整
- {
- int parent = (child - 1) / 2;
-
- //请注意(-1)/2=0 所以不能用parent>=0作为判断方式
-
- while (child > 0)//child到0就不用交换了
- {
- if (a[parent] > a[child])
- {
- swap(&a[parent], &a[child]);
- child = parent;
- parent = (child - 1) / 2;
- }
- else
- {
- break;
- }
- }
- }
在堆删除数据的时候使用,本质是找出次大或者次小
前提是左右子树都需要同时是大堆或者小堆
- void AdjustDown(int* a, int size,int parent)//从父亲的位置向下调整
- {
- assert(a);
-
- int minchild = parent * 2 + 1;
- while (minchild < size)
- {
- if (minchild + 1 < size)
- {
- if (a[minchild] > a[minchild + 1])//找到较小的子节点
- {
- minchild = minchild + 1;
- }
- }
-
- if (a[parent] > a[minchild])//条件满足,和较小的子节点交换位置
- {
- swap_(&a[parent], &a[minchild]);
- parent = minchild;
- minchild = parent * 2 + 1;
- }
- else
- {
- break;
- }
- }
- }
前提:这个排序需要让数组本身有序。
如果直接使用实现的堆这个数据结构,空间复杂度为O(N)
建堆排序——————————————————
1.建堆排序不是对这个数组处理,是会在堆中会额外开辟一片空间,从这个数组中拿数据。
可以写一个循环每次拿一个。
2.然后在其中建好堆之后(请注意堆中的数据不是有序的),开始取堆顶的数据,取堆顶数据时,方法需要把堆顶数据和最后一个数据进行交换,取最后一个数据,然后对于现在的第一个元素利用向下调整算法,重新调整。
3.这样每次堆顶的数据都是比较前一个次小或者次大的,需要这样依次取出按顺序放入原先数组中,才能完成排序。
堆排序——————————————————
实际当中堆排序,会传一个数组给这个排序函数,不会额外开辟一片空间。
void HeapSort(int* a, int n);
把这个数组本身转化成一个堆,利用堆的性质进行排序。
1.向下调整建堆O(N)————————————
向下调整有前提,必须左右子树都是小堆或者大堆才可以。可以从倒数第一个非叶节点(就是最后一个节点的父节点),开始向下调整建堆。
根据父节点的下标关系,调整完一个后下标--,找到前一个父节点,继续进行向下调整,以此类推。
如下所示:
- //建堆 向下调整
- for (parent = (n - 1 - 1) / 2; parent >= 0; parent--)
- {
- AdjustDown_(a, n, parent);
- }
2.向上调整建堆O(N*logN)———————————
利用直接插入的思想,模拟插入过程进行尾插+向上调整。
- int child = 0;
- for (child = 0; child < n; child++)
- {
- AdjustUp(a, child);
- }
堆排序本质是一种选择排序,找到最大的元素之后要考虑如何选次小的元素。
堆排序时要利用堆排序本身的优势,它的父子节点的关系。
以降序为例:
1.建小堆
2.第一个和最后一个元素进行位置交换,把最后一个元素不看做堆中的元素向下调整,选出次小的,以此类推
- //以排降序为例
- //交换位置,最小放最后,然后向下调整变成小根堆
- for (int i = 0; i < n; i++)
- {
- int last = n -1 - i;
- swap(&a[0], &a[last]);//交换第一个元素和最后一个元素
- AdjustDown(a, last, 0);//向下调整
- }
- #include<stdio.h>
- #include<assert.h>
- //交换
- void swap_(int* a, int* b)
- {
- int tmp = 0;
- tmp = *a;
- *a = *b;
- *b = tmp;
- }
-
- void AdjustDown_(int* a, int size,int parent)//从孩子的位置向下调整
- {
- assert(a);
-
- int minchild = parent * 2 + 1;
- while (minchild < size)
- {
- if (minchild + 1 < size)
- {
- if (a[minchild] > a[minchild + 1])//找到较小的子节点
- {
- minchild = minchild + 1;
- }
- }
-
- if (a[parent] > a[minchild])//条件满足,和较小的子节点交换位置
- {
- swap_(&a[parent], &a[minchild]);
- parent = minchild;
- minchild = parent * 2 + 1;
- }
- else
- {
- break;
- }
- }
- }
-
-
- // 对数组进行堆排序
- void HeapSort(int* a, int n)
- {
- //向下调整排序
-
- //排降序,小根堆
- int parent = 0;
-
- //建堆 向下调整
- for (parent = (n - 1 - 1) / 2; parent >= 0; parent--)
- {
- AdjustDown_(a, n, parent);
- }
-
-
- //交换位置,最小放最后,然后向下调整变成小根堆
- for (int i = 0; i < n; i++)
- {
- int last = n -1 - i;
- swap_(&a[0], &a[last]);
- AdjustDown_(a, last, 0);
- }
- }
-
以满二叉树的结构来计算
4.1.向下调整建堆 O(N)
4.2.向上调整建堆 O(N*logN)
你好,这里是媛仔与难搞的堆排序……整理下来感觉还是对于堆排序不够熟练,还是要多多练习啊。希望这篇文章对你能够有所帮助,也欢迎和我多多交流!!我们下一篇见~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。