最小堆,堆排序(c++代码)

来源:互联网 发布:mysql in exists 性能 编辑:程序博客网 时间:2024/06/16 17:42
//所谓的最大堆,最小堆其实是一颗完全二叉树.并以数组来存储树的节点元素.这里的示例从数组的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 0int 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

0 0