基数排序详解

基数排序

写在前头(〃‘▽’〃)

在这里插入图片描述
基数排序时桶排序的一种推广(桶排序详解),它所考虑的待排记录包含不止一个关键字。例如对一副牌进行整理,可将每张牌看做一个记录,包含两个关键字:花色、面值。一副理顺的牌是按如下顺序进行排放的:
在这里插入图片描述
可见一个有序结果是先按花色划分成四大块,每一块中有按面值大小排序。这是“花色”就是一张牌的“最主位关键字”,而“面值”是“最次位关键字”。
对于一般有K个关键字的情况,基数排序通常有两种方法:

  • 主位优先法(MOst Significant Digit Sort,简称MST)
    在这里插入图片描述
  • 次位优先法(Least Significant Digit Sort,简称LST)
    在这里插入图片描述

从上述例子可见,两种方法具有不同的特点:

  • 主位优先法基本是分而治之的思路,将序列分割成子序列后,分别排序再合并结果;
  • 次位优先法是将“排序”过程分解成了“分配”和“收集”这两个相对简单的步骤,并不需要分割子序列并排序,因此一般情况下次位优先法的效率更高一些。

更棒的栗子٩(๑>◡<๑)۶
  • 对于待排序列A[] = {83, 8, 269, 505, 184, 589, 930, 63, 109, 278},先倒着存进一个list中
  • 以数的位作为基数,利用次位优先法,第一趟按照个位搬来10个Buckets,相应元素丢桶;第二趟按照十位搬来10个Buckets,相应元素丢桶;第三趟按照百位搬来10个Buckets,相应元素丢桶,丢丢丢~~
  • 只需要收集最后一趟的排序结果,就得到最终的排序结果啦(。◕ˇ∀ˇ◕)
    在这里插入图片描述
    在这里插入图片描述

可食用的代码(参考)ヾ(๑╹◡╹)ノ"
#include <stdio.h>
#include <stdlib.h>
/*-----------LSD次位优先----------*/
/*假设元素最多有MaxDigit个关键字,每趟桶的个数相同*/
#define BucketSize 10  //每趟桶的个数
#define MaxDigit 4
typedef int ElementType;
typedef struct Node *PNode;
struct Node{//桶元素结点
   ElementType Data;
   PNode next;
};
struct HNode{//桶头结点
   PNode head, last;
};
typedef struct HNode Bucket[BucketSize];
void PrintBucket(PNode Blist);//打印当前桶内的元素
int GetDigit(int X, int D);//获得元素X所对应的桶的下标
void RadixSort(ElementType A[], int N);//核心排序函数

int GetDigit(int X, int D)
//获得桶的下标
{
   int index;
   for (int i = 1; i <= D; i++){
       index = X % BucketSize;
       X /= BucketSize;
   }
   return index;
}
void RadixSort(ElementType A[], int N)
//统一函数接口
{   
   Bucket B;
   int i, j, k, index;
   PNode list = NULL;
   //将数组A[]倒入链表list中,逆着倒
   for (i = 0; i < N; i++){
       PNode temp = (PNode)malloc(sizeof(struct Node));
       temp->Data = A[i];
       temp->next = list;
       list = temp;//list即为序列链表的头结点
   }
   for (i = 1; i < MaxDigit; i++){
       //初始化桶头结点
       for (j = 0; j < BucketSize; j++)
           B[j].head = B[j].last = NULL;
       //待排序列在链表list中,头结点为list
       //下面开始丢桶
       while (list){
           index = GetDigit(list->Data, i);//获得A[j]对应的桶下标
           //不能破坏原序列链表list,因此需要过渡结点tmp
           PNode tmp = list;
           list = list->next;
           tmp->next = NULL;
           if (B[index].head == NULL)
               B[index].head = B[index].last = tmp;
           else{
               B[index].last->next = tmp;
               B[index].last = tmp;
           }
       }
       //打印此时每个桶内的元素
       printf("---------pass_%d-------\n", i);
       for (k = 0; k < BucketSize; k++){
           printf("Bucket[%d] : ", k);
           PrintBucket(B[k].head);
       }
       //下面开始收集,即将每条桶链表按照顺序连接起来,倒回list中
       //同样需要逆着倒
       list = NULL;
       for (k = BucketSize - 1; k >= 0; k--){
           if (B[k].head){
               B[k].last->next = list;
               list = B[k].head;
               B[k].head = B[k].last = NULL;//清空桶
           }
       }
       //打印当前序列list
       PNode tmp = list;
       while (tmp){
           printf("%d ",tmp->Data);
           tmp = tmp->next;
       }
       printf("\n");
       
   }
   //将list倒回A[]中并释放空间
   for (int i = 0; i< N; i++){
       PNode tmp = list;
       list = list->next;
       A[i] = tmp->Data;
       free(tmp);
   }  
}

void PrintBucket(PNode Blist)
//打印当前桶内元素
{
   if (Blist == NULL);
   else{
       while (Blist){
           printf("%d ", Blist->Data);
           Blist = Blist->next;
       }
   }
   printf("\n");
}

int main(int argc, char const *argv[])
{
   ElementType A[] = {83, 8, 269, 505, 184, 589, 930, 63, 109, 278};
   RadixSort(A, 10);
   printf("------result-------\n");
   for (int i = 0; i < 10; i++){
       if (i == 9)
           printf("%d\n",A[i]);
       else
           printf("%d ",A[i]);
   }
   system("pause");
   return 0;
}

在这里插入图片描述


Reference

数据结构学习笔记排序 (快速,计数排序,表排序,桶排序,基数排序)
数据结构学习视频面试中的排序算法总结
基数排序与桶排序,计数排序【详解】

未完待续(因为MST还没写……༼༎ຶᴗ༎ຶ༽)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xuuyann

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值