[关闭]
@yanglt7 2018-10-21T15:48:11.000000Z 字数 10833 阅读 657

11_排序算法

数据结构和算法


11.1 排序算法

11.1.1 排序的基本概念与分类

11.1.2 排序的稳定性

11.1.3 影响排序算法性能的几个要素

11.2 冒泡排序

  1. #include <stdio.h>
  2. void BubbleSort(int k[], int n)
  3. {
  4. int i, j, temp, count1=0, count2=0;
  5. for( i=0; i < n-1; i++ )
  6. {
  7. for( j=i+1; j < n; j++ )
  8. {
  9. count1++;
  10. if( k[i] > k[j] )
  11. {
  12. count2++;
  13. temp = k[j];
  14. k[j] = k[i];
  15. k[i] = temp;
  16. }
  17. }
  18. }
  19. printf("总共进行了%d次比较,进行了%d次移动!\n", count1, count2);
  20. }
  21. int main()
  22. {
  23. int i;
  24. int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
  25. BubbleSort(a, 10);
  26. printf("排序后的结果是: \n");
  27. for( i=0; i < 10; i++ )
  28. {
  29. printf("%d", a[i]);
  30. }
  31. printf("\n");
  32. return 0;
  33. }
  1. #include <stdio.h>
  2. void BubbleSort(int k[], int n)
  3. {
  4. int i, j, temp, count1=0, count2=0;
  5. int flag = 1;
  6. for( i=0; i < n-1 && flag; i++ )
  7. {
  8. for( j=n-1; j > i; j-- )
  9. {
  10. count1++;
  11. flag = 0;
  12. if( k[j-1] > k[j] )
  13. {
  14. count2++;
  15. temp = k[j-1];
  16. k[j-1] = k[j];
  17. k[j] = temp;
  18. flag = 1;
  19. }
  20. }
  21. }
  22. printf("总共进行了%d次比较,进行了%d次移动!\n", count1, count2);
  23. }
  24. int main()
  25. {
  26. int i;
  27. int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
  28. BubbleSort(a, 10);
  29. printf("排序后的结果是: \n");
  30. for( i=0; i < 10; i++ )
  31. {
  32. printf("%d", a[i]);
  33. }
  34. printf("\n");
  35. return 0;
  36. }

11.3 选择排序

  1. #include <stdio.h>
  2. void SelectSort(int k[], int n)
  3. {
  4. int i, j, min, temp, count1=0, count2=0;
  5. for( i=0; i < n-1; i++ )
  6. {
  7. min = i;
  8. for( j=i+1; j < n; j++ )
  9. {
  10. count1++;
  11. if( k[j] < k[min] )
  12. {
  13. min = j;
  14. }
  15. }
  16. if( min != i )
  17. {
  18. count2++;
  19. temp = k[min];
  20. k[min] = k[i];
  21. k[i] = temp;
  22. }
  23. }
  24. printf("总共进行了%d次比较,进行了%d次移动!\n", count1, count2);
  25. }
  26. int main()
  27. {
  28. int i;
  29. int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
  30. SelectSort(a, 10);
  31. printf("排序后的结果是: \n");
  32. for( i=0; i < 10; i++ )
  33. {
  34. printf("%d", a[i]);
  35. }
  36. printf("\n");
  37. return 0;
  38. }

11.4 直接插入排序

  1. #include <stdio.h>
  2. void InsertSort(int k[], int n)
  3. {
  4. int i, j, temp;
  5. for( i=1; i < n; i++ )
  6. {
  7. if( k[i] < k[i-1] )
  8. {
  9. temp = k[i];
  10. for( j=i-1; k[j] > temp; j-- )
  11. {
  12. k[j+1] = k[j];
  13. }
  14. k[j+1] = temp;
  15. }
  16. }
  17. }
  18. int main()
  19. {
  20. int i;
  21. int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
  22. InsertSort(a, 10);
  23. printf("排序后的结果是: \n");
  24. for( i=0; i < 10; i++ )
  25. {
  26. printf("%d", a[i]);
  27. }
  28. printf("\n");
  29. return 0;
  30. }

11.5 希尔排序

初始关键字 49 38 65 97 76 13 27 49 55 04
一趟排序结果 13 27 49 55 04 49 38 65 97 76
二趟排序结果 13 04 49 38 27 49 55 65 97 76
三趟排序结果 04 13 27 38 49 49 55 65 76 97
  1. #include <stdio.h>
  2. void ShellSort(int k[], int n)
  3. {
  4. int i, j, temp;
  5. int gap = n;
  6. do
  7. {
  8. gap /= 3;
  9. for( i=gap; i < n; i++ )
  10. {
  11. if( k[i] < k[i-gap] )
  12. {
  13. temp = k[i];
  14. for( j=i-gap; k[j] > temp; j-=gap )
  15. {
  16. k[j+gap] = k[j];
  17. }
  18. k[j+gap] = temp;
  19. }
  20. }
  21. } while(gap > 0);
  22. }
  23. int main()
  24. {
  25. int i;
  26. int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
  27. ShellSort(a, 10);
  28. printf("排序后的结果是: \n");
  29. for( i=0; i < 10; i++ )
  30. {
  31. printf("%d", a[i]);
  32. }
  33. printf("\n");
  34. return 0;
  35. }

11.6 堆排序

  1. #include <stdio.h>
  2. int count = 0;
  3. void swap(int k[], int i, int j)
  4. {
  5. int temp;
  6. temp = k[i];
  7. k[i] = k[j];
  8. k[j] = temp;
  9. }
  10. void HeapAdjust(int k[], int s, int n)
  11. {
  12. int i, temp;
  13. temp = k[s];
  14. // i=2*s:左孩子; 2*s+1: 右孩子
  15. for( i=2*s; i <= n; i*=2 )
  16. {
  17. count++;
  18. if( i < n && k[i] < k[i+1] ) // 左孩子小于右孩子
  19. {
  20. i++; // 使得i指向最大的孩子的下标
  21. }
  22. if( temp >= k[i] ) // temp临时存放当前需要调整的双亲。如果大于孩子,则退出循环
  23. {
  24. break;
  25. }
  26. k[s] = k[i];
  27. s = i;
  28. }
  29. k[s] = temp;
  30. }
  31. void HeapSort(int k[], int n)
  32. {
  33. int i;
  34. // 从下至上,从右至左,层序遍历
  35. for( i=n/2; i > 0; i-- )
  36. {
  37. HeapAdjust(k, i, n); // 构建大顶堆的函数。 k:数组 i:当前双亲结点; n:长度
  38. }
  39. for( i=n; i > 1; i-- )
  40. {
  41. swap(k, 1, i); // 调整,将第一个元素和最后一个元素进行互换,i是变化的
  42. HeapAdjust(k, 1, i-1); // 重新调整
  43. }
  44. }
  45. int main()
  46. {
  47. int i;
  48. int a[10] = {-1, 5, 2, 6, 0, 3, 9, 1, 7, 4};
  49. HeapSort(a, 9);
  50. printf("总共执行 %d 次比较! \n", count);
  51. printf("排序后的结果是: ");
  52. for( i=1; i < 10; i++ )
  53. {
  54. printf("%d ", a[i]);
  55. }
  56. printf("\n");
  57. return 0;
  58. }

11.7 归并排序

  1. // 递归实现
  2. #include <stdio.h>
  3. #define MAXSIZE 10
  4. //实现归并,并把最后的结果存放到list1数组
  5. void merging(int *list1, int list1_size, int *list2, int list2_size)
  6. {
  7. int i, j, k, m;
  8. int temp[MAXSIZE];
  9. i = j = k = 0
  10. while( i < list1_size && j < list2_size )
  11. {
  12. if( list1[i] < list2[j] )
  13. {
  14. temp[k++] = list1[i++];
  15. }
  16. else
  17. {
  18. temp[k++] = list2[j++];
  19. }
  20. }
  21. while( i < list1_size )
  22. {
  23. temp[k++] = list1[i++];
  24. }
  25. while( j < list2_size )
  26. {
  27. temp[k++] = list2[j++];
  28. }
  29. for( m=0; m < (list1_size + list2_size); m++ )
  30. {
  31. list1[m] = temp[m];
  32. }
  33. }
  34. void MergeSort(int k[], int n)
  35. {
  36. if( n > 1 )
  37. {
  38. int *list1 = k;
  39. int list1_size = n/2;
  40. int *list2 = k + n/2; // 左半部分的地址加上左半部分的尺寸
  41. int list2_size = n - list1_size;
  42. MergeSort(list1, list1_size);
  43. MergeSort(list2, list2_size);
  44. merging(list1, list1_size, list2, list2_size);
  45. }
  46. }
  47. int main()
  48. {
  49. int i;
  50. int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
  51. MergeSort(a, 10);
  52. printf("排序后的结果是: \n");
  53. for( i=0; i < 10; i++ )
  54. {
  55. printf("%d", a[i]);
  56. }
  57. printf("\n");
  58. return 0;
  59. }
  1. // 迭代实现
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #define MAXSIZE 10
  5. void MergeSort(int k[], int n)
  6. {
  7. int i, next, left_min, left_max, right_min, right_max;
  8. // 申请空间存放数组
  9. int *temp = (int *)malloc(n * sizeof(int));
  10. // 逐级递增比较
  11. for( i=1; i < n; i*=2 ) // 步长i
  12. {
  13. for( left_min=0; left_min < n-i; left_min = right_max )
  14. {
  15. right_min = left_max = left_min + i;
  16. right_max = left_max + i;
  17. // 右边的下标最大值只能为n,防止越界
  18. if( right_max > n )
  19. {
  20. right_max = n;
  21. }
  22. // temp数组的下标,由于每次数据都有返回到k,因此每次都需重新置零
  23. next = 0;
  24. // 如果左边的数据还没有到分割线且右边的数据也没有到分割线,则循环
  25. while( left_min < left_max && right_min < right_max )
  26. {
  27. if( k[left_min] < k[right_min] )
  28. {
  29. temp[next++] = k[left_min++]; // 存放较小者
  30. }
  31. else
  32. {
  33. temp[next++] = k[right_min++];
  34. }
  35. }
  36. // 如果左边的游标没有到达分割线,则需要把数组接回去
  37. // 如果右边的游标没有到达分割线,则说明右边的数据比较大,不需要移动位置
  38. while( left_min < left_max )
  39. {
  40. k[--right_min] = k[--left_max];
  41. }
  42. while( next > 0 )
  43. {
  44. // 将排好序的数组返回给k
  45. k[--right_min] = temp[--next];
  46. }
  47. }
  48. }
  49. }
  50. int main()
  51. {
  52. int i;
  53. int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
  54. MergeSort(a, 10);
  55. printf("排序后的结果是: \n");
  56. for( i=0; i < 10; i++ )
  57. {
  58. printf("%d", a[i]);
  59. }
  60. printf("\n");
  61. return 0;
  62. }

11.8 快速排序

  1. #include <stdio.h>
  2. void swap(int k[], int low, int high)
  3. {
  4. int temp;
  5. temp = k[low];
  6. k[low] = k[high];
  7. k[high] = temp;
  8. }
  9. int Partition(int k[], int low, int high)
  10. {
  11. int point;
  12. point = k[low];
  13. while( low < high )
  14. {
  15. while( low < high && k[high] >= point )
  16. {
  17. high--;
  18. }
  19. swap(k, low, high);
  20. while( low < high && k[low] <= point )
  21. {
  22. low++;
  23. }
  24. swap(k, low, high);
  25. }
  26. return low;
  27. }
  28. void QSort(int k[], int low, int high)
  29. {
  30. int point;
  31. if( low < high )
  32. {
  33. point = Partition(k, low, high); // 计算基准点,将小于基准点的数放在左边,大的放在右边
  34. QSort(k, low, point-1);
  35. QSort(k, point+1, high);
  36. }
  37. }
  38. void QuickSort(int k[], int n)
  39. {
  40. QSort(k, 0, n-1);
  41. }
  42. int main()
  43. {
  44. int i;
  45. int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
  46. QuickSort(a, 10);
  47. printf("排序后的结果是: \n");
  48. for( i=0; i < 10; i++ )
  49. {
  50. printf("%d", a[i]);
  51. }
  52. printf("\n");
  53. return 0;
  54. }

11.8.1 快速排序的优化

