算法笔记九:桶排序

思路

  假设待排序的数据集,平均的分散在各个区间里(最理想的状态是每个区间有且只有一个元素),

  那么我只要将每个数据落入到响应的区间里,然后从小到大依次从区间中取出数据,即是已排序好的结果

  这里的区间,其实就是桶的概念


空间代价

    取决于放入桶中的元素的数据结构,我这里采用的是一个指向下一个元素的指针以及当前int元素,

    基本可以人物空间代价为O(n)


时间代价

    取决于每个桶中所有元素的排序算法的时间效率,教科书上TMD解释的非常复杂,看不懂,但一个基本原则就是,如果已知待排序的最大直和最小值,并且其均匀分布,则桶排序的效率还是比较乐观的,回头等这个系统全部写完了以后,会对这些方案进行一个全面的性能测试


算法实现


#ifndef __p1__BucketSort__
#define __p1__BucketSort__

#include <stdio.h>
#include <string.h>
#include <cstddef>
#include <list>
#include <math.h>

//?

//桶排序
//核心思想:
//假设待排序的数据集,平均的分散在各个区间里(最理想的状态是每个区间有且只有一个元素),
//那么我只要将每个数据落入到响应的区间里,然后从小到大依次从区间中取出数据,即是已排序好的结果
//这里的区间,其实就是桶的概念

//桶元素
typedef struct bucket_item {
    int value;//值
    struct bucket_item * next;
}BucketItem;

//桶
typedef struct bucket {
    int hasValue;// 1 表示当前位置有值
    BucketItem * head;
}Bucket;



class BucketSort {
    int _bucketSize = 100; //定义100个桶
    int _bucketRangeStep = 0;
    int needFreeItemCount = 0;//需要被free的元素的个数
    BucketItem * itemNeedToFree = NULL; //待free的元素空间
    
    
public:
    //计算给定数组的最大值和最小值
    void calculateMaxAndMinValue(int * data,int size,int * minValue,int * maxValue){
        if(size ==1){
            *(maxValue) = *data;
            *(minValue) = *data;
            return;
        }
        //size = 3
        int topIndex = (size % 2 == 0) ? size - 1  : size - 2 ,i = 0;
        for(;i <= topIndex - 1;){
            if (i == 0) {
                if (*(data + i) > *(data + i + 1)) {
                    *maxValue = *(data + i);
                    *minValue = *(data + i + 1);
                }else{
                    *maxValue = *(data + i + 1);
                    *minValue = *(data + i);
                }
            }else{
                //每两个元素只比较3次,较之每个元素比较两次(两个元素比较4次),要少一次比较
                if (*(data + i) > *(data + i + 1)) {
                    if(*(data + i) > *maxValue){
                         *maxValue = *(data + i);
                    }
                    if(*(data + i + 1) < *minValue){
                        *minValue = *(data + i + 1);
                    }
                   
                }else{
                    if(*(data + i + 1) > *maxValue){
                        *maxValue = *(data + i + 1);
                    }
                    if(*(data + i ) < *minValue){
                        *minValue = *(data + i );
                    }

                }
            }
            //跳过2个元素
            i = i + 2;
        }
        //奇数,还剩最后一个元素没比较,其只需要比较一次
        if(size % 2 != 0){
            if(*(data + size - 1) > *maxValue){
                *maxValue = *(data + size - 1);
            }else if(*(data + size - 1) < *minValue){
                *minValue = *(data + size - 1);
            }
        }
        
    }
    
    //初始化桶容器
    Bucket * initBucketContainer(int minValue,int maxValue){
        _bucketRangeStep = floorf((maxValue - minValue) / _bucketSize);
        
        Bucket *  buketContainer = new Bucket [_bucketSize];
        memset(buketContainer,'\0',sizeof(Bucket)*_bucketSize);
        
        return buketContainer;
    }
    
