• 数据结构与算法:排序专题


    思维导图:

    0.计数排序

    1. void CountSort(int* a, int n)
    2. {
    3. int min = a[0];
    4. int max = a[0];
    5. for (int i = 0; i < n; i++)
    6. {
    7. if (a[i] < min)
    8. min = a[i];
    9. if (a[i] > max)
    10. max = a[i];
    11. }
    12. int gap = max - min + 1;
    13. int* countarr = (int*)malloc(sizeof(int) * gap);
    14. memset(countarr, 0, sizeof(int) * gap);
    15. for (int i = 0; i < n; i++)
    16. {
    17. countarr[a[i] - min]++;
    18. }
    19. int j = 0;
    20. for (int i = 0; i < gap; i++)
    21. {
    22. if (countarr[i])
    23. {
    24. while (countarr[i]--)
    25. {
    26. a[j++] = i;
    27. }
    28. }
    29. }
    30. free(countarr);
    31. }

    思想:1.遍历原数组找出最大最小值 

    2.根据最大最小值确定所开数组大小

    3.再次遍历原数组,在countarr相应位置进行计数,类似哈希4.遍历countarr数组,遇到不为0的数给原数组赋值,原数组即有序

    1.冒泡排序

    1. void BubbleSort(int* a, int n)
    2. {
    3. for (int i = 0; i < n - 1; i++)
    4. {
    5. int flag = 0;
    6. for (int j = 0; j < n - 1 - i; j++)
    7. {
    8. if (a[j] > a[j + 1])
    9. {
    10. swap(&a[j], &a[j + 1]);
    11. flag = 1;
    12. }
    13. }
    14. if (flag == 0)//这一趟没有任何交换,结束排序
    15. {
    16. return;
    17. }
    18. }
    19. }

    思想:最简单的排序,每一次将最大的数放到最后即可 

    2.直接插入排序

    1. void InsertSort(int* a, int n)
    2. {
    3. for (int i = 0; i < n - 1; i++)
    4. {
    5. int end = i;
    6. int tmp = a[i + 1];
    7. while (end >= 0)
    8. {
    9. if (tmp < a[end])
    10. {
    11. a[end + 1] = a[end];
    12. end--;
    13. }
    14. else
    15. break;
    16. }
    17. a[end + 1] = tmp;
    18. }
    19. }

     类似扑克牌排序,从第一张牌开始,每摸到一张牌放到合适的位置,牌始终有序

    数组的第一个元素可以直接视为有序,拿起第二个元素,如果第二个元素第一个元素小,就将第一个元素往后移,那么前两个元素有序。之后每次将新元素拿起,进行类似的插入即可

    3.选择排序

    1. void SelectSort(int* a, int n)
    2. {
    3. int begin = 0;
    4. int end = n - 1;//限制需要排序的区间
    5. while (begin < end)
    6. {
    7. int maxi = begin;
    8. int mini = begin;
    9. for (int i = begin; i <= end; i++)//遍历限制范围内的数组
    10. {
    11. if (a[i] > a[maxi])
    12. maxi = i;
    13. if (a[i] < a[mini])
    14. mini = i;
    15. }
    16. //将最小值放在begin位置,最大值放在end位置
    17. //如果最大值在begin,那么第一次交换最大值将换到最小值的位置
    18. swap(&a[begin], &a[mini]);
    19. if (maxi == begin)
    20. {
    21. maxi = mini;
    22. }
    23. swap(&a[end], &a[maxi]);
    24. begin++;
    25. end--;
    26. }
    27. }

     思想:每次将最大值放在后面,最小值放在前面

    4.希尔排序

    1. void ShellSort(int* a, int n)
    2. {
    3. int gap = n;
    4. while (gap > 1)
    5. {
    6. gap = gap / 3 + 1;
    7. for (int i = 0; i + gap < n; i++)
    8. {
    9. int end = i;
    10. int tmp = a[i + gap];
    11. while (end >= 0)
    12. {
    13. if (tmp < a[end])
    14. {
    15. a[end + gap] = a[end];
    16. end -= gap;
    17. }
    18. else
    19. break;
    20. }
    21. a[end + gap] = tmp;
    22. }
    23. }
    24. }

    在插入排序的基础上增加了预排序,每间隔gap为一组进行排序,循环到最后gap等于1,就是一次插入排序

    5.堆排序

     

    1. void AdjustDown(int* a, int n, int parent)
    2. {
    3. int child = 2 * parent + 1;
    4. while (child < n)
    5. {
    6. if (child + 1 < n && a[child + 1] > a[child])
    7. {
    8. child++;
    9. }
    10. if (a[parent] < a[child])
    11. {
    12. swap(&a[parent], &a[child]);
    13. parent = child;
    14. child = parent * 2 + 1;
    15. }
    16. else
    17. break;
    18. }
    19. }
    20. void AdjustUp(int* a, int child)
    21. {
    22. int parent = (child - 1) / 2;
    23. while (child)
    24. {
    25. if (a[child] > a[parent])
    26. {
    27. swap(&a[child], &a[parent]);
    28. child = parent;
    29. parent = (child - 1) / 2;
    30. }
    31. else
    32. break;
    33. }
    34. }
    35. void HeapSort(int* a, int n)
    36. {
    37. //建堆
    38. //向上调整建堆
    39. /*for (int i = 1; i < n; i++)
    40. {
    41. AdjustUp(a, i);
    42. }*/
    43. //向下调整建堆
    44. for (int i = (n - 1 - 1) / 2; i >= 0; i++)
    45. {
    46. AdjustDown(a, n, i);
    47. }
    48. //调堆
    49. //建大堆,排升序;建小堆,排降序
    50. int end = n - 1;
    51. while (end)
    52. {
    53. swap(&a[0], &a[end]);
    54. AdjustDown(a, end, 0);
    55. end--;
    56. }
    57. }

     思想将在堆中进行讲解

    6.归并排序

    递归型

    1. void _MergeSort(int* a, int begin, int end, int* tmp)
    2. {
    3. if (begin == end)
    4. return;
    5. int mid = (begin + end) / 2;
    6. _MergeSort(a, begin, mid, tmp);
    7. _MergeSort(a, mid+1, end, tmp);
    8. int begin1 = begin, end1 = mid;
    9. int begin2 = mid+1, end2 = end;
    10. int j=begin;
    11. while (begin1 <= end1 && begin2 <= end2)
    12. {
    13. if (a[begin1] < a[begin2])
    14. {
    15. tmp[j++] = a[begin1++];
    16. }
    17. else
    18. {
    19. tmp[j++] = a[begin2++];
    20. }
    21. }
    22. while (begin1 <= end1)
    23. {
    24. tmp[j++] = a[begin1++];
    25. }
    26. while (begin2 <= end2)
    27. {
    28. tmp[j++] = a[begin2++];
    29. }
    30. memcpy(a + begin, tmp + begin, sizeof(int)*(end-begin+1));
    31. }
    32. void MergeSort(int* a, int n)
    33. {
    34. int* tmp = (int*)malloc(sizeof(int) * n);
    35. _MergeSort(a, 0, n - 1, tmp);
    36. free(tmp);
    37. }

    非递归型 

    1. void MergeSortNonR(int* a, int n)
    2. {
    3. int* tmp = (int*)malloc(sizeof(int) * n);
    4. int gap = 1;
    5. while (gap < n)
    6. {
    7. for (int i = 0; i < n; i+=2*gap)
    8. {
    9. int begin1 = i, end1 = i + gap - 1;
    10. int begin2 = i + gap, end2 = i + 2 * gap - 1;
    11. int j = i;
    12. if (begin2 >= n)
    13. {
    14. break;
    15. }
    16. if (end2 >= n)
    17. {
    18. end2 = n - 1;
    19. }
    20. while (begin1 <= end1 && begin2 <= end2)
    21. {
    22. if (a[begin1] < a[begin2])
    23. {
    24. tmp[j++] = a[begin1++];
    25. }
    26. else
    27. {
    28. tmp[j++] = a[begin2++];
    29. }
    30. }
    31. while (begin1 <= end1)
    32. {
    33. tmp[j++] = a[begin1++];
    34. }
    35. while (begin2 <= end2)
    36. {
    37. tmp[j++] = a[begin2++];
    38. }
    39. memcpy(a + i, tmp + i, sizeof(int) * (end2 - i));
    40. }
    41. gap *= 2;
    42. }
    43. free(tmp);
    44. }

    7.快速排序

    普通快排

    1. //hoare
    2. int PartSort1(int* a, int begin, int end)
    3. {
    4. int keyi = begin;//keyi在左,先动右指针
    5. while (begin < end)
    6. {
    7. while (begin < end && a[end] >= a[keyi])
    8. {
    9. end--;
    10. }
    11. while (begin < end && a[begin] <= a[keyi])
    12. {
    13. begin++;
    14. }
    15. swap(&a[begin], &a[end]);
    16. }
    17. swap(&a[keyi], &a[begin]);
    18. return begin;
    19. }
    20. //挖坑
    21. int PartSort2(int* a, int begin, int end)
    22. {
    23. int hole = begin;
    24. while (begin < end)
    25. {
    26. while (begin < end && a[end] >= a[hole])
    27. {
    28. end--;
    29. }
    30. swap(&a[end], &a[hole]);
    31. hole = end;
    32. while (begin < end && a[begin] <= a[hole])
    33. {
    34. begin++;
    35. }
    36. swap(&a[begin], &a[hole]);
    37. hole = begin;
    38. }
    39. return hole;
    40. }
    41. //前后指针
    42. int PartSort3(int* a, int begin, int end)
    43. {
    44. int key = a[begin];
    45. int prev = begin;
    46. int cur = begin + 1;
    47. while (cur <= end)
    48. {
    49. if (a[cur] <= key)
    50. {
    51. swap(&a[cur], &a[++prev]);
    52. }
    53. cur++;
    54. }
    55. swap(&a[begin], &a[prev]);
    56. return prev;
    57. }
    58. void QuickSort(int* a, int n)//可以有其他参数设置方法,这里跟其他排序函数参数保持一致
    59. {
    60. int begin = 0;
    61. int end = n - 1;
    62. if (begin >= end)
    63. return;
    64. int keyi = PartSort3(a, begin, end);
    65. QuickSort(a, keyi);
    66. QuickSort(a + keyi + 1, end - keyi);
    67. }

     针对重复数据的三路划分

    1. //三路划分
    2. void QuickSort2(int* a, int begin,int end)
    3. {
    4. if (begin >= end)
    5. return;
    6. int key = a[begin];
    7. int left = begin;
    8. int right = end;
    9. int cur = begin + 1;
    10. while (cur <= right)
    11. {
    12. if (a[cur] < key)
    13. {
    14. swap(&a[cur], &a[left]);
    15. cur++;
    16. left++;
    17. }
    18. else if (a[cur] > key)
    19. {
    20. swap(&a[cur], &a[right]);
    21. right--;
    22. }
    23. else
    24. {
    25. cur++;
    26. }
    27. }
    28. QuickSort2(a, begin, left-1);
    29. QuickSort2(a, right + 1, end);
    30. }

     不会因递归导致栈溢出的非递归快排

    1. //非递归快排
    2. void QuickSortNonR(int* a, int n)
    3. {
    4. Stack s;
    5. StackInit(&s);
    6. int begin = 0;
    7. int end = n - 1;
    8. StackPush(&s, begin);
    9. StackPush(&s, end);
    10. while (!StackEmpty(&s))
    11. {
    12. end = StackTop(&s);
    13. StackPop(&s);
    14. begin = StackTop(&s);
    15. StackPop(&s);
    16. int keyi = PartSort1(a, begin, end);
    17. if (keyi+1 < end)
    18. {
    19. StackPush(&s, keyi+1);
    20. StackPush(&s, end);
    21. }
    22. if (begin < keyi - 1)
    23. {
    24. StackPush(&s, begin);
    25. StackPush(&s, keyi-1);
    26. }
    27. }
    28. StackDestroy(&s);
    29. }

  • 相关阅读:
    MySQL之MHA高可用集群
    华为hcie认证培训报班培训好?还是自学好
    Windbg可以看到Visual Studio中看不到的有效函数调用堆栈
    RPA自动化全平台文章同步助手
    使用注解的方式导出excel数据
    高压放大器在扫描显微镜中的应用及优势是什么
    液位检测仪在线监测系统解决方案
    iOS逆向之汇编的常见指令
    c#设计模式-行为型模式 之 解释器模式
    DGIOT短信字段与腾讯云服务器短信字段的对应关系
  • 原文地址:https://blog.csdn.net/2201_75404212/article/details/133121914