目录
计数排序
现在假如说我给一个数组{3,4,1,7,7,5,9,6,2}来进行排序,我们先找到数组中最大的值max,开辟max+1(以0开始)的辅助空间,里面存放0,如下图
然后我们遍历数组a[],将数组a[]里的元素在help下标对应的位置,让这个下标对应的位置上的值+1
我们在help填入值后是这样的,然后我们需要遍历help中不为0的位置,填入a中覆盖原来的值
#include<iostream>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
using namespace std;
int main()
{
int a[] = { 8,5,6,20,7,16,18,13 };
int n = sizeof(a) / sizeof(int) - 1;
int maxn = *max_element(a,a+n);
int* cul = (int*)malloc(sizeof(int) * maxn);
for (int i = 0; i <= maxn; i++)
{
cul[i] = 0;
}
for (int i = 0; i <= n; i++)
{
cul[a[i]]++;
}
int k = 0;
for (int i = 0; i <= maxn; i++)
{
if (cul[i] != 0)
{
for (int j = cul[i]; j > 0; j--)
{
a[k] = i;
k++;
}
}
}
for (int i = 0; i <= n; i++)
{
cout << a[i] << " ";
}
return 0;
}
基数排序
我们先说说什么是基数:一个数值的各个位上的数字称为该位的基数,128的个位基数是8,十位基数是2,百位基数是1
基数排序的思路:假如我们要对{2,5,20,5,678,128,123}进行排序,我们先对个位上的数进行排序,在个位上有序的基础上对十位上的数进行排序,在此基础上对百位数上的数进行排序,最后得出来的数组就是有序的了,示意图如下
#include<iostream>
#include<vector>
using namespace std;
int maxwei(vector<int>input)//找到vector容器中最大值的位数
{
int max_num = input[0];
for (int i = 0; i < input.size(); i++)
{
if (input[i] > max_num)
{
max_num = input[i];
}
}
int p = 0;
while (max_num > 0)
{
p++;
max_num /= 10;
}
return p;
}
int GetNum(int num, int d)//取出数的第d位上的数字
{
int p = 1;
while (d - 1 > 0)
{
p *= 10;
d--;
}
return num / p % 10;
}
vector <int> RadixSort(vector<int> input, int length)//基数排序
{
vector<int>bucket(length);//创建临时存放排序过程中的数据
vector<int>count(10);
for (int d = 1; d <= maxwei(input); d++)
{
//计数器清0
for (int i = 0; i < 10; i++)
{
count[i] = 0;
}
//统计各个桶中的个数
for (int i = 0; i < length; i++)
{
count[GetNum(input[i], d)]++;
}
//得到的每个数应该放到bucket中的位置
for (int i = 1; i < 10; i++)
{
count[i] += count[i - 1];
}
for (int i = length - 1; i >= 0; i--)
//特别注意这一步,下面会有详细说明,为什么要这样逆序遍历
{
int k = GetNum(input[i], d);
bucket[count[k] - 1] = input[i];
count[k]--;
}
for (int j = 0; j < length; j++)
{
input[j] = bucket[j];
}
}
return input;
}
int main()
{
int a[] = { 258,6,3,1,69,7,35,1024,4,0 };
vector<int>test(a, a + sizeof(a) / sizeof(a[0]));
cout << "排序前" << ": ";
for (int i = 0; i < test.size(); i++)
{
cout << test[i] << " ";
}
cout << endl;
vector<int>result = test;
result = RadixSort(result, result.size());
cout << "排序后" << ": ";
for (int i = 0; i < result.size(); i++)
{
cout << result[i] << " ";
}
cout << endl;
system("pause");
}
我再次强调一下vector <int> RadixSort(vector<int> input, int length)这个基数排序的函数,我们先创建bucket来临时存放数组,假如说我对个位数进行排序后放到这个数组中,再将这里面的数值再赋值给input数组,count容器是用来记录位数的个数,但是记得每进行一次排序之后count值要清零,记录了count之后我怎么去通过count来进行排序呢?我们先将count进行下面的操作
for (int i = 1; i < 10; i++)
{
count[i] += count[i - 1];//上面这个图示,为了确定元素的位置
}for (int i = length - 1; i >= 0; i--)//下面有解释
{
int k = GetNum(input[i], d);
bucket[count[k] - 1] = input[i];
count[k]--;
}
为什么要逆序遍历呢?咱们用一个例子来说[212,213,312],第一次因为是将乱序进行个位排序,逆序对这一次是没啥影响的,但是对以后位数上的排序起着至关重要的作用,我们第一次按照个位排好序之后是[212,312,213],如果我们对十位进行正向遍历之后排序的时候,count中的1会出现3次,我们如果找到一个1之后,bucket[3-1]=input[1],这样bucket[2]=212,然后count[1]减成了2,bucket[2-1] = input[2],bucket[1] = 312,最后bucket[0]=input[3]=213,这样排出来的结果为[213,312,212],怎么我们发现213个位上是3,咋跑到个位上是2的前面了,就很离谱,所以这样是不对的,咱们一定要从后往前遍历,咱们看看从后往前遍历是咋样的!我们第一次排好序和前面是一样的[212,312,213],从后往前遍历,bucket[3-1] = input[2]=213,bucket[2-1]=input[1]=312,bucket[0]=input[0]=212,出来是[212,312,213]这样是正确的,咱们再来看第三回,count计数出来是2的位置上有2个,3的位置上有1个,
那count[2]=2,count[3]=3从后往前遍历的话,先找到input[2]:213,count[2]的位置上是2,南无bucket[2-1]=213,再找到312,bucket[3-1]=312,再找到212,bucket[1-1]=212