即使经过上面的改进依然不能做到稳定的排序,是因为我们按照 计数数组 的索引与次数 输出排序数组,无论如何都做不到稳定,因为两个相同的元素在 计数数组 的索引中是体现不出来区别的。
所以我们从根本上改变了思想,不按照技术数组简单输出,并做出如下改变
依然通过max和min创建计数数组,但计数时,把技术数组的次数变为累加值,即 包括自己在内前面所有元素出现次数的累加和 ;这是,如果累加次数值 为8,就意味着该元素在排序数组中 应该排在第8位
输出数组时,新定义一个和未排序数组大小相同的数组,因为我们一会要用到未排序数组,所以先备份一个
利用未排序数组 和 计数数组,从最右侧向最左侧遍历,遍历到一个元素,先找到其对应在计数数组中的 累加次数值 x(即该元素排序位置),就把其覆盖到备份数组中 x-1的索引处,同时 累加次数值-1(这样若左边还有相同元素,下次就会覆盖到前一个位置,就稳定了)
比较简单,直接看后面改进版把
void countingSort(vector<int> &array)
{
int max = array[0];
for(int index = 1;index<array.size();index++){
if(max<array[index]){
max = array[index];
}
}
int* counts = new int[max+1]{0};
for(int index = 0;index<array.size();index++){
counts[array[index]]++;
}
vector<int> sortedArray;
for(int index = 0;index <=max;index++){
for(int i = 0;i<counts[index];i++){
sortedArray.push_back(index);
}
}
array = sortedArray;
}
输入数组:
6 9 6 7 5 8 8 29 15 11 10
计数排序基础版
索引 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
次数 0 0 0 0 0 1 2 1 2 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
算法用时:(微秒)
[AlgoTime: 6001 us]
排序结果:
5 6 6 7 8 8 9 10 11 15 29
void countingSort2nd(vector<int> &array){
//遍历排序数组,记录最大值与最小值
int max = array[0];
int min = array[0];
for(int i = 1;i<array.size();i++){
if(max<array[i]){
max = array[i];
}
if(min>array[i]){
min = array[i];
}
}
//创建计数数组,长度为max-min+1,记住创建数组【】里的是长度,不是最大索引
int *counts = new int[max - min + 1]{0};
//进行计数,以及计数结果显示
for(int i = 0;i<array.size();i++){
counts[array[i]-min]++;
}
//按照计数数组,对array进行重置
int arrayIndex = 0;
for(int i = 0;i<max-min+1;i++){
while (counts[i]-->0)
{
array[arrayIndex] = i+min;
arrayIndex++;
}
}
}
输入数组:
-6 9 6 7 5 8 8 29 15 11 10
计数排序基础版
索引 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
次数 1 0 0 0 0 0 0 0 0 0 0 1 1 1 2 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
算法用时:(微秒)
[AlgoTime: 7003 us]
排序结果:
-6 5 6 7 8 8 9 10 11 15 29
void countingSort3rd(vector<int> &array){
//遍历未排序数组,记录最大最小值
int min = array[0];
int max = array[0];
for(int i = 1; i<array.size();i++){
if(min>array[i]){
min = array[i];
}
if(max <array[i]){
max = array[i];
}
}
//定义计数数组,进行计数
int* counts = new int [max -min +1]{0};
for(int i = 0;i<array.size();i++){
counts[array[i]-min]++;
}
//在原有计数数组的基础,对计数值进行累加,把计数值改为 该元素在排序数组中的位置
int locatingNum = 0;
for(int i = 0;i<max-min+1;i++){
if(counts[i] == 0){//如果排序数组中没有这个元素(计数值为0),不进行累加
continue;
}
locatingNum = locatingNum + counts[i];
counts[i] = locatingNum;
}
//打印累加计数数组
countsIndexPrint(min,max);
cout<<endl;
arrayPrint(counts,max-min+1);
//定义临时数组,根据累加计数数组的位置值,从右到左遍历未排序数组,把元素插入到对应位置
int* temp = new int[array.size()];
for(int index = array.size()-1;index>=0;index--){
//array[index]-min = counts数组对应元素索引
//counts[数组对应元素索引] = 数组对应元素在排序序列中的位置
//counts[数组对应元素索引] - 1 = 数组对应元素在排序数组中的索引
temp[counts[array[index]-min]-1] = array[index];
counts[array[index]-min]--;
}
//用备份数组覆盖原数组
for (int i = 0; i < array.size(); i++)
{
array[i]=temp[i];
}
}
输入数组:
-6 9 6 7 5 8 8 29 15 11 10
计数排序终极版
索引 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
累加次数 1 0 0 0 0 0 0 0 0 0 0 2 3 4 6 7 8 9 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 11
算法用时:(微秒)
[AlgoTime: 6000 us]
排序结果:
-6 5 6 7 8 8 9 10 11 15 29
#include
#include
#include "MeasureAlgoTime.hpp"
using namespace std;
void vectorPrint(vector<int> &array)
{
for (int i = 0; i < array.size(); i++)
{
cout << array[i] << ' ';
}
cout << endl;
}
void arrayPrint(int array[],int length){
cout<<"次数"<<" ";
for(int i = 0;i<length;i++){
cout<<array[i]<<" ";
}
}
void countsIndexPrint(int min,int max){
cout<<"索引"<<" ";
for(int i =min;i<=max;i++){
cout<<i<<" ";
}
}
void countingSort(vector<int> &array)
{
int max = array[0];
for(int index = 1;index<array.size();index++){
if(max<array[index]){
max = array[index];
}
}
int* counts = new int[max+1]{0};
for(int index = 0;index<array.size();index++){
counts[array[index]]++;
}
countsIndexPrint(0,max);
cout<<endl;
arrayPrint(counts,max-0+1);
vector<int> sortedArray;
for(int index = 0;index <=max;index++){
for(int i = 0;i<counts[index];i++){
sortedArray.push_back(index);
}
}
array = sortedArray;
}
void countingSort2nd(vector<int> &array){
//遍历排序数组,记录最大值与最小值
int max = array[0];
int min = array[0];
for(int i = 1;i<array.size();i++){
if(max<array[i]){
max = array[i];
}
if(min>array[i]){
min = array[i];
}
}
//创建计数数组,长度为max-min+1,记住创建数组【】里的是长度,不是最大索引
int *counts = new int[max - min + 1]{0};
//进行计数,以及计数结果显示
for(int i = 0;i<array.size();i++){
counts[array[i]-min]++;
}
countsIndexPrint(min,max);
cout<<endl;
arrayPrint(counts,max-min+1);
//按照计数数组,对array进行重置
int arrayIndex = 0;
for(int i = 0;i<max-min+1;i++){
while (counts[i]-->0)
{
array[arrayIndex] = i+min;
arrayIndex++;
}
}
}
void countingSort3rd(vector<int> &array){
//遍历未排序数组,记录最大最小值
int min = array[0];
int max = array[0];
for(int i = 1; i<array.size();i++){
if(min>array[i]){
min = array[i];
}
if(max <array[i]){
max = array[i];
}
}
//定义计数数组,进行计数
int* counts = new int [max -min +1]{0};
for(int i = 0;i<array.size();i++){
counts[array[i]-min]++;
}
//在原有计数数组的基础,对计数值进行累加,把计数值改为 该元素在排序数组中的位置
int locatingNum = 0;
for(int i = 0;i<max-min+1;i++){
if(counts[i] == 0){//如果排序数组中没有这个元素(计数值为0),不进行累加
continue;
}
locatingNum = locatingNum + counts[i];
counts[i] = locatingNum;
}
//打印累加计数数组
countsIndexPrint(min,max);
cout<<endl;
arrayPrint(counts,max-min+1);
//定义临时数组,根据累加计数数组的位置值,从右到左遍历未排序数组,把元素插入到对应位置
int* temp = new int[array.size()];
for(int index = array.size()-1;index>=0;index--){
//array[index]-min = counts数组对应元素索引
//counts[数组对应元素索引] = 数组对应元素在排序序列中的位置
//counts[数组对应元素索引] - 1 = 数组对应元素在排序数组中的索引
temp[counts[array[index]-min]-1] = array[index];
counts[array[index]-min]--;
}
//用备份数组覆盖原数组
for (int i = 0; i < array.size(); i++)
{
array[i]=temp[i];
}
}
int main()
{
Tools::Time::AlgoTimeUs time1;
Tools::Time::AlgoTimeUs time2;
Tools::Time::AlgoTimeUs time3;
vector<int> array;
array = {6, 9, 6, 7, 5, 8, 8, 29, 15, 11, 10};
vector<int> array2 = {-6, 9, 6, 7, 5, 8, 8, 29, 15, 11, 10};
vector<int> array3 = array2;
cout<<"输入数组:"<<endl;
vectorPrint(array);
time1.start();
cout << "计数排序基础版" << endl;
countingSort(array);
cout << "算法用时:(微秒)";
time1.printElapsed();
cout << "排序结果:" << endl;
vectorPrint(array);
cout << ' ' << endl;
cout<<"输入数组:"<<endl;
vectorPrint(array2);
time2.start();
cout << "计数排序第一次改进版" << endl;
countingSort2nd(array2);
cout <<endl<< "算法用时:(微秒)";
time2.printElapsed();
cout << "排序结果:" << endl;
vectorPrint(array2);
cout << ' ' << endl;
cout<<"输入数组:"<<endl;
vectorPrint(array3);
time3.start();
cout << "计数排序终极版" << endl;
countingSort3rd(array3);
cout <<endl<< "算法用时:(微秒)";
time3.printElapsed();
cout << "排序结果:" << endl;
vectorPrint(array3);
cout << ' ' << endl;
return 0;
}