【排序4】归并排序

29 篇文章 1 订阅
21 篇文章 8 订阅

【排序一】插入排序(直接插入排序&&希尔排序)

【排序二】选择排序(选择排序&&堆排序)

【排三】交换排序(冒泡排序&&序快速排序)


一、归并排序

1、基本思想

   归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。


算法原理

1>按照类似快速排序的方法递归地将待排序序列依次划分为两个区间,区间只剩一个数停止划分;
2>如果一个区间只剩一个数,我们可将其看做有序区间,然后对左右两个小区间进行归并,归并后仍要保持区间的有序性;
3>同2>提到的方法我们每次将两个有序的子区间归并为一个大的有序区间,并返回给上一层递归;

4>直到所有划分的区间归并为一个有序序列,归并排序就算完成。


算法图解(假设升序)



2、算法执行步骤

1》申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

2》设定两个指针,最初位置分别为两个已经排序序列的起始位置

3》比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

4》重复步骤3直到某一指针达到序列尾

5》将另一序列剩下的所有元素直接复制到合并序列尾


3、排序效果图



4、时间复杂度&&空间复杂度

归并排序,它采取分而治之(Divide-and-Conquer)的策略。归并排序的步骤如下:

<1> Divide: 把长度为n的输入序列分成两个长度为n/2的子序列。

<2> Conquer: 对这两个子序列分别采用归并排序。

<3> Combine: 将两个排序好的子序列合并成一个最终的排序序列。

比较操作的次数介于(n log n)/2n log n - n + 1。 赋值操作的次数是(2nlogn)

 归并算法的空间复杂度为:O(n*lgn).

归并排序的空间复杂度:O(n).


5、代码实现

//递归实现归并排序

#pragma once
#include <iostream>
#include <assert.h>
using namespace std;

void Merge(int* a,int* tmp,int left,int mid,int right)
{
	int begin1 = left;   //左区间的左边界
	int end1 = mid;      //左区间的右边界
	int begin2 = mid + 1;//右区间的左边界
	int end2 = right;    //右区间的右边界

	int index = left;//中间数组的下标
	while(begin1 <= end1 && begin2 <= end2)
	{
		//将左右区间中较小的值放入中间数组
		if (a[begin1] <= a[begin2])
		{
			tmp[index++] = a[begin1++];
		} 
		else
		{
			tmp[index++] = a[begin2++];
		}
	}
	//如果左区间还有数据,直接放到中间数组后边
	while(begin1 <= end1)
	{
		tmp[index++] = a[begin1++];
	}
	//如果右区间还有数据,直接放到中间数组后边
	while(begin2 <= end2)
	{
		tmp[index++] = a[begin2++];
	}
	//将中间数组的值考回原数组
	memcpy(a,tmp,index*sizeof(int));
	/*for (int i = left; i < index; ++i)
	{
		a[i] = tmp[i];
	}*/
}
void _MerSort(int* a,int* tmp,int left,int right)
{
	//当区间只有一个数或没有数据时递归返回
	if (left >= right)
		return;
	
	int mid = left + ((right - left)>>1);//划分左右区间的中间值

	_MerSort(a,tmp,left,mid);   //递归左边区间,使之有序
	_MerSort(a,tmp,mid+1,right);//递归右边区间,使之有序

	Merge(a,tmp,left,mid,right);//对左右两个有序区间进行归并
}
void MergeSort(int* a,size_t n)//归并排序
{
	assert(a);
	int* tmp = new int[n];//中间数组

	_MerSort(a,tmp,0,n-1);
	delete[]tmp;
}

void PrintArray(int* a,size_t n)
{
	for (size_t i = 0; i < n; ++i)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;
}
void TestMergeSort()
{
	int a[] = {2,5,4,9,3,6,8,7,1,0};
	size_t sz = sizeof(a)/sizeof(a[0]);

	MergeSort(a,sz);
	PrintArray(a,sz);
}


// 非递归实现归并排序

void Merge_sort(int *a, int length)
{  
	int i, begin1, end1, begin2, end2, index;  
	int *tmp = new int[length];  

	for (i = 1; i < length; i *= 2) 
	{
		for (begin1 = 0; begin1 < length - i; begin1 = end2)
		{   
			begin2 = end1 = begin1 + i;  
			end2 = end1 + i;  

			if (end2 > length)  
				end2 = length;  

			index = 0;  
			while (begin1 < end1 && begin2 < end2)  
				tmp[index++] = a[begin1] > a[begin2] ? a[begin2++] : a[begin1++];  

			while (begin1 < end1)  
				a[--begin2] = a[--end1];  

			while (index > 0)  
				a[--begin2] = tmp[--index];  
		}  
	}
	delete []tmp;
}  


运行结果:



二、各种排序的比较


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值