一、堆排序
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("原始序列: "); 10 for( i=0; i<n; ++i) 11 { 12 printf("%d ",v[i]); 13 } 14 printf(" "); 15 printf("中间序列: "); 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(" "); 33 } 34 printf("最终序列: "); 35 for( i=0; i<n; ++i) 36 { 37 printf("%d ",v[i]); 38 } 39 printf(" "); 40 } 41 void insert_sort() //简单插入排序 42 { 43 int i,j,k,temp; 44 printf("原始序列: "); 45 for( i=0; i<n; ++i) 46 { 47 printf("%d ",v[i]); 48 } 49 printf(" "); 50 printf("中间序列: "); 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(" "); 69 } 70 printf("最终序列: "); 71 for( i=0; i<n; ++i) 72 { 73 printf("%d ",v[i]); 74 } 75 printf(" "); 76 } 77 void select_sort() //简单选择排序 78 { 79 int i,j,k,temp,ans; 80 printf("原始序列: "); 81 for( i=0; i<n; ++i) 82 { 83 printf("%d ",v[i]); 84 } 85 printf(" "); 86 printf("中间序列: "); 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(" "); 106 } 107 108 printf("最终序列: "); 109 for( i=0; i<n; ++i) 110 { 111 printf("%d ",v[i]); 112 } 113 printf(" "); 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(" "); 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("原始序列: "); 163 for( i=0; i<n; ++i) 164 { 165 printf("%d ",v[i]); 166 } 167 printf(" "); 168 printf("中间序列: "); 169 170 quickSort(0,n-1); 171 172 printf("最终序列: "); 173 for( i=0; i<n; ++i) 174 { 175 printf("%d ",v[i]); 176 } 177 printf(" "); 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(" "); 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("原始序列: "); 234 for( i=0; i<n; ++i) 235 { 236 printf("%d ",v[i]); 237 } 238 printf(" "); 239 printf("中间序列: "); 240 241 headSort(v,n); 242 243 printf("最终序列: "); 244 for( i=0; i<n; ++i) 245 { 246 printf("%d ",v[i]); 247 } 248 printf(" "); 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 ( " "); 261 printf ( " "); 262 printf ( " "); 263 printf ("-------------------------------------- "); 264 printf ("-------------------------------------- "); 265 printf ("--------丨[0]冒泡排序 丨--- "); 266 printf ("--------丨[1]简单插入排序 丨--- "); 267 printf ("--------丨[2]简单选择排序 丨--- "); 268 printf ("--------丨[3]快速排序 丨--- "); 269 printf ("--------丨[4]堆排序 丨--- "); 270 printf ("--------丨[5]结束 丨--- "); 271 printf ("----------输入相应数字---------------- "); 272 printf ( " "); 273 printf ( " "); 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("程序运行结束 "); 304 } 305 else printf("输入错误 "); 306 }