1 /* This file contains a collection of sorting routines */ 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include "fatal.h" 5 6 typedef int ElementType; 7 8 void Swap(ElementType *Lhs, ElementType *Rhs) 9 { 10 ElementType Tmp; 11 Tmp = *Lhs; 12 *Lhs = *Rhs; 13 *Rhs = Tmp; 14 } 15 16 void PrintArray(ElementType A[], int N) 17 { 18 int i; 19 for(i = 0; i < N; ++i) 20 printf("%d ", A[i]); 21 printf(" "); 22 } 23 24 void InsertionSort(ElementType A[], int N) 25 { 26 int i, j; 27 ElementType Tmp; 28 29 for(i = 1; i < N; ++i) 30 { 31 Tmp = A[i]; 32 for(j = i; j >= 1 && A[j-1] > Tmp; --j) 33 A[j] = A[j-1]; 34 A[j] = Tmp; 35 } 36 } 37 38 void ShellSort(ElementType A[], int N) 39 { 40 int i, j, Increment; 41 ElementType Tmp; 42 43 for(Increment = N/2; Increment > 0; Increment /=2) 44 { 45 for(i = Increment; i < N; ++i) 46 { 47 Tmp = A[i]; 48 for(j = i; j >= Increment && A[j-Increment] > Tmp; j -= Increment) 49 A[j] = A[j-Increment]; 50 A[j] = Tmp; 51 } 52 } 53 } 54 55 // 简单选择排序 56 void SelectSort(ElementType A[], int N) 57 { 58 int i, j; 59 int MinIdx; 60 61 for(i = 0; i < N-1; ++i) // N-1次即可完成排序 62 { 63 MinIdx = i; 64 for(j = i+1; j < N; ++j) // 在[i+1, N)范围内查找最小值 65 { 66 if(A[j] < A[MinIdx]) 67 MinIdx = j; 68 } 69 if(i != MinIdx) 70 Swap(&A[i], &A[MinIdx]); 71 } 72 } 73 74 // 简单选择排序的改进: 在查找最小值的同时,可以查找出最大值, 75 // 最小值和第一个元素交换,最大值和最后一个元素交换。 76 void SelectSortII(ElementType A[], int N) 77 { 78 int i, j; 79 int MinIdx, MaxIdx; 80 81 for(i = 0; i < N/2; ++i) // 一次排好最小值和最大值, 因此N/2次循环可以排好整个序列 82 { 83 MinIdx = i; 84 MaxIdx = N-i-1; 85 for(j = i; j < N-i; ++j) // 在[i, N-i)范围内查找最小值和最大值, 注意不能从i+1开始 86 { 87 if(A[j] < A[MinIdx]) 88 MinIdx = j; 89 if(A[j] > A[MaxIdx]) 90 MaxIdx = j; 91 } 92 93 if(MinIdx != i) 94 Swap(&A[MinIdx], &A[i]); 95 if(MaxIdx != N-i-1) 96 Swap(&A[MaxIdx], &A[N-i-1]); 97 } 98 } 99 100 // 第6.3节讲的二叉堆左儿子为2*i, 右儿子为2*i+1, 下标为0的元素用于标记 101 // 堆排序中不使用头节点, 因此左儿子为2*i+1, 右儿子为2*i+2 102 #define LeftChild(i) ( 2 * (i) + 1 ) 103 104 void PercDown(ElementType A[], int i, int N) 105 { 106 int Child; 107 ElementType Tmp; 108 109 for(Tmp = A[i]; LeftChild(i) < N; i = Child) 110 { 111 Child = LeftChild(i); 112 if(Child != N-1 && A[Child + 1] > A[Child]) 113 Child++; 114 115 if(Tmp < A[Child]) 116 A[i] = A[Child]; 117 else 118 break; 119 } 120 A[i] = Tmp; 121 } 122 123 void HeapSort(ElementType A[], int N) 124 { 125 int i; 126 127 for(i = N/2; i >= 0; --i) /* BuildHeap */ 128 PercDown(A, i, N); 129 130 for(i = N-1; i > 0; --i) /* DeleteMax */ 131 { 132 Swap(&A[0], &A[i]); 133 PercDown(A, 0, i); 134 } 135 } 136 137 // N个元素需要N-1趟才可以排好, i的取值为[0, N-1); 138 // 每趟排序都会确定最后一个元素, 因此j的上界为N-i, 139 // 考虑到循环内部使用了j+1, 因此上界应该为N-i-1, 140 // 每趟比较从第0个元素开始, 下界为0 141 void BubbleSort(ElementType A[], int N) 142 { 143 int i, j; 144 145 for(i = 0; i < N-1; ++i) 146 { 147 for(j = 0; j < N-i-1; ++j) 148 { 149 if(A[j] > A[j+1]) 150 Swap(&A[j], &A[j+1]); 151 } 152 PrintArray(A, 7); 153 } 154 } 155 156 /* Lpos = start of left half, Rpos = start of right half */ 157 void Merge(ElementType A[], ElementType TmpArray[], 158 int Lpos, int Rpos, int RightEnd) 159 { 160 int i, LeftEnd, NumElements, TmpPos; 161 162 LeftEnd = Rpos - 1; 163 TmpPos = Lpos; 164 NumElements = RightEnd - Lpos + 1; 165 166 /* main loop */ 167 while(Lpos <= LeftEnd && Rpos <= RightEnd) 168 if(A[Lpos] < A[Rpos]) 169 TmpArray[TmpPos++] = A[Lpos++]; 170 else 171 TmpArray[TmpPos++] = A[Rpos++]; 172 while(Lpos <= LeftEnd) /* Copy rest of first half */ 173 TmpArray[TmpPos++] = A[Lpos++]; 174 while(Rpos <= RightEnd) /* Copy rest of second half */ 175 TmpArray[TmpPos++] = A[Rpos++]; 176 177 /* Copy TmpArray back */ 178 for(i = 0; i < NumElements; ++i, RightEnd--) 179 A[RightEnd] = TmpArray[RightEnd]; 180 } 181 182 void MSort(ElementType A[], ElementType TmpArray[], int Left, int Right) 183 { 184 int Center; 185 186 if(Left < Right) 187 { 188 Center = (Left + Right) / 2; 189 MSort(A, TmpArray, Left, Center); 190 MSort(A, TmpArray, Center+1, Right); 191 Merge(A, TmpArray, Left, Center+1, Right); 192 } 193 } 194 195 // MergeSort为递归例程MSort的驱动程序 196 void MergeSort(ElementType A[], int N) 197 { 198 ElementType *TmpArray; 199 200 TmpArray = (ElementType *)malloc(N * sizeof(ElementType)); 201 if(TmpArray != NULL) 202 { 203 MSort(A, TmpArray, 0, N-1); // 注意是N-1 204 free(TmpArray); 205 } 206 else 207 FatalError("Out of space!"); 208 } 209 210 /* Return median of Left, Center, and Right */ 211 /* Order these and hide the pivot */ 212 ElementType Median3(ElementType A[], int Left, int Right) 213 { 214 int Center = (Left + Right) / 2; 215 216 if(A[Left] > A[Center]) 217 Swap(&A[Left], &A[Center]); 218 if(A[Left] > A[Right]) 219 Swap(&A[Left], &A[Right]); 220 if(A[Center] > A[Right]) 221 Swap(&A[Center], &A[Right]); 222 223 /* Invariant: A[ Left ] <= A[ Center ] <= A[ Right ] */ 224 225 Swap(&A[Center], &A[Right-1]); /* Hide pivot */ 226 return A[Right-1]; /* Return pivot */ 227 } 228 229 #define Cutoff (3) 230 231 void Qsort(ElementType A[], int Left, int Right) 232 { 233 int i, j; 234 ElementType Pivot; 235 236 if(Left + Cutoff <= Right) 237 { 238 Pivot = Median3(A, Left, Right); 239 i = Left; 240 j = Right - 1; 241 for( ; ; ) 242 { 243 while(A[++i] < Pivot){} 244 while(A[--j] > Pivot){} 245 if(i < j) 246 Swap(&A[i], &A[j]); 247 else 248 break; 249 } 250 Swap(&A[i], &A[Right-1]); /* Restore pivot */ 251 252 Qsort(A, Left, i - 1); 253 Qsort(A, i + 1, Right); 254 } 255 else /* Do an insertion sort on the subarray */ 256 InsertionSort(A + Left, Right - Left + 1); 257 } 258 259 /* 260 // 测试通过, 选取最后一个元素为枢纽元的排序方法 261 void Qsort(ElementType A[], int Left, int Right) 262 { 263 int i, j; 264 ElementType Pivot; 265 266 if(Left < Right) // 这里用 < 或者 <=都可以 267 { 268 Pivot = A[Right]; // 选择最右边的元素为枢纽元 269 i = Left-1, j = Right; // 注意这里i= Left - 1 !!!! 270 for( ; ; ) 271 { 272 while(A[++i] < Pivot){} 273 while(A[--j] > Pivot){} 274 if(i < j) 275 Swap(&A[i], &A[j]); 276 else 277 break; 278 } 279 Swap(&A[i], &A[Right]); 280 281 Qsort(A, Left, i - 1); 282 Qsort(A, i + 1, Right); 283 } 284 } 285 */ 286 287 void QuickSort(ElementType A[], int N) 288 { 289 Qsort(A, 0, N-1); 290 } 291 292 /* Places the kth smallest element in the kth position */ 293 /* Because arrays start at 0, this will be index k-1 */ 294 void Qselect(ElementType A[], int k, int Left, int Right) 295 { 296 int i, j; 297 ElementType Pivot; 298 299 if(Left + Cutoff <= Right) 300 { 301 Pivot = Median3(A, Left, Right); 302 i = Left; 303 j = Right - 1; 304 for(; ;) 305 { 306 while(A[++i] < Pivot){} 307 while(A[--j] > Pivot){} 308 if(i < j) 309 Swap(&A[i], &A[j]); 310 else 311 break; 312 } 313 Swap(&A[i], &A[Right-1]); /* Restore pivot */ 314 315 if(k <= i) 316 Qselect(A, k, Left, i - 1); 317 else 318 Qselect(A, k, i + 1, Right); 319 } 320 else /* Do an insertion sort on the subarray */ 321 InsertionSort(A + Left, Right - Left + 1); 322 } 323 324 /* ROUTINES TO TEST THE SORTS */ 325 void Permute(ElementType A[], int N) 326 { 327 int i; 328 329 for(i = 0; i < N; ++i) 330 A[i] = i; 331 for(i = 1; i < N; ++i) 332 Swap(&A[i], &A[rand() % (i + 1)]); 333 } 334 335 void CheckSort(ElementType A[], int N) 336 { 337 int i; 338 339 for(i = 0; i < N; ++i) 340 if(A[i] != i) 341 printf("Sort fails: %d ", i); 342 printf("Check completed "); 343 } 344 345 void Copy(ElementType Lhs[], const ElementType Rhs[], int N) 346 { 347 int i; 348 for(i = 0; i < N; ++i) 349 Lhs[i] = Rhs[i]; 350 } 351 352 #define MaxSize 7000 353 int Arr1[MaxSize]; 354 int Arr2[MaxSize]; 355 356 int main() 357 { 358 int i; 359 for(i = 0; i < 10; ++i) 360 { 361 Permute(Arr2, MaxSize); // 生成一个随机数组 362 363 Copy(Arr1, Arr2, MaxSize); 364 InsertionSort(Arr1, MaxSize); 365 CheckSort(Arr1, MaxSize); 366 367 Copy(Arr1, Arr2, MaxSize); 368 ShellSort(Arr1, MaxSize); 369 CheckSort(Arr1, MaxSize); 370 371 Copy(Arr1, Arr2, MaxSize); 372 HeapSort(Arr1, MaxSize); 373 CheckSort(Arr1, MaxSize); 374 375 Copy(Arr1, Arr2, MaxSize); 376 MergeSort(Arr1, MaxSize); 377 CheckSort(Arr1, MaxSize); 378 379 Copy(Arr1, Arr2, MaxSize); 380 QuickSort(Arr1, MaxSize); 381 CheckSort(Arr1, MaxSize); 382 383 Copy(Arr1, Arr2, MaxSize); 384 Qselect(Arr1, MaxSize / 2 + 1 + i, 0, MaxSize - 1); 385 if(Arr1[MaxSize / 2 + 1 + i] != MaxSize / 2 + 1 + i) 386 printf("Select error: %d %d ", MaxSize / 2 + 1 + i, Arr1[MaxSize / 2 + 1 + i]); 387 else 388 printf("Select works "); 389 } 390 return 0; 391 }