一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C/C++ - C語言實現基于最大堆和最小堆的堆排序算法示例

C語言實現基于最大堆和最小堆的堆排序算法示例

2021-04-06 13:28黃儀標 C/C++

這篇文章主要介紹了C語言實現基于最大堆和最小堆的堆排序算法示例,分別是基于最大堆的升序排序和基于最小堆的降序排序實例,需要的朋友可以參考下

堆定義
堆實際上是一棵完全二叉樹,其任何一非葉節點滿足性質:
Key[i]<=key[2i+1]&&Key[i]<=key[2i+2](小頂堆)或者:Key[i]>=Key[2i+1]&&key>=key[2i+2](大頂堆)
即任何一非葉節點的關鍵字不大于或者不小于其左右孩子節點的關鍵字。

堆排序的思想
利用大頂堆(小頂堆)堆頂記錄的是最大關鍵字(最小關鍵字)這一特性,使得每次從無序中選擇最大記錄(最小記錄)變得簡單。

  • 最大堆:所有節點的子節點比其自身小的堆。
  • 最小堆:所有節點的子節點比其自身大的堆。

這里以最大堆為基礎,其基本思想為:

1.將初始待排序關鍵字序列(R1,R2....Rn)構建成大頂堆,此堆為初始的無序區;
2.將堆頂元素R[1]與最后一個元素R[n]交換,此時得到新的無序區(R1,R2,......Rn-1)和新的有序區(Rn),且滿足R[1,2...n-1]<=R[n];
3.由于交換后新的堆頂R[1]可能違反堆的性質,因此需要對當前無序區(R1,R2,......Rn-1)調整為新堆,然后再次將R[1]與無序區最后一個元素交換,得到新的無序區(R1,R2....Rn-2)和新的有序區(Rn-1,Rn)。不斷重復此過程直到有序區的元素個數為n-1,則整個排序過程完成。

C語言實現
1.基于最大堆實現升序排序

?
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// 初始化堆
void initHeap(int a[], int len) {
 // 從完全二叉樹最后一個非子節點開始
 // 在數組中第一個元素的索引是0
 // 第n個元素的左孩子為2n+1,右孩子為2n+2,
 // 最后一個非子節點位置在(n - 1) / 2
 for (int i = (len - 1) / 2; i >= 0; --i) {
  adjustMaxHeap(a, len, i);
 }
}
 
void adjustMaxHeap(int a[], int len, int parentNodeIndex) {
 // 若只有一個元素,那么只能是堆頂元素,也沒有必要再排序了
 if (len <= 1) {
  return;
 }
 
 // 記錄比父節點大的左孩子或者右孩子的索引
 int targetIndex = -1;
 
 // 獲取左、右孩子的索引
 int leftChildIndex = 2 * parentNodeIndex + 1;
 int rightChildIndex = 2 * parentNodeIndex + 2;
 
 // 沒有左孩子
 if (leftChildIndex >= len) {
  return;
 }
 
 // 有左孩子,但是沒有右孩子
 if (rightChildIndex >= len) {
  targetIndex = leftChildIndex;
 }
 // 有左孩子和右孩子
 else {
  // 取左、右孩子兩者中最大的一個
  targetIndex = a[leftChildIndex] > a[rightChildIndex] ? leftChildIndex : rightChildIndex;
 }
 
 // 只有孩子比父節點的值還要大,才需要交換
 if (a[targetIndex] > a[parentNodeIndex]) {
  int temp = a[targetIndex];
  
  a[targetIndex] = a[parentNodeIndex];
  a[parentNodeIndex] = temp;
  
  
  // 交換完成后,有可能會導致a[targetIndex]結點所形成的子樹不滿足堆的條件,
  // 若不滿足堆的條件,則調整之使之也成為堆
  adjustMaxHeap(a, len, targetIndex);
 }
}
 
