交换排序之冒泡与快速

提示:忧劳可以兴国,逸豫可以亡身


交换排序

提示:这里可以添加本文要记录的大概内容:

基本思想就是两两比较,如果发生逆序则交换,直到所有的记录都排好序为止 常见的就是冒泡排序与快速排序 。快速排序为什么快速可以突破下限 N平方,原因是每一次交换的也是一大步,详情原因请看希尔排序中的3.1


一、冒泡排序

就是基于简单的交换思想
基本思想
:每趟不断将记录两两比较,并按照“前小后大的规则进行交换” 所以第一趟的时候,最大的元素会到最后的位置上 第二趟的时候,次大的会到倒数第二个的位置上,每一趟都能让一个元素去到它应该待的位置上,这样的循环执行N 次 N个数就实现了有序,至于为什么最大的每一趟会来到此时的最后的位置上,建议找一个视频,脑子里有一个交换的过程,你理解了

1.1、冒泡代码

但是要注意每一个数要走的次数,与第几趟是有关系的,第一趟一直比较到最后一个位置,第二趟的这个数只需要比较到倒数第二个位置,因为倒数第一个已经是最大了,不需要比较了 所以这里是j<V.size()-1

void BubbleSort(vector<int> &V){
	for(int i=0;i<V.size();i++){//因为有N个数 所以要进行N趟 
		for(int j=1;j<V.size()-i;j++){
		/*每一个数要走的次数,与第几趟是有关系的,第一趟一直比较到最后一个位置,
		第二趟的这个数只需要比较到倒数第二个位置,因为倒数第一个已经是最大了,不需要比较了
		所以这里是j<V.size()-i*/ 
			if(V[j]<V[j-1]){
				swap(V[j],V[j-1]);
			} 
		}
	cout<<"此时是第"<<i<<"次冒泡结果如下"<<endl; 
	for(int i=0;i<V.size();i++){
		cout<<V[i]<<" ";
	}
		cout<<endl; 
	} 
}

1.2、运行截图

请添加图片描述

基于上述日志 可以看出确实是每一次都是最大的冒出来

1.3、优点

每一趟结束时候,不仅能挤出一个最大值到最后的位置上,还能同时梳理其他的元素

1.4、优化

一旦有一趟比较时不出现交换记录,就说明排序完成 ,就可以退出算法

void BubbleSort(vector<int> &V){
	for(int i=0;i<V.size();i++){//因为有N个数 所以要进行N趟
	bool flag=true; 
		for(int j=1;j<V.size()-i;j++){
		/*每一个数要走的次数,与第几趟是有关系的,第一趟一直比较到最后一个位置,
		第二趟的这个数只需要比较到倒数第二个位置,因为倒数第一个已经是最大了,不需要比较了
		所以这里是j<V.size()-1*/ 
			if(V[j]<V[j-1]){
				swap(V[j],V[j-1]);
				flag=false;
			} 
		}
	cout<<"此时是第"<<i<<"次冒泡结果如下"<<endl; 
	for(int i=0;i<V.size();i++){
		cout<<V[i]<<" ";
	}
	cout<<endl;
	if(flag==true) return; 
	} 
}

运行结果

请添加图片描述
通过日志对比,可以发现确实是减少了趟数

二、快速排序

2.1、基本思想

通过一趟排序,将待排序的记录分割成独立的两部分,其中一部分记录的关键字均比另外一个部分小,则可分别对这两个部分进行排序,以达到整个序列有序

2.2、实现步骤

1、任取一个元素为中心(通常选择第一个元素)
2、所有比它小的元素一律前放,比它大的元素一律后方 形成左右两个子表
3、然后对两个子表继续进行快速排序
4、直到每一个子表的元素只剩下一个
所以你应该也能感觉到,这里应该使用递归的方式 递归结束的条件就是只有一个元素的时候

2.3、返回轴点位置

如何做到比轴点大的放在轴点的后面,比轴点小的放在轴点的前面这个是这个算法的难点,虽然说是难点,但是其实也还好,这里其实我觉得也使用双指针的思想,假如我们以第一个为轴点,在这一趟遍历中,pre指向第一个元素,tail指向最后一个元素,我们使用一个temp将第一个元素存储下来,此时pre指向的就相当于是空了,我们将tail指针向前移动 找到一个比temp小的 放在pre的位置上,此时tail 指向的就相当于是空了,再移动pre从前向后找一个比tepm 小的放在tail位置上,pre==tail 的时候,pre与tail指向的就是空位置了,我们将temp 放在这个位置上就实现了左边比他小 右边比它大,
这里区间使用的是左闭右闭的形式,返回值是下标(从零开始)

