当前位置: 首页 > article >正文

归并排序【C语言版-笔记】

目录

  • 一、概念
  • 二、排序流程理解
  • 三、代码实现
    • 3.1主调函数
    • 3.2 merge函数
  • 四、性能分析

一、概念

归并是一种算法思想,是将两个或两个一上的有序表合并成一个长度较大的有序表。若一开始无序表中有n个元素,可以把n个元素看作n个有序表,把它们两两合并得到 ⌈ n / 2 ⌉ 个 \lceil n/2\rceil个 n/2长度为2或1(n为奇数时)的有序表,继续重复两两合并的操作,直到剩下一个有序表,即得到最终排序的结构,这是“二路归并排序”,还有多路的归并。

二、排序流程理解

给定一个序列如下:
在这里插入图片描述

1)不断地将当前序列平均分割成2个子序列,直到不能再分割(序列中只剩1个元素)
2)不断地将2个子序列合并成一个有序序列,直到最终只剩下1个有序序列
在这里插入图片描述
要点分析:
① 处理好边界和有序表分割位置选择问题
② 合并两个子序列的过程中,如何排序使合并后的序列是一个有序序列,称之为:merge

1、有序表分割的位置(排序使用到的参数:begin,mid,end)
初始时:
begin=0,mid=(begin+end)/2,end=length
规定:
左边表范围:[begin,mid)
右边表范围:[mid,end)
当无序表元素个数为偶数时,划分的左右子表元素个数相同,
当无序表元素个数为奇数时,划分的左右子表元素个数相差1,右子表多个一
不管奇偶情况如何,左子表元素个数为:mid-begin,右子表元素个数为:end-mid

2、merge过程中我们使用一个辅助数组leftArray,把位于[begin,end)
  范围的表中左边部分[begin,mid)之间的元素拷贝到leftArray中,用
  leftArray表中元素和右边部分元素依次比较,小的放入原表(即:[begin,end) )中的左边部分,
  直到leftArray或右边部分的元素比较完,然后把剩余的没比较的直接拷贝到原表中即可,一次merge完成。

在这里插入图片描述

◼ li == 0,le == mid – begin
◼ ri == mid,re == end

三、代码实现

3.1主调函数

void sort(int *nums,int begin,int end){
	if(end-begin<=1) return;//只有一个元素不用排序
	int mid=(begin+end)/2;//或(begin+end)>>1
	sort(nums,begin,mid);
	sort(nums,mid.begin);
	merge(nums,begin,mid,end);
}

3.2 merge函数

void merge(int *nums,int begin,int mid,int end){
	int li=0;
	int le=mid-begin;
	int ri=mid;
	int re=end;
	int ai=begin;
	int leftArray=(int*)malloc(le*sizeof(int));//辅助数组
	//初始化辅助数组
	for(int i=li;i<le;i++){
		leftArray[i]=nums[begin+i];//begin~end之间左边部分拷贝到夫leftArray
	}
	//在原存储空间上给两个有序子表重新排序(逻辑上是合并为一个有序表),两种可能:左边指针先走完(ri>=re)或右边指针先走完。
	//若左边先走完则直接把leftArray中li指针指向的及之后的元素复制到原存储空间(nums);若右边先走完,则结束
	while(li<le){
		if(ri<re&&nums[ri]<leftArray[li]){
			nums[ai++]=nums[ri++];//拷贝左边部分的元素到nums[ai]
		}else{
			nums[ai++]=leftArray[li++];//拷贝右边部分的元素到nums[ai]
		}
	}
}

四、性能分析

空间效率: merge函数中使用的辅助空间是n/2个单元,即算法的空间复杂度:O(n)
时间效率: 每趟归并的时间复杂度是O(n),总共需要进行 ⌈ l o g 2 n ⌉ \lceil log_2n\rceil log2n趟归并,总的时间复杂度:O(nlog2n)
稳定性: 不会改变相同关键字记录的相对次序(看merge函数中while循环的处理部分可知),因此二路归并排序是稳定的排序算法


http://www.kler.cn/news/328069.html

相关文章:

  • Unreal 实现建造游戏|地面交互shader
  • 06.C/C++内存管理
  • 【数据库】MongoDB 用户权限与数据之间的关系详解
  • Android studio配置AVD虚拟机
  • 【60天备战2024年11月软考高级系统架构设计师——第33天:云计算与大数据架构——大数据处理框架的应用场景】
  • 关于Java中的List<User>如何进行深拷贝
  • 贝锐蒲公英工业物联方案:助力美的智慧楼宇全球布局
  • Leetcode 611. 有效三角形的个数
  • 前端面试题(八)
  • 音视频入门基础:FLV专题(7)——Tag header简介
  • 【STM32单片机_(HAL库)】4-1【定时器TIM】定时器中断点灯实验
  • 【漏洞复现】JeecgBoot 积木报表 queryFieldBySql sql注入漏洞
  • 【进阶OpenCV】 (2)--Harris角点检测
  • 衡水中学资料大全-重构版(状元、学霸笔记)
  • .NET MAUI(.NET Multi-platform App UI)下拉选框控件
  • UE5: Content browser工具编写02
  • 【抽代复习笔记】29-群(二十三):生成子群的两道例题及子群陪集的定义
  • hdlbits系列verilog解答(Exams/m2014 q3)-77
  • 【qt】QQ仿真项目1
  • 【洛谷】P4551 最长异或路径 的题解
  • 自然语言处理的应用领域有哪些?
  • 【漏洞复现】孚盟云oa AjaxSendDingdingMessage接口 存在sql注入漏洞
  • 云计算 Cloud Computing
  • 前端——DOM与BOM总结
  • macOS开发环境配置与应用
  • vant 数据校验
  • 华为OD机试 - 最长回文字符串 - 贪心算法(Python/JS/C/C++ 2024 E卷 100分)
  • ZYNQ: GPIO 之 MIO 控制 LED 实验
  • Qt(9.28)
  • 深入理解 `strtok()` 函数:字符串分割的艺术