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

一,概念及其介绍

归并排序(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 arrmid = len(arr) // 2left_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 = 0right_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 += 1else: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://xiahunao.cn/news/3281759.html

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

相关文章

下载安装docker并解决拉去镜像的connect:connection refused问题(2024.7.31亲测有效)

原文链接&#xff1a;使用国内链接安装最新docker 最近dockerhub已经不能访问了&#xff0c;使用原先的方式安装docker&#xff0c;服务器上也总是连接不上&#xff0c;所以找了种可以在国内正常安装新版docker的方式 适用系统&#xff1a;centos7 先删除本机旧的或者残留的…

书生大模型实战营闯关 - 8GB显存玩转书生大模型demo

创建开发机 创建一个使用10%GPU算力&#xff0c;cuda12.2系统的开发机&#xff0c;并启动。由于开发机的IO性能较差&#xff0c;开发机共享盘中已经创建好了本次实验所需要的conda环境 # 启动共享的conda环境 conda activate /root/share/pre_envs/icamp3_demo部署cli模型 创…

Python安装与环境配置,2024最新,超详细保姆级教程!

安装Python 来到Python官网&#xff1a;https://www.python.org/ Downloads>Windows&#xff1a; 选择想要的版本后点击进去&#xff1a; 下载后点击安装&#xff1a; 在本地电脑输入命令提示符&#xff1a;winR 环境变量配置 若执行命令提示符&#xff0c;输入Python后&…

网工必装软件,SecureCRT从零到精通,不可错过

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 中午好&#xff0c;我的网工朋友。 相信在平时的日常工作中&#xff0c;大家经常需要通过安全的方式远程访问各种设备和服务。SecureCRT作为一款强…

SSM大学生体质管理系统-计算机毕业设计源码75960

摘要 基于SSM的大学生体质管理系统是一款综合性平台&#xff0c;融合了在线课程、健康知识、体测报告等多项功能&#xff0c;旨在为广大大学生提供全方位的健康管理服务。通过在线课程和健康知识模块&#xff0c;用户可以随时学习健康知识&#xff0c;掌握科学的健康管理方法&a…

前端面试宝典【设计模式】【1】

欢迎来到《前端面试宝典》,这里是你通往互联网大厂的专属通道,专为渴望在前端领域大放异彩的你量身定制。通过本专栏的学习,无论是一线大厂还是初创企业的面试,都能自信满满地展现你的实力。 核心特色: 独家实战案例:每一期专栏都将深入剖析真实的前端面试案例,从基础知…

C语言典型例题19

《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 例题2.7 检查浮点型数据的舍去误差 C语言知识&#xff1a; 浮点数在C语言用有两个类型&#xff0c;有float和double类型&#xff0c;其中double类型的数据精度更高 解题思路&#xff1a; 可以将一个double类型的…

根据需求修改el-tab的默认样式

根据需求修改el-tab的默认样式 样式代码&#xff1a; <style lang"scss" scoped>//去掉了最下面的那条线:deep(.el-tabs--card > .el-tabs__header){border-bottom: none}//单独给每一项添加下边框、修改背景色:deep(.el-tabs--card > .el-tabs__heade…

【Golang 面试 - 基础题】每日 5 题(九)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏…

redis集群(高可用)

redis集群&#xff08;高可用&#xff09; redis集群的三种模式 主从复制 奇数 3台 1主2从 哨兵模式 3台 1主2从 cluster 集群 6台 生产中&#xff1a;333 9台 主从复制&#xff1a; 和MySQL的主从复制类似&#xff0c;主可以写&#xff0c;写入主的数据通过RDB方式把数据…

ft232 win10驱动

ft232 win10驱动 https://ftdichip.com/drivers/d2xx-drivers/

Qt for MCUs 2.8 LTS已发布

本文翻译自&#xff1a;Qt for MCUs 2.8 LTS released 原文作者&#xff1a;Qt Group高级产品经理Yoann Lopes 我们很高兴地宣布Qt for MCUs 2.8 LTS版本已发布&#xff0c;该版本带来了激动人心的新变化&#xff0c;如GUI的构建模块、构建工具工作流程的改进、对Infineon TRA…

excel如何绘制多列数据的折线图

1.注意表中的数据必须是数据类型的&#xff0c;不能是字符串格式的。如果是用python生成的&#xff0c;需要填充int或者float型的数据。 2.选择数据&#xff08;多列数据的选择&#xff0c;可以按住ctrl键后选中多列&#xff09; 2. 选择插入 3.选择 推荐的图表->所有图表…

PostgreSQL——查询扫描介绍

顺序扫描 概述 顺序扫描&#xff08;Sequential Scan&#xff09;是PostgreSQL中一种基本的数据检索方式&#xff0c;它通过按顺序读取表中的所有页面来查找满足查询条件的记录。这种方式不依赖于索引&#xff0c;因此在某些情况下可能是唯一的选择&#xff0c;尤其是当表没有…

QT:控件圆角设置、固定窗口大小

实现控件圆角度设置//使用的是setStyleSheet方法 //改变的控件是QTextEdit&#xff0c;如果你想改变其他控件&#xff0c;将QTextEdit进行更换 this->setStyleSheet("QTextEdit{background-color:#FFFFFF;border-top-left-radius:15px;border-top-right-radius:15px;bo…

农合生活平台更新升级啦!了解详情戳这里

7月24日&#xff0c;农合生活平台完成了新一轮的版本更新。新版本上线后&#xff0c;农元NYT购买数量将不做限制&#xff0c;优惠券更易得&#xff0c;购物更划算&#xff0c;农元价值升值将进一步「加速度」。 更新说明 1. 数量&#xff1a;旧版本中农元只能定额定量购买&…

Vmware ubuntu22.04 虚拟机 连接windows主机虚拟串口

1.虚拟机配置 鼠标右键点击这个图标&#xff0c;在弹出的菜单里有“连接”或者的“断开连接”的选项&#xff0c;单击即可完成相应的操作。串口连接后图标下侧会出现一个小绿点&#xff0c;断开时没有小绿点。鼠标移动到这个图标上&#xff0c;会显示“串行端口&#xff1a;正在…

找到/打开pupprteer对应chrome版本

前期提要&#xff1a;导出pdf的时候&#xff0c;会用pupprteer启动一个浏览器实例&#xff0c;再打开指定页面进行打印&#xff0c;页面写成什么样&#xff0c;导出的pdf内容就是什么样&#xff0c;听起来很正常。 但是遇到了调试的时候页面显示很正常&#xff0c;而导出的内容…

PostgreSQL——tsearch全文搜索

背景 全文搜索&#xff08;文本搜索&#xff09;提供了一种可以检索出满足某个查询条件的自然语言文档的能力&#xff0c;并且还可以根据文档的相关性对文档进行排序。最常见的搜索是找出所有包含给出的查询词的文档&#xff0c;并且以它们符合查询的程度排序输出。 文本搜索…