• 数据结构——排序2


    目录

    归并排序

    递归

    非递归 

     非比较排序


    归并排序

    递归

    基本思想:
    归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。先递归,再排序


    1.把数组从中间俩边分开进行递归进行分解

    2.分解为最小后进行排序,分为左边和右边,将左边和右边的值想比较,最小的先放入tmp数组,之后把大的放入

    3.把左边或右边剩余的未拷贝的拷贝到tmp数组中

    4.把tmp数组中的数据拷贝回原数组

    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; int end1 = mid;
    9. int i = begin1;
    10. int begin2 = mid + 1; int end2 = end;
    11. while (begin1 <= end1 && begin2 <= end2)
    12. {
    13. if (a[begin1] < a[begin2])
    14. tmp[i++] = a[begin1++];
    15. else
    16. tmp[i++] = a[begin2++];
    17. }
    18. while (begin1 <= end1)
    19. tmp[i++] = a[begin1++];
    20. while (begin2<= end2)
    21. tmp[i++] = a[begin2++];
    22. memcpy(a + begin, tmp + begin, ((end - begin) + 1) * sizeof(int));
    23. }
    24. void MergeSort(int* a, int n)
    25. {
    26. int* tmp = (int*)malloc(sizeof(int) * n);
    27. if (tmp == NULL)
    28. return;
    29. _MergeSort(a, 0, n - 1, tmp);
    30. free(tmp);
    31. }
    32. void PrintArray(int* a, int n)
    33. {
    34. for (int i = 0; i < n; i++)
    35. printf("%d ", a[i]);
    36. printf("\n");
    37. }
    38. int main()
    39. {
    40. int a[8] = {10,6,7,1,3,9,4,2 };
    41. MergeSort(a,8);
    42. PrintArray(a, 8);
    43. return 0;
    44. }

     

    非递归 

     

    先1个2个归,然后再2个2个归,再4个4个归,这里要重新设置begin1 end1 begin2 end2

    因为随着gap的变化这四个变量的范围也有所变化,每归一轮结束后,gap要乘2,当gap>=n时,结束循环

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

     

     但是这样写会出问题,当数组内数字个数不是2的整数次幂的时候,就会发生越界

    9个数据和10个数据等都会发生越界,而越界的数字是end1,begin2,end2,为了防止越界,我们可把上面越界情况写出来end1 >= n,begin2 >= n,end2 >= n ,而在程序中如果要进入循环应执行以下语句

    while (begin1 <= end1 && begin2 <= end2)

    begin1<=end1,begin2<=end2才进入循环,根据这个循环,我们判断如果end1>=n,begin2>=n,end2>=n时,我们可将他们的范围修改,使其不进入循环或进入循环后没影响,对end1>=,我们可让end1=n-1,这样让其进入循环,但对结果也不会产生影响,如上面的[8,11],我们设置为[8,8]这样它归并后只会出去一个数字8,然后随便修正begin2和end2,使begin2

    加入下面循环语句‘

    1. if(end1>=n)
    2. {
    3. end1=n-1;
    4. begin2=n;
    5. end2=n-1;
    6. }
    7. else if(begin2>=n)
    8. {
    9. begin2=n;
    10. end2=n-1;
    11. }
    12. else if(end2>=n)
    13. {
    14. end2=n-1;
    15. }
    1. void PrintArray(int* a, int n)
    2. {
    3. for (int i = 0; i < n; i++)
    4. printf("%d ", a[i]);
    5. printf("\n");
    6. }
    7. void _MergeSort1(int* a, int n)
    8. {
    9. int* tmp = (int*)malloc(sizeof(int) * n);
    10. if (tmp == NULL)
    11. return;
    12. int gap = 1;
    13. while (gap < n)
    14. {
    15. for (int i = 0; i < n; i = i + 2 * gap)
    16. {
    17. int begin1 = i; int end1 = i + gap - 1;
    18. int begin2 = i + gap; int end2 = i + 2 * gap - 1;
    19. int j = begin1;
    20. if (end1 >= n)
    21. {
    22. end1 = n - 1;
    23. begin2 = n;
    24. end2 = n - 1;
    25. }
    26. else if (begin2 >= n)
    27. {
    28. begin2 = n;
    29. end2 = n - 1;
    30. }
    31. else if (end2 >= n)
    32. {
    33. end2 = n - 1;
    34. }
    35. while (begin1 <= end1 && begin2 <= end2)
    36. {
    37. if (a[begin1] < a[begin2])
    38. tmp[j++] = a[begin1++];
    39. else
    40. tmp[j++] = a[begin2++];
    41. }
    42. while (begin1 <= end1)
    43. tmp[j++] = a[begin1++];
    44. while (begin2 <= end2)
    45. tmp[j++] = a[begin2++];
    46. }
    47. memcpy(a, tmp, n * sizeof(int));
    48. gap = gap * 2;
    49. }
    50. PrintArray(a, 10);
    51. }
    52. void MergeSort1(int* a, int n)
    53. {
    54. _MergeSort1(a, n);
    55. }
    56. int main()
    57. {
    58. int a[10] = {10,6,7,1,3,9,4,2,10,11 };
    59. MergeSort1(a,10);
    60. return 0;
    61. }

    修正后的边界 

    这样不管对几个都可以进行排序,不存在越界问题

    另一种写法,当越界的时候,我们就不归了,但是要归并一次就要拷贝一次

    1. void MergeSortNonR(int* a, int n)
    2. {
    3. int* tmp = (int*)malloc(sizeof(int) * n);
    4. if (tmp == NULL)
    5. {
    6. printf("malloc fail\n");
    7. exit(-1);
    8. }
    9. int gap = 1;
    10. while (gap < n)
    11. {
    12. //printf("gap=%d->", gap);
    13. for (int i = 0; i < n; i += 2 * gap)
    14. {
    15. // [i,i+gap-1][i+gap, i+2*gap-1]
    16. int begin1 = i, end1 = i + gap - 1;
    17. int begin2 = i + gap, end2 = i + 2 * gap - 1;
    18. // end1越界或者begin2越界,则可以不归并了
    19. if (end1 >= n || begin2 >= n)
    20. {
    21. break;
    22. }
    23. else if (end2 >= n)
    24. {
    25. end2 = n - 1;
    26. }
    27. //printf("[%d,%d] [%d, %d]--", begin1, end1, begin2, end2);
    28. int m = end2 - begin1 + 1;
    29. int j = begin1;
    30. while (begin1 <= end1 && begin2 <= end2)
    31. {
    32. if (a[begin1] < a[begin2])
    33. {
    34. tmp[j++] = a[begin1++];
    35. }
    36. else
    37. {
    38. tmp[j++] = a[begin2++];
    39. }
    40. }
    41. while (begin1 <= end1)
    42. {
    43. tmp[j++] = a[begin1++];
    44. }
    45. while (begin2 <= end2)
    46. {
    47. tmp[j++] = a[begin2++];
    48. }
    49. memcpy(a + i, tmp + i, sizeof(int) * m);
    50. }
    51. gap *= 2;
    52. }
    53. free(tmp);
    54. }

     非比较排序

    非比较排序有桶排序,计数排序,基数排序

     计数排序

    计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。 操作步骤:
    1. 统计相同元素出现次数
    2. 根据统计的结果将序列回收到原来的序列中

     

    0出现2次,1出现0次,2出现2次,3出现3次,4出现0次,5出现1次 

    每个数出现几次相对应的位置就++几次

    然后再写回原数组 

    局限性:1.如果是浮点数,字符串就无法用这种方法

                   2.如果数据范围很大,空间复杂度就会很高,相对不适合

    如果数组是:1000,1005,1000,1008,1009,1006

    不可能开1000多个数据不然比较浪费,此时就要使用绝对映射

    使用相对映射:1000-0

                             1001-1

                              ……

                              1009-9

    这样即使有负数,也能进行排序

    -5对应0 

    1. void CountSort(int *a,int n)
    2. {
    3. int min = a[0], max = a[0];//先找到最大值和最小值
    4. for (int i = 0; i < n; i++)
    5. {
    6. if (a[i] < min)
    7. {
    8. min = a[i];
    9. }
    10. if (a[i] >max)
    11. {
    12. max = a[i];
    13. }
    14. }
    15. int range = max - min + 1;//算出范围
    16. int* count =(int*) malloc(sizeof(int) * range);
    17. if (count == NULL)
    18. return;
    19. memset(count, 0, sizeof(int) * range);
    20. for (int i = 0; i < n; ++i)
    21. {
    22. count[a[i] - min]++;//统计次数
    23. }
    24. //排序
    25. int j = 0;
    26. for (int i = 0; i < range; ++i)
    27. {
    28. //出现几次,回写几个i+min
    29. while (count[i]--)
    30. {
    31. a[j++] = i + min;
    32. }
    33. }
    34. }
    35. int main()
    36. {
    37. int a[10] = {10,6,7,1,3,9,4,2,10,11 };
    38. CountSort(a,10);
    39. return 0;
    40. }

     时间复杂度:O(max(range,N))

    空间复杂度:O(range)

  • 相关阅读:
    计算机毕设(附源码)JAVA-SSM旅行组团服务管理系统
    阿里、腾讯美国员工基本年薪曝光,资深算法工程师24万美元,高级研究员26万美元
    您需要知道的API基础知识都在这里
    基于 Vite + Vue3 的组件库打包并发布到npm
    python使用unittest进行单元测试
    MQ---第一篇
    论文解读(KP-GNN)《How Powerful are K-hop Message Passing Graph Neural Networks》
    分布式存储在数据治理场景中的价值
    二、初识FreeRTOS之FreeRTOS入门
    java集合框架
  • 原文地址:https://blog.csdn.net/weixin_49449676/article/details/126401571