Data Structures in C++:堆和堆排序


堆 Heap 這種數據結構其實就是一顆 “完全二叉樹”,每個節點的值總是不大於或不小於其父節點的值:一棵深度爲k的有n個結點的二叉樹,對樹中的結點按從上至下、從左到右的順序進行編號,如果編號爲i(1≤i≤n)的結點與滿二叉樹中編號爲i的結點在二叉樹中的位置相同,則這棵二叉樹稱爲完全二叉樹。一棵深度爲k且有 個結點的二叉樹稱爲 “滿二叉樹”。
在這裏插入圖片描述

堆的分類:

  • 大頂堆:每個節點的值都大於或等於其子節點的值
  • 小頂堆:每個節點的值都小於或等於其子節點的值
    在這裏插入圖片描述

大頂堆和小頂堆都可以用來“從小到大”或“從大到小”排序,一般使用大頂堆。


堆的代碼實現

堆就是一顆完全二叉樹,中間沒有空洞,因此可以使用內存連續的數組或動態數組來實現。以大頂堆爲例。

先將堆中結點的序號和數組索引進行對應:(與層次遍歷類似)
在這裏插入圖片描述
顯然,每對父子結點在數組中的索引存在數學關係:

  • 索引爲 tt 的結點,其父結點索引爲 (t1)/2(t-1)/2
  • 索引爲 tt 的結點,其左孩子索引爲 t×2+1t×2+1,右孩子索引爲 t×2+2t×2+2

插入操作:push

  • 先將元素插入到最後一個結點
  • 由此逐層向上滲透:若比父結點大,就交換
    在這裏插入圖片描述

刪除操作:pop

  • 先將根節點刪除,替換爲最後一個結點
  • 由此逐層向下滲透:若比左右結點小,就和bigger交換
    在這裏插入圖片描述

模板類代碼:

#pragma once
#include <vector>

template<typename T>
class MaxHeap
{
public:
    MaxHeap() {}
    ~MaxHeap() {}
    void push(T& x);
    void pop();
    bool empty() const;
    const T& top() const;

//private:
    std::vector<T> heap;
};

template<typename T>
inline void MaxHeap<T>::push(T& x)
{
    // 添加元素
    heap.push_back(x);
    // 向上滲透
    int index = heap.size() - 1;
    while (index > 0)
    {
        int parent = (index - 1) / 2;
        if (heap[parent] >= x) break;
        heap[index] = heap[parent];
        index = parent;
    }
    heap[index] = x;
}

template<typename T>
inline void MaxHeap<T>::pop()
{
    // 替換根結點
    T x = heap[0] = heap[heap.size() - 1];
    heap.pop_back();
    if (heap.empty()) return;
    // 向下滲透
    int index = 0;
    while (index * 2 + 1 < heap.size()) // 左子結點存在
    {
        int larger_child;
        int l_child = index * 2 + 1;
        int r_child = index * 2 + 2;
        if (r_child < heap.size() && heap[r_child] >= heap[l_child])  // 右子結點存在
        {
            larger_child = r_child;
        }
        else
        {
            larger_child = l_child;
        }
        if (x > heap[larger_child])   // 截止
            break;
        heap[index] = heap[larger_child];
        index = larger_child;
    }
    heap[index] = x;
}

template<typename T>
inline bool MaxHeap<T>::empty() const
{
    return heap.empty();
}

template<typename T>
inline const T& MaxHeap<T>::top() const
{
    return heap[0];
}

堆排序

堆排序是利用堆這種數據結構而設計的一種排序算法,堆排序是一種選擇排序,它的最壞、最好、平均時間複雜度均爲O(nlogn),是不穩定排序。

基本思想:

  1. 構造一個空的大頂堆;
  2. 將待排序序列push進入大頂堆,此時,整個序列的最大值就是堆頂的根節點
  3. 將大頂堆的根節點反覆讀出、刪除即得到有序序列

堆排序測試代碼:

#include <iostream>
#include "MaxHeap.h"

using namespace std;

int main(int argc, char* argv[])
{
    int a[10] = { 11,3,25,177,299,0,52,74,86,308 };
    int n = 10;

    MaxHeap<int> heap;
    for (auto x : a)
    {
        heap.push(x);
    }

    cout << "從小到大:";
    for (int i = n-1; i >=0; i--)
    {
        a[i] = heap.top();
        heap.pop();
    }

    //cout << "從大到小:";
    //for (int i = 0; i < n; i++)
    //{
    //    a[i] = heap.top();
    //    heap.pop();
    //}

	// 輸出排序結果
    for (int i = 0; i < n; i++)
        cout << a[i] << ", ";
    cout << endl;

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章