数组在链表中的基数排序(个人详解)

#include <stdio.h>
#include <malloc.h>
typedef struct Node
{
    int key;
    int value;
    struct Node *next;
}HashNode;

typedef struct a
{
    HashNode **bucket;
    int size;
}HashTable;

void chu_shi_hua(HashTable *table,int size)
{
    table->size = size;
    table->bucket = (HashNode**)malloc(size * sizeof(HashNode*));
    for(int i=0;i<size;i++)
    {
        table->bucket[i]=NULL;
    }
}

int add(HashTable *table,int key,int value)
{
    HashNode *p=(HashNode*)malloc(sizeof(HashNode));
    p->next=NULL;
    p->value=value;   
    HashNode *q=NULL;
    int index = key; //这里略改,因为在基数排序中已经把key赋予了新的值了 
    if(table->bucket[index]==NULL)
    {
        table->bucket[index]=p;
    }
    else
    {
        q=table->bucket[index];
        while(q->next!=NULL)
        {
            q=q->next;
        }
        q->next=p;
    }
    return 1;
}
//以上都是与哈希存储有关的链表步骤。 
//博主有详细解释,可以去博主主页看一下。 
//搜索“哈希存储,拉链法”即可 


//下面对链表的基数排序进行解释
//先了解它的运行方式和目标;
// 总的方向来说,就是先定义一个数组,
//然后将这个数组的所有元素用取余和除法的方法首先取出他们的个位,
//以它们的个位为key依次赋值给链表,重新把各元素  以各元素的个位的大小 进行在链表中排序 
//排序完之后再重新赋值给数组 
//到这里就是第一次循环 :以各元素的个位数值大小对各元素进行排序 

//第二次循环开始
//再用取余和除法的方法取出各元素的十位
// 以它们的十位为key依次赋值给链表,重新把各元素  以各元素的十位的大小 进行在链表中排序 
//排序完之后再重新赋值给数组 
//到这里就是第二次循环 :以各元素的十位数值大小对各元素进行排序 

//如果数组中最大值有n位数,它就会这样循环n次  

//总的来说方向就是先定义一个数组并且对它初始化,然后分别取出它们的个位十位百位等等。
//以个十百位依次作为数据要存放的位置,把数据传给链表(在传的过程中就已经排序了)
//把排好序的链表中的所有的数据再传给数组,然后再这样传给链表,这样循环就能达到基数排序的效果
//其实吧 它就是把数据在数组和链表之间来回倒腾  
 
//这个代码中有两个难点,一个是设计除法和取余的代码,一个是链表传值给数组.(因为数组传值给链表就用上面的add方法就行了) 

//下面正式开始编程 
void chuan_zhi(HashTable *table,int data[])//传值:这里是链表传给数组 
{
    HashNode *p=NULL,*q=NULL;//一个用来储存和赋值,一个用来释放空间 
    int i=0,k=0; 
    for(i=0;i<table->size;i++)//要把链表里所有的值传给数组 
    {
    
        p=table->bucket[i];         //用指针p指向 链表的值的具体位置 
        while(p!=NULL)     //根据拉链法知,链表的每一个下标所代表的地址都可能储存多个值(即链条),
                            //所以要边遍历,边传值。即p=p->next 
        {
            q=p;           //每次循环把p赋值给data之后他就没有用了,只能到下一步重新给p赋值,那么p的空间就多出来了
                            //这里用q=p,free(q)就相当于把已经传值给数组的数据在链表中释放了 
            data[k]=p->value;   //传值传的是各元素值,不是传各元素个十百位的值 
            k++;                //k代表的是数组的下标,k从0开始 
            p=p->next;         
            free(q);             //free释放空间 
        }
        table->bucket[i]=NULL;  //因为要多次重新赋值给这个链表,所以在传值结束后,赋予其NULL,使得链表回到空值的状态 
                                //以便下一次循环重新赋值 
    }
}

void output(int data[],int n)
{                                //这里就是简单的打印数组的函数(略过) 
    printf("\n");
    for(int i=0;i<n;i++)
    {
        printf("%5d",data[i]);
    }
    printf("\n");
}

void ji_pai(int data[],int n)//开始基数排序 
{
    HashTable table;         //先定义一个链表指针 
    chu_shi_hua(&table,10);   //对其进行初始化 
    int key;                 //这个用来表示数组各元素依次循环的个位,十位,百位等等 
    int k1=10,k=1;           //注意:这里是设计除法和取余的代码的开始 
    int max=data[0];          //找到这个数组的最大值,目的就是看这个最大值有几位 
    for(int k=0;k<n;k++)    
        if(data[k]>max)  max=data[k]; 
    while(max>0) // 如果数组中最大值有n位数,它就会这样循环n次  
    {
        for(int i=0;i<n;i++)
        {
            key = data[i]%k1/k;//找出各元素的个位,然后十位,然后百位....... 
            add(&table,key,data[i]);//以个位为例,这里就是以个位为key,把元素储存在这个key的后面,
                                    //这样循环操作就实现了以各元素的个位对其进行排序 
        }
    chuan_zhi(&table,data); //把在链表中排序好的所有元素按顺序再赋值给数组 
    output(data,n);       //每次输出元素 
    k1=k1*10;          //这里尤其重要★★★★★★ 
    k=k*10;                //★★★★★★★
    max=max/10;       //while循环条件 
    }
}

int main()
{
    int n =5;      //对数组定义和初始化 
    int data[n];
    data[0]=56;
    data[1]=244;
    data[2]=45;
    data[3]=2;
    data[4]=18;
    ji_pai(data,n); //用链表对其排序并输出 
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值