void heapSort(int a[], int len) {
 if (len <= 1) {
  return;
 }
 
 // 初始堆成無序最大堆
 initHeap(a, len);
 
 for (int i = len - 1; i > 0; --i) {
  // 將當前堆頂元素與最后一個元素交換,保證這一趟所查找到的堆頂元素與最后一個元素交換
  // 注意:這里所說的最后不是a[len - 1],而是每一趟的范圍中最后一個元素
  // 為什么要加上>0判斷?每次不是說堆頂一定是最大值嗎?沒錯,每一趟調整后,堆頂是最大值的
  // 但是,由于len的范圍不斷地縮小,導致某些特殊的序列出現異常
  // 比如說,5, 3, 8, 6, 4序列,當調整i=1時,已經調整為3,4,5,6,8序列,已經有序了
  // 但是導致了a[i]與a[0]交換,由于變成了4,3,5,6,8反而變成無序了!
  if (a[0] > a[i]) {
   int temp = a[0];
   a[0] = a[i];
   a[i] = temp;
  }
  
  // 范圍變成為:
  // 0...len-1
  // 0...len-1-1
  // 0...1 // 結束
  // 其中,0是堆頂,每次都是找出在指定的范圍內比堆頂還大的元素,然后與堆頂元素交換
  adjustMaxHeap(a, i - 1, 0);
 }
}

2.基于最小堆實現降序排序

?
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// 初始化堆
void initHeap(int a[], int len) {
 // 從完全二叉樹最后一個非子節點開始
 // 在數組中第一個元素的索引是0
 // 第n個元素的左孩子為2n+1,右孩子為2n+2,
 // 最后一個非子節點位置在(n - 1) / 2
 for (int i = (len - 1) / 2; i >= 0; --i) {
  adjustMinHeap(a, len, i);
 }
}
 
void adjustMinHeap(int a[], int len, int parentNodeIndex) {
 // 若只有一個元素,那么只能是堆頂元素,也沒有必要再排序了
 if (len <= 1) {
  return;
 }
 
 // 記錄比父節點大的左孩子或者右孩子的索引
 int targetIndex = -1;
 
 // 獲取左、右孩子的索引
 int leftChildIndex = 2 * parentNodeIndex + 1;
 int rightChildIndex = 2 * parentNodeIndex + 2;
 
 // 沒有左孩子
 if (leftChildIndex >= len) {
  return;
 }
 
 // 有左孩子,但是沒有右孩子
 if (rightChildIndex >= len) {
  targetIndex = leftChildIndex;
 }
 // 有左孩子和右孩子
 else {
  // 取左、右孩子兩者中最上的一個
  targetIndex = a[leftChildIndex] < a[rightChildIndex] ? leftChildIndex : rightChildIndex;
 }
 
 // 只有孩子比父節點的值還要小,才需要交換
 if (a[targetIndex] < a[parentNodeIndex]) {
  int temp = a[targetIndex];
  
  a[targetIndex] = a[parentNodeIndex];
  a[parentNodeIndex] = temp;
  
  
  // 交換完成后,有可能會導致a[targetIndex]結點所形成的子樹不滿足堆的條件,
  // 若不滿足堆的條件,則調整之使之也成為堆
  adjustMinHeap(a, len, targetIndex);
 }
}
 
void heapSort(int a[], int len) {
 if (len <= 1) {
  return;
 }
 
 // 初始堆成無序最小堆
 initHeap(a, len);
 
 for (int i = len - 1; i > 0; --i) {
  // 將當前堆頂元素與最后一個元素交換,保證這一趟所查找到的堆頂元素與最后一個元素交換
  // 注意:這里所說的最后不是a[len - 1],而是每一趟的范圍中最后一個元素
  // 為什么要加上>0判斷?每次不是說堆頂一定是最小值嗎?沒錯,每一趟調整后,堆頂是最小值的
  // 但是,由于len的范圍不斷地縮小,導致某些特殊的序列出現異常
  // 比如說,5, 3, 8, 6, 4序列,當調整i=1時,已經調整為3,4,5,6,8序列,已經有序了
  // 但是導致了a[i]與a[0]交換,由于變成了4,3,5,6,8反而變成無序了!
  if (a[0] < a[i]) {
   int temp = a[0];
   a[0] = a[i];
   a[i] = temp;
  }
  
  // 范圍變成為:
  // 0...len-1
  // 0...len-1-1
  // 0...1 // 結束
  // 其中,0是堆頂,每次都是找出在指定的范圍內比堆頂還小的元素,然后與堆頂元素交換
  adjustMinHeap(a, i - 1, 0);
 }
}