11.8.1.1 优化选取基准点

  1. #include <stdio.h>
  2. void swap(int k[], int low, int high)
  3. {
  4. int temp;
  5. temp = k[low];
  6. k[low] = k[high];
  7. k[high] = temp;
  8. }
  9. int Partition(int k[], int low, int high)
  10. {
  11. int point;
  12. int m = low + (high-low)/2;
  13. if( k[low] > k[high] )
  14. {
  15. swap(k, low, high);
  16. }
  17. if( k[m] > k[high] )
  18. {
  19. swap(k, m, high);
  20. }
  21. if( k[m] > k[low] )
  22. {
  23. swap(k, m, low);
  24. }
  25. // 将low变成中间值
  26. point = k[low];
  27. while( low < high )
  28. {
  29. while( low < high && k[high] >= point )
  30. {
  31. high--;
  32. }
  33. swap(k, low, high);
  34. while( low < high && k[low] <= point )
  35. {
  36. low++;
  37. }
  38. swap(k, low, high);
  39. }
  40. }
  41. void QSort(int k[], int low, int high)
  42. {
  43. int point;
  44. if( low < high )
  45. {
  46. point = Partition(k, low, high); // 计算基准点,将小于基准点的数放在左边,大的放在右边
  47. QSort(k, low, point-1);
  48. QSort(k, point+1, high);
  49. }
  50. }
  51. void QuickSort(int k[], int n)
  52. {
  53. QSort(k, 0, n-1);
  54. }
  55. int main()
  56. {
  57. int i;
  58. int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
  59. QuickSort(a, 10);
  60. printf("排序后的结果是: \n");
  61. for( i=0; i < 10; i++ )
  62. {
  63. printf("%d", a[i]);
  64. }
  65. printf("\n");
  66. return 0;
  67. }

11.8.1.2 优化不必要的交换

  1. #include <stdio.h>
  2. void swap(int k[], int low, int high)
  3. {
  4. int temp;
  5. temp = k[low];
  6. k[low] = k[high];
  7. k[high] = temp;
  8. }
  9. int Partition(int k[], int low, int high)
  10. {
  11. int point;
  12. int m = low + (high-low)/2;
  13. if( k[low] > k[high] )
  14. {
  15. swap(k, low, high);
  16. }
  17. if( k[m] > k[high] )
  18. {
  19. swap(k, m, high);
  20. }
  21. if( k[m] > k[low] )
  22. {
  23. swap(k, m, low);
  24. }
  25. // 将low变成中间值
  26. point = k[low];
  27. while( low < high )
  28. {
  29. while( low < high && k[high] >= point )
  30. {
  31. high--;
  32. }
  33. k[low] = k[high];
  34. while( low < high && k[low] <= point )
  35. {
  36. low++;
  37. }
  38. k[high] = k[low];
  39. }
  40. k[low] = point;
  41. }
  42. void QSort(int k[], int low, int high)
  43. {
  44. int point;
  45. if( low < high )
  46. {
  47. point = Partition(k, low, high); // 计算基准点,将小于基准点的数放在左边,大的放在右边
  48. QSort(k, low, point-1);
  49. QSort(k, point+1, high);
  50. }
  51. }
  52. void QuickSort(int k[], int n)
  53. {
  54. QSort(k, 0, n-1);
  55. }
  56. int main()
  57. {
  58. int i;
  59. int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
  60. QuickSort(a, 10);
  61. printf("排序后的结果是: \n");
  62. for( i=0; i < 10; i++ )
  63. {
  64. printf("%d", a[i]);
  65. }
  66. printf("\n");
  67. return 0;
  68. }

11.8.1.3 优化小数组时的排序方案

  1. #include <stdio.h>
  2. #define MAX_LENGTH_INSERT_SORT 7
  3. void ISort(int k[], int n)
  4. {
  5. int i, j, temp;
  6. for( i=1; i < n; i++ )
  7. {
  8. if( k[i] < k[i-1] )
  9. {
  10. temp = k[i];
  11. for( j=i-1; k[j] > temp; j-- )
  12. {
  13. k[j+1] = k[j];
  14. }
  15. k[j+1] = temp;
  16. }
  17. }
  18. }
  19. void InsertSort(int k[], int low, int high)
  20. {
  21. ISort(k+low, high-low+1);
  22. }
  23. void swap(int k[], int low, int high)
  24. {
  25. int temp;
  26. temp = k[low];
  27. k[low] = k[high];
  28. k[high] = temp;
  29. }
  30. int Partition(int k[], int low, int high)
  31. {
  32. int point;
  33. int m = low + (high-low)/2;
  34. if( k[low] > k[high] )
  35. {
  36. swap(k, low, high);
  37. }
  38. if( k[m] > k[high] )
  39. {
  40. swap(k, m, high);
  41. }
  42. if( k[m] > k[low] )
  43. {
  44. swap(k, m, low);
  45. }
  46. // 将low变成中间值
  47. point = k[low];
  48. while( low < high )
  49. {
  50. while( low < high && k[high] >= point )
  51. {
  52. high--;
  53. }
  54. k[low] = k[high];
  55. while( low < high && k[low] <= point )
  56. {
  57. low++;
  58. }
  59. k[high] = k[low];
  60. }
  61. k[low] = point;
  62. }
  63. void QSort(int k[], int low, int high)
  64. {
  65. int point;
  66. if( high - low > MAX_LENGTH_INSERT_SORT )
  67. {
  68. point = Partition(k, low, high); // 计算基准点,将小于基准点的数放在左边,大的放在右边
  69. QSort(k, low, point-1);
  70. QSort(k, point+1, high);
  71. }
  72. else
  73. {
  74. InsertSort(k, low, high);
  75. }
  76. }
  77. void QuickSort(int k[], int n)
  78. {
  79. QSort(k, 0, n-1);
  80. }
  81. int main()
  82. {
  83. int i;
  84. int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
  85. QuickSort(a, 10);
  86. printf("排序后的结果是: \n");
  87. for( i=0; i < 10; i++ )
  88. {
  89. printf("%d", a[i]);
  90. }
  91. printf("\n");
  92. return 0;
  93. }

