二叉堆的實現


二叉堆是一種特殊的堆,二叉堆是完全二元樹(二叉樹)或者是近似完全二元樹(二叉樹)。

二叉堆有兩種:最大堆和最小堆。

最大堆:父結點的鍵值總是大於或等於任何一個子結點的鍵值;

最小堆:父結點的鍵值總是小於或等於任何一個子節點的鍵值。

二叉堆一般都通過"數組"來實現。數組實現的二叉堆,父節點和子節點的位置存在一定的關系。我們將"二叉堆的第一個元素"放在數組索引0的位置。
假設"第一個元素"在數組中的索引為 0 的話,則父節點和子節點的位置關系如下: 
1、索引為i的左孩子的索引是 (2*i+1); 
2、索引為i的左孩子的索引是 (2*i+2); 
3、索引為i的父結點的索引是 floor((i-1)/2);

 

二叉堆這種有序隊列如何入隊呢?

假設要在這個二叉堆里入隊一個單元,只要在數組末尾加入這個元素,然后把這個元素往上挪,直到挪不動,經過了這種復雜度為Ο(logn)的操作,二叉堆性質沒有變化。

那如何出隊呢?

我們習慣將二叉堆畫成樹的形式,但本質上還是用數組實現的。

具體代碼如下:

  1 #include <vector>
  2 #include <iostream>
  3 using namespace std;
  4 
  5 template <typename T>
  6 class MinHeap
  7 {
  8 public:
  9     vector<T> m_array;
 10     int m_size;//總容量
 11 private:
 12     //最小堆的向下調整算法
 13     void FilterDown(int start, int end);
 14     //最小堆的向上調整算法
 15     void FilterUp(int start);
 16 public:
 17     MinHeap();
 18     MinHeap(int capacity);
 19     MinHeap(vector<T> data);
 20     ~MinHeap();
 21 
 22     //返回data在vector中的索引
 23     int GetIndex(T data);
 24     //刪除最小堆中的data
 25     bool Remove(T data);
 26     //將data插入到最小堆中
 27     void Insert(T data);
 28     //打印
 29     void Print();
 30 };
 31 
 32 template <typename T>
 33 MinHeap<T>::MinHeap(vector<T> data)
 34 {
 35     for (auto val : data)
 36     {
 37         Insert(val);
 38     }
 39 }
 40 
 41 
 42 template <typename T>
 43 MinHeap<T>::MinHeap(int capacity)
 44 {
 45     m_array.reserve(capacity);
 46     m_capacity = capacity;
 47 }
 48 
 49 template <typename T>
 50 MinHeap<T>::MinHeap()
 51 {
 52     m_array.reserve(100);
 53 }
 54 
 55 
 56 template <typename T>
 57 MinHeap<T>::~MinHeap()
 58 {
 59     m_size = 0;
 60     m_array.clear();
 61 }
 62 
 63 //得到data的索引,-1表示未找到
 64 template <typename T>
 65 int MinHeap<T>::GetIndex(T data)
 66 {
 67     for (int i = 0; i < m_size; ++i)
 68     {
 69         if (m_array[i] == data)
 70             return i;
 71     }
 72     return -1;
 73 }
 74 
 75 
 76 /*
 77 * 最小堆的向下調整算法
 78 *
 79 * 數組實現的堆中,第N個節點的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
 80 *
 81 * start -- 被下調節點的起始位置(一般為0,表示從第1個開始)
 82 * end   -- 截至范圍(一般為數組中最后一個元素的索引)
 83 */
 84 template <typename T>
 85 void MinHeap<T>::FilterDown(int start, int end)
 86 {
 87     int current = start;//當前結點位置
 88     int left = 2 * current + 1;//左兒子位置
 89     T tmp = m_array[current];//當前結點大小
 90 
 91     while (left <= end)
 92     {
 93         if (left < end && m_array[left] > m_array[left + 1])
 94         {
 95             left++;//左右孩子選較小者
 96         }
 97         if (tmp <= m_array[left])
 98             break;//調整結束
 99         else
100         {
101             m_array[current] = m_array[left];
102             current = left;
103             left = 2 * left + 1;
104         }
105     }
106     m_array[current] = tmp;
107 }
108 
109 //刪除最小堆中的data
110 template <typename T>
111 bool MinHeap<T>::Remove(T data)
112 {
113     int index;
114     if (m_size == 0)
115         return false;
116     index = GetIndex(data);
117     if (index == -1)
118         return false;
119     m_array[index] = m_array[--m_size];
120     m_array.erase(m_array.end() - 1);
121     FilterDown(index, m_size - 1);
122     return true;
123 }
124 
125 //向上調整
126 template <typename T>
127 void MinHeap<T>::FilterUp(int start)
128 {
129     int current = start;
130     int p = (current - 1) / 2;//父結點位置
131     T tmp = m_array[current];
132     while (current > 0)
133     {
134         if (m_array[p] <= tmp)
135             break;
136         else
137         {
138             m_array[current] = m_array[p];
139             current = p;
140             p = (p - 1) / 2;
141         }
142     }
143     m_array[current] = tmp;
144 }
145 
146 
147 template <typename T>
148 void MinHeap<T>::Insert(T data)
149 {
150     m_array.push_back(data);
151     m_size++;
152     FilterUp(m_size - 1);
153 }
154 
155 
156 template <typename T>
157 void MinHeap<T>::Print()
158 {
159     for (auto val : m_array)
160     {
161         cout << val << " ";
162     }
163 }

 

測試:

 1 #include "BinaryHeap.h"
 2 
 3 int main()
 4 {
 5     int tmp;
 6     vector<int> vec{ 80, 40, 30, 60, 90, 70, 10, 50, 20 };
 7     MinHeap<int> heap(vec);
 8     cout << "最小堆為:";
 9     heap.Print();
10     cout << "\n請輸入要添加的元素";
11     cin >> tmp;
12     heap.Insert(tmp);
13     cout << "添加之后最小堆為:";
14     heap.Print();
15     cout << "\n請輸入要刪除的元素:";
16     cin >> tmp;
17     heap.Remove(tmp);
18     cout << "刪除之后最小堆為:";
19     heap.Print();
20 
21 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM