數據結構基礎(19) --堆與堆排序

完全二叉樹

 

首先讓我們回顧一下完全二叉樹的兩個性質:

  性質1:具有n個結點的完全二叉樹的深度爲[logn](向下取整)+1。

  性質2:若對含 個結點的完全二叉樹從上到下且從左至右進行 至 的編號,則對完全二叉樹中任意一個編號爲 的結點:

    (1) 若 i=1,則該結點是二叉樹的根,無雙親,否則,編號爲 [i/2](向下取整)的結點爲其雙親結點;
    (2) 若 2i>n,則該結點無左孩子,否則,編號爲 2i 的結點爲其左孩子結點;
    (3) 若 2i+1>n,則該結點無右孩子結點,否則,編號爲2i+1 的結點爲其右孩子結點。

 

數組與完全二叉樹

 

從上圖可以看出, 如果完全二叉樹從上到下且從左至右進行從0至n-1進行編號,則對完全二叉樹的性質需要修改如下:

   (1) 若 i=0,則該結點是二叉樹的根,無雙親,否則,編號爲 [(i-1)/2](向下取整)的結點爲其雙親結點;
   (2) 若 2i+1>n,則該結點無左孩子,否則,編號爲 2i+1 的結點爲其左孩子結點;
   (3) 若 2i+2>n,則該結點無右孩子結點,否則,編號爲2i+2 的結點爲其右孩子結點。


大頂堆與小頂堆

 

堆是滿足下列性質的數列{r1, r2, …,rn}:


(小頂堆)


(大頂堆)

 

大頂堆的設計

  1. template <typename Type>  
  2. class MaxHeap  
  3. {  
  4. public:  
  5.     MaxHeap(int _maxSize = 10);  
  6.     virtual ~MaxHeap();  
  7.   
  8.     bool isEmpty() const;  
  9.     void push(const Type &item);  
  10.     void pop();  
  11.     const Type &top() const;  
  12.   
  13. private:  
  14.     //將堆的容量增大兩倍  
  15.     void resize();  
  16.     //向上滲透  
  17.     void trickUp(int index);  
  18.     //向下滲透  
  19.     void trickDown(int index);  
  20.   
  21. private:  
  22.     Type *heapArray;  
  23.     int maxSize;  
  24.     //currentSize有兩個含義:  
  25.     // 1.代表當前堆中已經存儲的元素數  
  26.     // 2.代表當前完全二叉樹的第一個空位  
  27.     int currentSize;  
  28. };  

大頂堆的實現

  1. //構造  
  2. template <typename Type>  
  3. MaxHeap<Type>::MaxHeap(int _maxSize)  
  4.     : maxSize(_maxSize),currentSize(0)  
  5. {  
  6.     if (maxSize < 1)  
  7.         throw std::length_error("heap size must >= 1");  
  8.   
  9.     heapArray = new Type[maxSize];  
  10. }  
  11. //析構  
  12. template <typename Type>  
  13. MaxHeap<Type>::~MaxHeap()  
  14. {  
  15.     delete []heapArray;  
  16.     heapArray = NULL;  
  17.     currentSize = 0;  
  18. }  
  19. //判空  
  20. template <typename Type>  
  21. bool MaxHeap<Type>::isEmpty() const  
  22. {  
  23.     return currentSize == 0;  
  24. }  

堆頂元素

  1. //查看堆頂元素  
  2. template <typename Type>  
  3. const Type &MaxHeap<Type>::top() const  
  4. {  
  5.     if (isEmpty())  
  6.         throw std::underflow_error("heap is empty");  
  7.   
  8.     return heapArray[0];  
  9. }  

插入元素

  1. //插入  
  2. template <typename Type>  
  3. void MaxHeap<Type>::push(const Type &item)  
  4. {  
  5.     //如果堆已滿, 則需要對堆進行擴充  
  6.     if (currentSize == maxSize)  
  7.     {  
  8.         resize();  
  9.     }  
  10.     //將元素插入到堆的第一個空位置上  
  11.     heapArray[currentSize] = item;  
  12.   
  13.     //維護堆的性質:向上滲透  
  14.     trickUp(currentSize);  
  15.     ++ currentSize;  
  16. }  
  1. //向上滲透, 將剛剛插入的元素移動到合適的位置上  
  2. template <typename Type>  
  3. void MaxHeap<Type>::trickUp(int index)  
  4. {  
  5.     //根據完全二叉樹的性質, 找到父節點  
  6.     int parent = (index-1)/2;  
  7.     Type bottom = heapArray[index];  
  8.   
  9.     //循環終止條件  
  10.     // 1. index = 0 //bottom元素插入到根節點  
  11.     // 2. heapArray[parent] >= bottom   //bottom插入到parent節點的一個子節點上  
  12.     while ((index > 0) && (heapArray[parent] < bottom))  
  13.     {  
  14.         //父節點下移  
  15.         heapArray[index] = heapArray[parent];  
  16.         index = parent;  
  17.         parent = (parent-1)/2;  
  18.     }  
  19.     //插入  
  20.     heapArray[index] = bottom;  
  21. }  
  1. //將堆的大小加倍  
  2. template <typename Type>  
  3. void MaxHeap<Type>::resize()  
  4. {  
  5.     int newSize = std::max(maxSize*2, 1);  
  6.     Type *newHeap = new Type[newSize];  
  7.     for (int i = 0; i < currentSize; ++i)  
  8.     {  
  9.         newHeap[i] = heapArray[i];  
  10.     }  
  11.   
  12.     delete []heapArray;  
  13.     heapArray = newHeap;  
  14.     maxSize = newSize;  
  15. }  

