优先队列 之 堆排序实现(堆排序思想)
2014-09-18 19:24
239 查看
/*
1、接上一篇文章,优先队列 之 插入排序 这里是用到了堆排序的思想,而非完全的堆排序的步骤;正如二分思想,他是一种思想,不要
停留在一种方法上、一种数据结构上。
2、poj 2833,因为优先队列是由最小(大)堆实现的,时间复杂度O(n*logn)----正好服务优先队列的要求,保证队首(栈顶)
元素的优先级最高,其他元素的优先级顺序不考虑。
3、数据结构和算法的完美结合,第一次尝试到了两者合力是如此的完美,正如优先队列用到了:
(1):元素出队列,相当于栈顶和最后一个元素交换后,向下调整的过程;(2):元素入队列,相当于向队尾增加一个元素,向上调整的过程。
4、下面并未体现出优先级的顺序,而是用数字的大校表示优先级,当然可以建立一个结构体struct { weight key },再加上一个template<class T>写成模板类
*/
改进之后的swap()函数,异或的好处,以及 位移 之 右移 >>(相当于除以2) 左移 << ( 相当于乘以2 )。
void my_swap(int &a, int &b)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
/*
基本函数说明及复杂度分析如下:
heap_down_adjust() 从第一个不满足堆的结点s开始向下做调整,使得维护一个堆,删除栈顶元素或者建立初始堆。
--------log(n)
heap_up_adjust() 从最后一个结点s开始向上做调整,使得维护一个堆,插入新元素的过程。
--------log(n)
en_heap_queue() 从尾部增加一个叶子节点到堆中,因为原本是满足堆的,所以只需要从下至上不断跟父结点进行交换,直至已满足堆退出,调用的heap_up_adjust()
--------log(n)
de_heap_queue() 把start跟end做交换,然后[start,end-1]从新做一次调整,使得[start,end-1]维护成一个堆,堆大小length随之-1,调用的heap_down_adjust() 。
--------log(n)
heap_init() 从第一个非终端结点开始->根节点不断做heap_adjust(),使之构成一个初始堆。
--------n / 2 * log(n)
heap_sort() 相当于重复n次de_heap_queue()操作,但length不改变。
--------n * log(n)
用类模板实现,参照 :http://www.cnblogs.com/slave_wc/archive/2010/12/23/1915293.html
*/
1、接上一篇文章,优先队列 之 插入排序 这里是用到了堆排序的思想,而非完全的堆排序的步骤;正如二分思想,他是一种思想,不要
停留在一种方法上、一种数据结构上。
2、poj 2833,因为优先队列是由最小(大)堆实现的,时间复杂度O(n*logn)----正好服务优先队列的要求,保证队首(栈顶)
元素的优先级最高,其他元素的优先级顺序不考虑。
3、数据结构和算法的完美结合,第一次尝试到了两者合力是如此的完美,正如优先队列用到了:
(1):元素出队列,相当于栈顶和最后一个元素交换后,向下调整的过程;(2):元素入队列,相当于向队尾增加一个元素,向上调整的过程。
4、下面并未体现出优先级的顺序,而是用数字的大校表示优先级,当然可以建立一个结构体struct { weight key },再加上一个template<class T>写成模板类
*/
#include <iostream> using namespace std; const int maxn = 100; void my_swap(int &a, int &b) { int tmp; tmp = a; a = b; b = tmp; } //void heap_sort(int arr[],const int &len); void heap_sort(int arr[],int &len); void heap_down_adjust(int arr[],int i,int &len); void heap_up_adjust(int arr[],int &len); void heap_init(int arr[],int &len); bool de_heap_queue(int arr[],int &len); void en_heap_queue(int arr[],int &len,const int &key); int main() { int i,len,t_len;// 数组的有效长度 int arr[maxn],tmp; len = 0; cout << "请输入一个序列(-1结束):" << endl; while(cin >> tmp) { if(tmp == -1) break; arr[len] = tmp; len++; } t_len = len; heap_init(arr,len);//调用建立初始堆 cout << "插入一个元素:" << endl; cin >> tmp; en_heap_queue(arr,len,tmp); cout << "按队列的优先顺序出队:" << endl; do { cout << "堆顶元素:" << arr[0] << " " << len << endl; }while(de_heap_queue(arr,len)); return 0; } // 堆排序 void heap_sort(int arr[],int &len) { int i; for(i=len/2-1; i>=0; --i)// 至于为什么是从i = len/2 -1开始,自己建立一个完全二叉树的数组即可发现规律。 { heap_down_adjust(arr,i,len); }// 建立一个初试堆 //以0 和 len-1为下标的元素交换,之后从0下标开始调整堆,直到剩下一个元素 for(i=len-1; i>0; --i) { my_swap(arr[0],arr[i]); heap_down_adjust(arr,0,i);// i 代表当前的数组长度 } } // 建立一个初始堆 void heap_init(int arr[],int &len) { int i; for(i=len/2-1; i>=0; --i)// 至于为什么是从i = len/2 -1开始,自己建立一个完全二叉树的数组即可发现规律,len是数组长度。 { heap_down_adjust(arr,i,len); }// 建立一个初试堆(大顶堆) } // 数组,调整位置,数组长度 void heap_down_adjust(int arr[],int i,int &len) { int lc;// 左孩子 for(; i*2+1<len; i=lc) { lc = i*2+1;// 从左孩子开始 if(lc+1<len && arr[lc+1]>arr[lc])//如果右侧孩子大,加一 lc++; if(arr[lc]>arr[i])//较大的孩子节点大于父节点 my_swap(arr[lc],arr[i]); else break;//父节点是最大的无需向下调整 } } // 数组,调整位置,数组长度,插入新元素,向上调整;比向下调整简单, //因为他需要判断左右孩子的最大值与最后一个值(因为是最后一个元素和零号元素交换的) void heap_up_adjust(int arr[],int i,int &len) { int parent; for(i=len-1;i>0;i=parent) { parent = (i-1)/2; if(arr[i]>arr[parent]) my_swap(arr[i],arr[parent]); else// 无需再向上调整 break; } } // 删除优先队列的队首元素 bool de_heap_queue(int arr[],int &len) { if(len<=1) return false; len--;// 相当于删除了,数组从0开始,所以Len-1才是最后一个元素 my_swap(arr[0],arr[len]); heap_down_adjust(arr,0,len); return true; } //插入队尾元素 void en_heap_queue(int arr[],int &len,const int &key) { arr[len] = key; len++; heap_up_adjust(arr,len,len); }
改进之后的swap()函数,异或的好处,以及 位移 之 右移 >>(相当于除以2) 左移 << ( 相当于乘以2 )。
void my_swap(int &a, int &b)
{
a = a ^ b;
b = a ^ b;
a = a ^ b;
}
/*
基本函数说明及复杂度分析如下:
heap_down_adjust() 从第一个不满足堆的结点s开始向下做调整,使得维护一个堆,删除栈顶元素或者建立初始堆。
--------log(n)
heap_up_adjust() 从最后一个结点s开始向上做调整,使得维护一个堆,插入新元素的过程。
--------log(n)
en_heap_queue() 从尾部增加一个叶子节点到堆中,因为原本是满足堆的,所以只需要从下至上不断跟父结点进行交换,直至已满足堆退出,调用的heap_up_adjust()
--------log(n)
de_heap_queue() 把start跟end做交换,然后[start,end-1]从新做一次调整,使得[start,end-1]维护成一个堆,堆大小length随之-1,调用的heap_down_adjust() 。
--------log(n)
heap_init() 从第一个非终端结点开始->根节点不断做heap_adjust(),使之构成一个初始堆。
--------n / 2 * log(n)
heap_sort() 相当于重复n次de_heap_queue()操作,但length不改变。
--------n * log(n)
用类模板实现,参照 :http://www.cnblogs.com/slave_wc/archive/2010/12/23/1915293.html
*/
相关文章推荐
- 利用优先队列实现堆排序(自顶向下自底向上堆化完全二叉树的运用)
- 堆的实现、堆排序、优先队列
- 利用优先队列实现堆排序(自顶向下自底向上堆化全然二叉树的运用)
- 优先队列(二叉堆实现) + 堆排序
- 算法基础:排序(四)——二叉堆、优先队列、堆排序——Python实现
- 算法设计之,堆,堆排序,基于最大堆的最大优先队列的实现(C++实现)
- 二叉堆,堆排序,STL优先队列的底层实现,剑指offer数据流中的中位数
- 最小堆得实现;优先队列的堆实现;堆排序的时间复杂度nlgn;
- 堆排序实现优先队列(Priority queue)
- 用java实现一个基于堆排序的优先队列
- 算法基础:排序(四)——二叉堆、优先队列、堆排序——Python实现
- 基于二叉堆实现的优先队列和堆排序
- 队列优先 之 插入排序实现(插入思想)
- 堆排序实现优先队列
- poj 3253 类似霍夫曼贪心思想,优先队列的运用
- 基于堆的优先队列的实现
- 优先队列--模板类实现
- 算法笔记(堆实现的最大优先队列)
- 算法笔记(堆实现的最大优先队列)
- 采用堆排序的优先队列