桶排序和基数排序

(快速总结了桶排序和基数排序,由于近期项目比较忙,很多地方没有考虑完整,日后有空再回来修改)

桶排序:
将数组分配到有限数量的桶子里,每个桶子再个别排序。
下列中:将数据作为桶(数组)的下标存储,适合于数据值的范围比较小;比如:求在1G大小的字符串中,出现次数最多的那个字符;因为字符char的边界是[0...255],就可以将所有的字符遍历、存储到[0...255]桶中(数组下标).

基数排序:
可以理解为对桶排序的扩充,将数据分别按个位、十位、百位...分别放入buckets[0...9][num]的桶中。
即:先将个位数存储到[0...9]的桶中,个位数将排好序
再按照个位数排好的序,将十位数存储到[0...9]的桶中,十位数排好序(个位数上一轮已经排好序)...
再百位,千位...每次放入桶中后,桶的顺序、桶内数据的顺序是排好的。
例如:
下例中数组:
int array[] = {2, 343, 342, 1, 123, 43, 4343, 433, 687, 654, 3};
按个位依次排序(到桶中)
0|
1|1,
2|2,342
3|343,123,43,4343,433,3
4|654 
5| 
6| 
7|687 
8| 
9|
按值的顺序存入到array[] = {1,2,342,343,123,43,4343,433,3,654,687};
由此可见,个位数是排好序的;

再将array[] = {1,2,342,343,123,43,4343,433,3,654,687}按十位数依次排序
0|1,2,3 
1| 
2|123  
3|433 
4|342,343,43,4343 
5|654  
6| 
7| 
8|687 
9|
按值的顺序存入到array[] = {1,2,3,123,433,342,343,43,4343,654,687}
由此可见,个位数、十位数是排好序的;

再将array[] = {1,2,3,123,433,342,343,43,4343,654,687}按百位数依次排序
0|1,2,3,43 
1|123  
2| 
3|342,343,4343   
4|433  
5|   
6|654,687 
7| 
8|  
9|
按值的顺序存入到array[] = {1,2,3,43,123,342,343,4343,433,654,687}
由此可见,个位数、十位数、百位数是排好序的; 

再将array[] = {1,2,3,43,123,342,343,4343,433,654,687}按千位数依次排序
0|1,2,3,43,123,342,343,433,654,687 
1| 
2| 
3|    
4|4343   
5|   
6|  
7| 
8|  
9|
按值的顺序存入到array[] = {1,2,3,43,123,342,343,433,654,687,4343}

这时整个数组已经按升序排序完成。

#include<math.h>
#include <iostream>
using namespace std;

//桶排序
int bucketSort()
{
	int array[]={9,8,7,9,8,7,1,2,3,0};
	int n = sizeof(array)/sizeof(array[0]);
	
	int bucket[sizeof(array)/sizeof(array[0])] = {0};
	
	for(int i = 0; i<n; i++)
	{
		int n = array[i];
		//用array数据作为bucket数组下标,因此下标的范围决定了数组的大小
		//++用于重复的数据
		bucket[n]++;
	}
 
	for(int j = 0; j<n; j++)
	{
	    //如果桶内没有数据,则跳过;有数据,输出下标。
		while(bucket[j]--)
			cout<<j<<endl;
	}		
}

//获取数字的位数
int getLoopTimes(int num)
{
	int count = 1;
	while(num = num/10)
	{	   
	   count++;
	}
	return count;
}

//查询数组中的最大数
int findMaxNum(int *p, int n)
{
    int max = 0;
    for(int i = 0; i < n; i++)
    {
        if(*(p + i) > max)
        {
            max = *(p + i);
        }
    }
    return max;
}

//将数字分配到各自的桶中[0...9],然后按照桶的顺序输出排序结果
void bucketsInRadix(int *p, int n, int loop)
{
    cout<<"===========Loop = "<<loop<<"==========="<<endl;
    //建立一组桶,10为桶的序列[0...9]
	//11为桶的容量,即数组的容量n,也是单桶的最大容量
    int buckets[10][11] = {0};	
	//tempNum用于求余数的值;按照个位、十位、百位分别除1,10,100用于求位数值
    int tempNum = (int)pow(10, loop - 1);
    int i, j;
	//int x = 0;
	cout<<"buckets: ";
	//i为数组数据遍历的变量
    for(i = 0; i < n; i++)
    {	    
	    //确定基数(尾数)
        int row_index = (*(p + i) / tempNum) % 10;
		//用于同“基数”存储,即同一个桶中数据的存储
		//如果桶中某一位不为0,说明该位置被占用,存储到下一个位置。
		//也可以简化为:buckets[row_index][x++] = *(p + i);但是桶内数据没有连续存储
        for(j = 0; j < n; j++)
        {		    
            if(buckets[row_index][j] == 0)
            {
                buckets[row_index][j] = *(p + i);
                break;
            }			
        }	
		cout<<buckets[row_index][j]<<" ";
    }
	cout<<endl;
	
    //将桶中的数,倒回到原有数组中
	cout<<"......p: ";
    int k = 0;
	//基数升序
    for(i = 0; i < 10; i++)
    {	    
	    //同“基数”值的倒回,即按照桶序列[0...9]中依次倒回
        for(j = 0; j < n; j++)
        {
		    //i对应桶,j对应桶内的值,j最大为数组的值
            if(buckets[i][j] != 0)
            {
                *(p + k) = buckets[i][j];
                buckets[i][j] = 0;				
				cout<<*(p + k)<<" ";	
                k++;
				
            }
        }		
    }
	cout<<endl;
}
//基数排序
void radixSort(int *p, int num)
{
    //获取数组中的最大数
    int maxNum = findMaxNum(p, num);
    //根据最大数获取最大的位数 
	//loopTimes即需要按位存储、排序的次数
    int loopTimes = getLoopTimes(maxNum);
     //对每一位进行桶分配
	//第一次循环之后,个位数已经排好序
	//第二次循环之后,十位数排好序(个位数上一轮已经排好序)...
    for(int i = 1; i <= loopTimes; i++)
    {
        bucketsInRadix(p, num, i);
    }
}
int main()
{
    cout<<"==============Test Bucket Sort ==============\n"<<endl;	
    bucketSort();
    
    cout<<"==============Test Radix Sort ==============\n"<<endl;
    int array[] = {2, 343, 342, 1, 123, 43, 4343, 433, 687, 654, 3};
     //计算数组长度
    int size = sizeof(array) / sizeof(int);
    //基数排序
    radixSort(array, size);
    //打印排序后的结果    
    for(int i = 0; i < size; i++)
    {
        cout<<array[i]<<endl;
    }
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值