您的位置:首页 > 其它

交换排序(冒泡排序--快速排序)

2017-10-10 21:30 393 查看

1、冒泡排序

(1)基本思想:

对相邻的元素进行两两比较,顺序相反则进行交换,这样,每一趟会将最小或最大的元素“浮”到顶端,最终达到完全有序

(2)排序过程:

(1)将整个待排序列分成有序区和无序区,初始状态有序区为空,无序区包括所有待排记录
(2)对无序区从前往后依次比较相邻记录,若反序则交换,这样小的往前移,大的往后移(从小到大排序),每一趟无序区最大元素移至最后
(3)重复(2),直到无序区没有反序元素

示例:



(3)算法分析:

若初始有序,则只需进行一趟排序,n-1次比较,且不移动;反之,初始逆序,则需进行n-1趟排序,n(n-1)/2次比较,和等数量级移动。故总的时间复杂度为O(n^2)。

代码1:高效的冒泡排序算法
#include <iostream>
#include <vector>
using namespace std;
void BubbleSort(int r[],int n)
{//对r[1]~r
排序
int exchange=n;
while(exchange)
{
int bound=exchange;//上次交换的位置
exchange=0;
for(int j=1;j<bound;j++)//只需比较到上次最后发生交换的位置
{
if(r[j]>r[j+1])
{
int temp=r[j];
r[j]=r[j+1];
r[j+1]=temp;
exchange=j;//最终记录最后一次交换的位置
//j是无序区最后一个数的位置
}
}
for(int j=1;j<=n;j++) cout<<r[j]<<' ';
cout<<endl;
}
}
int main()
{
int input[]={0,49,38,65,97,76,13,27,49};
int length=sizeof(input)/sizeof(int);
cout<<"原数组:"<<endl;
for(int i=1;i<=length-1;i++)
{
cout<<input[i]<<' ';
}
cout<<endl<<"排序过程:"<<endl;
BubbleSort(input,length-1);
return 0;
}
                                                            


若每趟排序结束后,exchange值保持为0.则表明不再有反序情况,故不需进行下一趟排序;若exchange不为0,则它记录本趟最后发生反序而进行交换的位置,也成为下趟排序上届。高效

代码2:不高效冒泡排序算法之一
#include <iostream>
#include <vector>
using namespace std;
void BubbleSort1(int r[],int n)
{//对r[1]~r
排序
int exchange=1;
for(int i=1;i<n&&exchange;i++)//只需比较到上次最后发生交换的位置
{
exchange=0;
for(int j=1;j<n-i+1;j++)
//首先对前n个数比较,然后对前n-1个比...对前2个比,完成。
{
if(r[j]>r[j+1])
{
int temp=r[j];
r[j]=r[j+1];
r[j+1]=temp;
exchange=1;//发生了交换
}
}
for(int j=1;j<=n;j++) cout<<r[j]<<' ';
cout<<endl;
}
}
int main()
{
int input[]={0,49,38,65,97,76,13,27,49};
int length=sizeof(input)/sizeof(int);
cout<<"原数组:"<<endl;
for(int i=1;i<=length-1;i++)
{
cout<<input[i]<<' ';
}
cout<<endl<<"排序过程:"<<endl;
BubbleSort1(input,length-1);
return 0;
}
该算法只记录了每趟排序是否发生了交换,但没有记录上界。故,第一趟是对前n个数比较,第二趟是对前n-1个数比较,......,最后对前2个数比较。结束。

代码3:不高效的冒泡排序算法之二
#include <iostream>
#include <vector>
using namespace std;
void BubbleSort2(int r[],int n)
{//对r[1]~r
排序
for(int i=1;i<n;i++)//只需比较到上次最后发生交换的位置
{
for(int j=1;j<n-i+1;j++)
//首先对前n个数比较,然后对前n-1个比...对前2个比,完成。
{
if(r[j]>r[j+1])
{
int temp=r[j];
r[j]=r[j+1];
r[j+1]=temp;
}
}
for(int j=1;j<=n;j++) cout<<r[j]<<' ';
cout<<endl;
}
}
int main()
{
int input[]={0,49,38,65,97,76,13,27,49};
int length=sizeof(input)/sizeof(int);
cout<<"原数组:"<<endl;
for(int i=1;i<=length-1;i++)
{
cout<<input[i]<<' ';
}
cout<<endl<<"排序过程:"<<endl;
BubbleSort2(input,length-1);
return 0;
}
该算法既没记录每趟是否发生元素交换,也没记录上界,效率最低,但最简单,故人们常用。

2、快速排序

(1)基本思想:

快速排序采用的思想是分治思想。

快速排序是找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值,如此作为基准的元素调整到排序后的正确位置。对左右分区递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正 确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。

(2)步骤:

一趟快速排序实际是确定基准Rx位置:
(1)取子序列第一个记录赋给Rx
(2)设两个序列变量i和j,i指向第一个记录,j指向最后一个记录
a、j从右至左找Kj<Kx的记录;若有,则将对应的Rj送到i新指的位置上
b、i从左至右找Ki>Kx的记录,若有,则将对应的Ri送到j新指的位置上
c、重复ab,直到i=j
d、将Rx放到位置i=j
示例:
一趟排序过程如下:
                                                               


                                                                     


