选择排序(简单选择排序--改进的简单选择排序--堆排序)

来源:互联网 发布:can数据帧的格式结构 编辑:程序博客网 时间:2024/06/06 00:01

选择排序:每一趟从待排序序列中选一个按序所需要的记录,放在已排好序的子序列之前或之后,保持有序,这样,有序子序列每次增加一个记录,直到全部记录排完为止。

1、简单选择排序

基本思想:每一趟从待排记录序列中选具有最小关键字值的记录,顺序放在已排好序的子序列后,直到全部记录排完。
步骤:
(1)在第i(i=1,2,3,......,n-1)次挑选步骤中,在记录r[i],r[i+1],r[n]中挑出最小值r
(2)交换r和r[i]。执行完第i步后,前i个记录r[1],r[2],......,r[i]有序。
示例:
初始序列:{49 27 65 97 76 12 38}
  第1趟:12与49交换:12{27 65 97 76 49 38}
  第2趟:27不动 :12 27{65 97 76 49 38}
  第3趟:65与38交换:12 27 38{97 76 49 65}
  第4趟:97与49交换:12 27 38 49{76 97 65}
  第5趟:76与65交换:12 27 38 49 65{97 76}
  第6趟:97与76交换:12 27 38 49 65 76 97 完成
算法分析:
(1)n个记录的序列只需n-1趟排序。按照算法的描述,n - 1 趟排序之后数组中的前 n - 1 个元素已经处于相应的位置,第 n 个元素也处于相应的位置上。
(2)稳定性:不稳定 (比如序列【5, 5, 3】第一趟就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面)
(3)时间复杂性:比较时间:T = (n-1))+ (n -2)+(n - 3).... + 1;  ===>>  T =  [n*(n-1) ] / 2;
 交换时间:最好的情况全部元素已经有序,则 交换次数为0;最差的情况,全部元素逆序,就要交换 n-1 次;
所以最优的时间复杂度  和最差的时间复杂度   和平均时间复杂度  都为 :O(n^2)
(4)空间复杂度:只需一个辅助空间作为交换机路用的暂存单元,O(1)
代码:
#include <iostream>#include <vector>using namespace std;void StraightSelectSort(int r[],int n){//对r[1]~r[n]排序    for(int i=1;i<n;i++)//n-1趟排序    {        int k=i;        for(int j=i+1;j<=n;j++)        {            if(r[j]<r[k]) k=j;//k记录r[i...n]中最小值的下标        }        if(k!=i)        {            int temp=r[i];            r[i]=r[k];            r[k]=temp;        }        cout<<endl;        for(int p=1;p<=n;p++) cout<<r[p]<<' ';    }}int main(){    int r[]={0,49,38,65,49,76,13,27,97};    int length=sizeof(r)/sizeof(int);    cout<<"原数组:"<<endl;    for(int i=1;i<=length-1;i++)    {        cout<<r[i]<<' ';    }    cout<<endl<<"排序过程:"<<endl;    StraightSelectSort(r,length-1);    return 0;}

2、改进的简单选择排序

由于简单选择排序不稳定,改进,即将要交换的两个元素a、b不立即直接交换,而是先取出后面的元素b,将后面元素b之前的元素直到前一个元素a向后平移一个位置,再将取出的元素赋在前面空出的位置上,就可形成稳定排序。

代码:

#include <iostream>#include <vector>using namespace std;void StraightSelectSort1(int r[],int n){//对r[1]~r[n]排序    for(int i=1;i<n;i++)//进行n-1趟排序    {        int k=i;        for(int j=i+1;j<=n;j++)        {            if(r[j]<r[k]) k=j;//k记录r[i...n]中最小值的下标        }        if(k!=i)        {            int temp=r[k];//记录下找到的最小值            for(int q=k-1;q>=i;q--) r[q+1]=r[q];//后移            r[i]=temp;        }        cout<<endl;        for(int p=1;p<=n;p++) cout<<r[p]<<' ';    }}int main(){    int r[]={0,49,38,65,49,76,13,27,97};    int length=sizeof(r)/sizeof(int);    cout<<"原数组:"<<endl;    for(int i=1;i<=length-1;i++)    {        cout<<r[i]<<' ';    }    cout<<endl<<"排序过程:"<<endl;    StraightSelectSort1(r,length-1);    return 0;}

3、堆排序

1、堆:n个元素的序列k1,k2,k3,......,kn,当且仅当:ki<=k(2i)且ki<=k(2i+1),或者ki>=k(2i)且ki>=k(2i+1),i=1,2,...,n/2,称之为堆。满足前一组关系为最小堆(小根堆),后一组最大堆(大根堆)。
                 
将待排序的记录序列即一维结构数组逻辑上看作一个完全二叉树上节点自顶向下自左自右的排列。若{r1,r2,...,rn}是最大堆,则堆顶记录对应最大值,在最小堆中,堆顶最小。
2、堆排序思想:首先将n个记录按关键字大小建成最大堆,堆顶就是最大的,将堆顶与最后一个交换,最大值排在最后。然后对前面n-1个记录只需从根开始调整成堆,堆顶又成n-1个中的最大值,与这n-1个的最后一个交换,如此反复,即可得到有序序列。
  利用大根堆进行排序算法步骤:
 (1)初始建堆。将n个待排序记录存储的一维数组看作一个完全二叉树上节点自顶向下自左自右的排列,最后一个非叶结点是第n/2个,从第n/2个节点开始,依次将第n/2个,第n/2-1个节点,......,第2个,第1 个节点,作为当前节点,按照大根堆定义逐一检查以其为根的子树是否构成大根堆。最大者在堆顶。
 (2)移走堆顶,将它与待排序中最后一个交换,将剩余记录再调整成堆。这样找到次大关键字。
 (3)重复(2),直到堆中只有一个记录为止(n-1趟排序)。
 顺序表中存放的就是从小到大的有序排列。
3、筛选法建堆:
由于其左右孩子作为根的子树均为堆,只需检查该节点:
取其左右孩子中较大者与其进行比较:
(1)若较大者不大于临时结构变量中关键字,则临时结构变量赋给较大者双亲,算法调整结束
(2)若较大者大于临时结构变量中关键字,则将较大者上移,再取上移者原左右孩子中较大者,重复(1)(2),或较大者再无孩子,则临时结构变量赋给较大者原所在位置,算法调整结束
           
          
          
           
          
             

4、算法分析:

堆排序的时间复杂度,主要在初始化堆过程和每次选取最大数后重新建堆的过程; 初始化建堆过程时间:O(n);堆排序的时间复杂度为:O(nlogn)

堆排序不稳定。

代码:
#include <iostream>#include <vector>using namespace std;////大根堆调整,inout[top...n-1]void adjustHeap(vector<int> &input,int top,int n){    //n为堆中元素总数    int j=2*top+1;//根节点i的左孩子    int temp=input[top];    while(j<n){        if(j<n-1&&input[j]<input[j+1])            j++;//使j指向左右孩子中较大者        if(input[j]<=temp)            break;        else{//根节点中元素与左右孩子节点中较大者交换:input[j]大时向上提升            input[top]=input[j];            top=j;            j=2*top+1;        }    }    input[top]=temp;}//堆排序,从小到大,n为堆中元素总数void heapSort(vector<int> &input,int n){    for(int i=n/2-1;i>=0;i--)//初始化堆        adjustHeap(input,i,n);    cout<<"调整后的大根堆:"<<endl;    for(int i=0;i<=input.size()-1;i++) cout<<input[i]<<' ';    cout<<endl;    for(int i=n-1;i>0;i--){        int temp=input[0];        input[0]=input[i];        input[i]=temp;        cout<<"第"<<input.size()-i<<"趟排序后,"<<endl;        for(int i=0;i<=input.size()-1;i++)            cout<<input[i]<<' ';        cout<<endl;        adjustHeap(input,0,i);        cout<<"第"<<input.size()-i<<"次排序(重新调整后),"<<"前"<<i<<"个为堆中元素"<<endl;        for(int i=0;i<=input.size()-1;i++)            cout<<input[i]<<' ';        cout<<endl;    }}int main(){    vector<int> input;    input.push_back(49);    input.push_back(38);    input.push_back(65);    input.push_back(97);    input.push_back(76);    input.push_back(13);    input.push_back(27);    input.push_back(49);    int length=input.size();    cout<<"原数组:"<<endl;    for(int i=0;i<=length-1;i++)    {        cout<<input[i]<<' ';    }    cout<<endl;    heapSort(input,length);    return 0;}
                                                                           


原创粉丝点击