<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
1.物理結構是陣列
2.邏輯結構是完全二元樹
3.大堆:所有的父親節點都大於等於孩子節點,小堆:所有的父親節點都小於等於孩子節點。
概念:有一個小/大堆,在陣列最後插入一個元素,通過向上調整,使得該堆還是小/大堆。
使用條件:陣列前n-1個元素構成一個堆。
以大堆為例:
邏輯實現:
將新插入的最後一個元素看做孩子,讓它與父親相比,如果孩子大於父親,則將它們交換,將父親看做孩子,在依次比較,直到孩子等於0結束調整·。
如果中途孩子小於父親,則跳出迴圈,結束調整。
參考程式碼:
void AdjustUp(HPDataType* a, int child) { int parent = (child - 1) / 2; while (child > 0) { if (a[child] > a[parent])//如果孩子大於父親,則將它們交換。 { Swap(&a[child], &a[parent]); //迭代過程: child = parent; parent = (child - 1) / 2; } else { //如果孩子小於父親,結束調整 break; } } }
向上調整應用
給大小堆加入新的元素之後仍使得大小堆還是大小堆。
概念:根節點的左右子樹都是大小堆,通過向下調整,使得整個完全二元樹都是大小堆。
使用條件:根節點的左右子樹都是大小堆。
如圖根為23,它的左右子樹都是大堆,但整顆完全二元樹不是堆,通過向下調整可以使得整顆完全二元樹是堆。
邏輯實現:
選出根的左右孩子較大的那個孩子,然後與根比較,如果比根大,則交換,否則結束調整。
參考程式碼:
void AdjustDown(HPDataType* a, int size, int root) { int parent = root; int child = parent * 2 + 1;//左孩子 while (child < size) { if (child + 1 < size && a[child] < a[child + 1])//如果左孩子小於右孩子,則選右孩子 { //務必加上child+1,因為當child=size-1時,右孩子下標是size,對其接參照會越界存取。 child++;//右孩子的下標等於左孩子+1 } if (a[child] > a[parent])//讓較大的孩子與父親比較,如果孩子大於父親,則將它們交換。 { Swap(&a[child], &a[parent]); //迭代過程 parent = child; child = parent * 2 + 1; } else { break; } } }
第一種:向上調整建堆(時間複雜度是O(N*logN),空間複雜度O(1))
思路是:從第二個陣列元素開始到最後一個陣列元素依次進行向上調整。
參考程式碼:
for (int i = 1; i < n; i++) { AdjustUp(a, i); }
時間複雜度計算:
以滿二元樹進行計算
最壞情況執行步數為:T=(2^1)*1+(2^2)*2+(2^3)*3+....+2^(h-1)*(h-1)
最後化簡得:T=2^h*(h-2)+2
又因為(2^h)-1=N
所以h=log(N+1)
帶入後得T=(N+1)*(logN-1)+2
因此它的時間複雜度是:O(N*logN)
第二種:向下調整建堆(時間複雜度是O(N),空間複雜度是O(1))
從最後一個非葉子節點(最後一個陣列元素的父親)開始到第一個陣列元素依次進行向下調整。
參考程式碼:
//n代表陣列元素個數,j的初始值代表最後一個元素的父親下標 for (int j = (n - 1 - 1) / 2; j >= 0; j--) { AdjustDown(a, n, j); }
時間複雜度計算:
以滿二元樹進行計算
最壞執行次數:
T=2^(h-2)*1+2^(h-3)*2+2^(h-4)*3+.....+2^3*(h-4)+2^2*(h-3)+2^1*(h-2)+2^0*(h-1)
聯立2^h-1=N
化簡得T=N-log(N+1)
當N很大時,log(N+1)可以忽略。
因此它的時間複雜度是O(N)。
因此我們一般建堆採用向下調整的建堆方式。
目前最好的排序演演算法時間複雜度是O(N*logN)
堆排序的時間複雜度是O(N*logN)
堆排序是對堆進行排序,因此當我們對某個陣列進行排序時,我們要先將這個陣列建成堆,然後進行排序。
首先需要知道的是:
對陣列升序,需要將陣列建成大堆。
對陣列降序,需要將陣列建成小堆。
這是為什麼呢?
這需要明白大堆和小堆的區別,大堆堆頂是最大數,小堆堆頂是最小數。
當我們首次建堆時,建大堆能夠得到第一個最大數,然後可以將它與陣列最後的元素進行交換,下一次我們只需要將堆頂的數再次進行向下調整,可以再次將陣列變成大堆,然後與陣列的倒數第二個元素進行交換,自此已經排好了兩個元素,使得它們儲存在需要的地方,然後依次進行取數,調整。
而如果是小堆,首次建堆時,我們能夠得到最小的數,然後將它放在陣列第一個位置,然後你要保持它還是小堆,該怎麼辦呢?只能從第二個元素開始從下建堆,而建堆的時間複雜度是O(N),你需要不斷重建堆,最終堆排序的時間複雜度是O(N*N),這是不明智的。
或者建好小堆後,你這樣做:
在開一個n個陣列的空間,選出第一個最小數就將它放在新開闢的陣列空間中儲存,然後刪除堆頂數,再通過向下調整堆頂的數,再將新堆頂數放在新陣列的第二個位置.......。
雖然這樣的時間複雜度是O(N*logN)。
但這樣的空間複雜度是O(N)。
也不是最優的堆排序方法。
而建大堆的好處就在它把選出的數放在最後,這樣我們就可以對堆頂進行向下調整,使得它還是大堆,而向下調整的時間複雜度是O(logN),最終堆排序的時間複雜度是O(N*logN)。
堆排序的核心要義:
通過建大堆或者小堆的方式,選出堆中最大或者最小的數,從後往前放。
參考程式碼:
int end = n - 1;//n代表陣列元素的個數 while (end > 0) { Swap(&a[0], &a[end]); AdjustDown(a, end, 0); end--; }
整個堆排序的程式碼:
void Swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } void AdjustUp(int* a, int child) { int parent = (child - 1) / 2; while (child > 0) { if (a[child] > a[parent]) { Swap(&a[child], &a[parent]); child = parent; parent = (child - 1) / 2; } else { break; } } } void AdjustDown(int* a, int n, int root) { int child = 2 * root + 1; while (child < n) { if (child + 1 < n && a[child] < a[child+1]) { child++; } if (a[child] > a[root]) { Swap(&a[child], &a[root]); root = child; child = 2 * root + 1; } else { break; } } } void HeapSort(int* a, int n) { //建大堆(向上調整) //for (int i = 1; i < n; i++) //{ // AdjustUp(a, i); //} //建大堆(向下調整) for (int j = (n - 1 - 1) / 2; j >= 0; j--) { AdjustDown(a, n, j); } //升序 int end = n - 1; while (end > 0) { Swap(&a[0], &a[end]); AdjustDown(a, end, 0); end--; } } void printarr(int* a, int n) { for (int i = 0; i < n; i++) { printf("%d ", a[i]); } printf("n"); } int main() { int arr[10] = { 9,2,4,8,6,3,5,1,10 }; int size = sizeof(arr) / sizeof(arr[0]); HeapSort(arr, size); printarr(arr, size); return 0; }
到此這篇關於C語言資料結構中堆排序的分析總結的文章就介紹到這了,更多相關C語言 堆排序內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45