被搜索引擎坑惨的C++桶排序

首先我要吐槽一下搜索引擎坑我的故事

  排序算法有很多,但第一次听到桶排序这个算法时,瞬间就被它可爱的名字给Q到,正好我看的一本C++书上有道桶排序的题目,费了一番功夫后解决了这道题,于是,就去百度,想看看大神们的桶排序算法是怎样写的,结果……搜索引擎把我坑惨了,如下图:
这里写图片描述
搜索到的前n条介绍,都很令人失望,我把他们的代码亲自跑了一遍,都是只能对10以内的数据排序???心里一万个mmp,如果真是这样,那还要桶排序干嘛?

我并不清楚正宗的桶排序到底是什么样子的,但我按照书上的题目,实现了一个功能还算强大的桶排序,由于我将数据储存为string类型,所以可以对很大的数排序,至于这个数到底有多大,那要看string类型数据的长度了(我又手贱百度了一下,好像这个数大到形容不出来……)。

书上的原题是这样的(我感觉这道题已经把桶排序介绍的很到位了,比百度上的各种解释都要清楚):
桶排序(bucket sort)从一个一维的待排序的正整数数组和一个二维整数数组开始,其中,二维数组的行下标是从0到9,列下标时从0到n-1,n时一位数组中待排序值的个数。这个二维数组的每一行都称为一个桶。编写一个函数bucketSort,它采用一个整数数组和该数组的大小作为参数,并执行以下操作:
a) 对于一位数组的每一个值,根据值的个位数,将其放到桶数组的各行中。例如,97放在第7行,3放在第3行,100放在第0行。这称为“分布过程”。
b) 在桶数组中逐行循环遍历 ,并把值复制回原始数组。这称为“收集过程”。上述值在一位数组中的新次序是100,3,97。
c) 对随后的每个数位(十位,百位,千位等)重复这一过程。
在第二遍排序时,100放在第0行,3放在第0行(因为3没有个位),97放在第9行。收集过程之后,一维数组中值的顺序为100,3,97。在第三遍排序时,100放在第1行,3放在第0行,97放在第0行(在3之后)。在最后一次收集过程之后,原始数组就是有序的了。

不扯废话了,直接上代码:

#include <iostream>
#include <string>

using namespace std;

//将字符串中指定下标处的字符转换为对应的数字
int stringToInt( string str, int sub )
{
    return ((int)str[sub] - 48);
}

//桶排序,参数len:待排序数据的个数
void bucketSort( string str[], int len )
{
    string arr2[10][len];  //桶

    int i;
    int j;

    //初始化桶
    for ( i = 0; i < 10; i++) {
        for ( j = 0; j < len; j++) {
            arr2[i][j] = "e";  //令桶中所有元素的值都为字符:e,避免与数字冲突(可以换成其它字符)
        }
    }

    int subStr;  //字符串中,指定下标处的字符所对应的数字
    int iSub;  //下标
    int flag = 1;  //记录循环次数
    int maxLength = 0;  //待排序的一组数中,最长的数的长度

    //找出桶中最大数的长度(用于判断循环是否需要结束)
    for ( i = 0; i < len; i++) {
        if (str[i].length() > maxLength) {
            maxLength = str[i].length();
        }
    }

    //排序
    while(1) {
        for ( i = 0; i < len; i++) {
            iSub = str[i].length() - flag;  //下标(初始取最后一个下标)

            if (iSub < 0) {  //下标为负的时候,令下标处的字符对应的数字为0
                subStr = 0;
            } else {
                subStr = stringToInt(str[i], iSub);  //将iSub下标处的字符,转换为对应的数字
            }

            //将数字存入对应的桶中
            for ( j = 0; j < len; j++) {
                if (arr2[subStr][j] == "e") {
                    arr2[subStr][j] = str[i];

                    break;
                }
            }
        }

        int counter = 0;  //计数器
        //收集桶中的数字
        for ( i = 0; i < 10; i++) {
            for ( j = 0; j < len; j++) {
                if (arr2[i][j] != "e") {
                    str[counter] = arr2[i][j];

                    counter += 1;
                }
            }
        }

        flag += 1;

        //循环maxLength次后,排序结束,此时flag值为maxLength + 1
        if (flag == (maxLength + 1)) {
            //打印结果
            for ( i = 0; i < len; i++) {
                cout << str[i] << " ";
            }
            cout << endl;

            return;
        }

        //重置桶
        for ( i = 0; i < 10; i++) {
            for ( j = 0; j < len; j++) {
                arr2[i][j] = "e";
            }
        }
    }
}

int main()
{
    string arr1[15] = { "33", "28", "0", "1", "436", "6", "100", "9", "211", "223", "95", "20", "560", "16", "999" };
    string arr2[10] = { "1", "28", "33", "100", "9", "223", "95", "560", "16", "999" };
    string arr3[5] = { "436", "6", "20", "99", "211" };
    string arr4[5] = { "10000", "6000000", "0", "999999", "11111111" };

    bucketSort(arr1, 15);  //1 6 9 16 20 28 33 95 99 100 211 223 436 560 999
    bucketSort(arr2, 10);  //1 9 16 28 33 95 100 223 560 999
    bucketSort(arr3, 5);  //6 20 99 211 436
    bucketSort(arr4, 5);  //0 10000 999999 6000000 11111111

    return 0;
}

编译器:CodeBlocks

对代码的补充说明:
  首先,我将数据储存为string类型一是因为能对很大很大的数排序,二是取某个数的某个位上的数比较方便。
  其次,从第四组测试数据可以看出,对很大很大的数排序完全没问题。
  但是有个缺点,就是不能对负数排序,emmm……可以把代码改进一下。


代码思路简单,注释也比较详细,看我这篇博客的大佬们肯定都能看懂滴,就不再赘述了。

结语:因水平有限,文章有错误或者不足,欢迎评论,希望轻拍,一起进步哦!

END!

猜你喜欢

转载自blog.csdn.net/qq_41139830/article/details/80611628