一、堆排序
1、部分概念
滿二叉樹:深度為k,且含有(2^k)-1個結點的二叉樹
完全二叉樹:深度為k的,又n個結點的,當且僅當其每一個節點都與深度為k的滿二叉樹種編號從1至n的節點一一對應時,稱為完全二叉樹
堆的結構可以分為大根堆和小根堆,是一個完全二叉樹
每個結點的值都大於其左孩子和右孩子結點的值,稱之為大根堆;每個結點的值都小於其左孩子和右孩子結點的值,稱之為小根堆。
(這個它們右兒子值與左兒子誰的值大誰的值小沒有要求)
1.父結點索引:(i-1)/2(這里計算機中的除以2,省略掉小數)
2.左孩子索引:2*i+1
3.右孩子索引:2*i+2
2、堆排序過程
升序----使用大頂堆
降序----使用小頂堆
思想(這里我們用大頂堆):
假設要對一個有n個元素的數組進行排序。這樣的話我們先把這個數組里面的前n個數據拿出來構建一個大頂堆。這個時候我們肯定能保證堆頂那個元素是最大的。然后我們把那個最大的元素放在數組的倒數第一個位置。然后在對數組里面前n-1個元素再構建一次大頂堆,這個時候再把堆頂元素拿出來放到數組倒數第二個位置。依次進行n-1次就完了。。。
怎么把一個二叉樹弄成大頂堆?看下面
由上面這個圖我么可以知道它的數組中元素順序是這樣:【9,1,6,4,5】
我們發現1號位置的權值並不大於它的兒子的權值,所以我們給它左右兒子中那個權值大的兒子交換
這個時候我們知道最大權值是9,那就讓最大權值放在數組倒數第一個位置,讓倒數第一個位置的權值和它交換一下
這個時候原數組就變成了:【1,5,6,4,9】,然后就接着對這個二叉樹改造,使它變成大頂堆(這個時候第4和位置就不再參與)
發現這樣就是一個大頂堆了
數組:【4,5,1,6,9】
又變成了大頂堆
數組:【1,4,5,6,9】
又變成了大頂堆
數組:【1,4,5,6,9】
循環了5-1=4次,所以該結束了
最后結果就是【1,4,5,6,9】
剩余四種排序算法見下一篇博客:
五種排序算法整理 二(堆排序,快速排序、插入排序、選擇排序、冒泡排序)
全部代碼(這個是五種算法的代碼):
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #define maxn 1005 5 int v[maxn],n,size=0; 6 void Bubble_sort() //冒泡排序 7 { 8 int i,j,temp; 9 printf("原始序列:\n"); 10 for( i=0; i<n; ++i) 11 { 12 printf("%d ",v[i]); 13 } 14 printf("\n"); 15 printf("中間序列:\n"); 16 for(i=0; i<n; ++i) 17 { 18 for(j=i+1; j<n; ++j) 19 { 20 if(v[i]>v[j]) //因為是從小到大排序,所以這個條件滿足就是交換他們的值 21 { 22 temp=v[i]; 23 v[i]=v[j]; 24 v[j]=temp; 25 } 26 } 27 28 for( j=0; j<n; ++j) 29 { 30 printf("%d ",v[j]); 31 } 32 printf("\n"); 33 } 34 printf("最終序列:\n"); 35 for( i=0; i<n; ++i) 36 { 37 printf("%d ",v[i]); 38 } 39 printf("\n"); 40 } 41 void insert_sort() //簡單插入排序 42 { 43 int i,j,k,temp; 44 printf("原始序列:\n"); 45 for( i=0; i<n; ++i) 46 { 47 printf("%d ",v[i]); 48 } 49 printf("\n"); 50 printf("中間序列:\n"); 51 for(i=1; i<n; ++i) 52 { 53 temp=v[i]; 54 for(j=i-1; j>=0; --j) 55 { 56 if(v[j]>temp) 57 { 58 v[j+1]=v[j]; 59 } 60 else break; 61 } 62 v[j+1]=temp; 63 64 for( j=0; j<n; ++j) 65 { 66 printf("%d ",v[j]); 67 } 68 printf("\n"); 69 } 70 printf("最終序列:\n"); 71 for( i=0; i<n; ++i) 72 { 73 printf("%d ",v[i]); 74 } 75 printf("\n"); 76 } 77 void select_sort() //簡單選擇排序 78 { 79 int i,j,k,temp,ans; 80 printf("原始序列:\n"); 81 for( i=0; i<n; ++i) 82 { 83 printf("%d ",v[i]); 84 } 85 printf("\n"); 86 printf("中間序列:\n"); 87 88 for(i=0; i<n-1; ++i) 89 { 90 temp=i; 91 for(j=i+1; j<n; ++j) 92 { 93 if(v[j]<v[temp]) temp=j; 94 } 95 if(temp!=i) //如果相等的話那它就不用換位置 96 { 97 ans=v[temp]; 98 v[temp]=v[i]; 99 v[i]=ans; 100 } 101 for( j=0; j<n; ++j) 102 { 103 printf("%d ",v[j]); 104 } 105 printf("\n"); 106 } 107 108 printf("最終序列:\n"); 109 for( i=0; i<n; ++i) 110 { 111 printf("%d ",v[i]); 112 } 113 printf("\n"); 114 } 115 void quickSort(int begin,int end) //快速排序 116 { 117 int k; 118 //如果區間不只一個數 119 if(begin < end) 120 { 121 int temp = v[begin]; //將區間的第一個數作為基准數 122 int i = begin; //從左到右進行查找時的“指針”,指示當前左位置 123 int j = end; //從右到左進行查找時的“指針”,指示當前右位置 124 //不重復遍歷 125 while(i < j) 126 { 127 //當右邊的數大於基准數時,略過,繼續向左查找 128 //不滿足條件時跳出循環,此時的j對應的元素是小於基准元素的 129 while(i<j && v[j] > temp) 130 j--; 131 //將右邊小於等於基准元素的數填入右邊相應位置 132 v[i] = v[j]; 133 //當左邊的數小於等於基准數時,略過,繼續向右查找 134 //(重復的基准元素集合到左區間) 135 //不滿足條件時跳出循環,此時的i對應的元素是大於等於基准元素的 136 while(i<j && v[i] <= temp) 137 i++; 138 //將左邊大於基准元素的數填入左邊相應位置 139 v[j] = v[i]; 140 for( k=0; k<n; ++k) 141 { 142 printf("%d ",v[k]); 143 } 144 printf("\n"); 145 } 146 147 //將基准元素填入相應位置 148 v[i] = temp; 149 //此時的i即為基准元素的位置 150 //對基准元素的左邊子區間進行相似的快速排序 151 quickSort(begin,i-1); 152 //對基准元素的右邊子區間進行相似的快速排序 153 quickSort(i+1,end); 154 } 155 //如果區間只有一個數,則返回 156 else 157 return; 158 } 159 void solve_quickSort() 160 { 161 int i,j; 162 printf("原始序列:\n"); 163 for( i=0; i<n; ++i) 164 { 165 printf("%d ",v[i]); 166 } 167 printf("\n"); 168 printf("中間序列:\n"); 169 170 quickSort(0,n-1); 171 172 printf("最終序列:\n"); 173 for( i=0; i<n; ++i) 174 { 175 printf("%d ",v[i]); 176 } 177 printf("\n"); 178 } 179 void swap(int *x,int *y) 180 { 181 int temp=*x; 182 *x=*y; 183 *y=temp; 184 } 185 int headSort(int* arr,int length) //堆排序 186 { 187 int idx,k; 188 if(length<=0) 189 return -1; 190 //數組中順序存放的數據就對應完全二叉樹堆中的對應結點的值,現在調整為大根堆 191 for( idx=length/2-1; idx>=0; --idx) //從最后一個非葉子結點開始調整為最大堆 192 { 193 adjust(arr,idx,length-1); //最后一個非葉子結點和它的孩子比較調整 194 } 195 //排序,根結點后最后一個結點交換,調整 196 for( idx=length-1; idx>0; --idx) 197 { 198 swap(&arr[0],&arr[idx]); //每次選出一個最大的數放到末尾,也就是數組末尾 199 for( k=0; k<n; ++k) 200 { 201 printf("%d ",v[k]); 202 } 203 printf("\n"); 204 adjust(arr,0,idx-1); //調整根結點到idx-1個結點為大根堆 205 } 206 return 0; 207 } 208 void adjust(int* arr,int idx1,int idx2) 209 { 210 int tmp,idx; 211 if(idx1>=idx2||idx1<0||idx2<0) 212 return ; 213 tmp = arr[idx1]; //暫時存放要調整的數據 214 for( idx=idx1*2+1; idx<=idx2; idx=idx*2+1) //從要調整的數據的左孩子開始比較 215 { 216 //選出左右孩子中的最大結點 217 if(idx+1<=idx2 && arr[idx]<arr[idx+1]) 218 ++idx; 219 if(arr[idx]>tmp) //不滿足大根堆,調整 220 { 221 arr[idx1] = arr[idx]; //交換,可能破壞子樹滿足大根堆的性質 222 idx1 = idx; //本來這里要交換的,但時tmp暫時存放了初始arr[idx1]的值,這里每次比較都是和tmp比較,好比交換了,所以可以不用先交換 223 //繼續向下調整,直到樹滿足大根堆性質 224 } 225 else 226 break; 227 } 228 arr[idx1] = tmp; 229 } 230 void solve_heapSort() 231 { 232 int i,j; 233 printf("原始序列:\n"); 234 for( i=0; i<n; ++i) 235 { 236 printf("%d ",v[i]); 237 } 238 printf("\n"); 239 printf("中間序列:\n"); 240 241 headSort(v,n); 242 243 printf("最終序列:\n"); 244 for( i=0; i<n; ++i) 245 { 246 printf("%d ",v[i]); 247 } 248 printf("\n"); 249 } 250 int main() 251 { 252 int i,x; 253 printf("輸入序列長度:"); 254 scanf("%d",&n); 255 for( i=0; i<n; ++i) 256 { 257 scanf("%d",&v[i]); 258 } 259 system("cls"); 260 printf ( " \n"); 261 printf ( " \n"); 262 printf ( " \n"); 263 printf ("-------------------------------------- \n"); 264 printf ("--------------------------------------\n"); 265 printf ("--------丨[0]冒泡排序 丨---\n"); 266 printf ("--------丨[1]簡單插入排序 丨---\n"); 267 printf ("--------丨[2]簡單選擇排序 丨---\n"); 268 printf ("--------丨[3]快速排序 丨---\n"); 269 printf ("--------丨[4]堆排序 丨---\n"); 270 printf ("--------丨[5]結束 丨---\n"); 271 printf ("----------輸入相應數字----------------\n"); 272 printf ( " \n"); 273 printf ( " \n"); 274 scanf("%d",&x); 275 if(x==0) 276 { 277 system("cls"); 278 Bubble_sort(); 279 } 280 else if(x==1) 281 { 282 system("cls"); 283 insert_sort(); 284 } 285 else if(x==2) 286 { 287 system("cls"); 288 select_sort(); 289 } 290 else if(x==3) 291 { 292 system("cls"); 293 solve_quickSort(); 294 } 295 else if(x==4) 296 { 297 system("cls"); 298 solve_heapSort(); 299 } 300 else if(x==5) 301 { 302 system("cls"); 303 printf("程序運行結束\n"); 304 } 305 else printf("輸入錯誤\n"); 306 }