归并排序 python C C++ 图解 代码 及解析

news2024/9/24 11:30:09

一,概念及其介绍

归并排序(Merge sort)是建立在归并操作上的一种有效、稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;若将两个有序表合并成一个有序表,称为二路归并

二,复杂度说明

时间复杂度: O(nlogn)

对于自顶向下的归并排序, 归并排序通过不断将数组对半划分,直到每个子数组只有一个元素(这需要 logn次划分)。然后,合并这些子数组的过程中,每个元素都需要被处理一次,总共需要处理 n个元素。所以总的操作次数约为 nlog n ,因此时间复杂度为 O(nlog n)

空间复杂度:  O(n)

空间复杂度为 O(n) 是因为在合并子数组的过程中,需要额外创建一个与原数组大小相同的辅助数组来存放合并后的结果。所以空间复杂度主要取决于这个辅助数组的大小,即为 O(n)。

三,过程图示

归并排序是递归算法的一个实例,这个算法中基本的操作是合并两个已排序的数组,取两个输入数组 A 和 B,一个输出数组 C,以及三个计数器 i、j、k,它们初始位置置于对应数组的开始端。

A[i] 和 B[j] 中较小者拷贝到 C 中的下一个位置,相关计数器向前推进一步。

当两个输入数组有一个用完时候,则将另外一个数组中剩余部分拷贝到 C 中

四.代码及解析

4.1 python 

思路:

使用两个函数完成,一个函数用于连接两个有序列表,返回一个有序的新列表,一个函数用于递归将已知列表分为左右两部分,递归分割,再进行连接,当列表中只有一个元素时则一定是有序的

知识点:

1.列表的append用于向列表添加一个元素

2.列表的extend用于向列表添加一个可迭代对象

# merge_sort的主要作用是通过递归地将输入的数组不断地分割成更小的子数组,
# 直到子数组的长度为 1 (此时子数组本身就是有序的),然后调用 merge 函数将这些有序的子数组合并起来,
# 最终实现对整个数组的排序
def merge_sort(arr):
    if len(arr) <= 1:
        return arr
    mid = len(arr) // 2
    left_half = merge_sort(arr[:mid])
    right_half = merge_sort(arr[mid:])
    return merge(left_half, right_half)

# arr = [12, 11, 13, 5, 6]
# merge函数用于连接两个有序数列。并存放到新数列中
def merge(left, right):
    merged = []
    left_index = 0
    right_index = 0
    # 两两对比,小的放入新列表,所在列表的下标指向往后移动,大的所在列表下标指向不变
    while left_index < len(left) and right_index < len(right):
        if left[left_index] < right[right_index]:
            merged.append(left[left_index])
            left_index += 1
        else:
            merged.append(right[right_index])
            right_index += 1
    # 利用切片将剩下的元素放到新列表中
    merged.extend(left[left_index:])
    merged.extend(right[right_index:])
    return merged

# 测试示例
arr = [12, 11, 13, 5, 6]
sorted_arr = merge_sort(arr)
print("排序后的数组:", sorted_arr)
排序后的数组: [5, 6, 11, 12, 13]

4.2 C

思路:

使用两个函数,一个函数用于递归将数组左右两部分割开,再递归分割,直到分割到只有一个元素时一定是有序的,再进行两个有序数组的连接,这里再定义另一个函数作用是连接两个有序数组

注意点:

1.直接传入数组进行操作,所以两个函数都不需要返回值

2.merge函数利用两个新的数组,分别存放左右两边的原数组,再进行比较,依次放入原数组

3.int m = l + (r - l) / 2; 这个表达式中使用 r - l 是为了计算数组区间 [l, r] 的长度。

通过 (r - l) 得到区间的长度后再除以 2,就能得到区间长度的一半。然后加上起始索引 l ,就可以得到区间的中间位置 m ,从而将数组划分为左右两个子区间 [l, m] 和 [m + 1, r] ,以便进行归并排序的递归操作

#include <stdio.h>

// 合并两个已排序的子数组为一个排序数组
void merge(int arr[], int l, int m, int r) {
    int n1 = m - l + 1; // 左边子数组的大小
    int n2 = r - m;     // 右边子数组的大小

    // 创建临时数组
    int L[n1], R[n2];

    // 复制数据到临时数组
    for (int i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (int j = 0; j < n2; j++)
        R[j] = arr[m + 1 + j];

    int i = 0, j = 0, k = l;

    // 合并临时数组回到原始数组
    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 l, int r) {
    if (l < r) {
        int m = l + (r - l) / 2; // 取中间元素作为分割点

        // 对左边的子数组进行排序
        mergeSort(arr, l, m);

        // 对右边的子数组进行排序
        mergeSort(arr, m + 1, r);

        // 合并两个已排序的子数组
        merge(arr, l, m, r);
    }
}

// 打印数组函数
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++)
        printf("%d ", arr[i]);
    printf("\n");
}

// 测试案例
int main() {
    int arr[] = {12, 11, 13, 5, 6};
    int arr_size = sizeof(arr) / sizeof(arr[0]);

    printf("before sort: \n");
    printArray(arr, arr_size);

    mergeSort(arr, 0, arr_size - 1);

    printf("after sort: \n");
    printArray(arr, arr_size);

    return 0;
}
before sort:
12 11 13 5 6
after sort:
5 6 11 12 13

4.3 C++

与C语言思路一致,只有一些语法上的小差别

#include <iostream>

// 合并两个已排序的子数组为一个排序数组
void merge(int arr[], int l, int m, int r) {
    int n1 = m - l + 1;
    int n2 = r - m;

    int L[n1], R[n2];

    for (int i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (int j = 0; j < n2; j++)
        R[j] = arr[m + 1 + j];

    int i = 0, j = 0, k = l;

    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 l, int r) {
    if (l < r) {
        int m = l + (r - l) / 2;
        mergeSort(arr, l, m);
        mergeSort(arr, m + 1, r);
        merge(arr, l, m, r);
    }
}

// 打印数组函数
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++)
        std::cout << arr[i] << " ";
    std::cout << std::endl;
}

// 测试案例
int main() {
    int arr[] = {12, 11, 13, 5, 6};
    int arr_size = sizeof(arr) / sizeof(arr[0]);

    std::cout << "排序前的数组为: ";
    printArray(arr, arr_size);

    mergeSort(arr, 0, arr_size - 1);

    std::cout << "排序后的数组为: ";
    printArray(arr, arr_size);

    return 0;
}
排序前的数组为: 12 11 13 5 6 
排序后的数组为: 5 6 11 12 13 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1963929.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大厂linux面试题攻略三之Shell编程

一、Shell编程文本截取类 1.有一个b.txt文本(内容如下)&#xff0c;要求将所有域名截取出来&#xff0c;并统计重复域名出现的次数 http://www.baidu.com/index.html https://www.atguigu. com/index.html http://www.sina.com.cn/1024.html …

二百四十八、Linux——删除/etc/.sudoers文件进程或修改/etc/.sudoers文件内容

一、目的 安装国产化数据库OceanBase的时候&#xff0c;需要创建用户&#xff0c;并在/etc/.sudoers文件中赋予用户root权限 二、删除/etc/.sudoers文件进程 1 报错 W10: Warning: Changing a readonly file E325: ATTENTION Found a swap file by the name "/etc/.su…

二叉树的性质证明

文章目录 二叉树的概念二叉树的性质1. 若规定根结点的层数为1&#xff0c;则一棵非空二叉树的第i层上最多有 2 i − 1 2^{i-1} 2i−1 个结点.2. 若规定根结点的层数为1&#xff0c;则深度为h的二叉树的最大结点数是 2 h − 1 2^h-1 2h−1.3. 对任何一棵二叉树, 如果度为0其叶结…

C++:函数模板与类模板详解

1.函数模板 在构造函数的时候&#xff0c;我们常常会考虑传入的参数的数据类型&#xff0c;比如我们写一个大小比较的函数mycmp(class1 a,class1 b)&#xff0c;则可以写出class1为int,float,double,string等各个种类的mycmp函数&#xff0c;这样会很麻烦&#xff0c;且当我们…

hot100-7-链表1

160相交链表 206反转链表 234回文链表 可以反转后半部分链表或者反转全部链表&#xff0c;然后对比输出 141环形链表 142环形链表2

大模型RAG入门及实践

前言 在大语言模型&#xff08;LLM&#xff09;飞速发展的今天&#xff0c;LLMs 正不断地充实和改进我们周边的各种工具和应用。如果说现在基于 LLM 最火热的应用技术是什么&#xff0c;检索增强生成&#xff08;RAG&#xff0c;Retrieval Augmented Generation&#xff09;技…

【JVM】JVM的组成与执行流程

JVM 由哪些部分组成&#xff0c;运行流程是什么&#xff1f; JVM 是什么 Java Virtual Machine Java程序的运行环境&#xff08;java二进制字节码的运行环境&#xff09; 好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收机制 JVM的组成 我…

redis集群 高可用

