排序算法——其他算法(那些不是很常见的排序算法)

一、计数排序

基本思想:计数排序的思想和桶排序类似。对于一个给定的序列,统计出序列中比每个数小的个数,就能知道这个数最终在序列中的位置。比如序列[2, 5, 3, 0, 2, 3, 0, 3],序列中比5小的数有7个,那么5在最终的排序序列中就位于第8位(下标为7)。计数排序适用于最大值与最小值相差不大的整数序列的排序。它比快速排序更快,但是不具有普遍适用性。

排序过程:现有一个长度为n的待排序整数序列,序列中的数的范围为0~5。最简单的计数排序过程如下图

这样的方法虽然能够得到正确排序后的序列,但是它存在一个问题。比如最后的序列中有两个2,我们不知道这两个2的初始下标的前后位置。这不满足稳定性的要求,进行适当改进即可。

1、在上图中的统计之后再进行一次统计,将统计数组(C)的值改为记录中小于当前下标所代表的数的记录的总和(即C'[i]=sum(C[0],C[1],...,C[i]))。

2、按倒序遍历原始待排序序列,其值对应的统计数组的值即为该记录在最终序列中的位置。找到位置后,将统计数组对应值减1。这样,遍历到相同的值时,它在最终序列中的下标就在现在这个位置之前,满足稳定性的要求。

其过程图示如下:

稳定计数排序的C++代码实现:

#include<iostream>
using namespace std;

int * countSort(int *array, int k, int length)
{
	//length-数组大小用于构造B数组
	int *C = new int[k + 1];//构造C数组
	for (int i = 0; i < k + 1; i++)//初始化C数组
	{
		C[i]=0;
	}
	int sum = 0;  
	int *B = new int[length];//构造B数组
	for (int i = 0; i < length; i++)
	{
		C[array[i]] += 1;// 统计A中各元素个数,存入C数组
	}
	for (int i = 0; i < k + 1; i++)//修改C数组
	{
		sum += C[i];
		C[i] = sum;
	}
	for (int i = length - 1; i >= 0; i--)//遍历A数组,构造B数组
	{
		int a = array[i];
		int b = C[a]-1;
		B[C[array[i]]-1] = array[i];//将A中该元素放到排序后数组B中指定的位置
		C[array[i]]--;//将C中该元素-1,方便存放下一个同样大小的元素

	}
	return B;//将排序好的数组返回,完成排序

}

int main()
{
	int length = 8;
	int *A = new int[8] {2, 5, 3, 0, 2, 3, 0, 3};
	cout << endl << "排序前:";
	for (int i = 0; i < length; i++)
	{
		cout << A[i]<<" ";
	}
	int *B = countSort(A, 5,length);
	cout <<endl<< "排序后:";
	for (int i = 0; i < length; i++)
	{
		cout << B[i]<<" ";
	}
	system("pause");
	return 0;
}

时间复杂度:Ο(n+k)

空间复杂度:Ο(n+k) 存储结果数组和统计数组

进一步改进:前面的待排序序列范围都是从0开始的,所以统计数组的长度为最大值+1。但是,如果倒排序序列的范围为90到99,如果把统计数组的长度设置为100,就会造成极大的空间和时间的浪费。可以设置一个等于最小值的偏移量来解决这个问题,使得统计数组的长度=最大值-最小值+1。

改进后的C++代码如下:

#include<iostream>
using namespace std;

int * countSort2(int *array, int length)
{
	//length-数组大小用于构造B数组
	//先遍历一遍找出序列中的最小值和最大值
	int min = 0;
	int max = 0;
	for (int i = 0; i < length; i++)
	{
		if (array[i] > max) max = array[i];
		if (array[i] < min) min = array[i];
	}
	int k = max - min + 1;//统计数组的长度k
	int *C = new int[k + 1];//构造C数组
	for (int i = 0; i < k + 1; i++)//初始化C数组
	{
		C[i] = 0;
	}
	int sum = 0;
	int *B = new int[length];//构造B数组
	for (int i = 0; i < length; i++)
	{
		//最小值作为偏移量
		C[array[i]-min] += 1;// 统计A中各元素个数,存入C数组
	}
	for (int i = 0; i < k + 1; i++)//修改C数组
	{
		sum += C[i];
		C[i] = sum;
	}
	for (int i = length - 1; i >= 0; i--)//遍历A数组,构造B数组
	{
		B[C[array[i]-min] - 1] = array[i];//将A中该元素放到排序后数组B中指定的位置
		C[array[i]-min]--;//将C中该元素-1,方便存放下一个同样大小的元素

	}
	return B;//将排序好的数组返回,完成排序

}

int main()
{
	int length = 8;
	int *A = new int[8] {92, 95, 93, 90, 92, 99, 90, 93};
	cout << endl << "排序前:";
	for (int i = 0; i < length; i++)
	{
		cout << A[i]<<" ";
	}
	int *B = countSort2(A,length);
	cout <<endl<< "排序后:";
	for (int i = 0; i < length; i++)
	{
		cout << B[i]<<" ";
	}
	system("pause");
	return 0;
}

 

二、拓扑排序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值