数据结构 排序 基数排序

 

    基数排序是一种借助多关键字排序思想对单关键字进行排序的方法,它是借助“分配”和“收集”2种操作对单关键字进行排序的。

链式基数排序程序:

c1.h

  /* c1.h (程序名) */
 #include
< string .h >
 #include
< ctype.h >
 #include
< malloc.h >   /* malloc()等 */
 #include
< limits.h >   /* INT_MAX等 */
 #include
< stdio.h >   /* EOF(=^Z或F6),NULL */
 #include
< stdlib.h >   /* atoi() */
 #include
< io.h >   /* eof() */
 #include
< math.h >   /* floor(),ceil(),abs() */
 #include
< process.h >   /* exit() */
 
/* 函数结果状态代码 */
 
#define  TRUE 1
 
#define  FALSE 0
 
#define  OK 1
 
#define  ERROR 0
 
#define  INFEASIBLE -1
 
/* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */
 typedef 
int  Status;  /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
 typedef 
int  Boolean;  /* Boolean是布尔类型,其值是TRUE或FALSE */

c10-3.h

  /* c10-3.h 基数排序的数据类型 */
 
#define  MAX_NUM_OF_KEY 8 /* 关键字项数的最大值 */
 
#define  RADIX 10 /* 关键字基数,此时是十进制整数的基数 */
 
#define  MAX_SPACE 1000
 typedef 
struct
 
{
   KeysType keys[MAX_NUM_OF_KEY]; 
/* 关键字 */
   InfoType otheritems; 
/* 其它数据项 */
   
int next;
 }
SLCell;  /* 静态链表的结点类型 */

 typedef 
struct
 
{
   SLCell r[MAX_SPACE]; 
/* 静态链表的可利用空间,r[0]为头结点 */
   
int keynum; /* 记录的当前关键字个数 */
   
int recnum; /*  静态链表的当前长度 */
 }
SLList;  /* 静态链表类型 */

 typedef 
int  ArrType[RADIX];  /* 指针数组类型 */

源文件:

  /* alg10-11.c 链式基数排序 */
 typedef 
int  InfoType;  /* 定义其它数据项的类型 */
 typedef 
int  KeyType;  /* 定义RedType类型的关键字为整型 */
 typedef 
struct
 
{
   KeyType key; 
/* 关键字项 */
   InfoType otherinfo; 
/* 其它数据项 */
 }
RedType;  /* 记录类型(同c10-1.h) */
 typedef 
char  KeysType;  /* 定义关键字类型为字符型 */
 #include
" c1.h "
 #include
" c10-3.h "
 
void  InitList(SLList  * L,RedType D[], int  n)
 
/* 初始化静态链表L(把数组D中的数据存于L中) */
   
char c[MAX_NUM_OF_KEY],c1[MAX_NUM_OF_KEY];
   
int i,j,max=D[0].key; /* max为关键字的最大值 */
   
for(i=1;i<n;i++)
     
if(max<D[i].key)
       max
=D[i].key;
   (
*L).keynum=(int)(ceil(log10(max)));
   (
*L).recnum=n;
   
for(i=1;i<=n;i++)
   
{
     (
*L).r[i].otheritems=D[i-1].otherinfo;
     itoa(D[i
-1].key,c,10); /* 将10进制整型转化为字符型,存入c */
     
for(j=strlen(c);j<(*L).keynum;j++/* 若c的长度<max的位数,在c前补'0' */
     
{
       strcpy(c1,
"0");
       strcat(c1,c);
       strcpy(c,c1);
     }

     
for(j=0;j<(*L).keynum;j++)
       (
*L).r[i].keys[j]=c[(*L).keynum-1-j];
   }

 }


 
int  ord( char  c)
 
/* 返回k的映射(个位整数) */
   
return c-'0';
 }


 
void  Distribute(SLCell r[], int  i,ArrType f,ArrType e)  /* 算法10.15 */
 
/* 静态键表L的r域中记录已按(keys[0],...,keys[i-1])有序。本算法按 */
   
/* 第i个关键字keys[i]建立RADIX个子表,使同一子表中记录的keys[i]相同。 */
   
/* f[0..RADIX-1]和e[0..RADIX-1]分别指向各子表中第一个和最后一个记录 */
   
int j,p;
   
for(j=0;j<RADIX;++j)
     f[j]
=0/* 各子表初始化为空表 */
   
for(p=r[0].next;p;p=r[p].next)
   
{
     j
=ord(r[p].keys[i]); /* ord将记录中第i个关键字映射到[0..RADIX-1] */
     
if(!f[j])
       f[j]
=p;
     
else
       r[e[j]].next
=p;
     e[j]
=p; /* 将p所指的结点插入第j个子表中 */
   }

 }


 
int  succ( int  i)
 
/* 求后继函数 */
   
return ++i;
 }


 
void  Collect(SLCell r[],ArrType f,ArrType e)
 
/* 本算法按keys[i]自小至大地将f[0..RADIX-1]所指各子表依次链接成 */
   
/* 一个链表,e[0..RADIX-1]为各子表的尾指针。算法10.16 */
   
int j,t;
   
for(j=0;!f[j];j=succ(j)); /* 找第一个非空子表,succ为求后继函数 */
   r[
0].next=f[j];
   t
=e[j]; /* r[0].next指向第一个非空子表中第一个结点 */
   
while(j<RADIX-1)
   
{
     
for(j=succ(j);j<RADIX-1&&!f[j];j=succ(j)); /* 找下一个非空子表 */
     
if(f[j])
     
/* 链接两个非空子表 */
       r[t].next
=f[j];
       t
=e[j];
     }

   }

   r[t].next
=0/* t指向最后一个非空子表中的最后一个结点 */
 }


 
void  printl(SLList L)
 
/* 按链表输出静态链表 */
   
int i=L.r[0].next,j;
   
while(i)
   
{
     
for(j=L.keynum-1;j>=0;j--)
       printf(
"%c",L.r[i].keys[j]);
     printf(
" ");
     i
=L.r[i].next;
   }

 }


 
void  RadixSort(SLList  * L)
 
/* L是采用静态链表表示的顺序表。对L作基数排序,使得L成为按关键字 */
   
/* 自小到大的有序静态链表,L.r[0]为头结点。算法10.17 */
   
int i;
   ArrType f,e;
   
for(i=0;i<(*L).recnum;++i)
     (
*L).r[i].next=i+1;
   (
*L).r[(*L).recnum].next=0/* 将L改造为静态链表 */
   
for(i=0;i<(*L).keynum;++i)
   
/* 按最低位优先依次对各关键字进行分配和收集 */
     Distribute((
*L).r,i,f,e); /* 第i趟分配 */
     Collect((
*L).r,f,e); /* 第i趟收集 */
     printf(
"第%d趟收集后: ",i+1);
     printl(
*L);
     printf(
" ");
   }

 }


 
void  print(SLList L)
 
/* 按数组序号输出静态链表 */
   
int i,j;
   printf(
"keynum=%d recnum=%d ",L.keynum,L.recnum);
   
for(i=1;i<=L.recnum;i++)
   
{
     printf(
"keys=");
     
for(j=L.keynum-1;j>=0;j--)
       printf(
"%c",L.r[i].keys[j]);
     printf(
" otheritems=%d next=%d ",L.r[i].otheritems,L.r[i].next);
   }

 }


 
void  Sort(SLList L, int  adr[])  /* 改此句(类型) */
 
/* 求得adr[1..L.length],adr[i]为静态链表L的第i个最小记录的序号 */
   
int i=1,p=L.r[0].next;
   
while(p)
   
{
     adr[i
++]=p;
     p
=L.r[p].next;
   }

 }


 
void  Rearrange(SLList  * L, int  adr[])  /* 改此句(类型) */
 
/* adr给出静态链表L的有序次序,即L.r[adr[i]]是第i小的记录。 */
   
/* 本算法按adr重排L.r,使其有序。算法10.18(L的类型有变) */
   
int i,j,k;
   
for(i=1;i<(*L).recnum;++i) /* 改此句(类型) */
     
if(adr[i]!=i)
     
{
       j
=i;
       (
*L).r[0]=(*L).r[i]; /* 暂存记录(*L).r[i] */
       
while(adr[j]!=i)
       
/* 调整(*L).r[adr[j]]的记录到位直到adr[j]=i为止 */
         k
=adr[j];
         (
*L).r[j]=(*L).r[k];
         adr[j]
=j;
         j
=k; /* 记录按序到位 */
       }

       (
*L).r[j]=(*L).r[0];
       adr[j]
=j;
     }

 }


 
#define  N 10
 
void  main()
 
{
   RedType d[N]
={{278,1},{109,2},{63,3},{930,4},{589,5},{184,6},{505,7},{269,8},{8,9},{83,10}};
   SLList l;
   
int *adr;
   InitList(
&l,d,N);
   printf(
"排序前(next域还没赋值): ");
   print(l);
   RadixSort(
&l);
   printf(
"排序后(静态链表): ");
   print(l);
   adr
=(int*)malloc((l.recnum)*sizeof(int));
   Sort(l,adr);
   Rearrange(
&l,adr);
   printf(
"排序后(重排记录): ");
   print(l);
 }

程序执行结果如下:

排序前(next域还没赋值):
keynum
= 3  recnum = 10
keys
= 278  otheritems = 1  next =- 858993460
keys
= 109  otheritems = 2  next =- 858993460
keys
= 063  otheritems = 3  next =- 858993460
keys
= 930  otheritems = 4  next =- 858993460
keys
= 589  otheritems = 5  next =- 858993460
keys
= 184  otheritems = 6  next =- 858993460
keys
= 505  otheritems = 7  next =- 858993460
keys
= 269  otheritems = 8  next =- 858993460
keys
= 008  otheritems = 9  next =- 858993460
keys
= 083  otheritems = 10  next =- 858993460
第1趟收集后:
930   063   083   184   505   278   008   109   589   269
第2趟收集后:
505   008   109   930   063   269   278   083   184   589
第3趟收集后:
008   063   083   109   184   269   278   505   589   930
排序后(静态链表):
keynum
= 3  recnum = 10
keys
= 278  otheritems = 1  next = 7
keys
= 109  otheritems = 2  next = 6
keys
= 063  otheritems = 3  next = 10
keys
= 930  otheritems = 4  next = 0
keys
= 589  otheritems = 5  next = 4
keys
= 184  otheritems = 6  next = 8
keys
= 505  otheritems = 7  next = 5
keys
= 269  otheritems = 8  next = 1
keys
= 008  otheritems = 9  next = 3
keys
= 083  otheritems = 10  next = 2
排序后(重排记录):
keynum
= 3  recnum = 10
keys
= 008  otheritems = 9  next = 3
keys
= 063  otheritems = 3  next = 10
keys
= 083  otheritems = 10  next = 2
keys
= 109  otheritems = 2  next = 6
keys
= 184  otheritems = 6  next = 8
keys
= 269  otheritems = 8  next = 1
keys
= 278  otheritems = 1  next = 7
keys
= 505  otheritems = 7  next = 5
keys
= 589  otheritems = 5  next = 4
keys
= 930  otheritems = 4  next = 0
Press any key to 
continue

算法的复杂度:O(n)。

程序参考:《《数据结构》算法实现及解析》。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值