日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

堆排序原理及其实现(C++)

發布時間:2023/12/3 c/c++ 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 堆排序原理及其实现(C++) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

https://blog.csdn.net/lzuacm/article/details/52853194

堆排序原理及其實現(C++)

1. 堆排序的引入

我們知道簡單選擇排序的時間復雜度為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)在1964年提出了另一種選擇排序,這就是下面要談的堆排序。

2. 什么是堆

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

3. 堆排序思想

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

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

堆排序的關鍵在于建堆和調整堆,下面簡單介紹一下建堆的過程:

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

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

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

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

  • 建堆(初始化+調整堆, 時間復雜度為O(n));

  • 拿堆的根節點和最后一個節點交換(siftdown, 時間復雜度為O(n*log n) ).

因而堆排序整體的時間復雜度為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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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 != iexchage A[i] with A[largest]MAX-HEAPIFY(A, largest)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3、Build Heap?
以最大堆為例,偽代碼:

BUILD-MAX-HEAP(A)

A.heap-size = A.length for A.length / 2 downto 1MAX-HEAPIFY(A, i)
  • 1
  • 2
  • 3
  • 4

4、Heapsort?
以最大堆為例,偽代碼:

HEAPSORT(A)?
BUILD-MAX-HEAP(A)

for i = A.length downto 2exchange A[1] with A[i]A.heap-size = A.heap-size - 1MAX-HEAPIFY(A, 1)
  • 1
  • 2
  • 3
  • 4
  • 5

C++完整代碼:

#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std;void adjust(int arr[], int len, int index) {int left = 2*index + 1;int right = 2*index + 2;int maxIdx = index;if(left<len && arr[left] > arr[maxIdx]) maxIdx = left;if(right<len && arr[right] > arr[maxIdx]) maxIdx = right; // maxIdx是3個數中最大數的下標if(maxIdx != index) // 如果maxIdx的值有更新{swap(arr[maxIdx], arr[index]);adjust(arr, len, maxIdx); // 遞歸調整其他不滿足堆性質的部分}} void heapSort(int arr[], int size) {for(int i=size/2 - 1; i >= 0; i--) // 對每一個非葉結點進行堆調整(從最后一個非葉結點開始){adjust(arr, size, i);}for(int i = size - 1; i >= 1; i--){swap(arr[0], arr[i]); // 將當前最大的放置到數組末尾adjust(arr, i, 0); // 將未完成排序的部分繼續進行堆排序} }int main() {int array[8] = {8, 1, 14, 3, 21, 5, 7, 10};heapSort(array, 8);for(auto it: array){cout<<it<<endl;}return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

為何堆排序是不穩定排序?

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

可重載比較函數的寫法:

#include<memory.h> #include<stdio.h> #include<stdlib.h> void swap(void* x, void* y, size_t sz) {void* t = malloc(sz);memcpy(t, x, sz);memcpy(x, y, sz);memcpy(y, t, sz);free(t); } void makeHeap(void* x, int i, int n, size_t sz, int(*cmp)(const void*, const void*)) {char* y = (char*)x;int l = 2 * i + 1;int r = 2 * i + 2;int m;if (l<n && (*cmp)(y + l*sz, y + i*sz)>0) m = l;else m = i;if (r<n && (*cmp)(y + r*sz, y + m*sz)>0) m = r;if (m != i){swap(y + i*sz, y + m*sz, sz);makeHeap(x, m, n, sz, cmp);} } void buildHeap(void* x, int n, size_t sz, int(*cmp)(const void*, const void*)) {for (int i = n / 2 - 1; i >= 0; i--) makeHeap(x, i, n, sz, cmp); } void heapSort(void* x, int n, size_t sz, int(*cmp)(const void*, const void*)) {buildHeap(x, n, sz, cmp);char* y = (char*)x;for (int i = n - 1; i >= 1; i--){swap(y, y + i*sz, sz);makeHeap(x, 0, --n, sz, cmp);} }void p(int* x,int n){for (int k = 0; k < n; k++){printf("%d ", x[k]);}printf("\n"); }int less(const void* a, const void* b){return *((int*)a) < *((int*)b); } int greater(const void* a, const void* b){return *((int*)a) > *((int*)b); } int main(){int x[] = { 2, 3, 4, 6, 8, 2, 9, 0 };// 降序全排列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++)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。