    //计算元素应该落在第几个桶中
    //规则是,按照最大和最小值,将元素均分为_bucketSize个分区
    int calculateBucketPosition(int data,int minValue,int maxValue){
        int position =  (data - minValue)/_bucketRangeStep;
        return position == 0 ? 0 : (position >= _bucketSize ? _bucketSize - 1 : position);
    }
    
    //将元素插入桶中
    void insertDataToBucketContainer(int data,int minValue,int maxValue,Bucket * bucketContainer){
        //计算桶的位置
        int bucketPosition = calculateBucketPosition(data,minValue,maxValue);
        //初始化桶元素  注意这里的资源应该是要被释放的哦
        BucketItem * _bucketItem = new BucketItem;
        _bucketItem->value = data;
        _bucketItem->next = NULL;
        
        //桶中没有元素
        if((bucketContainer + bucketPosition)->head == NULL){
            (bucketContainer + bucketPosition)->head = _bucketItem;
            return;
        }else{
            //桶中已经有数据了
            BucketItem * _exists_value = (bucketContainer + bucketPosition)->head;
            if (_exists_value -> value > data) {
                //第一个元素就大
                (bucketContainer + bucketPosition)->head = _bucketItem;
                _bucketItem->next = _exists_value;
            }else{
                int find = 0;
                while (_exists_value ->next != NULL) {
                    if (_exists_value ->next -> value > data) {
                        _bucketItem->next = _exists_value -> next;
                        _exists_value -> next = _bucketItem;
                        find = 1;
                        break;
                    }else{
                        _exists_value = _exists_value -> next;
                    }
                }
                if(find == 0){
                    //所有都比带插入的数据小,那么,就插到末尾吧
                    _exists_value ->next = _bucketItem;
                }
            }
            
            
        }
    }
    
    //将桶中的元素,依次取出,放入原数组中,记得同时释放桶中的元素
    void getOutItems(Bucket * bucketContainer,int * data){
        int j = 0;
        for(int i = 0;i < _bucketSize; i++){
            BucketItem * _bucketItem = (bucketContainer + i)->head;
            while (_bucketItem != NULL) {
                *(data + j) = _bucketItem->value;
                j++;
                BucketItem * _tmp_bucketItem = _bucketItem;
                _bucketItem = _bucketItem -> next;
                //释放资源
                delete _tmp_bucketItem;
            }
        }
        //释放资源
        delete [] bucketContainer;
    }
    
    
    
    //排序入口
    int * do_sorting(int * data,int size){
        int  _minValue = 0, _maxValue = 0;
        //计算最大最小值,给桶分区的计算提供参考
        calculateMaxAndMinValue(data,size,&_minValue,&_maxValue);
        //初始化桶
        Bucket * _bucket = initBucketContainer(_minValue,_maxValue);
        //将元素依次插入桶中
        for(int i = 0; i < size; i++){
            insertDataToBucketContainer(*(data + i),_minValue,_maxValue,_bucket);
        }
        //取出元素
        getOutItems(_bucket,data);
        return data;
    }
    
};

#endif /* defined(__p1__BucketSort__) */



算法总结

注意,这里在求一个数组的最大值和最小值时,使用了一个技巧,将时间代价由O(2n)降低为O(2/3 n).

另外,桶排序并不是hash算法哈,最本质的区别是,桶排序中每个桶是有大小顺序的,而hash算法的桶是没有大小排序的;

第二个区别是:二者的目的也不一样,桶排序是为了对数据完成排序,最后的数据结构还是数组,而hash是为了快速查找一个元素(虽然桶排序的最终目的也是快速查找元素),其最终的数据结构是hash桶

第三个区别是:二者在快速查找数据时,桶排序最终是使用二分查找法对已排好序的数组进行查找,而hash是使用key落入桶的快速定位法,如果落入的桶中的元素非常的多,又会变成一个线程的顺序查找,性能比二分查找差,而如果桶中就一个或者有限个元素,则其查找的次数又小于二分查找,其性能又好于二分查找




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值