zoukankan      html  css  js  c++  java
  • 数据结构-排序-桶排序

                                数据结构-排序-桶排序


    先看下桶排序的基本思想

    假定排序的值都在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);             //收集
        
    }

     

     

     

     

  • 相关阅读:
    链表--判断一个链表是否为回文结构
    矩阵--“之”字形打印矩阵
    二叉树——平衡二叉树,二叉搜索树,完全二叉树
    链表--反转单向和双向链表
    codeforces 490C. Hacking Cypher 解题报告
    codeforces 490B.Queue 解题报告
    BestCoder19 1001.Alexandra and Prime Numbers(hdu 5108) 解题报告
    codeforces 488A. Giga Tower 解题报告
    codeforces 489C.Given Length and Sum of Digits... 解题报告
    codeforces 489B. BerSU Ball 解题报告
  • 原文地址:https://www.cnblogs.com/DJC-BLOG/p/9096390.html
Copyright © 2011-2022 走看看