归并排序(递归和非递归)

归并排序主要讲二路归并排序

二路归并排序的基本思想:

     设数组a中存放了n个数据元素,初始时把他们看成是n个长度为1的有序子数组,然后从第一个子数组开始,把相邻的子数组进行两两合并,的到n/2的整数上界个长度为2的新的有序子数组(当n为奇数时最后一个新的有序子数组的长度为1);对这些新的有序子数组在两两归并;如此重复,直到得到一个长度为n的有序数组为止。

归并排序的过程图:

归并排序的完整代码(非递归):
#include<iostream>
#include<malloc.h>
using namespace std;
 void meger(int *arr,int len,int gap)
{
	int *buff=(int*)malloc(sizeof(int)*len);//设置一个临时的buff
	if(buff==NULL)
	{
		exit(0);
	}
	int i=0;
	int low1=0;
	int high1=low1+gap-1;
	int low2=high1+1;
	int high2=(low2+gap-1)  < len ? (low2+gap-1) : (len-1);//当第二段的数据小于len时,就用第二段的数据

	while(low2<len) //第二段有数据时候,第二段有数据才能进行归并
	{
		while(low1<=high1 && low2<= high2)
		{
			if(arr[low1]<=arr[low2])
			{
				buff[i++]=arr[low1++];
			}
			else if(arr[low1]>arr[low2])
			{
				buff[i++]=arr[low2++];
			}
		}
		while(low1<=high1)//第一段中有剩余,一定不要忘记写等号
		{
			buff[i++]=arr[low1++];
		}
		while(low2<=high2)//第二段中有剩余,不要忘记写等号
		{
			buff[i++]=arr[low2++];
		}
		low1=high2+1;
		high1=low1+gap-1;
		low2=high1+1;
		high2=(low2+gap-1) <len ? (low2+gap-1) : (len-1)  ;
	}
	while(low1<len)//只有第一段,没有第二段
	{
	   buff[i++]=arr[low1++];
	}
	for(int j=0;j<len;++j)
	{
		arr[j]=buff[j];//把数据拷贝过来
	}
	free(buff);
}

void merger_sort(int *arr,int len)
{
	for(int gap=1;gap<len;gap*=2)//把带排序的数组进行排序
	{
		meger(arr,len,gap);
	}
}
int main()
{
	int arr[]={12,56,89,45,1,46};
	int len=sizeof(arr)/sizeof(arr[0]);
	merger_sort(arr,len);
	for(int i=0;i<len;i++)
	{
		cout<<arr[i]<<"  ";
	}
	cout<<endl;
}
归并排序的代码(递归):
#include<iostream>
#include<malloc.h>
using namespace std;
#define  maxsize   10

void megering(int *left,int left_size,int *right,int right_size)
{
	int i=0;
	int j=0;
	int k=0;
	int temp[maxsize];//用来存储排序的数据
	while(i<left_size && j<right_size)
	{
		if(left[i]<=right[j])//左边数据《 右边的数据
		{
			temp[k++]=left[i++];//就把左边的数据存储到temp数组中
		}
		else
		{
			temp[k++]=right[j++];//右边的数据小,就存储右边的数据
		}
	}
	while(i<left_size)//左边的数据有剩余,直接把左边的数据拷贝到temp数组中
	{
		temp[k++]=left[i++];
	}
	while(j<right_size)//右边的数据有剩余,就把右边的数据拷贝到temp数组中
	{
		temp[k++]=right[j++];
	}
	for(int m=0;m<(left_size+right_size);++m)
	{
		left[m]=temp[m];//最后的结果存在left数组中
	}
}
void meger_sort(int *arr,int len)
{
	if(len>1)//递归调用的出口
	{
		int *left=arr;//left指向数组的首地址
		int left_size=len/2;//len/2代表的是数组一半的数据,left_size代表的是左半部分的数据个数
		int *right=arr+len/2;//right指向的是右边部分的首元素
		int right_size=len-left_size;//右边部分元素的个数
		
		meger_sort(left,left_size);//划分左边,递归左半部分,即左边一直分,直达只有一个元素
		meger_sort(right,right_size);//划分右边,递归右半部分,即右边一直分,直到只有一个元素

		megering(left,left_size,right,right_size);//归并
	}
}
int main()
{
	int arr[]={1,8,4,50,4};
	int len=sizeof(arr)/sizeof(arr[0]);
	meger_sort(arr,len);
	for(int i=0;i<len;i++)
	{
		cout<<arr[i]<<"  ";
	}
	cout<<endl;
}

