面试时这样介绍算法,想不高薪都难,排序算法(归并排序)

2023-11-13

算法背景

归并排序(Merge sort)是一种排序算法,它的目的是将一个无序的数组变成有序的。它采用分治法,将原数组不断地分成若干个小数组,直到每个小数组只有一个元素。然后把这些小数组按照顺序合并起来,最终得到一个有序的数组。

归并排序需要额外的空间来存放临时合并的数组,时间复杂度为O(nlogn),空间复杂度为O(n),属于稳定排序算法。

归并排序适用于大数据量排序,因为它具有较高的效率,在排序大数据量的时候比较常用。

归并排序是稳定排序算法,它能保证相同元素之间的顺序不变。

归并排序算法在排序大数据量的时候占有优势,在大数据量的排序场景中是一种非常有用的排序算法。

算法流程

归并排序是一种分治策略,将一个大的排序问题划分成小的子问题来解决。它的基本流程是:

输入:一个无序的整数数组

输出:一个有序的整数数组

算法核心部分的具体实现:

将整个数组分成两个子数组,分别对这两个子数组进行排序

将两个已经排好序的子数组进行合并,合并的时候需要比较两个子数组中的元素,将较小的元素先加入新数组中

重复步骤1和2,直到合并出最终有序数组

归并排序的时间复杂度为 O(nlogn),空间复杂度为 O(n)。因为归并排序需要额外的空间来存储新数组。

时间和空间复杂度

时间复杂度

归并排序是一种分治算法,它将一个数组分为两个子数组,分别对子数组进行排序,最后将排序好的子数组合并起来。

流程如下:

将数组平分成两个子数组

分别对子数组进行排序

将排序好的两个子数组合并

时间复杂度分析:

归并排序的时间复杂度为O(nlogn)。因为每次递归都会将数组平分成两个子数组,这样每次递归的时间复杂度就会减半,最后再将排序好的两个子数组合并,这一步的时间复杂度为O(n)。因此整个算法的时间复杂度为O(nlogn)。

总结:归并排序是一种高效的排序算法,它的时间复杂度为O(nlogn),是一种稳定的排序算法,适用于大规模数据的排序。

空间复杂度

归并排序的空间复杂度为 O(n),因为它需要一个辅助数组来存储归并之后的元素,但这个辅助数组的大小就是原始数组的大小。因此,它需要与数组大小线性相关的空间,而不是数组大小的平方或其他复杂的空间。

归并排序的优缺点

归并排序是一种排序算法,它的思路是将整个序列分成两个子序列,再将子序列分别排序,最后将排序后的子序列合并起来。

优点

时间复杂度为O(n log n),较快速排序算法

实现简单,可以递归实现

稳定排序,相同元素在排序前后相对位置不变

缺点

空间复杂度较高,需要额外的空间来存储子序列

数据规模较小时不如其他算法

适用场景

数据规模较大时,归并排序是一个很好的选择

数据稳定性要求较高时,归并排序是一个不错的选择

限制

空间限制较大时,归并排序不是很适合

数据规模较小时,其他算法更优秀

归并排序并不是在所有情况都是最优秀的排序算法,但是在数据规模较大时,稳定性要求较高,空间限制较小时是一个不错的选择.

示例代码

C++

#include <iostream>
using namespace std;

void merge(int arr[], int left, int mid, int right) {
    // 计算两个子序列的长度
    int n1 = mid - left + 1;
    int n2 = right - mid;

    // 创建两个辅助数组
    int L[n1], R[n2];

    // 拷贝数据到辅助数组
    for (int i = 0; i < n1; i++) {
        L[i] = arr[left + i];
    }
    for (int i = 0; i < n2; i++) {
        R[i] = arr[mid + 1 + i];
    }

    // 合并两个子序列
    int i = 0, j = 0, k = left;
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k++] = L[i++];
        } else {
            arr[k++] = R[j++];
        }
    }

    // 拷贝剩余元素
    while (i < n1) {
        arr[k++] = L[i++];
    }
    while (j < n2) {
        arr[k++] = R[j++];
    }
}

