算法 - 归并排序(Merge_sort)

这篇具有很好参考价值的文章主要介绍了算法 - 归并排序(Merge_sort)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

什么是归并排序(Merging_sort)?

归并排序的适用场景:

演示归并排序的过程(默认arr和brr两个数组都是有序的):

代码实现:

如果我们事先并没有分配好两个已经排序好的数组,而是直接的一个无序序列呢?

代码实现:


什么是归并排序(Merging_sort)?

在写归并排序的代码之前,我们先对归并排序的定义和排序原理进行梳理。

在严蔚敏的《数据结构(C语言版)》一书中对归并排序是这样定义的:

归并排序(Merging_Sort)是一类不同的排序方法。“归并”的含义是将两个或者两个以上的有序表组合成一个新的有序表。利用归并的思想容易实现排序,且这种实现方法已为读者熟悉,无论是顺序存储结构还是链表存储结构,都可以在O(m+n)的时间量级上实现。归并排序也是一个与插入排序、交换排序、选择排序不同的一类排序方法。

归并排序是一个基于分治法思想的算法,拿两个已经有序的序列重新组合成一个有序的序列。

归并排序的适用场景:

归并排序适合链表排序但不适合数组排序,归并在外部排序,比如磁盘文件的情况下比快速排序好,因为快排比较依赖数据的随机存取,而归并是顺序存取,对磁盘这种外村比较友好,还有很重要的一点就是快速排序和对排序都是不稳定排序,归并排序是稳定排序。

演示归并排序的过程(默认arr和brr两个数组都是有序的):

例如我在这里给出两个数组:

int arr[] = {1,3,5,7};
int brr[] = {2,4,6,8};

我们定义两个指针i和j分别指向arr数组和brr数组,在定义一个临时值temp,通过遍历这两个数组,每一次的遍历我们都对i和j所指向的值进行比较,找到两个数中较小的值放入临时值temp中,并拷贝一份放入到新的数组中,直到排序完成:

归并排序,算法,数据结构,算法,c语言

当我们的i遍历至元素1,j遍历至元素2时,i是小于j的,于是我们将i所指向的元素赋值给temp并放入到新的数组中,令i指针向前迁移一位进行下一次i和j的比较:

归并排序,算法,数据结构,算法,c语言

此时继续i和j指向元素的比较,我们发现,元素2小于3,这时我们将元素2赋值给temp并放入新数组中,并令j指针的位置加1:

归并排序,算法,数据结构,算法,c语言

此时继续进行比较,我们发现3 < 4,现在将元素3赋值给temp,放入至新数组中,所对应i指针的位置向后迁移一位:

归并排序,算法,数据结构,算法,c语言

过程以此类推:

 比较4和5:归并排序,算法,数据结构,算法,c语言

比较5和6:

 归并排序,算法,数据结构,算法,c语言

比较6和7:

归并排序,算法,数据结构,算法,c语言

比较7和8:

归并排序,算法,数据结构,算法,c语言

最后我们直接将元素8放至新数组的末尾:

归并排序,算法,数据结构,算法,c语言

同样的,如果我们的第二个数组的后面又加上9和10,我们在第一个数组已经遍历完了的情况下,直接将9和10安插在新数组的后面。

代码实现:

#include<stdio.h>
#include<assert.h>
#include<iostream>
void showar(int *ar,int len)
{
	assert(ar != nullptr);
	for(int i = 0;i < len;i++){
		printf("%d ",ar[i]);
	}
	printf("\n--------------------------\n");
}
void Merging_sort1(int *ar,int len1,int *br,int len2,int *temp)
{
	assert(ar != nullptr && br != nullptr && temp != nullptr);
	assert(len1 >= 0 && len2 >= 0);
	int i = 0,j = 0,k = 0;
	while(i < len1 && j < len2){
		if(ar[i] < br[j]){
			temp[k] = ar[i];
			i++;
			k++;
		}
		else{
			temp[k] = br[j];
			j++;
			k++;
		}
	}
	while(i < len1){
		temp[k] = ar[i];
		i++;
		k++;
	}
	while(j < len2){
		temp[k] = br[j];
		j++;
		k++;
	}
}
int main()
{
    int ar[4] = {1,3,5,7};
	int br[4] = {2,4,6,8};
	int len1 = sizeof(ar) / sizeof(ar[0]);
	int len2 = sizeof(br) / sizeof(br[0]);
	int temp[8] = {0};
	Merging_sort1(ar,len1,br,len2,temp);
	showar(temp,8);
	return 0;
}

