归并排序--自上而下和自下而上两种方法的实现

本文介绍了归并排序的思想,并详细阐述了使用自上而下的递归方法实现排序过程。同时,还探讨了自下而上的归并排序方法及其实现代码,包括关键函数merge和mergeSort的使用。文章最后提供了具体代码实现和调用方法,以及运行环境说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

归并排序思想

自上而下的递归

对一个数组(str)选中一个中间位置(mid=(start+end)/2),分别进行左递归(mergeSort(str,start,mid,length)),右递归(mergeSort(str,mid+1,end,length)),在回朔的时候分别对以中间为分割的数组进行排序(merge(str,start,end,mid)),此时是一个归并的过程,这是自上而下的方法。


自下而上的递归

自下而上归并其实就是自上而下的时候的回朔过程,先对每一个数字排序,在两两排序,在对结果两两排序,直到完成。


具体代码实现(自上而下)

int merge(long *str,int start,int end,int mid){
	long *tmp = (long *)malloc(sizeof(long)*(end-start+1));
	int i=start;
	int j=mid+1;	
	int k=0;
	while(i<=mid && j<=end){
		if(str[i]<str[j])
			tmp[k++]=str[i++];
		else
			tmp[k++]=str[j++];
	}
	while(i<=mid)
		tmp[k++] = str[i++];
	while(j<=end)
		tmp[k++] = str[j++];
	for(i=start;i<=end;i++)
		str[i]=tmp[i-start];
	free(tmp);
}
int mergeSort(long *str,int start ,int end,int length){
	if(str == NULL || start <0 || end >length || length <=0 || end <= start)
		return ;
	int mid = (start + end )/2;
	mergeSort(str,start,mid,length);
	mergeSort(str,mid+1,end,length);
	merge(str,start,end,mid);
}
void call(){
	long *array = (long *)malloc(sizeof(long)*10);
	genrand(10,array);
	mergeSort(array,0,9,10);
	int i=0;
	for(i;i<10;i++)
		printf("%ld\n",array[i]);
}

自下而上代码实现

void merge(long *str,int start ,int end,int mid){
	if(start>=end || mid >=end)
		return;
	int i =start;
	int j =mid+1;
	int k =0;
	long *tmp = (long *)malloc(sizeof(long)*(end-start+1));
	while(i<=mid && j<=end){
		if(str[i]<=str[j])
			tmp[k++]=str[i++];
		else
			tmp[k++]=str[j++];
		
	}
	while(i<=mid)
		tmp[k++]=str[i++];
	while(j<=end)
		tmp[k++]=str[j++];
	for(i=start;i<=end;i++)
		str[i]=tmp[i-start];

	free(tmp);
}
void mergeGroup(long *str,int len,int gap){
	int i=0;
	//需要归并的总长度
	int twoLen = 2*gap;
	//因为数组下标以0开始,所以要-1
	for(i=0;i+twoLen-1<len;i+=twoLen){
		//i是起点,起点+总长度-1 为终点,起点+每一个数组的长度-1为分割点
		merge(str,i,i+twoLen-1,i+gap-1);
	}
	//如果便利一遍后 分割点还是小于数组最后一个下标,则表示还有最后一个归并没有完成,起点为i终点为len-1
	if(i+gap-1 < len-1)
		merge(str,i,len-1,i+gap-1);
}
void mergeSortDownUp(long * str,int length){
	int n;
	if(str == NULL || length<=0)
		return;
	//n 可以理解为每一次归并的数组长度
	for(n=1;n<length;n*=2)
		mergeGroup(str,length,n);
}
void call(){
	long *array = (long *)malloc(sizeof(long)*10);
	genrand(10,array);
	mergeSortDownUp(array,10);
	int i=0;
	for(i;i<10;i++)
		printf("%ld\n",array[i]);

}

genrand() 和swap()函数的实现如下。

int genrand(int num,long * array ){
	if (num>10000)
		return 0 ;
	srand((unsigned int)time(0));
	int i=0;
	for(i=0;i<num;i++)
		array[i] = rand();
	return 1;
	
}

void swap(long *A,long *B){
    long tmp;
    tmp = *A;
    *A = *B;
    *B = tmp;
}

运行环境:ubuntu14.04 、gcc

注:如有错误望批评指正。