刪除堆頂元素

  1. //刪除  
  2. template <typename Type>  
  3. void MaxHeap<Type>::pop()  
  4. {  
  5.     if (isEmpty())  
  6.         throw std::underflow_error("heap is empty");  
  7.   
  8.     //只有一個元素  
  9.     if (currentSize == 1)  
  10.     {  
  11.         heapArray[0].~Type();  
  12.         currentSize = 0;  
  13.         return ;  
  14.     }  
  15.   
  16.     //顯示釋放堆頂元素  
  17.     heapArray[0].~Type();  
  18.     //直接將最有一個元素放到堆頂,  
  19.     //並且currentSize-1  
  20.     heapArray[0] = heapArray[-- currentSize];  
  21.   
  22.     //此時如果破壞了堆的性質:向下滲透  
  23.     trickDown(0);  
  24. }  
  1. //向下滲透  
  2. template <typename Type>  
  3. void MaxHeap<Type>::trickDown(int index)  
  4. {  
  5.     int largeChild;  
  6.     Type top = heapArray[index];  
  7.   
  8.     // 只需到達完全二叉樹的最後一層  
  9.     // 的上一層即可  
  10.     // 循環的終止條件:  
  11.     // 1. index已經到達了最後一層(index >= currentSize/2 :找到了一個比較合適的位置)  
  12.     // 2. 在堆的中間找到了一個合適的位置(top >= heapArray[largeChild])  
  13.     while (index < currentSize/2)  
  14.     {  
  15.         int leftChild = (index*2)+1;  
  16.         int rightChild = leftChild + 1;  
  17.   
  18.         //如果有右兒子節點, 而且右兒子節點還大於左兒子節點  
  19.         if (rightChild < currentSize && heapArray[rightChild] > heapArray[leftChild])  
  20.             largeChild = rightChild;  
  21.         else  
  22.             largeChild = leftChild;  
  23.   
  24.         if (top >= heapArray[largeChild])  
  25.             break;  
  26.   
  27.         //不然的話, 則需繼續向下滲透  
  28.         heapArray[index] = heapArray[largeChild];  
  29.         // index需要向下搜索  
  30.         index = largeChild;  
  31.     }  
  32.     //插入  
  33.     heapArray[index] = top;  
  34. }  

堆排序

  堆排序就是將元素一個一個插入到堆中, 然後再一個一個的取出來;

  1. //堆排序  
  2. template <typename Type>  
  3. void heapSort(Type *begin, Type *end)  
  4. {  
  5.     int size = end-begin;  
  6.     MaxHeap<Type> maxHeap(size);  
  7.     //存入堆中  
  8.     for (Type *current = begin; current < end; ++ current)  
  9.         maxHeap.push(*current);  
  10.   
  11.     //從堆中取出  
  12.     while (begin != end)  
  13.     {  
  14.         *begin = maxHeap.top();  
  15.         ++ begin;  
  16.         maxHeap.pop();  
  17.     }  
  18. }  
  19.   
  20. template <typename Type>  
  21. void heapSort(Type *array, int arraySize)  
  22. {  
  23.     return heapSort(array, array+arraySize);  
  24. }  

-測試代碼:

  1. int main()  
  2. {  
  3.     int array[20];  
  4.     for (int i = 0; i < 20; ++i)  
  5.     {  
  6.         array[i] = rand()%100;  
  7.         cout << array[i] << ' ';  
  8.     }  
  9.   
  10.     heapSort(array, 20);  
  11.   
  12.     cout << endl;  
  13.     for (int i = 0; i < 20; ++i)  
  14.     {  
  15.         cout << array[i] << ' ';  
  16.     }  
  17.     cout << endl;  
  18.   
  19.     return 0;  


原文地址:http://blog.csdn.net/zjf280441589/article/details/42682141

發佈了62 篇原創文章 · 獲贊 16 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章