[算法入门]--十分钟弄懂桶排序(基数排序)

目录

一、先看一个例子

我们先来看这样一个问题

思路解析

 二、基数排序的思路

思路:

三、用到的函数讲解

maxBits

findBit

randint

randomCreateArray

基数序函数radixSort

四、参考图

五、所有代码--VsCode(C++实现版本)


一、先看一个例子

我们先来看这样一个问题

如何将一群学生的年龄进行排序?

要求:时间复杂度O(n)

Tips:注意挖掘题目中的隐含条件!


思路解析

隐藏条件:学生的年龄在0-100之间,我们利用这一点建立一个学生年龄作为索引,存放值为对应年龄的学生人数的数组bucket(桶);将数据存入桶后倒入help临时数组,最后help数组覆盖需要处理的数据即可。

#include <iostream>
#include <vector>
using namespace std;

int main(){
	vector<int> ages;							//学生年龄 
	vector<int> bucket(100, 0);					//准备一个桶
	
	ages.push_back(12);
	ages.push_back(13);
	ages.push_back(14);
	ages.push_back(15);
	ages.push_back(11);
	ages.push_back(10);
	ages.push_back(9);
	
	vector<int> help;							//辅助空间 
	
	//动态数组压入学生年龄数据
	vector<int>::iterator it = ages.begin();	//初始化迭代器 
	for (; it < ages.end(); it++)
	{
		bucket.at(*it)++;						//bucket[年龄] = 人数 
	}
	
	it = bucket.begin();						//进入桶中迭代 
	
	for (; it < bucket.end(); it++)				//迭代器遍历桶 
	{
		int n = *it;							//对应年龄的人数			
		for (int j = 0; j < n; j++)
		{
			help.push_back(it - bucket.begin());
		}
	}
	
	ages = help;
	
	cout << "The ages:";
	for (int i = 0; i < ages.size(); i++)
	{
		cout << ages.at(i) << ' ';
	}cout << endl << endl;
	
	
	
}

 二、基数排序的思路

思路:

给定一个数组,

这个数组中最大的数是43,也就是说数组中所有的数的位数不会超过2,桶排序就是利用了这一个隐藏信息。

我们将数组排序两次,第一次按照所有数字的最后一位排序,那就是这样

按照从右往左排序对应的位,数组会按照最左边优先级最高来排序,因为最左边是最后被覆盖进数组的。

就是因为每一次按照位来排序,所以桶排序也叫基数排序

第二次再按照所有的数字的倒数第二位排序(也就是第一位),数组达到一个有序的状态。

所以,桶排序的原理其实很简单:

1.找出数组中最大数有几位

2.有几位我们就入桶出桶几次

3.每次准备一个(十进制的情况)大小为10的----[0, 9]

4.正序遍历数组,按照顺序取出对应的位

5.将位作为索引,值是该位出现的数量,进行统计

6.处理bucket中的数据,使它的值从原来的【索引位出现数量】--> 小于等于索引位的数量

换言之就是这个数出现的序号[我们说的序号从1开始,索引从0开始]

7.从右往左倒序遍历数组,取出每个数的对应位,查找桶中这个位对应的位置(或者说小于等于这个位的数量)将这个数放入对应位置的help辅助数组当中去

8.按照最大位的数量重复上述过程对应的次数即可(例如最大的数是2311,最大位就是四位,那么重复入桶出桶四次,每次排序的依据是倒数第一位->倒数第二位->倒数第三位->倒数第四位)

三、用到的函数讲解

设计一个返回数组中最大数位长度的函数,这个很简单就不解释了:

maxBits

int maxBits(vector<int> arr)
{
    int max = *arr.begin();
    for (auto i : arr)
    {
        if (i > max)
            max = i;
    }
    int count = 0;
    while (max > 0)
    {
        max /= 10;
        count++;
    }
    return count;
} // 返回数组中最大数有几位

 遍历数组找到最大值后再统计最大值的位数即可 。

findBit

int findBit(int n, int c)
{
    int bit;
    while (c--)
    {
        bit = n % 10;
        n /= 10;
    }
    return bit;

} // 返回从右往左数指定位

再设计一个数找到每次遍历的对应位

randint

int randint(int a, int b)
{
    return rand() % (b - a + 1) + a;
}

返回一个随机数用于随机创建数组,配合主函数的随机种子使用效果更佳!

randomCreateArray