void mergeSort(int arr[], int left, int right) {
    if (left < right) {
        // 找到中间位置
        int mid = (left + right) / 2;

        // 递归排序左半部分
        mergeSort(arr, left, mid);

        // 递归排序右半部分
        mergeSort(arr, mid + 1, right);

        // 合并两个子序列
        merge(arr, left, mid, right);
    }
}

int main() {
    int arr[] = {5, 2, 9, 1, 7, 6, 8, 3, 4};
    int n = sizeof(arr) / sizeof(arr[0]);

    mergeSort(arr, 0, n - 1);

    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }

    return 0;
}

这是一个归并排序算法的C++实现, mergeSort函数是主要的排序函数,它只有两个参数: arr是要排序的数组, left和right是数组的左右边界. 这个算法的思路是不断把整个序列分成两个子序列并对子序列进行排序, 一直到序列的长度为1为止.

具体实现中, 主要有三个函数:

mergeSort(int arr[], int left, int right) : 主要的排序函数, 递归分治,将序列分成两个子序列,分别对子序列进行排序,最后合并两个子序列

merge(int arr[], int left, int mid, int right) : 合并两个子序列的函数, 把两个子序列按照升序合并成一个序列

main() : 主函数, 测试代码

上面的代码中, arr是要排序的数组, left和right是数组的左右边界. 最后的结果会在输出中展示出来.

这个算法的时间复杂度是O(n log n),空间复杂度是O(n),归并排序不是一个原地排序算法,因为它需要额外的空间存储临时数组。在数据规模较大时,空间复杂度可能成为瓶颈。

这个算法的优点是稳定性较高,可以保证相同元素在排序前后相对位置不变,可以用于排序数据有要求的场景。缺点是空间复杂度较高,在数据规模较小时效率不如其他算法。

Python

def merge(left, right):
    """
    合并两个有序数组,返回一个新的有序数组
    """
    result = []
    i = 0
    j = 0
    # 比较两个数组的元素,把小的元素添加到新数组中
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    # 如果左边数组还有剩余元素,添加到新数组
    while i < len(left):
        result.append(left[i])
        i += 1
    # 如果右边数组还有剩余元素,添加到新数组
    while j < len(right):
        result.append(right[j])
        j += 1
    return result

def merge_sort(arr):
    """
    归并排序
    """
    if len(arr) <= 1:
        return arr
    # 找到中间位置
    mid = len(arr) // 2
    # 递归排序左半部分
    left = merge_sort(arr[:mid])
    # 递归排序右半部分
    right = merge_sort(arr[mid:])
    # 合并两个子序列
    return merge(left, right)

# 测试
arr = [5, 2, 9, 1, 7, 6, 8, 3, 4]
print(merge_sort(arr))

这是一个用 python 实现归并排序算法的示例,算法的核心是 merge_sort 函数,它通过递归把整个序列分成两个子序列,对子序列进行排序,最后通过 merge 函数合并两个子序列。

其中 merge 函数是合并两个子序列的函数,它会按照升序的顺序合并两个子序列,返回一个新的有序数组, 合并的过程是比较两个数组的元素, 选择较小的元素添加到新数组中.

merge_sort 函数是主要的排序函数, 通过递归的方式把整个序列分成两个子序列, 分别对子序列进行排序,最后通过 merge 函数合并两个子序列.

最后在main里面进行测试, 调用 merge_sort 函数, 排序后的结果会输出.

这个算法的时间复杂度是O(n log n),空间复杂度是O(n),同样不是一个原地排序算法,需要额外的空间存储临时数组。在数据规模较大时,空间复杂度可能成为瓶颈.

归并排序是一种稳定排序算法,具有很高的稳定性,对于数据有要求的场景是一个很好的选择. 但是在数据规模较小时,由于空间复杂度较高,效率不如其他算法.

JAVA

