排序是計算機的一項主要任務。這並不是因為排序本身非常有趣,而是因為很多其它演算法依賴於排序才能正常執行。本文主要描述如何實現堆排序演算法,該演算法依賴於稱為堆的資料結構。
本文的具體實現可以檢視對應的 xcode playground 檔案。
堆是乙個完整且部分排序的二叉樹。通俗一點講就是它總是將新資料節點插入最深一層的左側。從某種意義上講,元素間是有順序的,儘管實際上並未做排序操作。
在本教程中,我們將使用最大堆(max heap)實現乙個始終在 o(n * log(n)) 時間內執行的排序演算法。首先,我們將實現乙個sortingalgorithms
類,該類帶有乙個對陣列進行排序的靜態函式,然後再使用面向協議的解決方案。
關於最大堆,有三個重要事項:
首先,我們來擴充套件 swift 標準庫的 int 型別的實現,以抽象出獲取父節點和子節點索引的運算公式。如下**所示:
private
extension
int
var leftchild: int
var rightchild: int
}複製**
使用這些**,我們可以通過計算屬性來計算索引,而不是需要時直接用數學公式來計算。這樣保證了可讀性。另外這是乙個私有擴充套件,意味著它不會影響 int 的整體性,而只是在該檔案作用域中可用。
接下來,讓我們分步來說明排序演算法的各個步驟。
首先,我們將從陣列構建乙個最大堆。基本操作是將新元素插入到堆的末尾再交換到正確的位置,因此我們可以使用簡單的迴圈來模擬插入操作。我們先假定陣列只有兩個元素,「堆積」這兩個元素,在迴圈的每個迭代中,我們插入乙個元素並重新堆積。如下所示:
操作完成後,陣列看上去並沒有特意排序。事實上,看起來更糟糕。這是因為我們使用陣列儲存了樹的節點。看一下操作前後的對比:
看上去我們只是交換了元素,但事實上,我們剛剛建立了乙個將用於完成排序的屬性。
獲取第乙個元素,然後將其與最後乙個元素交換,我們可以把最大的元素放到最後。然後假定陣列長度減 1,然後重新堆積這個子陣列,又可以得到這個子陣列的最大元素。然後將子陣列的最大元素放到子陣列最後,這樣依此類推,就可以得到乙個完全排序的陣列。
我們的 .heapsort(_:) 方法的**如下,包括構建和縮小堆。
class
sortingalgorithms
public
static
func
heapsort
(_ array: inout [datatype])
buildheap(&array)
shrinkheap(&array)
} private
static
func
buildheap
(_ array: inout [datatype])
}}
private
static
func
shrinkheap
(_ array: inout [datatype])
else
if rightchild < index && array[rightchild] > array[maxchild]
guard array[maxchild] > array[parent] else
swap(parent, with: maxchild, in: &array)
parent = maxchild
leftchild = parent.leftchild
rightchild = parent.rightchild}}
} private
static
func
swap
(_ firstindex: int, with secondindex: int, in array: inout [datatype]) }
複製**
這就是我們想要的,不過我們可以讓它更乾淨一些。
通過擴充套件可比較元素型別的 array 型別,我們能得到一些好處。乙個是**量更少,另乙個是可以直接在物件上呼叫方法,而不需要如下處理:
sortingalgorithms.heapsort(&myarray)
複製**
而是這樣:
myarray.heapsort()
複製**
這樣更加清晰。元素型別不符合 comparable 協議時,編輯器甚至不會在陣列物件上智慧型提示 .heapsort()。
public
extension
array
where
element: comparable
private
mutating
func
buildheap()
}}
private
mutating
func
shrinkheap
() else
if rightchild < index && self[rightchild] > self[maxchild]
guard
self[maxchild] > self[parent] else
swapat(parent, maxchild)
parent = maxchild
leftchild = parent.leftchild
rightchild = parent.rightchild}}
}}複製**
done!!! 堆排序(Swift版本)
一 什麼是堆?堆可視為 以陣列方式儲存的一棵完全二叉樹 堆又分為最大堆和最小堆,最大堆就是對於整個二叉樹中的每乙個節點都滿足 節點的鍵值比其左右子節點的鍵值都要大,對應的最小堆則是 節點的鍵值比其左右子節點的鍵值都要小 二 堆排序的思路 對於乙個儲存最大堆的陣列arr 長度為size 根節點arr ...
堆排序實現
今天抽空寫了個堆排序的演算法,廢話不多說,直接上源 include include includeusing namespace std define maxsize 6 void print int a,int size maxsize void percolate up int a,int si...
堆排序實現
1 堆排序演算法描述 1 定義 n個關鍵字序列kl,k2,kn稱為 heap 當且僅當該序列滿足如下性質 簡稱為堆性質 1 ki k 2i 且ki k 2i 1 1 i n 2 當然,這是小根堆,大根堆則換成 號。k i 相當於 二叉樹的非 葉子結點,k 2i 則是左子節點,k 2i 1 是右子節點...