提示:忧劳可以兴国,逸豫可以亡身
文章目录
交换排序
提示:这里可以添加本文要记录的大概内容:
基本思想就是两两比较,如果发生逆序则交换,直到所有的记录都排好序为止 常见的就是冒泡排序与快速排序 。快速排序为什么快速可以突破下限 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;
}
}
}
运行截图
总结
希望有时间还是自己打一遍 其实也还好不难,感觉不错点个赞呗铁子