排序算法及逆序对超详注解

排序算法汇总

排序算法题目

给定你一个长度为 n的整数数列,将数组升序排列

所有的排序算法都是通过自定义的函数方式,便于理解

冒泡排序

思路

  • 二重循环,相邻逐个比较
#include<iostream>

using namespace std;

const int N = 1e6 + 10;
int q[N];

/*冒泡排序*/
void effervescence_sort(int q[] , int n){
	int i,j;
	/*升序*/
	for( i = 0 ; i < n ; i ++ ){
		for( j = n - 1 ; j >= i ; j -- ){
			if(q[j] < q[j - 1] ) swap( q[j] , q[ j - 1 ]);//将相邻对的进行比较,把小的放在左边
		}
	}
}

int main(){
	int n;
	cin >> n;
	for(int i = 0 ;i < n ;i ++ ) cin >> q[i];
	effervescence_sort(q , n);
	for( int i = 0 ; i < n;i ++ ) cout << q[i] <<" ";
	return 0;
}

选择排序

思路

  • 每次从 i 开始,查找当前(i – n - 1)最小值所在的位置,将最小的放在前面
#include<iostream>

using namespace std;

const int N = 1e6 + 10 ;
int q[N];

/*选择排序*/
void select(int q[] , int n ){
	for(int i = 0 ; i < n ; i ++ ) {
		int min = q[i];//升序
		int z=i;
		for(int j = i ; j < n ; j ++){
			if( min > q[j] ) {//选择最小的元素
				min = q[j];//找到最小的元素将它作为最小值
				z = j;//记录最小值的下标,便于一重循环的j
			}
		}
		swap(q[i] , q[z]);
	}
}

int main(){
	int n;
	cin >> n;
	for(int i = 0 ; i < n ; i ++ ) cin >> q[i];
	select( q , n );
	for(int i = 0 ; i < n ; i ++ ) cout<< q[i] <<" ";
	return 0;
}

快速排序

思路

  • 从数组中选择随机选择一个位置下标当作标准(用来对比,此处选择左端点)
  • 进入循环,一端从数组左(i),一端从数组右(j),左端小于该标准的值保留,大于该标准的与右边小于该标准的进行交换。
  • 因为做法是从两端开始的,所以此时数组左边全是小于(或等于)该值的,右边全是大于(或等于)该值的,进行左右递归
#include<iostream>

using namespace std;

const int N = 1e6 + 10;
int q[N];

/*快速排序*/
void quick_sort( int q[] ,int l ,int r ){
	if( l >= r) return ;
	int x = q[l] , i = l - 1, j = r + 1;//此处选取的是左端点为参考值,同样可以选择右端点(r),也可以选取随机值
	while( i < j ){
		do i ++ ; while( q[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(){
	int n;
	cin >> n;
	for(int i = 0 ; i < n ;i ++ ) cin>>q[i];
	quick_sort( q , 0 , n - 1 );//0和n - 1是数组的左端点和右端点的下标
	for(int i = 0 ; i < n ;i ++ ) cout << q[i] << " ";
	return 0;
}

归并排序及逆序对

归并排序

思路

大致思路

将数组进行无限划分(即小区域排序,再对两个递归数组进行排序合并成一个数组,持续操作后数组将由原来的分散数组再次合并成一个完整的数组),进行重组为一个递归数组

具体思路

  • 先将数组平分,然后再平分(先分到无法再分为止,也就是每一个小部分都只有一个数组元素),
  • 对每两个相邻单调的数组进行合并(开始时一个数组元素默认为单调的)
  • 重复2操作合并为一个完整的单调数组
#include<iostream>

using namespace std;

const int N = 1e6 +10;
int q[N], tmp[N];//定义两个数组,第一个是待排序的数组,第二个是用来将两个单调的数组进行汇总的数组,也可以理解为一个辅助数组

void merge_sort(int q[], int l, int r){
	if (l >= r) return ;
	int mid = l + r >> 1;//l+r除以二
	merge_sort(q, l, mid),merge_sort(q, mid + 1, r);//进行左右递归,细分数组
	
	int k = 0, i = l, j = mid + 1;//到这一步,因为已经对数组进行细分,数组传到这里就是两个单调增的数组
	/*对两个单调数组进行汇总在tmp中保存*/
	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 ++ ];
	/*把辅助数组tmp中的元素放进目标数组q中*/
	for(i = l,j = 0; i <= r; i ++, j ++) q[i] = tmp[j];
}

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

归并排序求逆序对

注:一定要先理解归并排序!!

逆序对题目

给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。

1≤n≤100000
数列中的元素的取值范围 [1,10^9]。

思路

  • 归并排序中排在后面的数组中的元素如果小于前面的将会产生逆序对

例如: 4 5 6,1 2 3这两个小的递增数组,首先比较4和1,因为1 < 4且该数组递归,那么1 将小于4所在的数组后面的每一个数组元素,则1 所贡献的逆序对有(4,1)(5,1)(6,1)也就是后面代码中提到的mid - i + 1,而在该数组中由于单调递增,则可以不需要考虑自己所在数组后面的元素。

#include<iostream>

using namespace std;

typedef long long LL;//此处开longlong是因为题目要求的范围在10^9

const int N = 1e6 + 10;
int q[N], tmp[N];

LL  merge_sort(int l, int r){//因为要返回一个值,所以和逆序排序不同的是,需要有返回值
	if(l >= r) return 0;
	int mid = l + r >> 1;
	LL res = merge_sort(l, mid) + merge_sort(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 ++ ];
        	res += mid - i + 1;//求逆序对的核心所在,其余的和逆序排序类似
		}
	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];
	return res;
}

int main(){
	int n;
	cin >> n;
	for(int i = 0; i < n; i ++ ) cin >> q[i];
	cout << merge_sort(0, n - 1);
	return 0;
}
欢迎留言讨论,评论私聊都会回复,希望这篇文章可以帮助你梳理关于排序算法的知识,对于文章存在的问题欢迎留言讨论,对你有用的话期待点赞收藏mua~
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值