import java.util.Arrays;

public class MergeSort {
    public static void merge(int[] arr, int left, int mid, int right) {
        // 计算两个子序列的长度
        int n1 = mid - left + 1;
        int n2 = right - mid;

        // 创建两个辅助数组
        int[] L = new int[n1];
        int[] R = new int[n2];

        // 拷贝数据到辅助数组
        for (int i = 0; i < n1; i++) {
            L[i] = arr[left + i];
        }
        for (int i = 0; i < n2; i++) {
            R[i] = arr[mid + 1 + i];
        }

        // 合并两个子序列
        int i = 0, j = 0, k = left;
        while (i < n1 && j < n2) {
            if (L[i] <= R[j]) {
                arr[k++] = L[i++];
            } else {
                arr[k++] = R[j++];
            }
        }

        // 拷贝剩余元素
        while (i < n1) {
            arr[k++] = L[i++];
        }
        while (j < n2) {
            arr[k++] = R[j++];
        }
    }

    public static void mergeSort(int[] arr, int left, int right) {
        if (left < right) {
            // 找到中间位置
            int mid = (left + right) / 2;

            // 递归排序左半部分
            mergeSort(arr, left, mid);

            // 递归排序右半部分
            mergeSort(arr, mid + 1, right);

            // 合并两个子序列
            merge(arr, left, mid, right);
        }
    }

    public static void main(String[] args) {
        int[] arr = {5, 2, 9, 1, 7, 6, 8, 3, 4};
        mergeSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }
}

这是一个用 java 实现归并排序算法的示例,算法的核心是 mergeSort 函数,它通过递归把整个序列分成两个子序列,对子序列进行排序,最后通过 merge 函数合并两个子序列。

其中 merge 函数是合并两个子序列的函数,它会按照升序的顺序合并两个子序列.首先会计算出两个子序列的长度,然后创建两个辅助数组,将数据拷贝到辅助数组中,之后进行合并,合并时是按照从小到大的顺序进行比较,选择较小的元素放到新数组中,并且记录下标.

合并完成之后,如果有剩余的元素,就把它们拷贝到新数组中.

mergeSort 函数是主要的排序函数, 通过递归的方式把整个序列分成两个子序列, 分别对子序列进行排序,最后通过 merge 函数合并两个子序列.

最后在main里面进行测试, 调用 mergeSort 函数, 排序后的结果会输出.

这个算法的时间复杂度是O(n log n),空间复杂度是O(n),同样不是一个原地排序算法,需要额外的空间存储临时数组。

适用场景

归并排序是一种稳定的排序算法,它可以用来对数据进行排序,也可以用来合并两个有序的数组。

适用场景:

  • 对大数据量进行排序,归并排序是稳定的算法,时间复杂度为 O(n log n),可以处理大数据量。

  • 对需要稳定排序的场景,归并排序保证相同元素在排序前后相对位置不变,是稳定的排序算法。

解决具体问题:

  • 对某个大数据库进行排序,归并排序能够保证排序结果是正确的,而且可以在大数据量的情况下进行排序。

  • 对某个大文件进行排序,使用归并排序可以分成多个小文件进行排序,最后合并成有序的文件。

  • 对两个有序的数组进行合并,归并排序可以通过排序的方式实现两个有序数组的合并。

例子:

  • 对一个学生成绩数据库进行排序,使用归并排序可以按照学生的成绩从大到小进行排序。

  • 对于一个文件系统,使用归并排序可以对文件进行按名称的排序,让文件名称有序排列,方便查找和管理。

  • 对两个已知为有序的数组A和B,归并排序可以通过比较两个数组的元素,将其合并成一个有序的数组C.

总的来说,归并排序是一种非常通用的算法,在很多场景下都可以使用,特别是对于大数据量和需要稳定排序的场景下都是非常好的选择.

正面例子

假设你有一个电商平台,需要对用户的订单数据进行排序。由于数据量非常大,超过了千万条订单,不能使用冒泡排序或者插入排序。你可以使用归并排序来解决这个问题。

