堆排序
来源:互联网 发布:模拟短信发送 java 编辑:程序博客网 时间:2024/06/18 04:04
自己写的程序实现:
值得注意的是:HeapAdust这个函数里面s为最中间的时候,他只有一个子节点的情况 那么 j+1造成数组越界,
因此一定要限制 j<m的情况下比较j和 j+1 也就是如果j=m 则 j就是本身了 不用跟j+1 比较
第二点: 数组的下标从零开始的,因此HeapSort ,最中间的那个s = n/2-1 子节点为 2*s+1 h 2*s + 2,而且最后一个节点不用再比较了
#include <iostream>#include <time.h>#include <string.h>#include <stdlib.h>using namespace std;void HeapSort ( int *a,int n);void HeapAdjust( int *a,int s, int m);void printArray(int (&a)[10]){ for(int i =0; i<10; i++) { cout<< a[i]<<" "; }}void swap( int &a, int &b){ int temp = a; a = b; b = temp;}int main(){ while(true) { system("cls"); time_t t; srand( (unsigned) time(&t)); int a[10] = {0}; for(int i = 0;i<10;i++) { a[i] = rand() % 11; } printArray(a); HeapSort(a,10); cout<<endl; printArray(a); cin.get(); } return 0;}void HeapAdjust( int *a,int s, int m){ for(int j=s * 2+1; j<=m; j = j*2+1) { //迭代的把当时这个元素赋值给一个临时的变量 //如果比子节点那个大的还小就交换两个值 //然后把新的那个值当成a[s]再循环 int temp = a[s]; //当 if(j<m&&(a[j]<a[j+1])) j++; if(temp > a[j]) break; if(temp < a[j]) { a[s] = a[j]; s=j; a[j] = temp; } }}void HeapSort ( int *a, int n){ for(int i = n/2 -1;i>=0;i--) { HeapAdjust(a,i,n-1); } for(int j = n-1;j>0;j--) { swap(a[0],a[j]); //当只有两个节点情况下,直接交换就好了,不需要再调整,否则浪费时间,直接跳出循环 if(j==1) break; //把第一个预案算a[0]每次最后一个a[j]交换以后,最后一个就不用比较了,因此j-1 HeapAdjust(a,0,j-1); }}
最近面试,老是被问到堆排序算法。
回答时老是感觉思路不清楚,现在总结一下,把思路弄清楚的。
1.堆排序是利用堆的特性对记录序列进行排序的一种排序方法。
好的那么堆得特性是什么呢?
堆得定义:
好的那么堆得特性是什么呢?
堆得定义:
堆是满足下列性质的数列{r1, r2, …,rn}:
![](http://hi.csdn.net/attachment/201109/22/0_1316660169VUBb.gif)
如下图最开始是一个小顶堆。当把97和13 交换后不是堆了,所以我们要调整根节点使之成为堆即筛选。(注意:是自堆顶到叶子的筛选过程,应该刚开始是堆由于把堆顶给换了,罪魁祸首是堆顶,其它小范围还是堆,所以是从堆顶开始)。
![](http://hi.csdn.net/attachment/201109/22/0_1316660397mmZ5.gif)
这其中还要注意一点。97 与13 交换后应该跟27 比较为什么呢?
1.因为是小顶堆,所以在97 的子节点里选择小者。如果把38放上去。38成了27的父节点比27大就不是小顶堆了。如果换成大顶堆就要比较把大的数据放上去。
所以程序里交换时要先要比较一下。
程序如下:
- //堆调整算法
- void HeapAdjust (HeapType &H, int s, int m)
- { // 已知 H.r[s..m]中记录的关键字除 H.r[s] 之外
- //均满足堆的特征,本函数自上而下调整 H.r[s]
- //的关键字,使 H.r[s..m] 也成为一个大顶堆
- rc = H.r[s]; // 暂存 H.r[s]
- for ( j=2*s; j<=m; j*=2 ) { // j 初值指向左孩子
- 自上而下的筛选过程;
- }
- // 自上而下的筛选过程
- if ( j<m && H.r[j].key>H.r[j+1].key ) ++j;
- // 左/右“子树根”之间先进行相互比较
- // 令 j 指示关键字较小记录的位置
- if ( rc.key <= H.r[j].key ) break;
- // 再作“根”和“子树根”之间的比较,
- // 若“>=”成立,则说明已找到 rc 的插
- // 入位置 s ,不需要继续往下调整
- H.r[s] = H.r[j]; s = j;
- // 否则记录上移,尚需继续往下调整
- H.r[s] = rc; // 将调整前的堆顶记录插入到 s (注意插入的位置为s j=2*s)
- } // HeapAdjust
//堆调整算法void HeapAdjust (HeapType &H, int s, int m){ // 已知 H.r[s..m]中记录的关键字除 H.r[s] 之外 //均满足堆的特征,本函数自上而下调整 H.r[s] //的关键字,使 H.r[s..m] 也成为一个大顶堆 rc = H.r[s]; // 暂存 H.r[s] for ( j=2*s; j<=m; j*=2 ) { // j 初值指向左孩子 自上而下的筛选过程; } // 自上而下的筛选过程 if ( j<m && H.r[j].key>H.r[j+1].key ) ++j; // 左/右“子树根”之间先进行相互比较 // 令 j 指示关键字较小记录的位置 if ( rc.key <= H.r[j].key ) break; // 再作“根”和“子树根”之间的比较, // 若“>=”成立,则说明已找到 rc 的插 // 入位置 s ,不需要继续往下调整 H.r[s] = H.r[j]; s = j; // 否则记录上移,尚需继续往下调整 H.r[s] = rc; // 将调整前的堆顶记录插入到 s (注意插入的位置为s j=2*s)} // HeapAdjust
2)建堆是一个从下往上进行“筛选”的过程 (首先要把底部的建成小堆,前面调整是因为只有堆顶,其它都已经是堆了。当我建堆到堆顶是也是从堆顶往下筛选)(所以说建堆大范围是从下往上筛选,在添加该结点时,还得从该节点往下筛选确保添加该节点后还是堆)。
如下图建堆过程: 从97 开始->65->38 ->49这是从下往上(大范围从下往上)。第二个图到65时又 65与13 调整了(从上往下调整)。当到49时也是49<-> 13 <-> 27所以也是从上之下调整(为了确保加入该结点后还是堆)。
![](http://hi.csdn.net/attachment/201109/22/0_1316662317U3FN.gif)
程序如下:
堆排序算法如下:
note: 堆排序算法以前看过几遍老是忘,问得时候思路不太清晰。只要把关键几个点弄清楚,把思路搞清楚了以后就不怕了。
如下图建堆过程: 从97 开始->65->38 ->49这是从下往上(大范围从下往上)。第二个图到65时又 65与13 调整了(从上往下调整)。当到49时也是49<-> 13 <-> 27所以也是从上之下调整(为了确保加入该结点后还是堆)。
![](http://hi.csdn.net/attachment/201109/22/0_1316662317U3FN.gif)
程序如下:
堆排序算法如下:
- void HeapSort ( HeapType &H ) {
- // 对顺序表 H 进行堆排序
- for ( i=H.length/2; i>0; --i )
- HeapAdjust ( H.r, i, H.length ); // 建小顶堆
- for ( i=H.length; i>1; --i ) {
- H.r[1]←→H.r[i];
- // 将堆顶记录和当前未经排序子序列
- // H.r[1..i]中最后一个记录相互交换
- HeapAdjust(H.r, 1, i-1); // 对 H.r[1] 进行筛选
- }
- } // HeapSort
void HeapSort ( HeapType &H ) { // 对顺序表 H 进行堆排序for ( i=H.length/2; i>0; --i ) HeapAdjust ( H.r, i, H.length ); // 建小顶堆for ( i=H.length; i>1; --i ) { H.r[1]←→H.r[i]; // 将堆顶记录和当前未经排序子序列 // H.r[1..i]中最后一个记录相互交换 HeapAdjust(H.r, 1, i-1); // 对 H.r[1] 进行筛选}} // HeapSort
note: 堆排序算法以前看过几遍老是忘,问得时候思路不太清晰。只要把关键几个点弄清楚,把思路搞清楚了以后就不怕了。
- 堆及堆排序
- 堆/堆排序特点
- 【二叉堆、堆排序】
- 二叉堆 & 堆排序
- 二叉堆 & 堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆和堆排序
- 堆排序(最大堆)
- 堆和堆排序
- 堆和堆排序
- 堆及堆排序
- 堆和堆排序
- 堆与堆排序
- java快捷键个人总结
- 加解密算法定位,还原,密钥寻找
- 黑马程序员--java网络编程
- 25个Vim教程、视频和资源
- [资源分享]Linode免费使用 [ 资源分享 ]
- 堆排序
- 黑马程序员--java反射
- [资源分享]Linode主机控制台介绍(篇一) [ 资源分享 ]
- Hdu 1233 - 还是通畅工程
- [资源分享]Linode主机控制台介绍(篇二) [ 资源分享 ]
- hdu1026 BFS+记录路径
- [Windows] Windows 2003 安装终端服务 [ 技术分享 ]
- 三节点RAC 调优前后比对(续)
- main already defined in *.obj 解决方法