编程珠玑: 14章 堆 14.1实现一个堆,对数组排序 -------解题总结

来源:互联网 发布:诸暨行知小学校园网 编辑:程序博客网 时间:2024/06/07 04:03
#include <iostream>#include <stdio.h>#include <vector>using namespace std;/*问题:实现一个堆排序分析:堆,用数组表示的话:设数组x[1..n],则有根节点为x[1],孩子结点下标为2*i,2*i+1,父节点下标为i/2,大顶堆:任何结点的值>=其父节点的值采用小顶堆排序的步骤:1 步骤1:设置第一个元素为根节点,后续插入的结点放在已有结点后面,采用向上调整方法进行调整;2 步骤2:输出结果: 拷贝一个堆,然后输出拷贝堆中根节点元素,然后交换根节点元素和最末端元素,将除最末端元素以外部分重新         用向下调整方法调整为堆。         (或者采用队列,先输入根节点,后续弹出结点,输出结点,这样的话需要建立一个结构体对象:包含元素的值和元素的下标,   应该用队列,不能采用队列,因为可能一个孩子结点所在树的元素都小于另一个)输入:12(数组元素个数)19 51 26 40 35 22 17 23 29 15 20 12输出:12 15 17 19 20 22 23 26 29 35 40 51关键:1采用小顶堆排序的步骤:1】 步骤1:设置第一个元素为根节点,后续插入的结点放在已有结点后面,采用向上调整方法进行调整;2】 步骤2:输出结果: 拷贝一个堆,然后输出拷贝堆中根节点元素,然后交换根节点元素和最末端元素,将除最末端元素以外部分重新         用向下调整方法调整为堆。         (或者采用队列,先输入根节点,后续弹出结点,输出结点,这样的话需要建立一个结构体对象:包含元素的值和元素的下标,   应该用队列,不能采用队列,因为可能一个孩子结点所在树的元素都小于另一个)2 堆排序是选择排序,因为:每次都是选择一个最小的元素,次最小的元素,...(小堆顶的堆顶最小)。  选择排序:第i趟从后面n-i个元素中选取最小的元素作为有序子序列第i个元素3 不需要临时数组拷贝结果,直接在原始数组上操作//这边交换n-1趟就可使得数组有序for(int i = size  ; i >= 1 ; i--)//重复size长度次,否则会漏掉一个元素{//交换堆顶和最末端元素swap(results.at(i) , results.at(1));//最后面是最小元素//然后进行向下调整adjustDown(results , i - 1);//这里设定长度为当前长度减1,因为最后一个元素不要弄了}*/void swap(int* ptr1 , int* ptr2){int temp = *ptr1;*ptr1 = *ptr2;*ptr2 = temp;}/*向上调整,先确定数组最后一个元素下标i,然后寻找其父节点下标i/2,判断如果结点的值<父节点的值,就交换结点和父节点,并继续向上调整,直到满足堆的性质,或者当前结点已经变成根节点*/void adjustUp(vector<int>& datas){if(datas.empty()){return;}int i = datas.size() - 1;//由于第一个元素不做数,因此这里下标要减一int p;while(true){//如果当前结点为根节点,直接退出if(1 == i){break;}//寻找父节点下标p = i / 2;//如果结点 < 父节点的值,就交换,交换后,需要另当前结点下标变成其父节点下标if( datas.at(i) < datas.at(p) ){swap(datas.at(i) , datas.at(p));i = p;}//如果发现符合堆的性质,直接退出else{break;}}}//向下调整:从根节点往下,如果发现根节点大于两个孩子结点中的较小值,就交换根节点和两个孩子结点中的较小值,直到处理结点的下标大于数组长度或者符合堆的性质void adjustDown(vector<int>& datas , int size){if(datas.empty()){return;}int i = 1;int c;while(true){//如果处理结点下标 > 数组长度,直接退出if(i > size){break;}//如果发现:当前结点 > 两个孩子结点中的较大值c = 2 * i;//如果孩子结点下标 > 数组长度,无需处理,直接退出if(c > size){break;}//如果该结点还有右孩子结点if(c + 1 <= size){//如果右孩子 < 左孩子if( datas.at(c + 1) < datas.at(c)){c++;}}//如果结点 > 两个孩子结点中的较大值,交换两个结点,并使得当前结点为其孩子结点if( datas.at(i) > datas.at(c) ){swap(datas.at(i) , datas.at(c) );i = c;}else{break;}}}vector<int> heapSort(vector<int>& datas){vector<int> results;//存放最终的堆if(datas.empty()){return results;}int size = datas.size();results.push_back(-1);//首先是建堆,采用向上调整,注意向上调整完以后,不需要从根节点继续向下判断是否满足堆,此时一定满足for(int i = 0 ; i < size ; i++){int value = datas.at(i);results.push_back(value);//向上调整adjustUp(results);}//这边交换n-1趟就可使得数组有序for(int i = size  ; i >= 1 ; i--)//重复size长度次,否则会漏掉一个元素{//交换堆顶和最末端元素swap(results.at(i) , results.at(1));//最后面是最小元素//然后进行向下调整adjustDown(results , i - 1);//这里设定长度为当前长度减1,因为最后一个元素不要弄了}return results;}void print(vector<int> results){if(results.empty()){cout << "No result " << endl;}else{int size = results.size();for(int i = size ; i >= 1 ; i--)//第0个元素不需要输出{cout << results.at(i) << " ";}cout << endl;}}void process(){int num;vector<int> datas;int value;vector<int> results;while(cin >> num){datas.clear();for(int i = 0 ; i < num ; i++){cin >> value;datas.push_back(value);}//下面进行堆排序results = heapSort(datas);print(results);}}int main(int argc , char* argv[]){process();getchar();return 0;}

0 0
原创粉丝点击