不基于比较的排序——基数排序的优化

桶排序(Bucket Sort)是一种排序算法,它将待排序的元素分布到一些有序的桶中,然后对每个桶中的元素进行排序,最后将这些桶按顺序合并成一个有序的序列。桶排序适用于待排序元素分布相对均匀的情况

常规的基数排序需要准备N个桶来计数(N为几进制),但还有更优化的办法 本文重点介绍不用桶的算法

前置:计数排序

计数排序的核心思想是统计每个元素的出现次数,然后根据这些统计信息将元素放回正确的位置。

计数排序适用于一些特殊情况,其中输入数据的范围相对较小,例如整数或有限范围的字符。在这些情况下,计数排序可以在线性时间内完成排序,效率非常高。

void countsort(vector& arr) {
	if (arr.empty())
		return ;
	int min= arr[0],max=arr[0];
	for (int i = 1; i < arr.size(); i++) {
		max = arr[i] > max ? arr[i] : max;
		min = arr[i] < min ? arr[i] : min;
	}
	int range = max - min + 1;
	vectorcountarr(range, 0);
	for (int i = 0; i < countarr.size(); i++) {
		countarr[arr[i] - min]++;
	}
	
	for (int i = 0,index=0; i < range; i++) {
		while (countarr[i]--) {
			arr[index++] = i + min;
		}
	}

}

缺点就是对数据状况有很高的要求 

优化:基数排序

不基于比较的排序——基数排序的优化_第1张图片

传统做法:设置N个桶(栈,队列,或者是数组) 根据个位数导入相应桶 再导出,根据十位数导入桶 再导出。。再依次对百位等高位重复相同的过程,直到最高位。

这种做法在数据范围比较大或位数较多的情况下,需要创建的桶数量可能较多,这可能会影响算法的空间复杂度。

下面重点介绍 优化做法 优雅的创建一个桶

count数组用来记录每数位的数出现次数

count‘是count的前缀和数组 然后再建一个help辅助数组

如图要排序的数组是[021,010,111,022,011,012]

将要排序的数组从右往左遍历 

012的出现范围是0-5(查前缀和数组)根据出桶顺序 放到数组第五位置

011放到第三位置。以此类推。这样就能得到一个类似桶的数组 且不用创建很多个桶 。

 另外,函数 getdigit 用于获取一个数字在某一位上的数字,如个位、十位等。这个函数帮助我们将数字分配到相应的桶中。

radix是进制数 进制数越大 时间复杂度越低 时间复杂度为nlogradix。

void radixSort(int arr[], int L, int R, int dight) {
	const int radix = 10; int i = 0, j = 0;
	int* help = new int[R - L + 1];
	for (int d = 1; d <= dight; d++) {
		int* count = new int[radix];//count[i] 当前位是0-i的数字的个数
		for (i = L; i <= R; i++) {
			j = getdigit(arr[i], d);
			count[j]++;
		}
		for (int i = 1; i < radix; i++)
			count[i] = count[i] + count[i - 1];//求前缀和数组
		for (i = R; i >= L; i--) {
			j = getdigit(arr[i], d);
			help[count[j] - 1] = arr[i];//arr[i]放到j的词频-1的位置
			count[j]--;
		}
		for (i = L, j = 0; i <= R; i++, j++)
			arr[i] = help[j];
	}
	
}
int getdigit(int x, int d) {
	return ((x / (int)pow(10, d - 1)) % 10);
}

最后将排序完的help拷贝到arr.

你可能感兴趣的:(数据结构)