算法设计与分析 自创O(n)排序算法 适用于任何有理数

受桶排序思想的启发,想到了这个算法。不同之处在于,桶排序是对于每个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");
}

猜你喜欢

转载自blog.csdn.net/sinat_42483341/article/details/89425660