你可以把这些订单按照时间戳分成若干个小的文件,对每一个文件使用归并排序算法进行排序。然后再把这些有序的文件合并起来,就能得到一个有序的订单列表。这样就能按照时间戳顺序排列所有订单。

由于归并排序是稳定排序算法,所以如果有多个订单的时间戳相同,它们的相对顺序不会改变。这样就能保证用户下单的先后顺序。

这样的实现方法不仅保证了排序的正确性,而且还能利用分治思想,把大量数据分成小块进行排序,减少内存和时间的消耗。这样就能在可接受的时间内对所有订单进行排序。

另外,由于归并排序是稳定算法,所以能保证相同时间戳的订单的相对顺序不变,这样更加符合实际的需求.

总的来说,这个例子说明了归并排序在大数据量的情况下的优秀表现,同时也说明了归并排序在稳定性上的优秀表现。

反面例子

假设你需要对一个很小的数组进行排序,比如只有5个元素。使用归并排序可能会带来额外的时间和空间的浪费,因为归并排序的时间复杂度是O(n log n),空间复杂度是O(n),而对于这么小的数组其实可以使用更简单的排序算法,如插入排序,冒泡排序等。

另外,归并排序不是一个原地排序算法,需要额外的空间存储临时数组,对于空间有限的系统来说,这可能是一个问题.

总的来说,对于小数据量的排序,归并排序可能并不是最优秀的选择,因为它带来了额外的时间和空间的浪费.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

面试时这样介绍算法,想不高薪都难,排序算法(归并排序) 的相关文章