(3)算法分析:

快速排序的时间主要耗费在划分操作上,对长度为k的区间进行划分,共需k-1次关键字的比较。

最坏情况是每次划分选取的基准都是当前无序区中关键字最小(或最大)的记录,划分的结果是基准左边的子区间为空(或右边的子区间为空),而划分所得的另一个非空的子区间中记录数目,仅仅比划分前的无序区中记录个数减少一个。时间复杂度为O(n*n)

在最好情况下,每次划分所取的基准都是当前无序区的"中值"记录,划分的结果是基准的左、右两个无序子区间的长度大致相等。总的关键字比较次数:O(nlgn)

尽管快速排序的最坏时间为O(n2),但就平均性能而言,它是基于关键字比较的内部排序算法中速度最快者,快速排序亦因此而得名。它的平均时间复杂度为O(nlgn)。
快速排序不稳定。
代码:
#include <iostream>
#include <vector>
using namespace std;
int Partition(int r[],int s,int t)
{
int x=r[s];//选r[s]为基准
int i=s,j=t;
while(i<j)
{
while(i<j&&r[j]>=x) j--;
if(i<j) r[i]=r[j];
while(i<j&&r[i]<=x) i++;
if(i<j) r[j]=r[i];
}
r[i]=x;//基准放到正确位置
for(int i=s;i<=t;i++) cout<<r[i]<<' ';
cout<<endl;
return i;//基准位置
}
void QuickSort(int r[],int first,int end)
{
if(first<end)
{
int pivot=Partition(r,first,end);
QuickSort(r,first,pivot-1);
QuickSort(r,pivot+1,end);
}
}
int main()
{
int input[]={49,38,65,97,76,13,27,49};
int length=sizeof(input)/sizeof(int);
cout<<"原数组:"<<endl;
for(int i=0;i<length;i++)
{
cout<<input[i]<<' ';
}
cout<<endl<<"排序过程:"<<endl;
QuickSort(input,0,length-1);
return 0;
}
                                                                      


(4)快速排序非递归形式

每次以基准划分待排序列后,先将右区间下界i+1和上界h入栈保存(i为基准位置),继续对左区间快速排序,直到划分所得左区间中只有一个元素,再从桟中取出待排序无序区的上界和下界继续进行快速排序。
代码:
void QuickSort2(int r[],int low,int high)
{//在序列low~high中进行非递归快速排序
int size=sizeof(r)/sizeof(int);
int s[size+1][2];//二维数组s作为桟,size+1为大于n的常量
int top=-1;//桟顶指针
do
{
while(low<high)
{
int i=Partition(r,low,high);//基准位置
top=top+1;
s[top][0]=i+1;//s第1列记录划分的右区间的下界
s[top][1]=high;//s第2列记录划分的右区间的上界
high=i-1;
}
if(top>=0)
{
low=s[top][0];//出桟
high=s[top][1];
top--;
}
}while((top!=-1)||low<high);
}

#include <iostream>
#include <vector>
using namespace std;
int Partition(int r[],int s,int t)
{
int x=r[s];//选r[s]为基准
int i=s,j=t;
while(i<j)
{
while(i<j&&r[j]>=x) j--;
if(i<j) r[i]=r[j];
while(i<j&&r[i]<=x) i++;
if(i<j) r[j]=r[i];
}
r[i]=x;//基准放到正确位置
for(int i=s;i<=t;i++) cout<<r[i]<<' ';
cout<<endl;
return i;//基准位置
}
void QuickSort2(int r[],int low,int high)
{//在序列low~high中进行非递归快速排序
int size=sizeof(r)/sizeof(int);
int s[size+1][2];//二维数组s作为桟,size+1为大于n的常量
int top=-1;//桟顶指针
do
{
while(low<high)
{
cout<<"排序:";
int i=Partition(r,low,high);//基准位置
top=top+1;
cout<<"top="<<top<<' ';
s[top][0]=i+1;//s第1列记录划分的右区间的下界
cout<<"s[top][0]:"<<s[top][0]<<' ';
s[top][1]=high;//s第2列记录划分的右区间的上界
cout<<"s[top][1]:"<<s[top][1]<<' '<<"进桟"<<endl;
high=i-1;
}
if(top>=0)
{
low=s[top][0];//出桟
cout<<"low:"<<low<<' ';
high=s[top][1];
cout<<"high:"<<high<<' '<<"出桟"<<endl;
top--;
cout<<"top:"<<top<<' '<<endl;
}
}while((top!=-1)||low<high);
}
int main()
{
int input[]={49,38,65,97,76,13,27,49};
int length=sizeof(input)/sizeof(int);
cout<<"原数组:"<<endl;
for(int i=0;i<length;i++)
{
cout<<input[i]<<' ';
}
cout<<endl<<"排序过程:"<<endl;
QuickSort2(input,0,length-1);
return 0;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: