今天多睡了半小時,看來是太累了,可是還不能令自己滿意,還要繼續努力,一頭扎在堆裡。。。
堆排序,今天就來看下另一種排序演算法:堆排序。
堆排序其實是對選擇排序的改進。
改進的著眼點:
減少關鍵碼間的比較次數。若能利用每趟比較後的結果,也就是在找出鍵值最小記錄的同時,也找出鍵值較小的記錄,則可減少後面的選擇中所用的比較次數,從而提高整個排序過程的效率。在選擇排序中,為找出關鍵字最小的記錄需要作n-1次比較,然後為尋找關鍵字次小的記錄要對剩下的n-1個記錄進行n-2次比較。在這n-2次比較中,有許多次比較在第一次排序的n-1次比較中已做了。
事實上,直接選擇排序的每次排序除了找到當前關鍵字最小的記錄外,還產生了許多比較結果資訊,這些資訊在以後的各次排序中還有用,但由於沒有儲存這些資訊,所以每次排序都要對剩餘的全部記錄的關鍵字重新進行一遍比較,這樣就大大增加了時間開銷。
堆排序是針對直接選擇排序所存在的上述問題的一種改進方法。它在尋找當前關鍵字最小的記錄的同時,還儲存了本次排序過程所產生的其他比較資訊。下面先介紹有關堆的概念。
堆的定義:
n個關鍵字序列稱為堆,當且僅當該序列滿足特性: (1)ki≤k2i 且 ki≤k2i+1 或 (2)ki≥k2i 且堆排序基本思想:ki≥k2i+1
從堆的定義可以看出,堆實質上是滿足如下性質的完全二叉樹:樹中任一非葉子結點的關鍵字均小於等於(或大於等於)其左右孩子結點的關鍵字值。
堆是具有下列性質的完全二叉樹:每個結點的值都小於或等於其左右孩子結點的值(稱為小根堆),或每個結點的值都大於或等於其左右孩子結點的值(稱為大根堆)。
首先將待排序的記錄序列構造成乙個堆,此時,選出了堆中所有記錄的最大者,然後將它從堆中移走,並將剩餘的記錄再調整成堆,這樣又找出了次小的記錄,以此類推,直到堆中只有乙個記錄。初始堆的建立:將乙個無序序列建成乙個堆
每加入乙個都要調整一次堆,所以先從堆調整來看。
堆調整演算法描述:
void sift ( int r[ ], int k, int m )
}r[i]=temp; //將篩選記錄移到正確位置
}
有了堆調整,初始化堆就好辦了。
演算法描述:
for (i=n/2; i>=1; i--)
sift(r, i, n) ;
然後每次取出堆頂元素按順序存入就好了。
堆排序演算法描述:
void heapsort ( int r, int n)
}
堆排序演算法的效能分析:
第1個for迴圈是初始建堆,需要o(n)時間;
第2個for迴圈是輸出堆頂重建堆,共需要取n-1次堆頂記錄,第 i 次取堆頂記錄重建堆需要o(logi)時間,需要o(nlogn)時間;
因此整個時間複雜度為o(nlogn),這是堆排序的最好、最壞和平均的時間代價。
堆排序不是乙個穩定的排序。
a little more for everyday.
基本演算法 堆排序 Java實現
堆排序就是將序列調整為指定的堆,然後調整首尾元素的位置,取出末尾元素,反覆進行,直到將所有元素取出,形成乙個有序的序列。假設存在 個元素的序列 其中父節點值不大於子節點值的堆稱為小根堆 r i r2 i 1且 ri r 2i 2 父節點的值不小於子節點的堆稱為大根堆 r i r2 i 1且 存在乙個...
基本排序演算法 之七 堆排序
首先放遞迴的版本,因為遞迴版本更容易理解過程。堆排序實際是把數列看成一顆完全二叉樹,而不是真的去用 指標結構體 構造一顆二叉樹。數列在堆中從上到下,從左至右依次排成一棵樹。下面是遞迴版本的 用來調整節點,保證節點大於左右孩子 templatevoid adjustnode t arr,int nod...
排序演算法 堆排序
1 什麼是堆 首先它是一顆完全二叉樹,並且父結點的值大於子節點的值 最大堆 或父結點的值小於子結點的值 最小堆 小根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最小者的堆稱為小根堆,又稱最小堆。大根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最大者,稱為大根堆,又稱最大堆。2 堆...