基础算法:快排与归并

本期介绍下两种基础算法的写法与区别,希望对您有些许帮助。

一.快排:

快排的排序方法是先排再分开,如此循环往复排出来正确顺序。

大体方式是一个数组,两个端点,两个下标,我们随机选取一个数为标准值,让两个下标分别从两头出发,之后遇到与大于(或小于)x的数就停下,两边都停下的话就交换数,之后会以x为界限形成左右两边要么都大于或都小于x的数组,然后继续分。

那么我们可以通过一个递归程序实现,递归中程序如下:

void quick_sort(int q[], int l, int r){//快排模板,l左边固定端点,r右边固定端点
	if(l>=r) return;//如果左右两端点重合就结束
	int x=q[(l+r)>>1], i=l-1, j=r+1;//随便规定一个x值来以他为大小界限,i和j(移动端点)先都在l和r的外侧
	while(i<j){//当i,j未重合,就移动
		do i++; while(q[i]<x);//先执行移动操作,再进行比较:如果i这个位置的数小于x,则继续移动,直到大于等于的数
		do j--; while(q[j]>x);//大小反之
		if(i<j) swap(q[i],q[j]);//如果两个都停了,就交换两个数继续走
	}
	quick_sort(q,l,j);//排完一轮后继续排两边
	quick_sort(q,j+1,r);
}

快排中的x是可以随意规定的,但是有时候处理不好会陷入死循环,所以给大家一个模板仅供参考。

完整代码如下:

#include <iostream>
using namespace std;
const int M = 1e6+7;
int n, q[M];

void quick_sort(int q[], int l, int r){//快排模板,l左边固定端点,r右边固定端点
	if(l>=r) return;//如果左右两端点重合就结束
	int x=q[(l+r)>>1], i=l-1, j=r+1;//随便规定一个x值来以他为大小界限,i和j(移动端点)先都在l和r的外侧
	while(i<j){//当i,j未重合,就移动
		do i++; while(q[i]<x);//先执行移动操作,再进行比较:如果i这个位置的数小于x,则继续移动,直到大于等于的数
		do j--; while(q[j]>x);//大小反之
		if(i<j) swap(q[i],q[j]);//如果两个都停了,就交换两个数继续走
	}
	quick_sort(q,l,j);//排完一轮后继续排两边
	quick_sort(q,j+1,r);
}
int main(){
	scanf("%d",&n);
	for(int i=1; i<=n; i++) scanf("%d",&q[i]);
	quick_sort(q,1,n);
	for(int i=1; i<=n; i++) printf("%d ",q[i]);
	return 0;
}

二.归并:

归并排序与快速排序有所不同,归并排序是先将原数组分开变为一个个小数组,之后经过递归程序在将排好的数组重新填回原数组。

具体实现:先将数组分开,分开之后会形成两个数组,为这两个数组规定两个下标,让下标所对应的数进行比较,哪一边数小就将那个数填入新数组,并且下标向前移动。而另一个数组的下标不动,最后会出现有一边的数组下标没走完,则这时候需要将剩下的数填入新数组就可以(因为这些数组中的数的排序是通过最小的数组合并出来的,所以顺序都是由小到大,直接填入新数组就可以),然后这时将新数组中的数覆盖掉原数组中对应的位置的数即可,代码如下:

#include <iostream>
using namespace std;
const int M =1e6+7;
int n;
int q[M],tmp[M];
void merge_sort(int q[], int l, int r){//归并模板:l左端点,r右端点
	if(l>=r) return;//如果左右端点重合就结束
	int mid=l+r>>1; 
	merge_sort(q,l,mid); merge_sort(q,mid+1,r);//归并就是先把所有数分开在合并,所以先分开数
	int k=1, i=l,j=mid+1;//分完后一个新数组tmp代表排完序的数组,i是左边分出来数组的下标,j是右边的下标(可移动)
	while(i<=mid&&j<=r) {//mid和r就分别是左右两个数组的尾端点
		if(q[i]<=q[j]) tmp[k++]=q[i++];//去比较左右两个数组中的数,哪个小就先进tmp数组,然后下标往后走继续比较
		else tmp[k++]=q[j++];
	}
	while(i<=mid) tmp[k++]=q[i++];//如果哪边下标走完了就看另一个数组,让其剩下的数排进tmp
	while(j<=r) tmp[k++]=q[j++];
	for(int i=l, j=1; i<=r; i++, j++) q[i]=tmp[j];//然后将这一段的tmp数组返回给这一段的q数组就可
}

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值