随机推荐

  • 51单片机使用定时器0定时1ms的配置操作

    51单片机使用定时器0定时1ms的配置操作 51单片机的定时器0结构 配置的定时器0的方式 配置的程序代码内容 51单片机的定时器0结构 51单片机是一种广泛应用于嵌入式系统中的芯片 具有强大的计时和计数功能 其中的定时器0可以用来实现精确
  • 嘴说手画Spark的Bykey操作-groupByKey、reduceByKey、aggregateByKey 和 sortByKey

    之前写过一篇文章分析Spark Shuffle的原理 知道了Shuffle是性能杀手的原因 但在实际业务中 Shuffle操作通常不可避免 毕竟Spark基础的用途就是对大数据进行统计分析 由于数据分布的分散性 导致相同Key的数据汇集到一
  • 只能看到部分局域网计算机,为什么局域网中只能看到部分电脑

    局域网中只能看到部分电脑的原因 那是因为其他电脑没有开启共享模式 也就是来宾账号关闭了 需要在用户组中打开才行 局域网共享设置步骤如下 1 更改不同的计算机名 设置相同的工作组 2 我的电脑右键 管理 计算机管理 本地用户和组 用户 更改管
  • 计算机基础 英语名称,计算机英语词汇:计算机基础知识

    computer n 电脑 电子计算机 arithmetic logic unit 算术逻辑部件 manipulate vt 操纵 操作 keyboard n 键盘 information n 消息 知识 printer n 打印机 han
  • Log.d 日志调试查看(所有平台)

    https www cnblogs com onechen p 6436748 html http docwiki embarcadero com Libraries Berlin en FMX Types Log d 转载于 https
  • 如何去除数据库中重复的数据

    去除数据库中重复的数据 准备工作 方法一 用distinct 联合去重 方法二 使用窗口函数限制row number 1 方法三 使用窗口函数删除row number gt 1 方法四 group by去重 准备工作 原始表users CR
  • vs调试时报错:变量已被优化掉,因而不可用

    前言 使用vs运行程序时 发现不是每次运行的结果都一致 抛开多线程的因素 比方说我用openGL加载骨骼动画数据 有时候能加载出骨骼纹理 有时候就不行 很头疼 在调试问题的时候就遇见vs调试器报错 变量已被优化掉 因而不可用 解决 在vs顶
  • USB Audio&hid 混合设备的描述符详解

    USB Standard Device Descriptor ALIGN BEGIN uint8 t USBD HS DeviceDesc USB LEN DEV DESC ALIGN END 0x12 bLength USB DESC T
  • OpenCV中的姿势估计及3D效果(3D坐标轴,3D立方体)绘制

    OpenCV中的姿势估计及3D效果 3D坐标轴 3D立方体 绘制 1 效果图 2 原理 3 源码 3 1 姿态估计后绘制3D坐标轴 3 2 姿态估计后绘制立方体 参考 这篇博客将延续上一篇博客 OpenCV中的相机失真 内外参 不失真图像
  • 【泛微E9】JS限制明细表文本框包含特殊文字

  • 使用IDEA工具不能自动导包的处理方法

    使用IDEA工具不能自动导包的处理方法 当我们在使用idea的时候 有时候会出现它不自动导包的情况 这是因为你没有选中自动导包的按钮 那怎么选择呢 首先点击File选项中Settings 如图 之后在搜索框中搜索Maven 再选中Impor
  • 未来刷脸支付设备圈地运动将会加剧

    未来刷脸支付设备的圈地运动将会加剧 而支付宝方面数据显示 自从去年支付宝宣布刷脸支付大规模商业化后 与刷脸支付相关的上下游产业链 催生的研发 生产 安装调试人员就已经达到50万人 刷脸支付项目合作推广更是成为市场热门 抓住移动支付发展的浪潮
  • 【FFmpeg】多媒体文件处理

    1 ffmpeg的日志打印 include
  • Rancher 集群安装

    一 Rancher 是什么 Rancher 是一个 Kubernetes 管理工具 用于在任何地方和任何提供商上部署和运行集群 Rancher 可以从托管提供商调配 Kubernetes 调配计算节点 然后将 Kubernetes 安装到这
  • TCP应用层协议

    TCP IP是个协议组 可分为三个层次 网络层 传输层和应用层 在网络层有IP协议 ICMP协议 ARP协议 RARP协议和BOOTP协议 在传输层中有TCP协议与UDP协议 在应用层有FTP HTTP TELNET SMTP DNS等协议
  • 准备刺第一针了(飞秋官方下载)

    WZSZF飞鸽 2013年10月26日 它还有一双花椒粒一样大小的眼睛 它还会丰富多腔地叫唤 叫起来婉转动听 毛大爹 原来我们不能离开眼镜啊 第二天 呜的一声 简直不相信自己的耳朵 放生青蛙今天外公外婆叔叔阿姨们要来我家吃饭 我终于撑到最后
  • Z-Statk协调器 路由器 终端的确定---Simple例程(一)

    Z Statk协调器 路由器 终端的确定 Simple例程 一 2010 12 24 09 42 10 分类 嵌入式 当我们选择了终端 路由器 或者协调器的时候 来看一下程序中是怎么判断的 也就是如何作为其中的各个角色进行启动 是加入网络
  • 使用内网负载机(Linux)执行Jmeter性能测试

    一 背景 在我们工作中有时候会需要使用客户提供的内网负载机进行性能测试 一般在什么情况下我们需要要求客户提供内网负载机进行性能测试呢 遇到公网环境下性能测试达到了带宽瓶颈 那么这时 我们就需要考虑在内网环境负载机下来执行我们的性能测试以达到
  • 给button设置背景图片不显示解决了

    以前给按钮设置背景图片但是图片不显示 一直没有解决 网上也找不到正确的方法 今天终于被我解决了 其实就把button的背景颜色改改就OK了
  • 面试时这样介绍算法,想不高薪都难,排序算法(归并排序)

    算法背景 归并排序 Merge sort 是一种排序算法 它的目的是将一个无序的数组变成有序的 它采用分治法 将原数组不断地分成若干个小数组 直到每个小数组只有一个元素 然后把这些小数组按照顺序合并起来 最终得到一个有序的数组 归并排序需要