int Pation(vector<int> &V,int from,int to){
	int pre=from;
	int tail=to;
	int temp=V[from];//存储轴点的值,相当于腾出一个空间 
	while(pre<tail){
		while(pre<tail&&V[tail]>temp){//先从后往前,因为我们腾出的是第一个位置
			 tail-=1;
		}//退出这个while的时候自然是找到了一个或者pre==tail
		if(pre!=tail){
			V[pre]=V[tail];	
		}
		else {
			V[pre]=temp;
			return tail;
		}
		while(pre<tail&&V[pre]<temp){
			pre+=1;
		}
		if(pre!=tail){
			V[tail]=V[pre];
		}
		else{
			V[pre]=temp;
			return tail;
		}
	}
}

2.4、快速排序代码分析

返回的位置是下标(从0 开始) 要注意一点就是返回的位置可能是location=0 所以此时不能使用location-from=1; 因为location是可能为零 或则为size()-1的 要跳过中间的轴点

void QuickSort(vector<int> &V,int from,int to){
	if(to<=from){
		return;
	}
	//因为我们需要划分两个子区域,所以必须知道划分点在哪 
	int location=Pation(V,from,to);
	QuickSort(V,from,location-1);//要考虑location==0 
	QuickSort(V,location+1,to);//要考虑location==size()-1; 
}

可执行代码汇总

#include<bits/stdc++.h>
using namespace std;
void swap(int &a,int &b){
	a^=b;
	b^=a;
	a^=b;
} 
void BubbleSort(vector<int> &V){
	for(int i=0;i<V.size();i++){//因为有N个数 所以要进行N趟
	bool flag=true; 
		for(int j=1;j<V.size()-i;j++){
		/*每一个数要走的次数,与第几趟是有关系的,第一趟一直比较到最后一个位置,
		第二趟的这个数只需要比较到倒数第二个位置,因为倒数第一个已经是最大了,不需要比较了
		所以这里是j<V.size()-1*/ 
			if(V[j]<V[j-1]){
				swap(V[j],V[j-1]);
				flag=false;
			} 
		}
	cout<<"此时是第"<<i<<"次冒泡结果如下"<<endl; 
	for(int i=0;i<V.size();i++){
		cout<<V[i]<<" ";
	}
	cout<<endl;
	if(flag==true) return; 
	} 
}
int Pation(vector<int> &V,int from,int to){
	int pre=from;
	int tail=to;
	int temp=V[from];//存储轴点的值,相当于腾出一个空间 
	while(pre<tail){
		while(pre<tail&&V[tail]>temp){//先从后往前,因为我们腾出的是第一个位置
			 tail-=1;
		}//退出这个while的时候自然是找到了一个或者pre==tail
		if(pre!=tail){
			V[pre]=V[tail];	
		}
		else {
			V[pre]=temp;
			return tail;
		}
		while(pre<tail&&V[pre]<temp){
			pre+=1;
		}
		if(pre!=tail){
			V[tail]=V[pre];
		}
		else{
			V[pre]=temp;
			return tail;
		}
	}
}
void QuickSort(vector<int> &V,int from,int to){
	if(to<=from){
		return;
	}
	//因为我们需要划分两个子区域,所以必须知道划分点在哪 
	int location=Pation(V,from,to);
	QuickSort(V,from,location-1);//要考虑location==0 
	QuickSort(V,location+1,to);//要考虑location==size()-1; 
}
int main(){
	int choice;int a;
	vector<int> V;
	cout<<"请输入你要排序的值"<<endl;
	while(scanf("%d",&a)!=EOF) V.push_back(a);
	cout<<"请选择你要进行时的排序方式"<<endl;
	cout<<"1、冒泡排序"<<endl;
	cout<<"2、快速排序"<<endl;
	cin>>choice;
	switch(choice){
		case 1:{
			BubbleSort(V);
			break;
		}
		case 2:{
			QuickSort(V,0,V.size()-1);
			for(int i=0;i<V.size();i++){
				cout<<V[i]<<" ";
			}
			break;
		}
		default:{
			cout<<"你输入的不正确"<<endl;
			break;
		}
	}
	
}

运行截图

请添加图片描述

总结

希望有时间还是自己打一遍 其实也还好不难,感觉不错点个赞呗铁子

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值