<think>好的,我现在需要帮助用户理解递归实现自上而下自下而上的过程解析。首先,用户的问题涉及到编译原理中的语法分析方法,但同时也提到了递归在算法中的应用,比如快速排序归并排序。我需要结合用户提供的引用内容,尤其是引用[1]、[2]、[3]、[5],来构建一个清晰的回答。 首先,我应该先定义递归的基本概念,确保用户对递归有一个正确的理解。根据引用[4],递归是函数调用自身的方法,而迭代则是循环结构。这可以作为开头,区分递归迭代的不同。 接下来,需要详细解释自上而下自下而上两种递归实现方式。根据引用[1][2],自上而下分析是从顶层开始逐步展开,类似于分治法,将大问题分解成子问题。比如快速排序的例子,用户提供的引用[3]中也提到了分治法在递归中的应用,这里可以结合具体例子说明。 然后,自下而上方法需要从基础情况开始构建,逐步解决更大的问题。例如斐波那契数列的迭代方法或者动态规划,这可能涉及到引用中没有明确提到的例子,但根据用户的问题,我需要用这些常见例子来帮助理解。 用户提供的引用[5]提到了递归下降法对文法的限制,即LL(k)文法,这可能需要简要提及,但用户的问题更侧重于过程解析,所以这部分可能作为补充信息。 需要注意将理论知识与实际代码示例结合,比如递归实现的阶乘斐波那契数列,这样用户可以更直观地理解两者的区别。同时,需要确保所有数学表达式用$...$格式,独立公式用$$...$$,比如斐波那契数列的递推式。 还要检查是否有遗漏的引用内容,比如引用[3]中提到的分治法在快速排序归并排序中的应用,需要确保在回答中提到这些例子,以增强回答的相关性。 最后,生成的相关问题需要涵盖递归的应用、区别、优缺点以及实际案例,确保用户可以通过这些问题进一步深入学习。</think>### 递归实现自上而下自下而上过程解析 #### 一、递归的基本原理 递归是通过函数调用自身解决问题的编程方法[^4]。其核心是将问题分解为更小的子问题,直到达到可直接解决的**基线条件**(Base Case)。例如计算阶乘$n!$的递归实现: $$n! = n \times (n-1)! \quad \text{(基线条件:} 0! = 1 \text{)}$$ #### 二、自上而下(Top-Down)解析 **1. 过程特点** - 从顶层目标开始,逐步分解为子问题(类似语法分析的递归下降法[^1]) - 依赖递归调用链,通过**分治法**(Divide and Conquer)实现 - 典型应用:快速排序、二叉树遍历 **2. 代码示例**(快速排序核心逻辑) ```python def quick_sort(arr): if len(arr) <= 1: # 基线条件 return arr pivot = arr[0] # 分解为子问题并递归解决 return quick_sort([x for x in arr[1:] if x < pivot]) + [pivot] + quick_sort([x for x in arr[1:] if x >= pivot]) ``` **3. 数学表达** 设问题规模为$n$,每次分解为$a$个子问题,则时间复杂度可表示为: $$T(n) = aT(n/b) + O(n^d)$$ 其中$b$为子问题规模缩减因子,$d$为合并操作复杂度[^3]。 #### 三、自下而上(Bottom-Up)解析 **1. 过程特点** - 从基线条件开始,逐步构建更大问题的解 - 通常通过**迭代**或**动态规划**实现 - 典型应用:斐波那契数列、矩阵链乘法 **2. 代码示例**(斐波那契数列迭代实现) ```python def fib(n): a, b = 0, 1 for _ in range(n): a, b = b, a + b return a ``` **3. 数学表达** 斐波那契数列的递推关系: $$F(n) = F(n-1) + F(n-2) \quad (F(0)=0, F(1)=1)$$ 自下而上解法的时间复杂度为$O(n)$,而递归解法为$O(2^n)$。 #### 四、关键差异对比 | 特性 | 自上而下 | 自下而上 | |--------------|------------------------------|--------------------------| | **执行顺序** | 从目标问题到子问题 | 从子问题到目标问题 | | **实现方式** | 显式递归调用 | 迭代/动态规划 | | **空间效率** | 可能产生较深调用栈 | 通常更优 | | **典型场景** | 分治法、语法分析[^5] | 动态规划、数值计算 | #### 五、选择策略建议 1. 优先选择自下而上:当问题存在**重叠子问题**(如斐波那契数列)时,可避免重复计算 2. 适用自上而下:问题分解逻辑清晰且子问题独立(如树形结构处理) 3. 混合使用:记忆化搜索(Memoization)结合两种方式优势
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值