受桶排序思想的启发,想到了这个算法。不同之处在于,桶排序是对于每个bucket各自排序,而本算法桶内部不需要排序。
功能
本算法可以在有限空间内,将任意有理数排序,平均时间复杂度为O(n)
输入:需要排序的数(正有理数 / 负有理数 / 0)
输出:本算法排序结果 + 用于比对的标准答案
思路
利用桶排序的思想,不同之处在于(在不浪费的基础上)建立足够多的桶(同时保证桶的数量为有限个),每个桶只存存放相同数值的元素
1、找到精度最高的数,(精度最高的数,也就是小数点后面位数最多,记其小数点后位数为len
)
2、找到待排序元素的最大值max
,最小值min
3、建立桶,建立哈希函数,将数据放入桶中
4、遍历桶,逆推函数,输出
例如,要排序的数字为:-4 2.1 2 1 5,则桶的个数为(max-min)*10^len+1=91个,这样能保证所有值不同的元素都有且只有一个桶可放。值相同的元素放在相同的桶中。映射关系如下:
运行结果示例
请输入你要排序的数字个数:20
5
-6.2
-6.3
2.22
2.23
1
8.2
10
10
8.3
8.4
10
2.2
3.5
2.2
7
0
5.1
7
4.2
小数点后最多 2 位
最小:-6.3
最大:10
桶的个数:1631
排序后:
元素 重复次数
-6.3 1
-6.2 1
0 1
1 1
2.2 2
2.22 1
2.23 1
3.5 1
4.2 1
5 1
5.1 1
7 2
8.2 1
8.3 1
8.4 1
10 3
正确答案
-6.3
-6.2
0
1
2.2
2.2
2.22
2.23
3.5
4.2
5
5.1
7
7
8.2
8.3
8.4
10
10
10
代码
第45、46行使用了字符串处理有关的函数,如果说整个算法不是严格意义上的O(n)的话,大概是因为这两行吧…
#include<iostream>
#include<string>
#include<vector>
#include<time.h>
#include<algorithm>
#include<math.h>
#define SWAP(a,b) {Node t;t=a;a=b;b=t;}
using namespace std;
class Node//被排序的元素
{
public:
double val;
int afterPoint;
};
int mysort(Node a1, Node a2)//此函数未在算法中调用 仅用于检测结果正确性
{
return a1.val < a2.val;
}
int main()
{
//总元素个数
srand((int)time(NULL));
int total;
cout << "请输入你要排序的数字个数:";
cin >> total;
/*--------------------------------------以下为O(n)排序算法--------------------------------------*/
//读取每一个元素 并记录最大的小数点后数字位数 如:2.555的afterPoint=3 1.2的afterPoint=1
string str;
vector <Node> arr;
Node oneNode;
int afterPointMax = 0;
int i;
cout << "请输入你要排序的数字:\n";
for (i = 0; i < total; i++)
{
cin >> str;
oneNode.val = atof(str.c_str());//string to double
int pointPlace = str.find_first_of(".");//小数点位置
oneNode.afterPoint = (pointPlace == -1 ? 0 : str.length() - pointPlace - 1);//计算小数点后面的位数
afterPointMax = (afterPointMax > oneNode.afterPoint ? afterPointMax : oneNode.afterPoint);//记录最大的小数位数
arr.push_back(oneNode);
}
cout << "小数点后最多 " << afterPointMax << " 位" << endl;
//同时找最大最小
//偶数个 分两半 一半含有最大 一半含有最小 O(n/2)
double max, min;
for (i = 0; i < total / 2; i++)
{
if (arr[i].val > arr[total / 2 + i].val)
{
SWAP(arr[i], arr[total / 2 + i]);//小的放左边
}
}
//找最小 O(n/2)
min = arr[0].val;
for (i = 0; i < total / 2; i++)
{
if (arr[i].val < min)
{
min = arr[i].val;
}
}
//找最大 O(n/2)
max = arr[total / 2].val;
for (i = total / 2; i < total; i++)
{
if (arr[i].val > max)
{
max = arr[i].val;
}
}
//如果最后元素轮空 再加一次比较
if (total % 2 != 0)
{
if (arr[total - 1].val < min)min = arr[total - 1].val;
if (arr[total - 1].val > max)max = arr[total - 1].val;
}
//输出
cout << "最小:" << min << endl;
cout << "最大:" << max << endl;
//桶的个数
double bucketNum;
bucketNum = (max - min)*pow(10, afterPointMax) + 1;
cout << "桶的个数:" << bucketNum << endl;
//定义桶并初始化为0
int* bucket = new int[(int)bucketNum];
for (i = 0; i < bucketNum; i++)
{
bucket[i] = 0;
}
//类似构建一个哈希函数
int t;
for (i = 0; i < total; i++)
{
t = pow(10, afterPointMax);
bucket[(int)((arr[i].val - min) / (max - min)*(bucketNum - 1) + 0.5)]++;//0.5用于强制四舍五入
}
//函数逆推并输出排序结果
cout << "\n排序后:\n元素\t重复次数\n";
for (i = 0; i < bucketNum; i++)
{
if (bucket[i] != 0)
{
cout << (i / (bucketNum - 1)*(max - min)) + min << "\t";
cout << bucket[i] << endl;
}
}
/*--------------------------------------以上为O(n)排序算法--------------------------------------*/
//正确性检测:以下输出正确答案作为对比
cout << "\n正确答案\n";
sort(arr.begin(), arr.end(), mysort);
for (i = 0; i < total; i++)
{
cout << arr[i].val << endl;
}
cout << endl;
system("pause");
}