桶排序 与 基数排序 与 外部排序(C++)

桶排序:

    对于任何一种需要比较的排序算法,其最优的时间下界也在NlogN处,但如果已知了一部分的信息,甚至能将这个时间优化为近乎线性,这便是桶排序的一种想法。对于已知的数据量上下界,为其建立好一个个桶,每遇到一个元素,就将其放进相应的桶里,最后来统计桶中的球的数量。但即便这样还是有些抽象,建议看一些大佬们画的图解。

    以及有的时候,我们的数据块并不是整数,而是一个个非常大的节点。它们无法全都装到内存里面去,所有如果仍然执行交换操作,将会浪费非常多的时间在这里。一种简单的操作方法是,为这些数据建立一个指针数组,数组的第一格存放的指针指向最小的数据块,第二格,第三格......

    这样,在需要排序的时候,我们实际只需要排序指针的位置,而不需要移动数据本来的位置。从而能减少很多时间。

    如下代码是我自己写的桶排序与外部排序的结合,通过链表的方式实现。

全代码:

typedef struct Queue* Position;
typedef struct Node* pNode;
struct Node
{
	int Key;
	pNode Next;
};
struct Queue
{
	pNode Data;
};
Position BucketSort(Node *A,int Size,int MaxNumber)
{
	Position P;
	P = new Queue[MaxNumber];
	pNode tmp;
	for (int i = 0; i < MaxNumber; i++)
		P[i].Data = NULL;
	for (int i = 0; i < Size; i++)
	{
		tmp = P[A[i].Key].Data;
		while (tmp->Next)
			tmp = tmp->Next;
		tmp->Next = &A[i];
		tmp->Next->Next = NULL;
	}
	return P;
}

    不是很复杂,主要是针对[0,MaxNumber)区间的一系列能够依靠整数关键字来排序。

基数排序:(算是桶排序的变种)

    原理并不复杂。最低位的次序关系将会在其高位的排序中保留下来。

    基础的这种算法只能用于排序整数。并且如果算法设计的不是很好,MSD(最高位优先)很可能不稳定。以下代码位LSD(最低位优先)。

int MaxGet(int *Source,int N)
{
	int tmp=0;
	for (int i = 0; i < N; i++)
	{
		if (Source[i] > tmp)
			tmp = Source[i];
	}
	return tmp;
}
int BitGet(int A)
{
	int d = 0;
	while (A > 0)
	{
		A /= 10;
		d++;
	}
	return d;
}
void RadixSort(int *Source,int N)//Least Significant Digit
{
	int MaxNumber = MaxGet(Source,N);
	int Bit = BitGet(MaxNumber);
	int* tmplist = new int[N];
	int* Count = new int[10];
	int k = 0,radix = 1;
	for (int i = 0; i <= Bit; i++)
	{
		for (int j = 0; i < 10; j++)
			Count[j] = 0;
		for (int j = 0; j < N; j++)
		{
			k = (Source[j]/radix) % 10;
			Count[k]++;
		}
		for (int j = 1; j < 10; j++)
			Count[j] = Count[j - 1] + Count[j];
		for (int j = N-1; j >=0; j++)
		{
			k = (Source[j]/radix) % 10;
			tmplist[Count[k] - 1] = Source[j];
			Count[k]--;
		}
		for (int j = 0; j < N; j++)
		{
			Source[j] = tmplist[j];
		}
		radix *= 10;
	}
	delete[]tmplist;
	delete[]Count;
}

    ①首先获取整个数组中最高的数位(比如最大有1000,那Bit就应该为4)

    ②建立临时数组tmplist和计数器Count。声明变量。

    ③进入循环。Count初始化,并统计最低位为 k 的数的个数。

    ④将Count中保存的个数转换为对应的tmplist中的索引编号

    (比方说,Count[0]=2,Count[1]=3。那最低位为0的数就应该摆在tmplist[0~1],而最低位为1的数则在tmplist[2~4]。将计算好的Count[j]-1就是低位相同的数的最高储存索引(比如说tmplist[0~5],那它就会把6存在Count里))。

    ⑤将每一个数全都按照低位的大小排入tmplist,并将tmplist数据复制到Source中(如果不吝啬代码的长度,可以改为两个数组的交替使用,可以在一定程度上再提高一点效率)。

    ⑥再按照第二位重复如上操作,直到最高位也结束排序。最后将tmplist和Count的空间都释放掉。

猜你喜欢

转载自blog.csdn.net/Tokameine/article/details/113918737