码迷,mamicode.com
首页 > 其他好文 > 详细

小堆 大堆

时间:2016-08-09 00:40:25      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:堆排

1、堆

        一种完全二叉树的线性表示方法;就是数组形式保存数据。

        大堆:根(父)结点大于左右结点数据       ------->降序

        小堆:根(父)结点小于左右结点              ------->升序

小堆如图:

技术分享

小堆符合每个根(父)结点都比左右结点小!!!

堆的存储结构,就是一个线性表结构:

private:
    enum{HEAP_DEFAULT_SIZE = 10};  //默认数组空间为10
    Type *heap;     //堆的数组名称
    int capacity;   //堆空间大小
    int size;       //有效元素个数

2、小堆

        根据一组无序的数字创建小堆--------->最后实现堆排!

        C++中创建小堆,可以通过构造函数一次性创建;也可以调用插入函数创建小堆;

技术分享

小堆:堆顶的数据最小。

一些方法的实现:

        (1)、删除函数    作用:每次删除堆顶,拿最后一个元素放到堆顶,在向下调整成小堆,这样就成升序输出了;

    bool remove(Type &v){
        if(size == 0){
            return false;
        }
        v = heap[0];
        heap[0] = heap[size-1];
        size--;
        siftDown(0, size-1);

        return true;
   }

        (2)、插入函数  作用:向上构建小堆

    bool insert(const Type &x){
        if(size > capacity){
            return false;
        }
        heap[size] = x;
        siftUp(size);
        size++;
        return true;
    }

        (3)、一次向下调整函数    作用:向下构建小堆

    void siftDown(int start, int end){
        int i = start;
        int j = 2*i+1;

        Type tmp = heap[i];
        while(j <= end){
            if(j+1 <= end && heap[j] > heap[j+1]){
                j = j+1;
            }
            if(tmp > heap[j]){
                heap[i] = heap[j];  //要是写交换函数的话,太浪费内存空间!!
            }else{
                break;
            }
            i = j;
            j = 2*i+1;
        }
        heap[i] = tmp;
    }

        (4)、一次向上调整函数

    void siftUp(int start){
        int j = start;
        int i = (j-1)/2;  //父结点,这里的求法要注意。

        Type tmp = heap[j];  //保存的是要插入的数据
        while(j > 0){
            if(heap[i] > tmp){
                heap[j] = heap[i];
            }else{
                break;
            }

            j = i;
            i = (j-1)/2;
        }
        heap[j] = tmp;
    }

小堆的完整程序:

#ifndef _MIN_HEAP_H_
#define _MIN_HEAP_H_

#include<iostream>
using namespace std;

template<typename Type>
class MinHeap{
public:
    MinHeap(int sz = HEAP_DEFAULT_SIZE){
        capacity = sz > HEAP_DEFAULT_SIZE ? sz : HEAP_DEFAULT_SIZE;
        heap = new Type[capacity];
        size = 0;
    }
    MinHeap(Type ar[], int n){
        capacity = n > HEAP_DEFAULT_SIZE ? n : HEAP_DEFAULT_SIZE;
        heap = new Type[capacity];
        size = n;

        for(int i = 0; i < n; i++){
            heap[i] = ar[i];
        }

        int curPos = n/2 - 1;  //从最后一个非叶子结点开始调整,
        while(curPos >= 0){
            siftDown(curPos, n-1);
            curPos--;  //一直调整到根结点
        }
    }
    ~MinHeap(){
        delete []heap;
        heap = NULL;
        capacity = size = 0;
    }
public:
    bool remove(Type &v){
        if(size == 0){
            return false;
        }
        v = heap[0];
        heap[0] = heap[size-1];
        size--;
        siftDown(0, size-1);

        return true;
    }
    bool insert(const Type &x){
        if(size > capacity){
            return false;
        }
        heap[size] = x;
        siftUp(size);
        size++;
        return true;
    }
    void showHeap()const{
        for(int i = 0; i < size; i++){
            cout<<heap[i]<<" ";
        }
        cout<<endl;
    }
protected:
    void siftDown(int start, int end){
        int i = start;  //父结点
        int j = 2*i+1;  //子节点(左孩子)

        Type tmp = heap[i];
        while(j <= end){
            if(j+1 <= end && heap[j] > heap[j+1]){
                j = j+1;
            }
            if(tmp > heap[j]){
                heap[i] = heap[j];  //要是写交换函数的话,太浪费内存空间!!采用了直接覆盖的方法。
            }else{
                break;
            }
            i = j;
            j = 2*i+1;
        }
        heap[i] = tmp;
    }
    void siftUp(int start){
        int j = start;
        int i = (j-1)/2;  //父结点,这里的求法要注意。

        Type tmp = heap[j];
        while(j > 0){
            if(heap[i] > tmp){
                heap[j] = heap[i];
            }else{
                break;
            }

            j = i;
            i = (j-1)/2;
        }
        heap[j] = tmp;
    }
private:
    enum{HEAP_DEFAULT_SIZE = 10};
    Type *heap;
    int capacity;
    int size;
};