vector<int> randomCreateArray(int size, int a, int b)
{
    cout << "creating array: ";
    vector<int> arr;
    for (int i = 0; i < size; i++)
    {
        arr.push_back(randint(a, b));
        cout << arr[i] << ' ';
    }
    cout << endl;
    return arr;
}

 随机创建数组便于测试

基数序函数radixSort

void radixSort(vector<int> &arr, int radix) // 基数radix代表具体的进制
{
    int maxbits = maxBits(arr);                // 寻找数组中最大数有几位
    for (int i = 1; i <= maxbits; i++)         // 进行多轮处理
    {                                       // 例如:12345: 5 -> 4 -> 3 -> 2 -> 1
        vector<int> help(arr.size(), 0);    //定义临时数组空间
        vector<int> bucket(radix, 0);       // 初始化一个桶来统计位的出现次数
        for (auto k : arr)                  // 遍历数组提取出大循环所对应的位
        {
            int bit = findBit(k, i);        //找到对应位
            bucket[bit]++;                  //对应位加一
        }
        for (int j = 1; j < bucket.size(); j++)
        {
            bucket[j] += bucket[j - 1];     //bucket中的数代表<=它的数字的个数(也索引位的数的位置)
        }
        for (int k = arr.size() - 1; k > -1; k--)
        {                                          //倒着遍历数组
            int bit = findBit(arr[k], i);          //找到数组所遍历的数对应的位
            int index = bucket[bit];               //存放小于等于bit位的数量              
            help[index - 1] = arr[k];              //将该数存入临时数组
            bucket[bit]--;                           //用完少一个
        }
        arr = help;
    }
}

四、参考图

最后附上我用来理解桶排序所做的图解:

五、所有代码--VsCode(C++实现版本)

#include <iostream>
#include <vector>
#include <ctime>
using namespace std;


int randint(int a, int b)
{
    return rand() % (b - a + 1) + a;
}

vector<int> randomCreateArray(int size, int a, int b)
{
    cout << "creating array: ";
    vector<int> arr;
    for (int i = 0; i < size; i++)
    {
        arr.push_back(randint(a, b));
        cout << arr[i] << ' ';
    }
    cout << endl;
    return arr;
}

int findBit(int n, int c)
{
    int bit;
    while (c--)
    {
        bit = n % 10;
        n /= 10;
    }
    return bit;

} // 返回从右往左数指定位

int maxBits(vector<int> arr)
{
    int max = *arr.begin();
    for (auto i : arr)
    {
        if (i > max)
            max = i;
    }
    int count = 0;
    while (max > 0)
    {
        max /= 10;
        count++;
    }
    return count;
} // 返回数组中最大数有几位

void radixSort(vector<int> &arr, int radix) // 基数radix代表具体的进制
{
    int maxbits = maxBits(arr);                // 寻找数组中最大数有几位
    for (int i = 1; i <= maxbits; i++)         // 进行多轮处理
    {                                       // 例如:12345: 5 -> 4 -> 3 -> 2 -> 1
        vector<int> help(arr.size(), 0);    //定义临时数组空间
        vector<int> bucket(radix, 0);       // 初始化一个桶来统计位的出现次数
        for (auto k : arr)                  // 遍历数组提取出大循环所对应的位
        {
            int bit = findBit(k, i);        //找到对应位
            bucket[bit]++;                  //对应位加一
        }
        for (int j = 1; j < bucket.size(); j++)
        {
            bucket[j] += bucket[j - 1];     //bucket中的数代表<=它的数字的个数(也索引位的数的位置)
        }
        for (int k = arr.size() - 1; k > -1; k--)
        {                                          //倒着遍历数组
            int bit = findBit(arr[k], i);          //找到数组所遍历的数对应的位
            int index = bucket[bit];               //存放小于等于bit位的数量              
            help[index - 1] = arr[k];              //将该数存入临时数组
            bucket[bit]--;                           //用完少一个
        }
        arr = help;
    }
}

int main()
{
    srand(time(0));
    const int radix = 10;
    cout << findBit(1, 2);
    vector<int> arr = randomCreateArray(10, 1, 100);
    for (auto i : arr)
    {
        cout << i << ' ';
    }//打印
    radixSort(arr, radix);                       //按照十进制的规则排序数组
    cout << endl;
    cout << "The sorted array:";
    for (auto i : arr)
    {
        cout << i << ' ';
    }//打印排序之后的数组
    system("pause");
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值