桶排序、基数排序,C++ 二维vector实现


前言

本站及网络上现有的桶排序基数排序的C++相关算法代码大部分都是基于C语言,并且使用一维数组实现,通过从前往后累加元素出现的次数,确定元素在结果数组中出现的位置,不易于理解,本文主要使用二维vector数组实现。


一、准备工作

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
class Solution {
public:
	// 打印数组
    static void showArrays(vector<int> nums) {
        for (int &n: nums) {
            cout << n << " ";
        }
        cout << endl;
    }
    
    // 桶排序
    void bucketSort(vector<int> nums);
    // 基数排序
    void radixSort(vector<int> nums); 
}

int main() {
    Solution s;
    vector<int> nums = {22, 5, 43, 99, 2, 5, 17};
	
	cout << "countSort:\n";
	s.countSort(nums);

	cout << "BucketSort:\n";
    s.bucketSort(nums);

    vector<int> numsRadixSort = {112, 34, 678, 1999, 234, 6, 89, 5678};
    cout << "radixSort:\n";
    s.radixSort(numsRadixSort);
}

二、桶排序

1.算法原理

桶排序的核心思想就是将要排序的数据分到几个有序的桶里,每个桶里的数据再单独进行排序。桶排序完之后,再把每个桶里的数据按照顺序依次取出,组成的序列就是有序的了。

对于桶的数量,一般使用这组数据中的最大值减去最小值,再除以元素数量来确定。
具体每个桶内的使用的排序算法,没有规定,本文主要使用快速排序,文末附有作者的实现代码,可参考。

2.实现代码

   void bucketSort(vector<int> nums) {
        int n = nums.size();
        // 使用下面两条语句分别获取vector数组中的最大值和最小值
        int maxNum = *(max_element(nums.begin(), nums.end()));
        int minNum = *(min_element(nums.begin(), nums.end()));
		
		// 计算桶的数量,加1是为了后续方便存放数据
        int bucketNum = (maxNum - minNum) / n + 1;
        // 即要使用的桶,上一句获得了桶的数量,但每个桶里具体存放多少数据还不清楚,后续使用push_back动态扩容
        vector<vector<int>> bucket(bucketNum);

        for (int i = 0; i < n; i++) {
        	// 算出当前的元素应该放在那个桶,index为桶的索引
            int index = (nums[i] - minNum) / n;
            bucket[index].push_back(nums[i]);
        }
		
		// 打印数组,用于Debug,可注释掉
        for (int i = 0; i < bucket.size(); i++) {
            if(bucket[i].empty()){
                continue;
            }
            for (int j = 0; j < bucket[i].size(); j++) {
                cout << bucket[i][j] << " ";
            }
            cout << endl;
        }

        int resIndex = 0;	// 结果数组的索引
        for (int i = 0; i < bucketNum; i++) {
        	// 使用快速排序对每个桶内的数据进行排序,此函数需要单独实现,当然也可以直接调用sort库函数
            quickSort(bucket[i], 0, bucket[i].size() - 1);
            // 桶内元素已经有序,直接取出来放到结果数组就行
            for (int j = 0; j < bucket[i].size(); j++) {
                nums[resIndex++] = bucket[i][j];
            }
        }
        showArrays(nums);
    }

三、基数排序

1.算法原理

举个例子,有一个整数序列,{112, 34, 678, 1999, 234, 6, 89, 5678},下面是排序过程:
第一次排序,个位,112 34 234 6 678 5678 1999 89
第二次排序,十位,6 112 34 234 678 5678 89 1999
第三次排序,百位,6 34 89 112 234 678 5678 1999
第四次排序,千位,6 34 89 112 234 678 1999 5678
最终结果,6 34 89 112 234 678 1999 5678 , 排序完成。

2.实现代码

    void radixSort(vector<int> nums) {
        int n = nums.size();

        // 求所有数据的最大位数
        int maxNum = *(max_element(nums.begin(), nums.end()));
        int numBit = 0;
        while (maxNum > 0) {
            maxNum /= 10;
            ++numBit;
        }
        // cout << "最大元素的位数:" << numBit << endl;
		
		// radix作为除数用于在每次循环中得到位数
        int radix = 1;
        // 第一次循环计算个位,以此十位、百位等
        for (int k = 1; k <= numBit; k++) {
            vector<vector<int>> bucket(10);
            for (int j = 0; j < n; j++) {
            	// 得到该数的当前判断的位数
                int index = (nums[j] / radix) % 10;     
                bucket[index].push_back(nums[j]);
            }
			
			// 先分散放到各个桶里,然后再收集起来
            int resIndex=0;
            for (int i = 0; i < bucket.size(); i++) {
                if (bucket[i].empty()) {
                    continue;
                }
                for (int j = 0; j < bucket[i].size(); j++) {
                    nums[resIndex++] = bucket[i][j];
                }
            }

            showArrays(nums);
            // 乘以10用于计算下次位数
            radix *= 10;
        }
        showArrays(nums);
    }

参考代码运行结果:
在这里插入图片描述


四、快速排序

实现代码

    
    void quickSort(vector<int> &nums, int left, int right) {
        if (left < right) {
            int pivot = partition(nums, left, right);
            quickSort(nums, left, pivot - 1);
            quickSort(nums, pivot + 1, right);
        }
//        showArrays(nums);
    }

    int partition(vector<int> &nums, int left, int right) {
        int pivot = nums[left];
        while (left < right) {
            while (left < right && nums[right] >= pivot) {
                right--;
            }
            nums[left] = nums[right];
            while (left < right && nums[left] <= pivot) {
                left++;
            }
            nums[right] = nums[left];
        }
        nums[left] = pivot;
//        showArrays(nums);
        return left;
    }

后记

关于十大排序算法,比较热门的快排,堆排等网上的内容都挺丰富的了,我也整理了一遍。但对于桶排序和基数排序这俩的C++代码实现基本都是一个版本,个人感觉看的很难受。于是自己摸索着简单实现了这个版本,所以想着写个博客记录下,也不知道有人看没,等有时间的话看自己会不会把其他排序也写下吧。

本文写于2022/06/27,前一阵子写自己项目的README.md还觉得挺有成就感的,就发了这个也是我自己的第一篇技术文章,马上开始提前批了,希望自己能找到个好工作!冲!

update 2022/8/9
其他排序方法可以看我的github项目,面试主要掌握快速排序,堆排序和归并排序三种即可。
源代码里有注释,欢迎访问。

链接: github/CPlusClassicCode

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值