3.C語言版測試

大家可以測試一下:

?
1
2
3
4
5
6
7
// int a[] = {5, 3, 8, 6, 4};
int a[] = {89,-7,999,-89,7,0,-888,7,-7};
heapSort(a, sizeof(a) / sizeof(int));
 
for (int i = 0; i < sizeof(a) / sizeof(int); ++i) {
  NSLog(@"%d", a[i]);
}

延伸 · 閱讀

精彩推薦
  • C/C++深入理解goto語句的替代實現方式分析

    深入理解goto語句的替代實現方式分析

    本篇文章是對goto語句的替代實現方式進行了詳細的分析介紹,需要的朋友參考下...

    C語言教程網7342020-12-03
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下...

    青山的青6062022-01-04
  • C/C++C/C++經典實例之模擬計算器示例代碼

    C/C++經典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關于C/C++經典實例之模擬計算器的相關資料,文中通過示...

    jia150610152021-06-07
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數使用

    詳解c語言中的 strcpy和strncpy字符串函數使用

    strcpy 和strcnpy函數是字符串復制函數。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
  • C/C++學習C++編程的必備軟件

    學習C++編程的必備軟件

    本文給大家分享的是作者在學習使用C++進行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++C語言實現電腦關機程序

    C語言實現電腦關機程序

    這篇文章主要為大家詳細介紹了C語言實現電腦關機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++c++ 單線程實現同時監聽多個端口

    c++ 單線程實現同時監聽多個端口

    這篇文章主要介紹了c++ 單線程實現同時監聽多個端口的方法,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內存中的數據都是暫時的,當程序結束時,它們都將丟失,為了永久性的保存大量的數據,C語言提供了對文件的操作,這篇文章主要給大家介紹了關于C語言中文件...

    針眼_6702022-01-24
主站蜘蛛池模板: 成人免费影院 | 操弄哥哥的108种姿势 | 国内精品久久久久影院中国 | hezyo加勒比一区二区三区 | 欧美3d怪物交videos网站 | 操熟美女又肥又嫩的骚屁股 | 国产ay | 欧美人做人爱a全程免费 | 91手机在线| 香蕉精品高清在线观看视频 | 精品国产乱码久久久人妻 | 亚洲国产欧美在线人成aaaa20 | 东方影视欧美天天影院 | 99色在线播放| 韩国情事伦理片观看地址 | 红楼梦黄色小说 | 免费观看成年肉动漫网站 | 国产福利一区二区在线精品 | 亚洲一二区视频 | 亚洲男人第一天堂 | 日韩精品视频福利资源站 | 国产欧美精品一区二区三区–老狼 | 国产日产韩产麻豆1区 | 1717国产精品视频免费 | 日韩视频免费一区二区三区 | 日本免费在线观看 | 9久re热视频这里只有精品 | x8x8在线观看 | 成人综合网址 | 2020最新版的ab片| 国产一级免费片 | 爱情岛论坛亚洲一号路线 | 三级无删减高清在线影院 | 日韩在线一区 | 青青久久久国产线免观 | 亚洲高清在线视频 | 很黄的孕妇a级黄毛片 | 女人爽到喷水的视频免费 | 97久久天天综合色天天综合色hd | 洗濯屋H纯肉动漫在线观看 武侠艳妇屈辱的张开双腿 午夜在线观看免费观看 视频 | 午夜免费无码福利视频麻豆 |