目录 主从复制 主从复制的流程 部署主从复制 步骤 哨兵模式 数据流向 步骤 故障恢复 cluster集群 数据流向 步骤 redis集群的三种模式&#xff1a; 主从复制 奇数台 1主2从 哨兵模式 奇数台 1主2从 cluster 集群 6 台 主从复制 原理&#xff1a;主可以…

(四)延时任务篇——redisson实现延迟任务实战

前言 上一节内容中介绍了如何使用redis的zset结构实现延迟任务的实战内容&#xff0c;从使用角度来说还是略显繁琐&#xff0c;而且定时任务的方式扫描redis获取过去的任务也会存在任务空转的问题。在此基础上&#xff0c;我们可以使用redisson的阻塞队列&#xff0c;完成延迟…

探索 Python 的新世界:funcy 库的神奇之旅

文章目录 探索 Python 的新世界&#xff1a;funcy 库的神奇之旅背景&#xff1a;为何 funcy 如此迷人&#xff1f;简介&#xff1a;funcy 库是什么&#xff1f;安装&#xff1a;如何将 funcy 纳入你的项目&#xff1f;功能&#xff1a;funcy 的五大法宝应用&#xff1a;funcy 在…

图方法与机器学习实战:从理论到应用的全景指南

《动手学图机器学习》并不是一本纯粹介绍图机器学习理论的著作&#xff0c;Alessandro Negro 博士作为科学家和 Reco4 公司的 CEO&#xff0c;长期维护图数据源的推荐系统。他结合机器学习工程和图机器学习方法&#xff0c;通过推荐引擎、欺诈检测和知识图谱等案例&#xff0c;…

一键式RWKV RAG、RWKV-Keras、新论文...RWKV社区7月动态速览!

大家好&#xff0c;《RWKV 社区最新动态》迎来了第三期内容&#xff0c;本期统计了 RWKV 社区 7 月的重要动态&#xff0c;一起来看看吧&#xff01; 省流版本&#xff1a; RWKV 官方公告 RWKV-6-World 14B 模型已发布RWKV 中文官网 rwkv.cn 正式上线 RWKV 社区新项目 RWKV R…

LeetCode删除链表的倒数第 N 个结点

给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 示例 3&#x…

C++进阶(12)智能指针

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;C 一、概述 智能指针在构造的时候开辟空间&#xff0c;当智能指针生命周期结束则会自动调用析构函数释放空间。 解决问题&#xff1a;对于new开辟的时候出现异常&#xff0c;导致之前开辟的空间没有手动释放…

VMware虚拟机安装Windows7教程(超详细)

目录 1. 下载2. 安装 VMware3. 安装 Window73.1 新建虚拟机3.2 安装操作系统 4. 设置共享文件夹5. 安装 VMware Tools5.1 下载&安装缺少驱动5.2 开始安装 VMware Tools 6. 未&#x1f414;&#x1f525;解决 创作不易&#xff0c;禁止转载抄袭&#xff01;&#xff01;&…

MyBatis代码生成器:SpringBoot 引入MybatisGenerator

1. 引入插件 <plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.5</version><configuration><!--generator配置⽂件所在位置--><configurati…

7.5 grafana上导入模板看图并讲解告警

本节重点介绍 : blackbox_exporter grafana大盘导入和查看告警配置讲解 grafana大盘 grafana 上导入 blackbox_exporter dashboard 地址 https://grafana.com/grafana/dashboards/13659举例图片http总览图value_mapping设置 展示设置阈值&#xff0c;展示不同背景色 告警配…

过滤和筛选树形结构数据

场景 在平时项目开发中经常会遇到树形数据的处理&#xff0c;如树形数据根据条件值过滤掉不符合条件的选项&#xff0c;如果是最后的子数据符合条件那么就会保存这条树形链路的所有直属数据并过滤掉所有非直属的数据。如果是符合条件的数据还有子元素&#xff0c;那么就保留所…

算法强训day18

一、压缩字符串 链接&#xff1a;压缩字符串(一)_牛客题霸_牛客网 #include<iostream> using namespace std; #include<vector> class Solution { public:/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可***…

mac电脑不能快速传输文件的原因是什么 mac无法拷贝文件到移动硬盘的原因是什么 macbook传输速度慢

新买的移动硬盘连接上Mac电脑&#xff0c;想要将Mac上的文件拷贝到移动硬盘里&#xff0c;但是Mac无法拷贝文件到移动硬盘里&#xff0c;直接拖拽、剪切都不行&#xff0c;尤其是一些大的安装包或视频文件的拷贝&#xff0c;需要花费大量的时间&#xff0c;给Mac用户造成了很多…