经典算法(九)----基数排序----图解法让你快速入门

引言

     只要设计到数据,就会涉及到数据的排序问题,比如给你随机给你十个数 让你进行排序,那我们该怎样才是实现对这些整数的排序呢 ?

    答案是多种多样的,比如用冒泡排序、希尔排序、计数排序、基数排序、快速排序等等,这些排序方法都可以实现对整数排序,而这篇文章要讲的就是基数排序

    在学基数排序的时候,一定要先把计数排序学会,因为在代码中利用了计数排序的思想,如果计数排序不太理解,可以点击后面的链接,先把计数排序学会(重要)。  经典算法(八)----计数排序----图解法让你快速入门

本文将从以下几个问题对基数排序进行分析和讲解:

  1. 什么是基数排序?
  2. 基数排序的具体过程是什么?
  3. 基数排序的完整代码
  4. 基数排序的代码详解。

一、什么是基数排序 

下面先看看百度百科对基数排序的定义:

       基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。

简单来说:比如我们要对13,52,72,65,54,90,25,44,75,81这十个数排序,那么利用基数排序,他的思想就是先按个位数的大小排(也可先按高位排序,这篇文章采取的是先按低位排序),再按十位排序。

  1. 先按个位排序,得到的是 90 81 52 72 13 54 44 65 25 75
  2. 再按十位排序,得到的是 13 25 44 52 54 65 72 75 81 90

因为上面的数最高位是十位,所以进行两边排序就可以了,因此在排序前,我们要求出这组数最大的位数。

其中每边排序采取的都是计数排序的方法,所以要提前学会计数排序,在学基数排序。

二、基数排序的具体过程是什么?

首先我们就是要求出要排序数组中最大数的位数。这个决定了要进行几次计数排序的过程

        求解过程就是遍历数组,在这个过程中,对每个数的位数都求出来,去最大值即可,下面直接看代码(我相信你一定能看懂)

//统计数组中 最大数的位数 
int max(int arr[],int len)
{
	int maxn=0;
	for(int i=0;i<len;i++)
	{
		int count=0,data=arr[i];
		while(data != 0)
		{
			count++;
			data/=10;
		}
		if(count>maxn)
			maxn=count;
	}
	return maxn;
} 

然后就可以开始遍历,第一次就是把每个数的个位数放到count数组里面。

如果对上面的count表有问题,为啥他要累加,这里累加的作用是解决排序的稳定性问题,如果对这排序的稳定性问题有疑问,那么你可以去看看这篇文章 ——>   经典算法(八)----计数排序----图解法让你快速入门

在计数排序文章中详细讲解了计数排序的实现过程,下面我们就需要利用计数排序的方法去学习基数排序。

一旦把数据放到了count数组之后,下面的过程就和计数排序一样了,我们直接放代码

//基数排序函数    稳定 
void RadixSort(int arr[],int len)
{
	int maxn=max(arr,len);//首先求出最大位数
	int num=1;//求位数用 
	for(int k=0;k<maxn;k++)//根据位数,判断遍历几次 
	{
		int count[10]={0};
		for(int i=0;i<len;i++)//把数据放入桶内 
		{
			int k=arr[i]/num%10;
			count[k]++;
		}
		
		//下面的过程都是计数排序的过程。
		//根据计数排序,把桶内数据排序即可 
		for(int i=1;i<10;i++)//累加 
		{
			count[i]=count[i]+count[i-1];
		}
		
		int temp[10]={0};//用来存放排序后的结果 
		for(int i=len-1;i>=0;i--)//逆序遍历,保证稳定性 
		{
			int ans=arr[i]/num%10;
			temp[count[ans]-1]=arr[i]; 
			count[ans]--;  
		} 
		
		for(int i=0;i<len;i++)
		{
			arr[i]=temp[i]; 
		} 
		
		num*=10;//求更高位 
	}
		
}

如果上面代码有些步骤不是很清楚 ,可以点击上面计数排序的链接。

三、基数排序的完整代码

下面看完整的代码

#include<iostream>
using namespace std;

//统计数组中 最大数的位数 
int max(int arr[],int len)
{
	int maxn=0;
	for(int i=0;i<len;i++)
	{
		int count=0,data=arr[i];
		while(data)
		{
			count++;
			data/=10;
		}
		if(count>maxn)
			maxn=count;
	}
	return maxn;
} 

//基数排序函数    稳定 
void RadixSort(int arr[],int len)
{
	int maxn=max(arr,len);//首先求出最大位数
	int num=1;//求位数用 
	for(int k=0;k<maxn;k++)//根据位数,判断遍历几次 
	{
		int count[10]={0};
		for(int i=0;i<len;i++)//把数据放入桶内 
		{
			int k=arr[i]/num%10;
			count[k]++;
		}
		
		//下面的过程都是计数排序的过程。
		//根据计数排序,把桶内数据排序即可 
		for(int i=1;i<10;i++)//累加 
		{
			count[i]=count[i]+count[i-1];
		}
		
		int temp[10]={0};//用来存放排序后的结果 
		for(int i=len-1;i>=0;i--)//逆序遍历,保证稳定性 
		{
			int ans=arr[i]/num%10;
			temp[count[ans]-1]=arr[i]; 
			count[ans]--;  
		} 
		
		for(int i=0;i<len;i++)
		{
			arr[i]=temp[i]; 
		} 
		
		num*=10;//求更高位 
	}
		
}
//输出数组的值
void printf(int arr[],int len)
{
	for(int i=0;i<len;i++)
		cout<<arr[i]<<" ";
	cout<<endl;
}
int main()
{
	//要排序的数组 
	int arr[]={13,52,72,65,54,90,25,44,75,81};
	int len=10;//要排序的数组长度 
	
	//排序 
	RadixSort(arr,len);
	
	//输出 
	printf(arr,len);
	return 0;
}

运行结果:

四、基数排序的代码详解

  1. 学习这个基数排序,首先要知道基数排序的思想,知道它的大概过程是什么。
  2. 我认为最难的点就是把要排序的数组和count计数数组处理好,比如一开始count数组要存各个数的个位数,该怎样计数。等到逆序遍历(保证稳定性)的时候,怎样利用计数数组和要排序的数组,把每个数放到合适的位置上去。

本文参考以及引用:

百度百科

猜你喜欢

转载自blog.csdn.net/weixin_44820625/article/details/106818813