Michael

写写代码,说说人生

您好,我是Michael,欢迎来到我的个人家园。
代码搬运工,目前就职于XX证券,努力修行中。


H5 / Java / Objc / Swift / Vue / RN

算法-归并排序

阅读量真是少,又不想投稿,怎么办

前言

归并排序思路简单,速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列。

核心思想

比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

示例

分治

  1. 首先我们拿到原始数组{100,5,3,11,33,6,8,7,1,3},然后将数组对半分。

  2. {100,5,3,11,33},{6,8,7,1,3},继续半分。

  3. {100,5,3},{11,33};{6,8,7,},{1,3},多于两个值的集合,继续半分。

  4. {100,5},{3};{11,33};{6,8},{7};{1,3},拆分完成后,每个集合先内部排序,再按拆分的顺序合并。

归并

  1. {100,5}->{5,100}对比1次,对比顺序:5:100,调整后数组变为{5,100,3,11,33,6,8,7,1,3}

  2. {5,100},{3}->{3,5,100}对比1次,对比顺序:5:3,调整后数组变为{3,5,100,11,33,6,8,7,1,3}

  3. {11,33}无变化对比1次,对比顺序:11:33,调整后数组变为{3,5,100,11,33,6,8,7,1,3}

  4. {3,5,100},{11,33}->{3,5,11,33,100}对比4次,对比顺序:3:11,5:11,100:11,100:33,调整后数组变为{3,5,11,33,100,6,8,7,1,3}

  5. {6,8}无变化对比1次,对比顺序:6:8,调整后数组变为{3,5,11,33,100,6,8,7,1,3}

  6. {6,8},{7}->{6,7,8}对比2次,对比顺序:6:8,8:7,调整后数组变为{3,5,11,33,100,6,7,8,1,3}

  7. {1,3}无变化对比1次,对比顺序:1:3,调整后数组变为{3,5,11,33,100,6,7,8,1,3}

  8. {6,7,8},{1,3}->{1,3,6,7,8}对比2次,对比顺序: 6:1,6:3,调整后数组变为{3,5,11,33,100,1,3,6,7,8}

  9. {3,5,11,33,100},{1,3,6,7,8}->{1,3,3,5,6,7,8,11,33,100}对比7次,对比顺序:1:3,3:3,5:3,5:6,11:6,11:7,11:8,整个数组完成排序。

C语言代码

#pragma mark - 归并排序
void mergeList (int arr[], int first, int middle, int last ,int temp[]) {
    printf("待排序数组\n");

    for (int i = first; i <= last; i++) {
        printf("%d\t",arr[i]);
    }
    
    int leftStartIndex = first;
    int leftEndIndex = middle;
    
    int rightStartIndex = middle + 1;
    int rightEndIndex = last;
    
    int tempIndex = 0;

    // 寻找两个子序列,顺序遍历,将值小的复制到临时数组中,直到其中一个子序列遍历完毕
    while (leftStartIndex <= leftEndIndex && rightStartIndex <= rightEndIndex) {
        // 值小的就复制到临时数组中
        printf("\nleft:%d right:%d\n",arr[leftStartIndex],arr[rightStartIndex]);
        if (arr[leftStartIndex] <= arr[rightStartIndex]) {
            printf("temp加入left:%d\n",arr[leftStartIndex]);
            temp[tempIndex++] = arr[leftStartIndex++];
        } else {
            printf("temp加入right:%d\n",arr[rightStartIndex]);
            temp[tempIndex++] = arr[rightStartIndex++];
        }
    }
    
    // 有可能左子序列更长,因此将剩下的部分直接复制到临时数组中
    while (leftStartIndex <= leftEndIndex) {
        temp[tempIndex++] = arr[leftStartIndex++];
    }
    
    // 有可能右子序列更长,因此将剩下的部分直接复制到临时数组中
    while (rightStartIndex <= rightEndIndex) {
        temp[tempIndex++] = arr[rightStartIndex++];
    }
    
    int i = 0;
    while (first+i <= last) {
        arr[first+i] = temp[i];
        i++;
    }
    
    printf("进行排序数组\n");
    for (int i = first; i <= last; i++) {
        printf("%d\t",arr[i]);
    }
    printf("\n更新数组\n");
    printfArr(arr, 10);
}

void mergeSort (int arr[], int first, int last, int temp[]) {
    if (first == 0 && last == 9) {
        printfArr(arr, 10);
    }
    if (last > first) {
        int middle = (first+last)/2;
        // 归并左方子列
        mergeSort(arr, first, middle, temp);
        // 归并右方子列
        mergeSort(arr, middle+1, last, temp);
        // 合并
        mergeList(arr, first, middle, last, temp);
    }
}

时间复杂度

时间复杂度为O(nlogn) 这是该算法平均的时间性能,空间复杂度为 O(n),比较操作的次数介于(nlogn) / 2和nlogn - n + 1。

结语

从新写一遍算法,理解果然更透彻了,本文没有使用图片,感觉用文字就已经足够描述了😅。


最后给出最近几篇关于排序算法的源代码

最近的文章

使用 TensorFlow 实现神经网络

介绍  一直关注 数据科学 、 机器学习 的同学,一定会经常看到或听到关于 深度学习 和 神经网络 相关信息。如果你对 深度学习 感兴趣,但却还没有实际动手操作过,你可以从这里得到实践。  在本文中,我将介绍 TensorFlow , 帮你了解 神经网络 的实际作用,并使用 TensorFlow 来解决现实生活中的问题。 读这篇文章前,需要知道 神经网络 的基础知识和一些熟悉编程理念,文章中的代码是使用 Pyhton 编写的,所以还需要了解一些 Python 的基本语法,才能更有利对于文章...…

机器学习继续阅读
更早的文章

算法-堆排序

赶紧让你的大脑来一套广播体操前言慢慢的,我们脱离了”小学生“算法,开始接触一些需要绕圈子的思路,赶紧沉浸入堆排序的头脑风暴当中吧。简介堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一...…

算法设计继续阅读