#endif

测试程序:

#include"minHeap.h"

int main(void){
    int ar[] = {53, 17, 78, 9, 45, 65, 87, 23,};
    int n = sizeof(ar)/sizeof(int);
    int i;
    MinHeap<int> hp;
    //MinHeap<int> hp(ar, n);
    for(i = 0; i < n; i++){
        hp.insert(ar[i]);
    }
    hp.showHeap();

    int value;
    for(i = 0; i < n; i++){
        hp.remove(value);
        cout<<value<<" ";
    }
    cout<<endl;
    return 0;
}

测试结果:

技术分享

3、大堆------->降序

        思想和小堆差不多,具体也不再分析了;

        代码如下:

#ifndef _MAX_HEAP_H_
#define _MAX_HEAP_H_

#include<iostream>
using namespace std;

template<typename Type>
class MaxHeap{
public:
    MaxHeap(int sz = DEFAULT_HEAP_SIZE){
        capacity = sz > DEFAULT_HEAP_SIZE ? sz : DEFAULT_HEAP_SIZE;
        heap = new Type[capacity];
        size = 0;
    }
    MaxHeap(int ar[], int n){
        capacity = n > DEFAULT_HEAP_SIZE ? n : DEFAULT_HEAP_SIZE;
        heap = new Type[capacity];
        size = n;
        for(int i = 0; i < n; i++){
            heap[i] = ar[i];
        }

        int curPos = n/2-1;
        while(curPos >= 0){
            siftDown(curPos, size-1);
            curPos--;
        }

    }
    ~MaxHeap(){}
public:
    bool insert(const Type &x){
        if(size > capacity){
            return false;    
        }
        heap[size] = x;
        siftUp(size);
        size++;

        return true;
    }
    void remove(int &value){
        value = heap[0];
        heap[0] = heap[size-1];
        size--;
        siftDown(0, size-1);
    }
    void showHeap(){
        for(int i = 0; i < size; i++){
            cout<<heap[i]<<" ";
        }
        cout<<endl;
    }
protected:
    void siftDown(int start, int end){
        int i = start;
        int j = 2*i+1;
        int tmp = heap[i];
        while(j <= end){
            if(j+1 <= end && heap[j] < heap[j+1]){
                j = j+1;
            }

            if(heap[j] > tmp){
                heap[i] = heap[j];
            }else{
                break;
            }
            i = j;
            j = 2*i+1;
        }
        heap[i] = tmp;
    }
    void siftUp(int start){
        int j = start;
        int i = (j-1)/2;
    
        Type tmp = heap[j];
        while(j > 0){
            if(heap[i] < tmp){
                heap[j] = heap[i];
            }else{
                break;
            }
            j = i;
            i = (j-1)/2;
        }
        heap[j] = tmp;
    }
private:
    enum{DEFAULT_HEAP_SIZE = 10};
    Type *heap;
    int capacity;
    int size;
};

#endif

测试代码:

#include"maxHeap.h"

int main(void){
    int ar[] = {23, 45, 12, 6, 4, 9, 33,};
    int n = sizeof(ar)/sizeof(int);
    int i;

    MaxHeap<int> hp;
    for(i = 0; i < n; i++){
        hp.insert(ar[i]);
    }
    hp.showHeap();

    int value;
    for(i = 0; i < n; i++){
        hp.remove(value);
        cout<<value<<" ";
    }
    cout<<endl;
    
    
    return 0;
}

测试结果:

技术分享



小堆 大堆

标签:堆排

原文地址:http://11596096.blog.51cto.com/11586096/1835842

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!