二叉堆是完全二叉樹或者是近似完全二叉樹。
二叉堆滿足二個特性:
1.父結點的鍵值總是大於或等於(小於或等於)任何乙個子節點的鍵值。
2.每個結點的左子樹和右子樹都是乙個二叉堆(都是最大堆或最小堆)。
當父結點的鍵值總是大於或等於任何乙個子節點的鍵值時為最大堆。當父結點的鍵值總是小於或等於任何乙個子節點的鍵值時為最小堆。如下圖所示
一般都用陣列來表示堆,i結點的父結點下標就為(i – 1) / 2。它的左右子結點下標分別為2 * i + 1和2 * i + 2。如第0個結點左右子結點下標分別為1和2。
這裡以大頂堆為例
#define l (2*x+1)
#define r (2*x+2)
void adjustmaxheap(int a, int i, int n) //調整大頂堆
每次插入都是將新資料放在陣列最後。可以發現從這個新資料的父結點到根結點必然為乙個有序的數列,現在的任務是將這個新資料插入到這個有序資料中。
堆中每次都只能刪除第0個資料。為了便於重建堆,實際的操作是將最後乙個資料的值賦給根結點,然後再從根結點開始進行一次從上向下的調整。調整時先在左右兒子結點中找最大的,如果父結點比這個最大的子結點還大說明不需要調整了,反之將父結點和它交換後再考慮後面的結點。相當於從根結點將乙個資料的「下沉」過程。
void maxheapfix(int a, int &n, int k) //堆的插入
n++;
}
void maxheapdelete(int a, int &n) //堆的刪除
首先可以看到堆建好之後堆中第0個資料是堆中最大的資料。取出這個資料再執行下堆的刪除操作。這樣堆中第0個資料又是堆中最大的資料,重複上述步驟直至堆中只有乙個資料時就直接取出這個資料。
堆化陣列後,第一次將a[0]與a[n - 1]交換,再對a[0…n-2]重新恢復堆。第二次將a[0]與a[n – 2]交換,再對a[0…n - 3]重新恢復堆,重複這樣的操作直到a[0]與a[1]交換。由於每次都是將最大的資料併入到後面的有序區間,故操作完成後整個陣列就有序了。下面附上完整的**:
//堆排序具體實現
#include #include using namespace std;
#define n 1000
#define l (2*x+1)
#define r (2*x+2)
#define max 0x3fffff
void swap(int &a, int &b)
void adjustmaxheap(int a, int i, int n) //調整大頂堆
n++;
}void maxheapdelete(int a, int &n) //堆的刪除
int main()
for(int i=0; i使用最大堆排序後是遞增陣列,要得到遞減陣列,可以使用最小堆,時間複雜度o(n * logn)。
堆與堆排序
堆排序與快速排序,歸併排序一樣都是時間複雜度為o n logn 的幾種常見排序方法。堆排序是就地排序,輔助空間為o 1 它是不穩定的排序方法。排序的穩定性是指如果在排序的序列中,存在前後相同的兩個元素的話,排序前 和排序後他們的相對位置不發生變化 先說說什麼是堆,堆通常是乙個可以被看做一棵樹的陣列物...
堆與堆排序
堆排序與快速排序,歸併排序一樣都是時間複雜度為o n logn 的幾種常見排序方法。學習堆排序前,先講解下什麼是資料結構中的二叉堆。二叉堆是完全二叉樹或者是近似完全二叉樹。二叉堆滿足二個特性 1 父結點的鍵值總是大於或等於 小於或等於 任何乙個子節點的鍵值。2 每個結點的左子樹和右子樹都是乙個二叉堆...
堆與堆排序
堆的儲存 一般都用陣列來表示堆,i結點的父結點下標就為 i 1 2。它的左右子結點下標分別為2 i 1和2 i 2。如第0個結點左右子結點下標分別為1和2。堆排序的思想 利用大頂堆 小頂堆 堆頂記錄的是最大關鍵字 最小關鍵字 這一特性,使得每次從無序中選擇最大記錄 最小記錄 變得簡單。其基本思想為 ...