11.8.1.4 优化递归操作

  1. #include <stdio.h>
  2. #define MAX_LENGTH_INSERT_SORT 7
  3. void ISort(int k[], int n)
  4. {
  5. int i, j, temp;
  6. for( i=1; i < n; i++ )
  7. {
  8. if( k[i] < k[i-1] )
  9. {
  10. temp = k[i];
  11. for( j=i-1; k[j] > temp; j-- )
  12. {
  13. k[j+1] = k[j];
  14. }
  15. k[j+1] = temp;
  16. }
  17. }
  18. }
  19. void InsertSort(int k[], int low, int high)
  20. {
  21. ISort(k+low, high-low+1);
  22. }
  23. void swap(int k[], int low, int high)
  24. {
  25. int temp;
  26. temp = k[low];
  27. k[low] = k[high];
  28. k[high] = temp;
  29. }
  30. int Partition(int k[], int low, int high)
  31. {
  32. int point;
  33. int m = low + (high-low)/2;
  34. if( k[low] > k[high] )
  35. {
  36. swap(k, low, high);
  37. }
  38. if( k[m] > k[high] )
  39. {
  40. swap(k, m, high);
  41. }
  42. if( k[m] > k[low] )
  43. {
  44. swap(k, m, low);
  45. }
  46. // 将low变成中间值
  47. point = k[low];
  48. while( low < high )
  49. {
  50. while( low < high && k[high] >= point )
  51. {
  52. high--;
  53. }
  54. k[low] = k[high];
  55. while( low < high && k[low] <= point )
  56. {
  57. low++;
  58. }
  59. k[high] = k[low];
  60. }
  61. k[low] = point;
  62. }
  63. void QSort(int k[], int low, int high)
  64. {
  65. int point;
  66. if( high - low > MAX_LENGTH_INSERT_SORT )
  67. {
  68. while( low < high )
  69. {
  70. point = Partition(k, low, high); // 计算基准点,将小于基准点的数放在左边,大的放在右边
  71. if( point-low < high-point )
  72. {
  73. QSort(k, low, point-1);
  74. low = point + 1;
  75. }
  76. else
  77. {
  78. QSort(k, point+1, high);
  79. high = point-1;
  80. }
  81. }
  82. }
  83. else
  84. {
  85. InsertSort(k, low, high);
  86. }
  87. }
  88. void QuickSort(int k[], int n)
  89. {
  90. QSort(k, 0, n-1);
  91. }
  92. int main()
  93. {
  94. int i;
  95. int a[10] = {5, 2, 6, 0, 3, 9, 1, 7, 4, 8};
  96. QuickSort(a, 10);
  97. printf("排序后的结果是: \n");
  98. for( i=0; i < 10; i++ )
  99. {
  100. printf("%d", a[i]);
  101. }
  102. printf("\n");
  103. return 0;
  104. }

11.9 总结回顾

排序方法 平均情况 最好情况 最坏情况 辅助空间 稳定性
冒泡排序 O(n^2) O(n) O(n^2) O(1) 稳定
选择排序 O(n^2) O(n^2) O(n^2) O(1) 稳定
直接插入排序 O(n^2) O(n) O(n^2) O(1) 稳定
希尔排序 O(nlogn)~O(n^2) O(n^1.3) O(n^2) O(1) 不稳定
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定
归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定
快速排序 O(nlogn) O(nlogn) O(n^2) O(nlogn)~O(n) 不稳定
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注