小大根交替堆

来源:互联网 发布:淘宝自己开的店铺呢 编辑:程序博客网 时间:2024/06/13 11:24

基于论文“Min-Max Heaps and Generalized Priority Queues”

  • 定义
  • 抽象数据类型
  • 源代码
  • 截图
  • 应用

定义

values stored at nodes on even (odd) levels are smaller than or equal to (respectively, greater than) values stored at their descendants.

抽象数据类型

template<class T>class min_max_heap{public:    min_max_heap(int initialCapacity = 10);//默认参数为10    ~min_max_heap() { delete[] heap; }//析构函数    bool empty() const { return heapSize == 0; }//判断堆是否为空    int size() const {//返回堆的大小        return heapSize;    }    T* getHeap() const {        return heap;    }    void  initialize(T *theHeap,int theSize);//根据已知数组建堆    const T& getMax();//得到最大值    const T& getMin();//得到最小值    void insert(T&);//插入值    const T& popMin();//删除最小值    const T& popMax();//删除最大值    void output(ostream& out);//输出public:    int heapSize;//堆大小    int arrayLength;//堆的最大值    T *heap;//堆数组};

源代码

template<class T>min_max_heap<T>::min_max_heap(int initialCapacity) {//构造函数    if (initialCapacity < 1) {//初始大小必须大于0        ostringstream s;        s << "Error : Initial capacity = " << initialCapacity << " Must be > 0";        throw s.str();    }    arrayLength = initialCapacity + 1;//    heap = new T[arrayLength];    heapSize = 0;}int is_min_level(int i) {//返回下标为i的数据的层(大层还是小层)    if ((int)(floor(log(i) / log(2))) % 2) {        return 0;    }    else {        return 1;    }}template<class T>int index_min_child_grandchild(min_max_heap<T>* h ,int i) {//找出下标为i的结点的儿子和孙子中最小的值    int a = first_child(i);    int b = second_child(i);    int d = second_child(a);    int c = first_child(a);    int f = second_child(b);    int e = first_child(b);    int min_idx = -1;    if (a <= h->heapSize) min_idx = a;    if (b <= h->heapSize && h->heap[b] < h->heap[min_idx]) min_idx = b;    if (c <= h->heapSize && h->heap[c] < h->heap[min_idx]) min_idx = c;    if (d <= h->heapSize && h->heap[d] < h->heap[min_idx]) min_idx = d;    if (e <= h->heapSize && h->heap[e] < h->heap[min_idx]) min_idx = e;    if (f <= h->heapSize && h->heap[f] < h->heap[min_idx]) min_idx = f;    return min_idx;}template<class T>int index_max_child_grandchild(min_max_heap<T>* h, int i) {//找出下标为i的结点的儿子和孙子中最小的值    int a = first_child(i);    int b = second_child(i);    int d = second_child(a);    int c = first_child(a);    int f = second_child(b);    int e = first_child(b);    int max_idx = -1;    if (a <= h->heapSize) max_idx = a;    if (b <= h->heapSize && h->heap[b] > h->heap[max_idx]) max_idx = b;    if (c <= h->heapSize && h->heap[c] > h->heap[max_idx]) max_idx = c;    if (d <= h->heapSize && h->heap[d] > h->heap[max_idx]) max_idx = d;    if (e <= h->heapSize && h->heap[e] > h->heap[max_idx]) max_idx = e;    if (f <= h->heapSize && h->heap[f] > h->heap[max_idx]) max_idx = f;    return max_idx;}template<class T>void swap(min_max_heap<T>* h, int i, int m) {//交换堆中下标为i和m的数据    T temp = h->heap[i];    h->heap[i] = h->heap[m];    h->heap[m] = temp;if(flagPrint)cout << "     heap[" << i << "]:" << h->heap[m] << "<-->" << "heap[" << m << "]:" << h->heap[i] << endl <<"h:\n"<< *h << endl;}/*小层下滤,先找到自己儿子和孙子中最小的值。如果该值为儿子,证明自己没有孙子,这时只需比较该最小值与自己,如果该最小值小,则与自己交换位置,下滤结束;否则不变化,下滤结束;如果该值为孙子,则比较该最小值与自己,如果该最小值大于自己,则证明以该元素为根节点的树的最小值就是该元素,下滤完成;否则如果该最小值小于自己,则进行交换位置,交换后判断自己与父亲结点的大小关系:    如果父亲节点(大层)小于自己,则交换位置,交换后只有该父亲节点元素位置不正确,所以对父亲节点元素重新进行下滤;    否则父亲节点大于自己,则对自己重新进行下滤操作。*/template<class T>void TrickleDownMin(min_max_heap<T>* h,int i) {//小层下滤(用于删除)    int m = index_min_child_grandchild(h,i);//得到儿子和孙子中最小的值    if (m <= -1)  return;    if (m > second_child(i)) {//如果孙子最小        if (h->heap[m] < h->heap[i]) {            swap(h, i, m);            if (h->heap[m] > h->heap[parent(m)]) {                swap(h, m, parent(m));            }        TrickleDownMin(h, m);        }    }    else {//如果儿子最小        if (h->heap[m] < h->heap[i]) {            swap(h, i, m);        }    }}template<class T>void TrickleDownMax(min_max_heap<T>* h,int i) {//大层下滤(用于删除)    int m = index_max_child_grandchild(h, i);//得到儿子和孙子最大值    if (m <= -1) {        return;    }    if (m > second_child(i)) {//如果孙子最大        if (h->heap[m] > h->heap[i]) {            swap(h, i, m);            if (h->heap[m] < h->heap[parent(m)]) {                swap(h, m, parent(m));            }            TrickleDownMax(h, m);        }    }    else {//如果儿子最大        if (h->heap[m] > h->heap[i]) {            swap(h, i, m);        }    }}template<class T>void trickleDown(min_max_heap<T>* h,int i) {//下滤,用于删除//cout << "先判断是删除了最小元素,还是最大元素" << endl;    if (is_min_level(i)) {        TrickleDownMin(h, i);    }    else {        TrickleDownMax(h, i);    }}template<class T>void bubbleup_min(min_max_heap<T>* h, int i) {//小层上滤    int pp_i = parent(parent(i));    if (pp_i <= 0) return;    if (h->heap[i]<h->heap[pp_i]) {//如果祖父比自己大,则交换        swap(h, i, pp_i);        bubbleup_min(h, pp_i);    }}template<class T>void bubbleup_max(min_max_heap<T>* h, int i) {//大层上滤    int pp_i = parent(parent(i));    if (pp_i <= 0) return;    if (h->heap[i]>h->heap[pp_i]) {//如果祖父比自己小则交换        swap(h, i, pp_i);        bubbleup_max(h, pp_i);    }}template<class T>void BubbleUp(min_max_heap<T>* h, int i) {//上滤,可用于插入    int p_i = parent(i);    if (p_i <= 0) return;    if (is_min_level(i)) {//如果是小层,进行父亲节点与自己的值大小比较        if (h->heap[i] > h->heap[p_i]) {//若父节点小,则交换,并进行大层上滤            swap(h, i, p_i);            bubbleup_max(h, p_i);        }        else {//如果父节点大则进行小层上滤            bubbleup_min(h, i);        }    }    else {//否则是大层        if (h->heap[i] < h->heap[p_i]) {//若父亲节点大于自己,则交换,并进行小层上滤            swap(h, i, p_i);            bubbleup_min(h, p_i);        }        else {//否则父亲节点小于自己,进行大层交换            bubbleup_max(h, i);        }    }}template<class T>void min_max_heap<T>::initialize(T *theHeap, int theSize) {//初始化堆    delete[] heap;    heap = theHeap;    heapSize = theSize;    for (int root = heapSize / 2; root >= 1; root--)    {        trickleDown(this, root);    }}template<class T>void min_max_heap<T>::insert(T& Element) {//插入if (flagPrint) {    cout << "插入操作-插入";    cout << Element;    cout << ":" << endl;}    //如果堆满可增加数组的长度,此处扩展为原先的2倍;    if (heapSize == arrayLength - 1) {        changeArrayLength(heap, arrayLength, 2 * arrayLength);        arrayLength *= 2;    }    int currentNode = ++heapSize;    heap[currentNode] = Element;if(flagPrint)cout <<"h:\n"<<*this<<endl;    BubbleUp(this, currentNode);}template<class T>const T& min_max_heap<T>::getMax() {//返回最大值    printf("得到最大值操作:");    if (heapSize > 2) {//比较heap[2]和heap[3]        printf("%d\n", heap[2] < heap[3] ? heap[3] : heap[2]);        return heap[2] < heap[3] ? heap[3] : heap[2];    }    if (heapSize == 2) {        printf("%d\n", heap[2]);        return heap[2];    }    if (heapSize == 1) {        printf("%d\n", heap[1]);        return heap[1];    }    throw "错误:空堆不能得到最大值\n";}template<class T>const T& min_max_heap<T>::getMin() {//返回根节点(即第一个元素)即最小元素    if (heapSize > 0) {cout << "得到最小值操作:" <<heap[1] << endl;        return heap[1];    }    throw "错误:空堆不能得到最小值\n";    //printf("错误:空堆\n");    //return NULL;}template<class T>const T& min_max_heap<T>::popMin() {//删除最小值if (flagPrint)cout << "删除最小值操作" << endl;    if (heapSize > 1) {        T d = heap[1];//cout << "将根节点" << heap[1] << "(最小值)替换为最后一个元素" << heap[heapSize] << ",开始下滤:" << endl;        heap[1] = heap[heapSize--];if(flagPrint)cout << "heap[1] = "<<heap[1]<< endl <<"h:\n"<<*this << endl;        trickleDown(this, 1);        return d;    }    if (heapSize == 1) {if (flagPrint)cout << "只有一个元素,故删除后堆为空" << endl;        heapSize--;        return heap[1];    }    throw "错误:空堆不能删除最小值\n";    //printf("错误:空堆\n");    //return NULL;}template<class T>const T& min_max_heap<T>::popMax() {//删除最大值if (flagPrint)cout << "删除最大值操作" << endl;    if (heapSize > 2) {        int index = 2;        if (heap[2] < heap[3]) index = 3;        T d = heap[index];        heap[index] = heap[heapSize--];if (flagPrint)cout << "heap["<<index<<"] = " << heap[index] << endl <<"h:\n"<<*this << endl;        trickleDown(this, index);        return d;    }    if (heapSize == 2) {if (flagPrint)cout << "两个元素,返回heap[2]即可" << endl;        heapSize--;        return heap[2];    }    if (heapSize == 1) {if (flagPrint)cout << "只有一个元素,故删除后堆为空" << endl;        heapSize--;        return heap[1];    }    throw "错误:空堆不能得到最小值\n";}//template<class T>template<class T>void min_max_heap<T>::output(ostream& out) {//输出堆元素    T **heapTreeMatrix;    if (heapSize == 0) throw "Error : empty heap not output!";    int level = 0;    int high = (int)(floor(log(heapSize) / log(2)));//high从0层开始    int bottle_node_count_max = pow(2, high);//最下层最多可以拥有的结点数    heapTreeMatrix = new T*[high + 1];    for (int i = 0; i < high + 1; i++) {        heapTreeMatrix[i] = new T[bottle_node_count_max * 2];    }    T *t = new T(INF);    for (int i = 0; i < high+1 ; i++) {        for (int j = 0; j < bottle_node_count_max*2; j++) {            heapTreeMatrix[i][j] = *t;        }    }    int index = 1;    while (level < high + 1) {        int inscrease = bottle_node_count_max * 2 / pow(2, level);        for (int j = inscrease/2 ; j < bottle_node_count_max * 2; j += inscrease) {            if(index<=heapSize)            heapTreeMatrix[level][j] = heap[index++];        }        level++;    }    for (int i = 0; i < high + 1; i++) {        for (int j = 0; j < bottle_node_count_max * 2; j++) {            if (heapTreeMatrix[i][j] == *t) {                printf("    ");            }            else {                out << setw(4) << heapTreeMatrix[i][j];            }        }        printf("\n");    }    for (int i = 0; i < high + 1; i++) {        delete[] heapTreeMatrix[i];    }    delete[] heapTreeMatrix;}template<class T>ostream& operator<<(ostream& out, min_max_heap<T>& x) {//<<运算符重载    x.output(out);    out << endl;    return out;}

测试代码

char choose;min_max_heap<int> h(10);int initSize = 0;//初始化数组元素个数int array[2000];//初始化数组 int main(){    while (1) {        printf("****************************************************************************************\n");        printf("菜单 小大根交替堆实现双端优先队列\n");        printf("** u 建立小大根交替堆\n");        printf("** i 插入元素\n");        printf("** b 删除最大值\n");        printf("** s 删除最小值\n");        printf("** g 得到最大值\n");        printf("** h 得到最小值\n");        printf("** q 退出\n");        printf("****************************************************************************************\n");        cin >> choose;        int a;//临时存放int值         char c;//临时存放char值         try{        switch (choose) {        case 'u':            printf("建立小大根交替堆:\n");            printf("请输入关键值:\n");            getchar();            flagPrint = false;            while (1) {                scanf("%d", &a);                c = getchar();                //h.insert(a);                array[++initSize] = a;//初始化数组                if (c == '\n') break;            }            h.initialize(array, initSize);            cout << "建堆如下:"<<endl << h << endl;            //printf("按f回到主菜单\n");            break;        case 'i':            printf("插入:");            scanf("%d", &a);            flagPrint = true;            h.insert(a);            break;        case 'b':            flagPrint = true;            a = h.popMax();            printf("删除元素为%d\n", a);            break;        case 's':            flagPrint = true;            a = h.popMin();            printf("删除元素为%d\n", a);            break;        case 'h':            h.getMin();            break;        case 'g':            h.getMax();            break;        case 'q':            return 0;        default:            printf("输入有误,请重新输入\n");            break;        }        }        catch (string s) {            cout << s << endl;        }        catch (char* s) {            cout << s << endl;        }    }return 0;}

测试截图

这里写图片描述

应用

可以用来实现双端优先队列Double_Ended_Priority_Queue,方便的得到最大最小值。

0 0
原创粉丝点击