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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

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

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

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

堆排序原理及其實(shí)現(xiàn)(C++)

1. 堆排序的引入

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

2. 什么是堆

首先堆heap是一種數(shù)據(jù)結(jié)構(gòu),是一棵完全二叉樹且滿足性質(zhì):所有非葉子結(jié)點(diǎn)的值均不大于或均不小于其左、右孩子結(jié)點(diǎn)的值.

3. 堆排序思想

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

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

堆排序的關(guān)鍵在于建堆和調(diào)整堆,下面簡單介紹一下建堆的過程:

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

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

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

其實(shí)整個(gè)堆排序過程中, 我們只需重復(fù)做兩件事:

  • 建堆(初始化+調(diào)整堆, 時(shí)間復(fù)雜度為O(n));

  • 拿堆的根節(jié)點(diǎn)和最后一個(gè)節(jié)點(diǎn)交換(siftdown, 時(shí)間復(fù)雜度為O(n*log n) ).

因而堆排序整體的時(shí)間復(fù)雜度為O(n*log n).

下面通過一組數(shù)據(jù)說明堆排序的方法:

9, 79, 46, 30, 58, 49

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

2:完全二叉樹的最后一個(gè)非葉子節(jié)點(diǎn),也就是最后一個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn)。最后一個(gè)節(jié)點(diǎn)的索引為數(shù)組長度len-1,那么最后一個(gè)非葉子節(jié)點(diǎn)的索引應(yīng)該是為(len-1)/2.也就是從索引為2的節(jié)點(diǎn)開始,如果其子節(jié)點(diǎn)的值大于其本身的值。則把他和較大子節(jié)點(diǎn)進(jìn)行交換,即將索引2處節(jié)點(diǎn)和索引5處元素交換。交換后的結(jié)果如圖:

建堆從最后一個(gè)非葉子節(jié)點(diǎn)開始即可

3:向前處理前一個(gè)節(jié)點(diǎn),也就是處理索引為1的節(jié)點(diǎn),此時(shí)79>30,79>58,因此無需交換。

4:向前處理前一個(gè)節(jié)點(diǎn),也就是處理索引為0的節(jié)點(diǎn),此時(shí)9 < 79,9 < 49, 因此需交換。應(yīng)該拿索引為0的節(jié)點(diǎn)與索引為1的節(jié)點(diǎn)交換,因?yàn)?9>49. 如圖:

5:如果某個(gè)節(jié)點(diǎn)和它的某個(gè)子節(jié)點(diǎn)交換后,該子節(jié)點(diǎn)又有子節(jié)點(diǎn),系統(tǒng)還需要再次對該子節(jié)點(diǎn)進(jìn)行判斷。如上圖因?yàn)?處,3處,4處中,1處的值大于3,4出的值,所以還需交換。

牢記:?將每次堆排序得到的最大元素與當(dāng)前規(guī)模的數(shù)組最后一個(gè)元素交換。

偽代碼如下:

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個(gè)數(shù)中最大數(shù)的下標(biāo)if(maxIdx != index) // 如果maxIdx的值有更新{swap(arr[maxIdx], arr[index]);adjust(arr, len, maxIdx); // 遞歸調(diào)整其他不滿足堆性質(zhì)的部分}} void heapSort(int arr[], int size) {for(int i=size/2 - 1; i >= 0; i--) // 對每一個(gè)非葉結(jié)點(diǎn)進(jìn)行堆調(diào)整(從最后一個(gè)非葉結(jié)點(diǎn)開始){adjust(arr, size, i);}for(int i = size - 1; i >= 1; i--){swap(arr[0], arr[i]); // 將當(dāng)前最大的放置到數(shù)組末尾adjust(arr, i, 0); // 將未完成排序的部分繼續(xù)進(jìn)行堆排序} }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

為何堆排序是不穩(wěn)定排序?

當(dāng)數(shù)組中有相等元素時(shí),堆排序算法對這些元素的處理方法不止一種,故是不穩(wěn)定的。

可重載比較函數(shù)的寫法:

#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個(gè)元素,在數(shù)組末尾heapSort(x, 4, sizeof(int), less);p(x, 8); }

總結(jié)

以上是生活随笔為你收集整理的堆排序原理及其实现(C++)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。