c语言归并排序,快速排序,基于二分、分治思想的排序应用(y 总模板)


🐧 这里先要友情提示一下,本篇文章可能对没有算法基础的同学有点难度,这里重点讲解 排序边界问题的处理方式 ,顺带提一下快速排序基于二分思想的应用好题。

排序的边界问题

如果大家经常写排序代码,会发现时不时会报错,循环结束不了,这就是排序边界问题引起的。

🐧 例子

假设我们对数组 a[2] = { 1 , -1 } 进行快速排序
👍quick_sort ( a, 0 ,1)
当我们使用快速排序后,在这个快速排序的调用里面有两个子调用,这里我先用含有 l , r 表达式表示出来
😁quick_sort( a , l , i - 1) , quick ( a, i, r); // l = 0 ,r = 1, i = ( l + r ) /2 = 0
如果留心看这里,我们会发现调用的式子为
🐧quick_sort( a , 0, - 1) , quick ( a, 0, 1); // l = 0 ,r = 1, i = ( l + r ) /2
这里注意看,我标记的两个式子,一模一样对吧。这不就是我们刚开始调用的函数吗?那么是不是就会一直这样调用下去呢?
显然,是的,这就是为什么会死循环的原因了。

🐧边界问题小结

这里会出现两种边界问题。
😒情况1: 母调用quick_sort ( a, 0 ,1):
子调用: quick_sort( a , l , i - 1) , quick ( a, i, r); 如果是这样就会陷入死循环

其实这里我们只要修改成 : quick_sort ( a ,low, j), quick_sort ( a, j+1 , high)

😒情况2:其实这里对应的和情况1 有一种相反的感觉。情况1出现陷入死循环的原因其实就是因为,我们快速排序中点的选择为左端点
左端点算法: (0+1)/2 所以当我们是左端点时候,由以上情况1的分析,我们需要用 sort( low ,j ), sort( j, high)
右端点算法 (0+1+1)/2 那么反过来,当我们使用的是右端点的时候,我们就使用sort(low ,i - 1),sort (i , high)

🐧代码模板

😁这里我给出 y 总代码模板,如果实在不想去讨论边界问题的话,那我们直接上模板永远不会错。

#include <stdio.h>
#define N 1000000
int q[N],n;

void quick_sort(int *q,int low,int high)
{
   if(low >= high) return ;
   
   int i = low - 1, j = high + 1, x = q[(low + high) >> 1];
   while( i < j )
   {
       do i++; while(q[i] < x);
       do j--; while(q[j] > x);
       if(i < j)  q[i] = q[i] ^ q[j] , q[j] = q[j] ^ q[i] , q[i] = q[i] ^ q[j];
   }
   quick_sort(q,low,j),quick_sort(q,j+1,high);
}

int main()
{
   scanf("%d",&n);
   for(int i = 0;i < n ; i++)
   scanf("%d",&q[i]);
   
   quick_sort(q,0,n-1);
   
   for(int i = 0;i < n ; i++)
   printf("%d ",q[i]);
   return 0;
}

🤞 这里再提一点,归并排序的边界问题也是对应我们快速排序,对于中间点的左值选择或者右值选择而言的,这里我给出归并排序的模板。

void merge_sort(int q[], int l, int r)
{
   if (l >= r) return;

   int mid = l + r >> 1;
   merge_sort(q, l, mid);
   merge_sort(q, mid + 1, r);
   
   int k = 0, i = l, j = mid + 1;
   while (i <= mid && j <= r)
       if (q[i] < q[j]) tmp[k ++ ] = q[i ++ ];
       else tmp[k ++ ] = q[j ++ ];
   
   while (i <= mid) tmp[k ++ ] = q[i ++ ];
   while (j <= r) tmp[k ++ ] = q[j ++ ];
   
   for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];

}

这里特别指出,这都是再Acwing上y总给出的模板

排序结合二分的洛谷好题

这里通过快速排序的一道改进题来讲解,排序和分治以及二分法结合的应用
洛谷 寻找第k个数p1932
🐧这道题的数据是被加强了的,所以直接排序是不能做出来的。
如果是按照 Acwing 上第 k 个数的做法只能得到80分,第五个测试点会时间超限

ac demo

#include<bits/stdc++.h>
using namespace std;
int x[5000005],k;
void qsort(int l,int r)
{
	int i=l,j=r,mid=x[(l+r)/2];
	do
	{
		while(x[j]>mid)
			j--;
		while(x[i]<mid)
			i++;
		if(i<=j)
		{
			swap(x[i],x[j]);
			i++;
			j--;
		}
	}
	while(i<=j);
	//快排后数组被划分为三块: l<=j<=i<=r
	if(k<=j) qsort(l,j);//在左区间只需要搜左区间
	else if(i<=k) qsort(i,r);//在右区间只需要搜右区间
	else //如果在中间区间直接输出
	{
		printf("%d",x[j+1]);
		exit(0);
	}
}
int main()
{
	int n;
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++)
		scanf("%d",&x[i]);
	qsort(0,n-1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我不会画饼鸭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值