排序2(数据结构)

4.选择排序

选择排序的基本思想就是:每一趟从待排序记录中选出关键字最小的记录,将顺序将其放在已排好序的序列的最后,知道排完为之。

4.1简单选择排序

又称直接选择排序。

就是从第一个开始,经过n-1排序,选出最小的记录。

//简单选择排序
void SelectSort(SqList &L)
{
    int i;
    for(i=0;i<L.length;i++)
    {
        k=SelectMinkey(L,i);
        if(k!=i)//需要交换两个数值,方便后续寻找
        {
            int a;
            a=L.r[i];
            L.r[i]=L.r[k];
            L.r[k]=a;
        }
    }
}
int SelectMinkey(SqList &L,int n)
{
    int min;
    int i;
    min=n;
    for(i=n;i<L.length;i++)
    {
        if(L.r[i]<L.r[min])
        {
            min=i;
        }
        
    }
    return min;//返回最小值的位置,而不是最小值
}

时间复杂度为O(n的平方)。

空间复杂度为O(1)。

算法特点:本身是中稳定的排序方法,也可用于链式存储结构,移动次数比较少,当每一记录占用空间较多时,此方法比直接插入排序快。

4.2堆排序

堆排序是一种树形选择排序,在排序过程中,将排序记录看成一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点的内在关系,在当前无序的序列中选择关键字最大(或最小)的记录。

//堆排序(操作复杂度为logn)
void HeapAdjust(SqList &L,int i,int m)//这个就是将数组变成二叉树,然后调整成大根堆或者小根堆
{
    int a;
    a=L.r[i];//保留变量
    for(j=2*i;j<=m;j*=2)//子树就是×2
    {
        if(L.r[j]<L.r[j+1])//先比较左右子树
        {
            j=j+1;
        }
        if(L.r[j]=<a)//这个就是较大的子树跟父亲结点比较
            break;
        L.r[i]=L.r[j];
        i=j;//改变初变量的位置
    }
    L.r[i]=a;
}
void HeapSort(SqList &L)//调用前面的函数
{
    int i;
    for(i=L.length/2;i>0;i--)//从最后一个结点的父亲结点开始,从下往上依次调用
    {
        HeapAdjust(L,i,L.length);
    }
    for(i=L.length;i>0;i--)
    {
        int b;
        b=L.r[i];
        L.r[i]=L.r[1];
        L.r[1]=b;//将头结点跟尾结点交换
        HeapAdjust(L,1,i-1);//因为前面只是交换了一个结点,不需要重新排列,只需将第一个结点重新排序即可
    }
}

时间复杂度堆排序在最坏的情况下,时间复杂度为O(nlogn)

实验研究表明,堆排序的平均性能接近于最坏性能

空间复杂度:O(1)

算法特点:是不稳定排序,不能用于链式存储结构,初始建堆所需的比较次数较多,因此记录数较少时不宜采用。最坏情况下,比快速排序更有优势,记录较多时较为高效。

5.归并排序

归并排序就是将两个或两个以上的有序表合并成一个有序表的过程。

//归并排序
void Merge(SqList &L,SqList &t,int low,int mid,int high)
{
    int j=0;
    for(i=low,k=mid+1;i<=mid&&k<=high;j++)
    {
        if(L.r[i]<=L.r[k])
        {
            T.r[j]=L.r[i];
            i=i+1;
        }
        if(L.r[i]>L.r[k])
        {
            T.r[j]=L.r[k];
            k=k+1;
        }
    }
    while(i<=mid)
    {
        T.r[j++]=L.r[i++];
    }
    while(k<=high)
    {
        T.r[j++]=L.r[k++];
    }
}
void MSort(SqList &L,SqList &t,int low,int high)//递归程序不太好想,就是先划分然后利用递归合并
{
    if(low==high)//递归出口
    {
        t.r[low]=L.r[low];
    }
    else{
        int m;
        SqList S;//记得先给S分配空间
        m=(low+high)/2;
        MSort(L,S,low,m);//对左边进行划分
        MSort(L,S,m+1,high);//对右边进行划分
        Merge(S,T,low,m,high);//进行逆序合并,将S合并到T里面
    }
}

写代码时先写两个有序表合成一个有序表的算法,最后再想递归。

时间复杂度:当有n个时,需要logn趟排序,每一趟关键字的比较不会超过n,移动次数都是n,所以时间复杂度为O(nlogn);

空间复杂度为:顺序表进行归并排序时,需要与待排序记录个数相等的辅助空间,为O(n)。 

算法特点:稳定排序,可用于链式存储,不需要辅助空间,但递归时需要开辟相应的工作栈。

6.基数排序

基数排序是根据关键字中各位的值,通过对待排序记录进行若干趟“分配”与“收集”来实现排序的。

有最高位优先法和最低位优先法(先从最不重要的开始排)两种。

算法一般不需要掌握,了解过程即可。

时间复杂度为:O(d(n+rd))

空间复杂度为:O(n+rd)

算法特点:是稳定排序,可用于链式结构,也可用于顺序结构,时间复杂度可突破基于关键字比较一类方法的下界,达到O(n),基数排序使用条件有严格的要求:需要知道各级关键字的主次关系和各级关键字的取值范围。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值