### 归并排序递归非递归实现的差异 #### 1. 基本原理的区别 归并排序的核心思想是分治法,即将大问题分解成若干个小问题来解决。递归版本通过函数调用栈自然实现了这一过程[^1],而非递归版本则需要显式地借助辅助数据结构(通常是队列或循环控制变量)来完成相同的功能[^4]。 #### 2. 数据结构的使用 - **递归实现**:依赖于系统的函数调用栈,每次划分一个区间 `[left, right]` 后,会进一步划分子区间 `[begin, mid]` `[mid+1, end]` 并对其进行递归操作[^3]。 - **非递归实现**:通常采用自底向上的方法,初始时将每个元素视为独立的一组,逐步合并相邻的小数组形成更大的有序数组,直至整个数组被排序完毕。 #### 3. 时间复杂度空间复杂度 两种实现的时间复杂度均为 \(O(n \log n)\),但在空间复杂度方面存在细微差别: - **递归实现**:由于涉及多层嵌套的函数调用,其额外的空间开销主要来自于系统栈,最坏情况下可能达到 \(O(\log n)\)。 - **非递归实现**:不需要维护递归调用栈,因此可以节省这部分内存消耗;然而为了存储中间结果,仍需分配一定大小的临时缓冲区用于合并阶段的操作[^5]。 #### 4. 编码难度对比 从编码角度来看, - **递归实现**更加直观简洁,易于理解编写,因为它直接映射了分而治之的思想模型[^2]; - 而**非递归形式**相对较为繁琐一些,尤其是当涉及到边界条件判断以及索引管理时容易出错。 以下是两者的伪代码表示: ```python # 递归实现 def merge_sort_recursive(arr, temp_arr, left, right): if left < right: mid = (left + right) // 2 merge_sort_recursive(arr, temp_arr, left, mid) # 左半部分排序 merge_sort_recursive(arr, temp_arr, mid + 1, right) # 右半部分排序 merge(arr, temp_arr, left, mid, right) # 合并已排序的部分 def merge(arr, temp_arr, left, mid, right): i = j = k = 0 while i <= mid and j <= right: if arr[i] <= arr[j]: temp_arr[k] = arr[i] i += 1 else: temp_arr[k] = arr[j] j += 1 k += 1 while i <= mid: temp_arr[k] = arr[i] i += 1 k += 1 while j <= right: temp_arr[k] = arr[j] j += 1 k += 1 for loop_var in range(left, right + 1): arr[loop_var] = temp_arr[loop_var] ``` ```python # 非递归实现 def merge_sort_iterative(arr): length = len(arr) position = 1 while position < length: left = 0 while left < length - 1: mid = min((left + position - 1), (length - 1)) right = ((position * 2 + left - 1), (length - 1))[(position * 2 + left - 1) >= (length - 1)] merge(arr, left, mid, right) left += position * 2 position *= 2 def merge(arr, l, m, r): n1 = m - l + 1 n2 = r - m L = [0] * n1 R = [0] * n2 for i in range(0 , n1): L[i] = arr[l + i] for j in range(0 , n2): R[j] = arr[m + 1 + j] i = 0 j = 0 k = l while i < n1 and j < n2 : if L[i] <= R[j]: arr[k] = L[i] i += 1 else: arr[k] = R[j] j += 1 k += 1 while i < n1: arr[k] = L[i] i += 1 k += 1 while j < n2: arr[k] = R[j] j += 1 k += 1 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值