各种排序算法的实现

来源:互联网 发布:sybase数据库用户 编辑:程序博客网 时间:2024/04/19 10:22

数据类型设置

数据存储方式为顺序存储结构,待排序的一组记录存放在地址连续的一组存储单元上

typedef int KeyType;        //定义关键字类型为整数类型typedef struct{    KeyType key[MAXSIZE+1]; //key[0]闲置或用作哨兵    int length;             //顺序表长度}


插入排序

1.直接插入排序

主要思想:

将一个记录插入到已经排好序的有序表中,得到一个新的、长度加1的有序表

算法:

void InsertSort(SqList &l){    //插入排序    int i,j;    for(i=2;i<=l.length;i++)    {        if(l.key[i]<l.key[i-1])                 //待插入关键字l.key[i]比已排好序部分l.key[1...i-1]小时进行插入        {            l.key[0]=l.key[i];                  //复制哨兵            for(j=i-1;l.key[0]<l.key[j];j--)    //记录后移                l.key[j+1]=l.key[j];            l.key[j+1]=l.key[0];                //插入到正确位置        }    }}

直接插入排序容易实现,辅助空间只需一个。时间上,最好情况比较次数为n-1,不需要移动。最坏情况比较次数为(n+2)(n-1)/2,移动次数(n+4)(n-1)/2,时间复杂度为O(n²)


2.折半插入排序

主要思想:

插入排序的基本操作为在一个有序表中进行查找和插入,查找利用折半查找实现

算法:

void BInsertSort(SqList &l){    //折半插入排序    int i,j,low,high,mid;    for(i=2;i<=l.length;i++)    {        l.key[0]=l.key[i];                      //l.keyp[i]暂存到l.key[0]        low=1;        high=i-1;        while(low<=high)                        //折半查找有序插入的位置        {            mid=(low+high)/2;            if(l.key[0]<l.key[mid])                high=mid-1;            else                low=mid+1;        }        for(j=i-1;j>=high+1;j--)                //记录后移            l.key[j+1]=l.key[j];        l.key[high+1]=l.key[0];                 //插入    }}

折半插入排序辅助空间和直接插入排序形同。时间上,折半排序减少了比较次数,记录移动次数不变,时间复杂度为O(n²)


3.希尔排序

主要思想:

将整个待排序列分割成若干个子序列分别进行直接插入排序,等到整个序列整体有序时,再对全体记录进行一次直接插入排序


算法:

void ShellSort(SqList &l,int dlta[],int t){    //希尔排序    int i,j,k;    for(k=0;k<t;k++)                            //增量序列中的值没有除1之外的公因子    {                                           //最后一个增量值必须为1        int dk=dlta[k];        for(i=dk+1;i<=l.length;i++)        {            if(l.key[i]<l.key[i-dk])            //将l.key[i]插入有序增量子表,此过程为直接插入排序            {                l.key[0]=l.key[i];              //l.key[0]暂存数据                for(j=i-dk;j>0&&l.key[0]<l.key[j];j-=dk)                    l.key[j+dk]=l.key[j];                l.key[j+dk]=l.key[0];            }        }    }}

希尔排序时间效率较前两种排序方法有较大进步,时间跟所取的增量序列有关,增量序列中的的值没有除1之外的公因子,且最后一个增量值必须为1



交换排序

1.冒泡排序

主要思想:

第一趟,将关键字最大的记录安置在最后一个记录位置上;第二趟排序,将前n-1个记录中关键字最大的记录安置在第n-1个位置;以此类推

整个排序要进行k(1≤k≤n-1),当一趟排序中没有进行交换记录的操作时结束排序

算法:

void BubbleSort(SqList &l){    //冒泡排序    int i,j,temp,flag=1;    for(i=1;flag==1;i++)                //当在一趟排序中没有进行交换记录的操作时结束排序    {        flag=0;        for(j=1;j<=l.length-i;j++)        {            if(l.key[j]>l.key[j+1])            {                temp=l.key[j+1];                l.key[j+1]=l.key[j];                l.key[j]=temp;                flag=1;            }        }    }}

冒泡排序借助交换进行排序,辅助空间只需一个。时间上,最好情况进行n-1比较,不移动记录,最坏情况需要进行n-1趟排序,要进行n(n-1)/2次比较,时间复杂度为O(n²)


2.快速排序

主要思想:

取一个记录作为枢纽,通过一趟排序将待排记录分割成独立的两部分,一部分记录关键字记录小于枢纽记录,另一部分记录大于枢纽记录,继续对两部分记录进行排序


算法:

void QuickSort(SqList &l,int low,int high){    //快速排序    if(low<high)    {        int pivotloc=Partition(l,low,high);     //找出枢纽,将l.key[low...high]一分为二        QuickSort(l,low,pivotloc-1);            //对低子表递归排序        QuickSort(l,pivotloc+1,high);           //对高子表递归排序    }}int Partition(SqList &l,int low,int high){    //将枢纽移至正确位置    int pivotkey=l.key[low];                    //用第一个记录作为枢纽记录    l.key[0]=l.key[low];                        //记录枢纽关键字    while(low<high)                             //从表的两端向中间扫描    {        while(low<high&&l.key[high]>=pivotkey)            high--;        l.key[low]=l.key[high];                 //将比枢纽记录小的记录移到低端        while(low<high&&l.key[low]<=pivotkey)            low++;        l.key[high]=l.key[low];                 //将比枢纽记录大的记录移到高端    }    l.key[low]=l.key[0];    return low;                                 //返回枢纽位置}

快速排序需要一个栈空间实现递归。时间上,快速排序平均时间复杂度为O(nlogn),平均性能最好,但不稳定当序列基本有序时,蜕化为冒泡排序,时间复杂度为O(n²)


选择排序

1.简单选择排序

主要思想:

通过n-i次关键字间的比较,从n-i+1个记录中选择出关键字最小的记录,并和第i个记录交换

算法:

void SelectSort(SqList &l){    //简单选择排序    int i,j,temp,k;    for(i=1;i<=l.length;i++)    {        temp=l.key[i];        k=i;        for(j=i;j<=l.length;j++)        //选择第i小的记录        {            if(temp>l.key[j])            {                temp=l.key[j];                k=j;            }        }        if(k!=i)        {            l.key[k]=l.key[i];            l.key[i]=temp;        }    }}

简单选择排序辅助空间只需一个。时间上,比较次数为n(n-1)/2,移动次数为0-3(n-1),时间复杂度为O(n²)

2.堆排序



归并排序

主要思想:

将数组中前后相邻的两个有序序列归并为一个有序序列


算法:

void MergeSort(SqList l1,SqList &l2,int s,int t){    //归并排序    //将l1.key[s...t]归并排序为l2.key[s...t]    if(s==t)        l2.key[s]==l1.key[s];    else    {        int m=(s+t)/2;        MergeSort(l1,l1,s,m);        //递归将l1.key[s..m]归并为有序        MergeSort(l1,l1,m+1,t);      //递归将l1.key[m+1..t]归并有序        Merge(l1,l2,s,m,t);          //将l1.key[s..m]和l1.key[m+1..t]归并到l2[s..t]    }}void Merge(SqList l1,SqList &l2,int i,int m,int n){    //将有序的l1.key[i...m]和l1.key[m+1...n]归并为有序的l2.key[i..n]    int j,k;    for(j=m+1,k=i;i<=m&&j<=n;k++)    {        if(l1.key[i]<l1.key[j])            l2.key[k]=l1.key[i++];        else            l2.key[k]=l1.key[j++];    }    if(i<=m)        while(i<=m)            l2.key[k++]=l1.key[i++];    if(j<=n)        while(j<=n)            l2.key[k++]=l1.key[j++];}

归并排序是一种稳点的排序方法,辅助空间需要n个,时间复杂度为O(nlogn)



基数排序

1.简单选择排序

主要思想:

借助多关键字排序的思想对单逻辑关键字进行排序


算法:

typedef struct LNode{    KeyType data;    struct LNode *next;}LNode,*LinkList;void RadixSort(SqList &l){    //基数排序    LinkList ll[10];    for(int i=0;i<10;i++)                           //构造静态链表    {        ll[i]=(LinkList)malloc(sizeof(LNode));        ll[i]->data=0;        ll[i]->next=NULL;    }    for(int i=1;i<=MAX_NUM_OF_KEY;i++)              //按最低位优先依次对各关键字进行分配和收集    {                                               //MAX_NUM_OF_KEY为关键字的最大位数        Distribute(l,ll,i);                         //第i趟分配        Collect(l,ll);                              //第i趟收集    }}void Distribute(SqList l,LinkList *ll,int i){    int j,k;    int a[l.length+1];    for(j=1;j<=l.length;j++)                        //求各关键字的第i位上的值    {        ll[j-1]->data=0;                            //每趟分配中,初始化链表长度        a[j]=l.key[j];        for(k=1;k<=i;k++)        {            a[j]=a[j]/10;        }        a[j]=a[j]%10;    }    for(j=1;j<=l.length;j++)                        //映射到链表中    {        LinkList node;        node=(LinkList)malloc(sizeof(LNode));        node->data=l.key[j];        node->next=NULL;        int num=0;        LinkList p=ll[a[j]];        while(num++<(ll[a[j]]->data))            p=p->next;        p->next=node;        ll[a[j]]->data++;                           //链表头结点记录链表的长度    }}void Collect(SqList &l,LinkList *ll){    int i,num,k;    for(i=0,k=1;i<10;i++)                           //将各链表连接起来    {        LinkList p=ll[i];        num=0;        while(num<ll[i]->data)        {            p=p->next;            l.key[k++]=p->data;            num++;        }    }}
基数排序的辅助空间需要rd个,r为基数值,d为关键字位数。时间上,每一趟分配时间复杂度为O(n),每一趟收集时间复杂度为O(rd),时间复杂为O(d(n+rd))



各种内部排序方法的比较




参考书目:数据结构(C语言版) 严蔚敏

图片来源于网络




0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机没有返回键怎么办 手机总显示内存不足怎么办 扩音器耳麦接触不良怎么办 音响插头接触不良怎么办 华为手机耳机声音小怎么办 苹果耳机孔变形怎么办 耳机孔松了怎么办 荣耀9青春版费电怎么办 华为双清了怎么办 华为开不开机怎么办 华为手机黑屏打不开怎么办 荣耀v8指纹消失怎么办 耳机话筒进水了怎么办 beats耳机进水了怎么办 音量孔进水了怎么办 苹果手机屏幕进水了怎么办 耳机孔进水了怎么办 华为v10声音小怎么办 荣耀v10声音小怎么办 华为变耳机模式怎么办 小米六耳机模式怎么办 苹果成耳机模式怎么办 苹果调耳机模式怎么办 ipad耳机孔进水怎么办 iphone一直是耳机模式怎么办 华为耳机音质不好怎么办 苹果声音键失灵怎么办 苹果耳机不兼容怎么办 usb耳机声音小怎么办 手机不认耳机怎么办 华为手机视频无声怎么办 苹果进入耳机模式怎么办 号码丢了怎么办挂失 移动手机卡丢了怎么办 连接不上蓝牙怎么办 音响主板坏了怎么办 索尼耳机开不了怎么办 蓝牙耳机容易掉怎么办 华为耳机戴不稳怎么办 苹果蓝牙不匹配怎么办 华为手机不能开机怎么办