您的位置:首页 > 编程语言 > C语言/C++

最小堆,堆排序(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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: