• 数据结构-排序-桶排序


                                数据结构-排序-桶排序


    先看下桶排序的基本思想

    假定排序的值都在0~m-1之间,设置m个桶,依次把值为i的记录分配到第i个桶中,然后把个个桶的记录依次收集起来。

    首先上下结构图

    下标 key next
    0 3(1) 1
    1 5(1) 2
    2 3(2) 3
    3 1 4
    4 5(2) 5
    5 6 6
    6 3(3) -1

    这就是我们用静态链表存储待的排序记录,我们会让first指向下标为0的地方,只要next不为-1就接着遍历。

    初始化代码如下

    struct Node
    {
        int key;
        int next;//记录下一个键值在数组中的下标
    };
    //传入参数Node r[],n  这里其实是默认了node数组里面key值已经存在
    for(int i=0;i<n;i++)
    {
        r[i].next=i+1;
    }
    r[n-1].next=-1;//设置最后一个的next为-1
    first=0;

     


     

    然后我们会传入某个值,比如这里最大的数为6,我们传个7或者8差不多偏大点的数字作为桶的个数。这里假设传m个

    然后构造m个队列,为了存储以后相同的元素。

    构造队列如下:

    struct QueueNode//定义静态链队列存储桶
    {
       int front;
       int rear;
    };
    
    //然后申明一组数组就行,m将是我们传入的参数
       QueueNode q[m];//初始化m个静态队列
        for(int i=0;i<m;i++)

    q[i].front=q[i].rear=-1;

    我们现在要把序列传入,然后分配

    先放图   1图是待排序  2图是排序队列

    下标 key next
    0 3 1
    1 2 2
    2 3 -1

     

    下标 front rear
    0 -1  -1
    1 -1 -1
    2 1 1
    3 0 2
    4 -1 -1

     

    遍历下标0的时候发现key=3,我们就去排序队列下标3的地方把front和rear都设为0,就相当于吧下标入队

    然后遍历到下标2时候,发现key又=3我们就找到排序组的rear,这个rear的作用可以看作保存了上一次的入队的值在待排序组的下标

    然后我门找到待排序组中这个数,怎么获取就是通过  ----- 待排序组【排序组【当前key值】.rear】里面的排序组【当前key值】.rear就是获取上次入队的下标。

    然后我们只需要------待排序组【排序组【当前key值】.rear】=当前遍历下标就行了

    排序后我们观察待排序图就是这样

    下标 key next
    0 3 2
    1 2 -1
    2 3 -1

    注意这里的下标0的next就变成了2,下标2中正好是3

     

     

     

    代码如下

    //分配算法
    void Distribute(Node r[],int n,QueueNode q[],m,int first)
    {
        int i=first;//first为静态链表的头指针,从下标0开始存放待排序序列。
        while(r[i].next!=-1)//遍历待排序组
        {
            int k=r[i].key;         //获取key值
            if(q[k].front==-1)q[k].front=i;//处理队列为空,则把待排序的下标插入队列的front
            else r[q[k].rear].next=i;//假如改队列不为空就把待排序队列上个同值的next标记为下当前的i值
            q[k].rear=i;    //修改队尾指针
            i=r[i].next;    //i后移动,处理下一个记录
        }
    }

    接下来是收集操作就是把已经排序好的队列首位相连接

    我们同样还是用上面那323的简单例子,一步步将

    这是我们的原料,我们则么把队列都连起来呢?

    首先我们看右边图,我们先找到不为空的序列,很简单判断front是不是-1就行了

    然后遍历到2,找到front=1,发现next=-1说明没有下一个同样的值了,这时候我们已经遍历完一个队列,我们为了可以让这个队列的下一个可以接上,我们设个last保存当前下标

    也就是1,然后我们接着遍历排序组,到了3,front!=-1,我们就把  ----待排序组[last].next=排序组[当前下标].front这样就首位相连了,然后再保存当前的rear的值到last继续下一个首尾相连

    //收集算法
    void collect(Node r[],int n,QueueNode q[],int m,int first)
    {
        int k=0;
        while(q[k].front!=-1)//找非空队列
                k++;
        first=q[k].front;//获取第一个非空的排序组的front
        int last=q[k].rear; //获取第一个非空的排序组的rear
        while(k<m)//遍历排序组每一个队列
        {
            k++;      
            if(q[k].front!=-1)           //如果队列不为空
            {
                r[last].next=q[k].front;        //q[k].font是第一个入队的下标,也就是待排序中第一个出现这个值的下标
                                                                    //r[last]是待排序中最后一个出现这个值的位置,把它的next指向第一个入队的下标
                last=q[k].rear;                         //q[k].rear的值表示待排序组中最后一次出现k值的下标
            }
        }
        r[last].next=-1;//待排序 最后一个设为-1
    }

    全部代码如下:

    #include<iostream>
    using namespace std;
    struct Node
    {
        int key;
        int next;//记录下一个键值在数组中的下标
    };
    
    struct QueueNode//定义静态链队列存储桶
    {
       int front;
       int rear;
    };
    //分配算法
    void Distribute(Node r[],int n,QueueNode q[],int m,int first)
    {
        int i=first;//first为静态链表的头指针,从下标0开始存放待排序序列。
        while(r[i].next!=-1)//遍历待排序组
        {
            int k=r[i].key;         //获取key值
            if(q[k].front==-1)q[k].front=i;//处理队列为空,则把待排序的下标插入队列的front
            else r[q[k].rear].next=i;//假如改队列不为空就把待排序队列上个同值的next标记为下当前的i值
            q[k].rear=i;    //修改队尾指针
            i=r[i].next;    //i后移动,处理下一个记录
        }
    }
    //收集算法
    void collect(Node r[],int n,QueueNode q[],int m,int first)
    {
        int k=0;
        while(q[k].front!=-1)//找非空队列
                k++;
        first=q[k].front;//获取第一个非空的排序组的front
        int last=q[k].rear; //获取第一个非空的排序组的rear
        while(k<m)//遍历排序组每一个队列
        {
            k++;      
            if(q[k].front!=-1)           //如果队列不为空
            {
                r[last].next=q[k].front;        //q[k].font是第一个入队的下标,也就是待排序中第一个出现这个值的下标
                                                                    //r[last]是待排序中最后一个出现这个值的位置,把它的next指向第一个入队的下标
                last=q[k].rear;                         //q[k].rear的值表示待排序组中最后一次出现k值的下标
            }
        }
        r[last].next=-1;//待排序 最后一个设为-1
    }
    
    //桶排序算法
    void BucketSocket(Node r[],int n, int m)
    {
        for(int i=0;i<n;i++)    //初始化静态链表
            r[i].next=i+1;
        r[n-1].next=-1;
        int first=0;
        QueueNode q[m];//初始化m个静态队列
        for(int i=0;i<m;i++)
            q[i].front=q[i].rear=-1;
        Distribute(r,n,q,m,first);      //分配
        collect(r,n,q,m,first);             //收集
        
    }

     

     

     

     

  • 相关阅读:
    Win10 注册IIs4.0的解决方案
    Win10 注册IIs4.0的解决方案
    Methods for Using Message Queuing Telemetry Transport for Sensor Networks to Support Sleeping Devices
    Win10 注册IIs4.0的解决方案
    真正聪明的人,为什么从不去社交?
    真正聪明的人,为什么从不去社交?
    真正聪明的人,为什么从不去社交?
    真正聪明的人,为什么从不去社交?
    真正聪明的人,为什么从不去社交?
    真正聪明的人,为什么从不去社交?
  • 原文地址:https://www.cnblogs.com/DJC-BLOG/p/9096390.html
Copyright © 2020-2023  润新知