慕课(10)

排序:
快速排序:

思路分析:快速排序采用双向查找的策略,每一趟选择当前所有子序列中的一个关键字作为枢纽轴,将子序列中比枢纽轴小的前移,比枢纽轴大的后移,当本趟所有子序列都被枢轴按上述规则划分完毕后将会得到新的一组更短的子序列,他们将成为下趟划分的初始序列集。

时间复杂度:最好情况(待排序列接近无序)时间复杂度为O(nlog2n),最坏情况(待排序列接近有序)时间复杂度为O(n2),平均时间复杂度为O(nlog2n)。

#include<stdio.h>
int main()
{
    int arr[1000],low=0,high,temp,i,n;
    scanf("%d",&n);
    for(i=0;i<n;i++)
        scanf("%d",&arr[i]);
        high=n-1;
    temp=arr[low];
    while(low<high)
    {
        while(low<high&&arr[high]>temp)
        {
            high--;
        }
        if(low>=high)
        {
            break;
        }
        else
        {
            arr[low]=arr[high];
        }
        while(low<high&&arr[low]<temp)
        {
            low++;
        }
        if(low>=high)
            break;
        else
        {
            arr[high]=arr[low];
        }
    }
    arr[low]=temp;
    return low;
}

关于这个快排,C语言里面有个qsort函数可以快速调用:

#include<stdio.h>
#include<stdlib.h>
int cmp(const void *a, const void *b)
{
    return *(int*)a - *(int*)b; //由小到大排序
    //return *(int *)b - *(int *)a; 由大到小排序
}
int main()
{
    int a[100];
    int i;
    for(i=0;i<10;i++)
        scanf("%d",&a[i]);
    qsort(a,10,sizeof(int),cmp);
    for(i=0;i<10;i++)
        printf("%d ",a[i]);
    return 0;
}

表排序:
表插入排序的思想: 在不进行记录的移动的情乱下,西永存储结构的有关信息的改变达到排序的目的。可以给每个记录附加一个指针域 Link,类型为整形,在插入 Ri 时,R1,R2, R3,…已经通过各种的指针域按排序码排序成一个静态链表,将记录 Ri 的排序码key于表中已经排好序的排序码从表头向右依次比较,找到 Ri 的位置,将其插入

将无序表{49,38,76,13,27}用表插入排序的方式进行排序,其过程为:

#include <stdio.h>
#include <stdlib.h>
#define SIZE 6

typedef struct 
{
    int rc;    //记录项
    int next;   //指针项,由于在数组中,所以只需要记录下一个结点所在数组位置的下标即可。
}SLNode;

typedef struct 
{
    SLNode r[SIZE];  //存储记录的链表
    int length;     //记录当前链表长度
}SLinkListType;

// 重新排列函数
void Arrange(SLinkListType *SL)
{
    // 令 p 指向当前要排列的记录
    int p = SL->r[0].next;
    for (int i=1; i<SL->length; i++) 
   {
        // 如果条件成立,证明原来的数据已经移动,需要通过不断找 next 域,找到其真正的位置
        while (p<i) 
     {
            p = SL->r[p].next;
        }
        // 找到之后,令 q 指针指向其链表的下一个记录所在的位置
        int q = SL->r[p].next;
        // 条件成立,证明需要同下标为 i 的记录进行位置交换
        if (p != i) 
     {
            SLNode t;
            t = SL->r[p];
            SL->r[p] = SL->r[i];
            SL->r[i] = t;
            // 交换完成后,该变 next 的值,便于后期遍历
            SL->r[i].next = p;
        }
        // 最后令 p 指向下一条记录
        p = q;
    }
}

int main(int argc, const char * argv[]) 
{
    SLinkListType *SL = (SLinkListType*)malloc(sizeof(SLinkListType));
    SL->length = 6;
    SL->r[0].rc = 0;
    SL->r[0].next = 4;
   
    SL->r[1].rc = 49;
    SL->r[1].next = 3;
   
    SL->r[2].rc = 38;
    SL->r[2].next = 1;
   
    SL->r[3].rc = 76;
    SL->r[3].next = 0;
   
    SL->r[4].rc = 13;
    SL->r[4].next = 5;
   
    SL->r[5].rc = 27;
    SL->r[5].next = 2;
   
    Arrange(SL);
    for (int i=1; i<6; i++) 
   {
        printf("%d ", SL->r[i].rc);
    }

    return 0;
}

基数排序:
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog®m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。

实现方法
最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。
最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。

inline void Qsort(){
    for(int i=0;i<M;++i) b[i]=0;// b[i]表示 i 这个数值出现了多少次
    for(int i=1;i<=n;i++) b[(a[i]/base)%10]++,rank[i]=0;//统计所有数当前位的数值个数
    for(int i=1;i<M;i++) b[i]+=b[i-1];//做前缀和
    for(int i=n;i>=1;i--)
        rank[b[(a[i]/base)%10]--]=a[i];//硬核排序
    for(int i=1;i<=n;i++) a[i]=rank[i];//把排好序的数赋给原数组
}

inline void sort(){
    int max=0;
    for(int i=1;i<=n;i++)
        if(a[i]>max) max=a[i]; //统计最大值,最大值的位数决定了此次基数排序需要枚举的位数
    while(max/base){//如果当前位没有大于最大数的最高位,说明排序没有完成
        Qsort();//基数排序
        base=(base<<1)+(base<<3);//枚举下一位
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值