排序之其他(归并排序,基数排序)

1. 归并排序

a. 基本思想

     ”归并”的含义是将两个或两个以上的有序表归并组合成一个新的有序表。例如: 待排序表含有n个记录,则可以看成是n个有序的子表,每个子表长度为1,然后两两归并,得到[n/2]个长度为2或1(遗留的1); 再两两归并。。。如此重复直到合并成一个长度为n的有序表为止。2-路归并排序。当然还有3路,4路。。。等
     

b. 代码
ElemType *B=(ElemType *)malloc((n+1)*sizeof(ElemType));       //辅助数组B
void Merge(ElemType A[], int low, int mid, int high){
    //表A的两段A[low....mid]和A[mid+1......high]各自有序,将它们合并成一个有序表
    for(int k=low;k<=high;k++)
        B[k]=A[k];              //将A中2段区域的元素复制到B中
        for(i=low,j=mid+1,k=i;i<=mid&&j<high;k++){
            if(B[i]<=B[j])                    //比较B的左右两段中的元素
                A[k]=B[i++];              //将较小值复制到A中
            else 
                A[k]=B[i++];
        }//for
        while(i<=mid) A[k++]=B[i++];              //若第一个表未检测完,复制
        while(j<=high) A[k++]=B[j++];             //若第二个表未检测完,复制。2个只会有一个检测完
}

void MergeSort(ElemType A[], int low, int high){
    if(low<high){
        int mid = (low+high)/2;            //中间划分2个子序列.(适用2路归并,)
        MergeSort(A,low,mid);              //对左侧子序列进行递归排序
        MergeSort(A,mid+1,high);           //对右侧子序列进行递归排序
        Merge(A,low,mid,high);             //归并
    }//if
}
c. 性能分析

     空间复杂度:O(n)
     时间复杂度:O(nlogn)
     稳定性:Merge()操作不会改变相同关键字记录的相对次序,所以2路归并是稳定的。

2. 基数排序

a. 基本思路

      采用多关键字排序思想(即基于关键字个位的大小进行排序),借助“分配”和“收集”两种操作对单逻辑关键字进行排序。基数排序又分为最高位优先(MSD)排序和最低位优先(LSD)排序

b. 实现过程

      1). 假设线性表由节点序列a0,a1,a2,…..,an-1构成,每个节点的关键字由d元组组成。在排序过程中,使用r个队列Q0,Q1,Q2,……,Qr-1。排序如下:(对i=0,1,2,…..,d-1,依次做一次“分配”和“收集”。就是一次稳定的排序过程)
       2). 分配:开始时,把Q0, Q1, ….. , Qr-1各个队列置成空队列,然后考察线性表中的每一个结点aj(j=0,1, ….. ,n-1),如果aj的关键字kj=k,就把aj放入Qk队列中
       3). 收集:把Q0,Q1,…..,Qr-1各个队列中的节点依次首尾相接,得到新的结点序列,从而组成新的线性表。

其实应该是0,1,…,9依次排开说明更好。有个更好的图解https://blog.csdn.net/qq_35820702/article/details/52975231

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>

//初始化一个队列
LINK_SORT *init_queue()   
{
    LINK_SORT *p = (LINK_SORT *)malloc(sizeof(LINK_SORT));
    assert(p != NULL);
    p->data = 0;
    p->next = NULL;
    return p;
}
//销毁队列
bool destory_queue(LINK_SORT *phead)  
{
    if (phead == NULL)
    {
        return false;
    }

    LINK_SORT *p = phead->next;
    //释放队列中的元素
    while (p != NULL)
    {
        phead->next = p->next;
        free(p);
        p = phead->next;
    }

    free(phead);     //释放头结点
    return true;
}

//申请一个结点
static LINK_SORT *alloc_node(elem_type e)
{
    LINK_SORT *tmp = (LINK_SORT *)malloc(sizeof(LINK_SORT));
    assert(tmp != NULL);

    tmp->data = e;
    tmp->next = NULL;

    return tmp;
}

//判断队列是否为空
bool is_empty(LINK_SORT *phead)
{
    if (phead == NULL)
    {
        return false;
    }
    return phead->next == NULL;
}

//查看队列中的第一个元素,只是查看,并不出队列
bool get_head(LINK_SORT *phead, elem_type *e)
{
    if (phead == NULL)
    {
        return false;
    }
    *e = phead->next->data;
    return true;
}

//入队列
bool push(LINK_SORT *phead, elem_type e)
{
    if (phead == NULL)
    {
        return false;
    }

    LINK_SORT *p = phead;
    LINK_SORT *tmp = alloc_node(e);
    while(p->next != NULL)
    {
        p = p->next;
    }

    p->next = tmp;

    return true;

}

//出队列
bool pop(LINK_SORT *phead, elem_type *e)
{
    if (phead == NULL || is_empty(phead))
    {
        return false;
    }

    LINK_SORT *p = phead->next;

    phead->next = p->next;
    *e = p->data;
    free(p);
    return true;
}

//计算数组中最大元素的位数
int get_base(int *arr,int len)
{
    int max = arr[0];
    //求数组中的最大元素
    for (int i=1;i<len;i++)
    {
        if (max < arr[i])
        {
            max = arr[i];
        }
    }
    int count = 0;

    // 计算最大元素的位数
    while(max != 0)
    {
        max /= 10;
        count++;
    }
    return count;
}

//排序
void base_sort(int *arr, int len, int base,int radix)
{
    LINK_SORT **bucket = (LINK_SORT **)malloc(sizeof(LINK_SORT *) * radix);//二级指针用来保存队列的地址
    assert(bucket != NULL);

    for (int i = 0;i<len;i++)
    {
        bucket[i] = init_queue();//以待排序数组的长度为标准初始化队列
    }

    for (int i = 0;i<base;i++)//遍历每个元素的每一位
    {
        for (int j = 0;j<len;j++)
        {
            //将数组中的元素逐一放进它第base位所对应的队列中
            push(bucket[(arr[j]/(int)pow((double)radix,i))%radix],arr[j]);
        }
        int k = 0;

        for (int j = 0;j<len;j++)
        {
            while(!is_empty(bucket[j]))//当队列不为空时,出队列,并继续放到数组中
            {
                pop(bucket[j],&arr[k]); 
                k++;

            }
        }
    }
    for (int i = 0;i<len;i++)
    {
        destory_queue(bucket[i]);
    }
    free(bucket);
} 
int main()
{
    int arr[] = {278,109,63,930,589,184,505,269,8,83};
    int len = sizeof(arr)/sizeof(arr[0]);
    int base = get_base(arr,len);
    int radix = 10;
    base_sort(arr, len, base,radix);
    for (int i=0;i<len;i++)
    {
        printf("%d ",arr[i]);
    }
    printf("\n");
    return 0;
}
c. 性能分析

     空间效率O(r)。r个队列用来排序
     时间复杂度: d趟分配和收集,分配O(n),收集O(r)。O(d(n+r))
     稳定性:是稳定的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值