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

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[n]排序
    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[n]排序
    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[n]排序
    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;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值