C++ 最大堆

#include <iostream>
#include <stack>

const int DefaultSize = 100;

template <class T>
class MaxHeap{
public:
    MaxHeap(int sz = DefaultSize);
    MaxHeap(T arr[], int n);
    ~MaxHeap(){delete []heap;}
    bool Insert(const T &x); // 插入
    bool RemoveMin(); // 删除
    bool isEmpty()const; // 是否为空
    bool isFull()const; // 是否已满
    void InOrder(); // 中序遍历完全二叉树
private:
    T *heap; // 动态数组存储最小堆
    int CurrentSize; // 目前最小堆的结点数
    void ShiftDown(int start, int m); // 下滑
    void ShiftUp(int start); // 上浮
};

// 构造函数
template <class T>
MaxHeap<T>::MaxHeap(int sz) {
    heap = new T[sz]; // 创建堆空间
    CurrentSize = 0;
}

// 构造函数
template <class T>
MaxHeap<T>::MaxHeap(T arr[], int n) {
    // 为什么求最后非叶要CurrentSize减去2,再除以2,而不是减去1,再除以2
    // 因为最后一个数组下标是CurrentSize-1,又因为:左结点j = 2 * i +
    //  1,知道j,想求i。可知是:i = (j - 1) / 2;所以,就出现了
    // CurrentPos = (CurrentSize - 2) / 2
    heap = new T[DefaultSize]; // 创建堆空间
    CurrentSize = n; // 当前堆大小
    for(int i = 0; i < n; i++)
        heap[i] = arr[i];
    int CurrentPos = (CurrentSize - 2) / 2; // 最后非叶
    while(CurrentPos >= 0) {
        // 从下到上逐渐扩大,形成堆
        ShiftDown(CurrentPos, CurrentSize-1);
        // 到CurrentSize-1为止
        CurrentPos--;
    }
}

// 向下调整
template <class T>
void MaxHeap<T>::ShiftDown(int start, int m) {
    int i = start, j = 2 * i + 1; // j是i的左子女
    
    T temp = heap[i];
    while(j <= m) {
        if(j < m && heap[j] < heap[j+1])
            j++; // 选两个子女中较大者
        if(temp >= heap[j])
            break;
        else {
            heap[i] = heap[j];
            i = j;
            j = 2 * j + 1;
        }
    }
    heap[i] = temp;
}

// 向上调整
template <class T>
void MaxHeap<T>::ShiftUp(int start) {
    // 从start开始,直到0或者当前值小于双亲结点的值时,调整堆
    int j = start, i = (j-1)/2; // i是j的双亲
    
    T temp = heap[j];
    while(j > 0) {
        if(heap[i] >= temp)
            break;
        else {
            heap[j] = heap[i];
            j = i;
            i = (j - 1) / 2;
        }
    }
    heap[j] = temp;
}

// 堆插入
template <class T>
bool MaxHeap<T>::Insert(const T &x) {
    // 在堆中插入新元素x
    if(CurrentSize == DefaultSize) { // 堆满
        std::cout << "堆已满!\n";
        return false;
    }
    heap[CurrentSize] = x; // 插在表尾
    ShiftUp(CurrentSize); // 向上调整
    CurrentSize++;
    return true;
}

// 堆删除
template <class T>
bool MaxHeap<T>::RemoveMin() {
    int x;
    
    if(!CurrentSize) {
        std::cout << "堆已空!\n";
        return false;
    }
    x = heap[0]; // 最大元素出列
    heap[0] = heap[CurrentSize-1]; // 用最后一个元素填补
    CurrentSize--;
    ShiftDown(0, CurrentSize-1); // 从0位置开始向下调整
    return true;
}

// 判断堆是否已空
template <class T>
bool MaxHeap<T>::isEmpty()const {
    if(!CurrentSize)
        return true;
    return false;
}

// 判断堆是否已满
template <class T>
bool MaxHeap<T>::isFull()const {
    if(CurrentSize == DefaultSize)
        return true;
    return false;
}

// 中序遍历
template <class T>
void MaxHeap<T>::InOrder() {
    std::stack<int> s;
    int i;
    
    i = 0;
    while(i < CurrentSize || !s.empty()) {
        while(i < CurrentSize) {
            s.push(i);
            i = 2 * i + 1;
        }
        if(!s.empty()) {
            i = s.top();
            s.pop();
            std::cout << heap[i] << " ";
            i = 2 * i + 2; // 右孩子
        }
    }
}

int main(int argc, const char * argv[]) {
    int finished, choose, x, len;
    int arr[] = {9, 17, 65, 23, 45, 78, 87, 53};
    
    len = sizeof(arr) / sizeof(arr[0]);
    finished = 0;
    MaxHeap<int> h = MaxHeap<int>(arr, len);
    while(!finished) {
        std::cout << "\n*************菜单*************\n";
        std::cout << "1:往最大堆中插入一个值:\n";
        std::cout << "2:删除最大堆中的最大值\n";
        std::cout << "3:判断最大堆是否为空\n";
        std::cout << "4:判断最大堆是否已满\n";
        std::cout << "5:中序遍历最大堆\n";
        std::cout << "6:退出\n";
        std::cout << "请输入你的选择[1-6]:";
        std::cin >> choose;
        switch(choose) {
            case 1:
                std::cout << "请输入要插入的值:";
                std::cin >> x;
                h.Insert(x);
                break;
            case 2:
                h.RemoveMin(); // 删除最大值
                break;
            case 3:
                if(h.isEmpty())
                    std::cout << "最大堆为空!\n";
                else
                    std::cout << "最大堆不为空!\n";
                break;
            case 4:
                if(h.isFull())
                    std::cout << "最大堆已满\n";
                else
                    std::cout << "最大堆还没满!\n";
                break;
            case 5:
                std::cout << "最大堆的数据为:\n";
                h.InOrder();
                std::cout << std::endl;
                break;
            case 6:
                finished = 1;
                break;
            default:
                std::cout << "选择输入错误,请重新输入!\n";
        } // switch
    } // while
    return 0;
}

猜你喜欢

转载自blog.csdn.net/chuanzhouxiao/article/details/88550791
今日推荐