最小堆,堆排序(c++代码)
2014-12-22 12:25
120 查看
//所谓的最大堆,最小堆其实是一颗完全二叉树.并以数组来存储树的节点元素.这里的示例从数组的0下标开始存储树的节点. //最小堆的父节点<=子节点,最大堆的父节点>=子节点. //最大堆常用于实现优先队列等,最小堆常用于实现定时器(例如libevent)等. //以下代码实现了最小堆和堆排序的算法,作为备忘笔记.使用的时候可以封装成模板类,这里只是算法的示例代码. //从大到小排序使用最小堆,从小到大排序使用最大堆. //要改成最大堆只需要改几个(<=)运算符. //如有错误,欢迎指正. #include <stdlib.h> #include <stdio.h> #include <vector> #define HEAP_PARENT(i) ((i-1)/2) #define HEAP_LEFTCHILD(i) (2*i+1) #define HEAP_RIGHTCHILD(i) (2*i+2) using namespace std; //节点 struct HeapNode{ HeapNode(int k) : key(k){} int key; }; // struct Heap{ Heap():size_(0) {} vector<HeapNode*> vec_; int size_; }; //下移pos位置节点. //如果pos位置的节点 > 其子节点,则将pos位置元素和其子节点中较小的节点交换.并重复此过程,直到不能再下移. void shiftDown( Heap & h , int pos ) { int last_index = h.size_ - 1; while (1){ //叶节点,下移结束 bool has_child = HEAP_LEFTCHILD(pos) <= last_index ? true : false; if ( !has_child ) break; //找到父子三个节点中最小节点的位置 int min_index; min_index = h.vec_[pos]->key <= h.vec_[HEAP_LEFTCHILD(pos)]->key ? pos : HEAP_LEFTCHILD(pos); bool has_right_child = HEAP_RIGHTCHILD(pos) <= last_index ? true : false; if (has_right_child){ min_index = h.vec_[min_index]->key <= h.vec_[HEAP_RIGHTCHILD(pos)]->key ? min_index : HEAP_RIGHTCHILD(pos); } //如果父节点不是最小则和最小的子节点交换位置 if ( pos == min_index) break; //交换节点数据,更新pos,进行下一轮下移. HeapNode * temp = h.vec_[ pos ]; h.vec_[ pos ] = h.vec_[ min_index ]; h.vec_[ min_index ] = temp; pos = min_index; } } //上移pos位置节点. //如果pos位置的节点小于父节点,则和父节点交换.并重复此过程,直到不能再上移. void shiftUp( Heap & h , int pos ){ while ( pos > 0) { int parent = HEAP_PARENT(pos); if ( h.vec_[parent]->key <= h.vec_[pos]->key) break; // HeapNode * temp = h.vec_[pos]; h.vec_[pos] = h.vec_[parent]; h.vec_[parent] = temp; pos = parent; } } //将新节点加入到最后,并且上移该节点到适当位置. void push( Heap & h , HeapNode * newNode ){ int pos = h.size_; h.vec_.push_back(newNode); h.size_++; shiftUp(h , pos); } //将第一个节点与最后一个节点交换,再删除最后一个节点,从而弹出树顶端的节点. //将交换后的第一个节点下移到适当位置. HeapNode * pop(Heap & h){ if ( h.size_ == 0 ) return NULL; HeapNode * res = h.vec_[0]; h.vec_[0] = h.vec_[ h.size_ - 1 ]; h.vec_.pop_back(); h.size_--; shiftDown( h , 0 ); return res; } //建堆 //从最后一个非叶子节点开始下移.直到根节点下移.将无序的数组创建为一个最小堆. void makeHeap(Heap & h){ for (int i = h.size_/2 - 1 ; i >= 0 ; i--){ shiftDown(h , i); } } //堆排序 //由于最小堆的树顶元素为最小值,将树顶元素与最后一个元素交换,并且减小堆的大小.然后维护堆的性质. //等到树中只剩下一个元素的时候,存储堆的数组就是一个有序的序列. void heapSort(Heap & h){ for( int i = h.size_ - 1 ; i>=1 ; i-- ){ // HeapNode * temp = h.vec_[i]; h.vec_[i] = h.vec_[0]; h.vec_[0] = temp; h.size_--; // shiftDown(h , 0); } } void print_vec( Heap & h ){ for (int i = 0 ; i < h.vec_.size() ; i++){ printf("%d " , h.vec_[i]->key); } } #if 0 int main(){ Heap h; HeapNode * node; printf("\n=====push , pop=======\n"); push(h , new HeapNode(100) ); push(h , new HeapNode(88) ); push(h , new HeapNode(89) ); push(h , new HeapNode(111) ); push(h , new HeapNode(60) ); while( (node = pop(h)) != NULL ){ printf( "%d " , node->key ); } printf("\n=====make heap , pop=======\n"); h.vec_.push_back( new HeapNode(100) ); h.vec_.push_back( new HeapNode(88) ); h.vec_.push_back( new HeapNode(89) ); h.vec_.push_back( new HeapNode(111) ); h.vec_.push_back( new HeapNode(60) ); h.size_ = 5; makeHeap(h); while( (node = pop(h)) != NULL ){ printf( "%d " , node->key ); } printf("\n=====make heap , heap sort=======\n"); h.vec_.push_back( new HeapNode(100) ); h.vec_.push_back( new HeapNode(88) ); h.vec_.push_back( new HeapNode(89) ); h.vec_.push_back( new HeapNode(111) ); h.vec_.push_back( new HeapNode(60) ); h.size_ = 5; makeHeap(h); heapSort(h); print_vec(h); } #endif
相关文章推荐
- 最短路+邻接表+最小堆的C++代码实现
- 数据结构 - 堆排序(heap sort) 详解 及 代码(C++)
- 选择排序——简单选择排序和堆排序,C++代码实现
- 堆的操作和堆排序-最小堆实现递减排序-C++
- 堆排序:源码(C++)--伪代码--时间复杂度解析
- C++实现堆、最大堆、最小堆 -- 堆排序插入删除操作
- C++代码,数据结构-内部排序-选择排序-堆排序
- 算法代码实现之堆排序,C/C++实现
- 创建堆,堆排序的详细实现过程,C++完整代码
- 排序法系列之六---堆排序(C++代码实现)
- 数据结构 - 堆排序(heap sort) 具体解释 及 代码(C++)
- 插入排序、冒泡排序、选择排序、希尔排序、快速排序、归并排序、堆排序和LST基数排序的C++代码实现
- C++代码优化方法总结
- 【分析】C++中通过溢出覆盖虚函数指针列表执行代码
- symbian c++ 学习 2 数据类型及代码规范
- VS.NET 2005 Beta 2初体验(2)-用C++开发Native代码
- 终于可以在Eclipse下编译C++代码了
- GNU的C++代码书写规范
- C++代码优化Tips
- C++ 栈类实力 代码分析