我们对排序的代码做一下简洁优化(三目运算符):

void Merging_sort1(int *ar,int len1,int *br,int len2,int *temp)
{
	assert(ar != nullptr && br != nullptr && temp != nullptr);
	assert(len1 >= 0 && len2 >= 0);
	int i = 0,j = 0,k = 0;
	while(i < len1 && j < len2){
		temp[k++] = ar[i] < br[j] ? ar[i++] : br[j++];
	}
	while(i < len1){
		temp[k++] = ar[i++];
	}
	while(j < len2){
		temp[k++] = br[j++];
	}
}

运行结果:

归并排序,算法,数据结构,算法,c语言

如果我们事先并没有分配好两个已经排序好的数组,而是直接的一个无序序列呢?

例如在这里我给出一个无序数组:

int arr[9] = {5,8,2,3,1,4,7,6};

归并排序的思想就是分治法,我们将数组中的8个数全部分成单一的数,把他们均看作是一个小数组:

归并排序,算法,数据结构,算法,c语言

现在形成了8个长度为1的数组 ,然后我们两两进行归并,并把相对较小的元素放在前面:

归并排序,算法,数据结构,算法,c语言

现在形成了4个长度为2的数组,我们继续进行两两归并:

这次我们对58和23进行归并,我们先放2再放3,然后依次放5和8,后面两个数组也是这样:

归并排序,算法,数据结构,算法,c语言

现在形成了两个长度为4的数组,继续对这两个数组进行归并:

归并排序,算法,数据结构,算法,c语言

代码实现:

#define MAXSIZE 11
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<iostream>
#include<time.h>
void initar(int *ar,int len)//初始化ar数组,用小于30的int类型数填充
{
	assert(ar != nullptr);
	for(int i = 0;i < len;i++){
		ar[i] = rand() % 30;
	}
}
void showar(int *ar,int len)//打印数组函数
{
	assert(ar != nullptr);
	for(int i = 0;i < len;i++){
		printf("%d ",ar[i]);
	}
	printf("\n--------------------------\n");
}
void merge(int *ar,int low,int middle,int high,int *temp)//归并排序
{
	int i = low;//通过I遍历左半边数组
	int j = middle + 1;//通过j遍历右半边数组
	int k = low;//通过k遍历整个数组
	while(i <= middle && j <= high){//循环通过I和j分别遍历从中间划分开来的两个数组,并分开比较大小
		temp[k++] = ar[i] < ar[j] ? ar[i++] : ar[j++];//如果前者小于后者就将前者直接添加至新数组的后面,依此类推
	}
	while(i <= middle)//如果比较完了,但左半边数组还有剩余的元素,直接将这些元素添加至新数组的后方
	temp[k++] = ar[i++];
	while(j <= high)//同理,比较完了右半边还有剩余的,也直接添加至新数组的后方
	temp[k++] = ar[j++];
	for(i = low;i <= high;i++){//最后将新数组的所有元素赋值给ar数组
		ar[i] = temp[i];
	}
}
void merge_sort(int *ar,int low,int high,int *temp)
{
	if(low >= high){//如果左边界大于右边界,直接返回
		return;
	}
	int middle = low + (high - low) / 2;//相比较(low + high)/ 2;的优化写法,可以防止越界
	merge_sort(ar,low,middle,temp);递归调用,左半部分循环归并
	merge_sort(ar,middle + 1,high,temp);//右半部分循环归并
	merge(ar,low,middle,high,temp);//递归操作
}
void mergesort(int *ar,int len)//最终归并函数
{
	int *temp = (int *)malloc(sizeof(int)*len);//向堆区申请len个int类型大小的空间赋给temp新数组
	assert(temp != nullptr);//断言新数组不为空
	merge_sort(ar,0,len - 1,temp);//递归归并操作
	free(temp);//释放temp的内存空间
    temp = NULL;//将temp置空
}
int main()
{
    srand((unsigned int)time(NULL));
	int ar[MAXSIZE];
	initar(ar,MAXSIZE);
	printf("原始数据为:\n");
	showar(ar,MAXSIZE);
    printf("\n经过归并排序后的数据为:\n");
	mergesort(ar,MAXSIZE);
	showar(ar,MAXSIZE);
	return 0;
}

运行结果: 

 归并排序,算法,数据结构,算法,c语言

如图,成功将系统随机生成的十一个数完成升序排序。文章来源地址https://www.toymoban.com/news/detail-540130.html

到了这里,关于算法 - 归并排序(Merge_sort)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构和算法笔记4:排序算法-归并排序

    归并排序算法完全遵循分治模式。直观上其操作如下: 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列。 解决:使用归并排序递归地排序两个子序列。 合并:合并两个已排序的子序列以产生已排序的答案。 我们直接来看例子理解算法的过程,下面是要排序

    2024年01月21日
    浏览(47)
  • 数据结构与算法—归并排序&计数排序

    目录 一、归并排序 1、主函数 2、递归实现 3、优化递归  4、非递归实现 5、特性总结: 二、计数排序 1、代码: 2、特性总结: 三、各种排序总结 时间空间复杂度汇总  基本思想: 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用 分治法 的一个非常典型的

    2024年02月04日
    浏览(32)
  • 数据结构与算法:归并排序

    在讲解归并排序前,我们先看到一个问题: 对于这样两个有序的数组,如何将它们合并为一个有序的数组? 在此我们处理这个问题的思路就是:开辟一个新的数组,然后分别安置一个指针在左右数组,利用指针遍历数组,每次对比将比较小的那个元素插入到数组的尾部。 像

    2024年01月21日
    浏览(33)
  • 数据结构算法--5 归并排序

    我们先看一下归并排序是怎么归并的  两个有序列表,有low指针指向2,high指针指向6,mid指针指向9 再建一个新列表,12,所以1放到列表,右指针右移一位,再比较2和3,2放入列表,左指针右移一位,以此类推,肯定有一部分列表率先没有数,这时将另一列表直接append进入新

    2024年02月11日
    浏览(38)
  • python算法与数据结构---排序和归并排序

    掌握归并排序的基本原理 使用python语言解答归并排序题目 原理及过程 将两个有序的数组合并成一个有序数组称为 从上往下分解:把当前区间一分为二,直至分解为若干个长度为1的子数组 从上往下的合并:两个有序的子区域两两向上合并; 体现了分治思想,稳定排序 复杂

    2024年01月21日
    浏览(58)
  • 【数据结构】排序算法(二)—>冒泡排序、快速排序、归并排序、计数排序

    👀 樊梓慕: 个人主页  🎥 个人专栏: 《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.冒泡排序 2.快速排序 2.1Hoare版 2.2占坑版 2.3前后指针版 2.4三数取中对快速排序的优化 2.5非递归版 3.归

    2024年02月08日
    浏览(35)
  • 【数据结构与算法】:非递归实现快速排序、归并排序

    🔥 个人主页 : Quitecoder 🔥 专栏 :数据结构与算法 上篇文章我们详细讲解了递归版本的快速排序,本篇我们来探究非递归实现快速排序和归并排序 快速排序的非递归实现主要依赖于栈(stack)来模拟递归过程中的函数调用栈。递归版本的快速排序通过递归调用自身来处理子

    2024年03月24日
    浏览(44)
  • [数据结构 -- 手撕排序算法第七篇] 递归实现归并排序

    目录 1、归并的思想 2、归并排序的思想 2.1 基本思想 2.2 图解分析 3、归并排序递归版本代码实现 3.1 代码解析 3.2 注意事项 3.2.1错误划分:[begin, mid-1],[mid, end] 3.2.2 正确划分:[begin, mid], [mid+1, end] 4、归并排序的测试 5、时间复杂度、空间复杂度分析 5.1 时间复杂度 5.2 空间复杂

    2024年02月16日
    浏览(37)
  • 【一起学数据结构与算法】几种常见的排序(插入排序、选择排序、交换排序、归并排序)

    排序是计算机内经常进行的一种操作,其目的是将一组 “无序” 的记录序列调整为 “有序” 的记录序列。分 内部排序 和 外部排序 ,若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序。反之,若参加排序的记录数量很大,整个序列的排序过程不可能

    2023年04月09日
    浏览(30)
  • 【数据结构】- 排序(详细介绍几种排序算法!!!*直接插入排序,*希尔排序,*选择排序,*堆排序,*冒泡排序,*快速排序,*归并排序)

    排序无处不在,所谓排序,就是使一串记录,按照其中的某个或某些的大小,递增或递减的排列起来的操作。 内部排序 :数据元素全部放在内存中的排序。 外部排序 :数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。 今天

    2024年01月20日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包