堆排序原理及其實現 C

2021-08-20 23:11:32 字數 4186 閱讀 9246

我們知道簡單選擇排序的時間複雜度為o(n^2),熟悉各種排序演算法的朋友都知道,這個時間複雜度是很大的,所以怎樣減小簡單選擇排序的時間複雜度呢?簡單選擇排序主要操作是進行關鍵字的比較,所以怎樣減少比較次數就是改進的關鍵。簡單選擇排序中第i趟需要進行n-i次比較,如果我們用到前面已排好的序列a[1...i-1]是否可以減少比較次數呢?答案是可以的。舉個例子來說吧,a、b、c進行比賽,b戰勝了a,c戰勝了b,那麼顯然c可以戰勝a,c和a就不用比了。正是基於這種思想,有人提出了樹形選擇排序:對n個記錄進行兩兩比較,然後在([n/2]向上取整)個較小者之間在進行兩兩比較,如此重複,直到選出最小記錄。但是這種排序演算法需要的輔助空間比較多,所以威洛姆斯(j . willioms)在2023年提出了另一種選擇排序,這就是下面要談的堆排序。www.gaimor.cn

首先堆heap是一種資料結構,是一棵完全二叉樹且滿足性質:所有非葉子結點的值均不大於或均不小於其左、右孩子結點的值.

堆排序的基本思想是利用heap這種資料結構(可看成乙個完全二叉樹),使在排序中比較的次數明顯減少。

堆排序的時間複雜度為o(n*log(n)), 非穩定排序,原地排序(空間複雜度o(1))。

wwwww.gaimor.cn堆排序的關鍵在於建堆和調整堆,下面簡單介紹一下建堆的過程:

第1趟將索引0至n-1處的全部資料建大頂(或小頂)堆,就可以選出這組資料的最大值(或最小值)。將該堆的根節點與這組資料的最後乙個節點交換,就使的這組資料中最大(最小)值排在了最後。

第2趟將索引0至n-2處的全部資料建大頂(或小頂)堆,就可以選出這組資料的最大值(或最小值)。將該堆的根節點與這組資料的倒數第二個節點交換,就使的這組資料中最大(最小)值排在了倒數第2位。

第k趟將索引0至n-k處的全部資料建大頂(或小頂)堆,就可以選出這組資料的最大值(或最小值)。將該堆的根節點與這組資料的倒數第k個節點交換,就使的這組資料中最大(最小)值排在了倒數第k位。www.acgred.cn

其實整個堆排序過程中, 我們只需重複做兩件事:

因而堆排序整體的時間複雜度為o(n*log n).

下面通過一組資料說明堆排序的方法:

9, 79, 46, 30, 58, 49

1: 先將待排序的數視作完全二叉樹(按層次遍歷順序進行編號, 從0開始),如下圖:

2:完全二叉樹的最後乙個非葉子節點,也就是最後乙個節點的父節點。最後乙個節點的索引為陣列長度len-1,那麼最後乙個非葉子節點的索引應該是為(len-1)/2.也就是從索引為2的節點開始,如果其子節點的值大於其本身的值。則把他和較大子節點進行交換,即將索引2處節點和索引5處元素交換。交換後的結果如圖:

建堆從最後乙個非葉子節點開始即可

3:向前處理前乙個節點,也就是處理索引為1的節點,此時79>30,79>58,因此無需交換。

4:向前處理前乙個節點,也就是處理索引為0的節點,此時9 < 79,9 < 49, 因此需交換。應該拿索引為0的節點與索引為1的節點交換,因為79>49. 如圖:

5:如果某個節點和它的某個子節點交換後,該子節點又有子節點,系統還需要再次對該子節點進行判斷。如上圖因為1處,3處,4處中,1處的值大於3,4出的值,所以還需交換。

牢記:將每次堆排序得到的最大元素與當前規模的陣列最後乙個元素交換。

1、由於是完全二叉樹, 故有:

parent(i)

return i / 2

left(i)

return 2 * i

right(i)

2 * i + 1

2、heapify

以最大堆為例,偽**:

max-heapify(a, i)

l = lift(i)

r = right(i)

if l <= a.heapsize and a[l] > a[i]

largest = l

else largest = i

if r <= a.heapsize and a[r] > a[largest]

largest = r

if largest != i

exchage a[i] with a[largest]

max-heapify(a, largest)

3、build heap

以最大堆為例,偽**:

build-max-heap(a)

a.heap-size = a.length

for a.length / 2 downto 1

max-heapify(a, i)

4、heapsort

以最大堆為例,偽**:

heapsort(a)

build-max-heap(a)

for i = a.length downto 2

exchange a[1] with a[i]

a.heap-size = a.heap-size - 1

max-heapify(a, 1)

#include

#include

#include

#include

using

namespace

std;

void adjust(int arr, int len, int index)

}void heapsort(int arr, int size)

for(int i = size - 1; i >= 1; i--)

}int main()

; heapsort(array, 8);

for(auto it: array)

當陣列中有相等元素時,堆排序演算法對這些元素的處理方法不止一種,故是不穩定的。

#include

#include

#include

void swap(void* x, void* y, size_t sz)

void makeheap(void* x, int i, int n, size_t sz, int(*cmp)(const

void*, const

void*))

}void buildheap(void* x, int n, size_t sz, int(*cmp)(const

void*, const

void*))

void heapsort(void* x, int n, size_t sz, int(*cmp)(const

void*, const

void*))

}void p(int* x,int n)

printf("\n");

}int less(const

void* a, const

void* b)

int greater(const

void* a, const

void* b)

int main();

// 降序全排列

heapsort(x, 8, sizeof(int), less);

p(x, 8);

// 公升序全排列

heapsort(x, 8, sizeof(int), greater);

p(x, 8);

// 最大的4個元素,在陣列末尾

heapsort(x, 4, sizeof(int), less);

p(x, 8);

}

堆排序原理及其實現 C

我們知道簡單選擇排序的時間複雜度為o n 2 熟悉各種排序演算法的朋友都知道,這個時間複雜度是很大的,所以怎樣減小簡單選擇排序的時間複雜度呢?簡單選擇排序主要操作是進行關鍵字的比較,所以怎樣減少比較次數就是改進的關鍵。簡單選擇排序中第i趟需要進行n i次比較,如果我們用到前面已排好的序列a 1.i ...

堆排序原理及其實現 C

我們知道簡單選擇排序的時間複雜度為o n 2 熟悉各種排序演算法的朋友都知道,這個時間複雜度是很大的,所以怎樣減小簡單選擇排序的時間複雜度呢?簡單選擇排序主要操作是進行關鍵字的比較,所以怎樣減少比較次數就是改進的關鍵。簡單選擇排序中第i趟需要進行n i次比較,如果我們用到前面已排好的序列a 1.i ...

堆排序原理及其實現 c

老生常談,開篇介紹,定義先行 堆排序 英語 heapsort 是指利用堆這種資料結構所設計的一種排序演算法。堆是乙個近似完全二叉樹的結構,並同時滿足堆積的性質 即子結點的鍵值或索引總是小於 或者大於 它的父節點 實現 include using namespace std 交換 void swap ...