1. 程式人生 > >c++堆排序實現(heapsort) (演算法導論)

c++堆排序實現(heapsort) (演算法導論)

利用最大堆實現。

最大堆:最大堆性質是除了根結點意外的所有結點 i 都要滿足A[parent[i]] >= A[i]

需要利用到的一個性質:當用陣列表示儲存n個元素的堆時,葉結點的下標分別是n/2, n/2+1, n/2 + 2, ......,n - 1.  (下標從0開始)

需要用到的函式有:

void max_heapify(int *a, int i)    //通過讓a[i]的值在最大堆中“逐級下降”,從而使得以下標i為根結點的字數重新遵循最大堆的性質。O(lgn)

void build_max_heap(int *a)            //對樹中非葉結點都呼叫一次max_heapify(a, i)。  O(n)

void heapsort(int *a, int n)        //對長度為n的陣列a呼叫堆排序。  O(nlgn)

//heapsort.cpp
inline void swap(int &a, int &b) { int t = a; a = b; b = t; }
inline int parent(int i) { return (i-1) >> 1; }         //下標都是從0開始,與算導上不一樣
inline int left(int i) { return (i << 1) + 1; }
inline int right(int i) { return (i << 1) + 2; }

int heap_size, heap_length;          //heap_length是陣列元素個數,heap_size是有多少個元素儲存在陣列中。0<=heap_size<=heap_length

void max_heapify(int *a, int i) {             //O(lgn), 維護heap的性質,使得以下標i為根結點的子樹重新遵循最大堆的性質
	int l = left(i), r = right(i);
	int largest = 0;
	if (l < heap_size && a[l] > a[i])
		largest = l;
	else
		largest = i;
	if (r < heap_size && a[r] > a[largest])
		largest = r;
	if (largest != i) {
		swap(a[i], a[largest]);
		max_heapify(a, largest);
	}
}

void build_max_heap(int *a) {             //O(n), 對樹中非葉結點都呼叫一次 max_heapify
	heap_size = heap_length;
	for (int i = heap_length/2 - 1; i >= 0; --i)   //可以證明下標為n/2-1到0的結點為非葉結點
		max_heapify(a, i);              //i逆序遞減的原因:任何時候對結點i呼叫max_heapify,該i的兩個子樹都是最大堆
}

void heapsort(int *a, int n) {           //O(nlgn),呼叫heapsort(a, n)對陣列a排序
	heap_length = n;
	build_max_heap(a);
	for (int i = heap_length - 1; i >= 1; --i) {
		swap(a[0], a[i]);
		--heap_size;
		max_heapify(a, 0);
	}
}