您的位置:首页 > 编程语言 > Java开发

线性时间排序

2016-07-28 16:13 399 查看

线性时间排序

前面写的排序的算法,平均时间复杂度是O(nlogn)的,现在介绍三个线性时间复杂度的排序算法。

一、计数排序

计数排序:假设n个输入元素位于区间[0,k]之间的元素,k为某个整数,当k=O(n)时,排序的运行时间为O(n)

基本思想:对于一个输入元素x,确定小于x的元素的个数。就可以直接把x放在相应的位置上。这个排序算法需要使用两个辅助空间,一个用于存放排序的数组,一个用于存放[0,k]的数应该存放的最末位置。每次从A中取出一个数,将其放在排序数组的正确位置。需要传入k的值。

实现:

public static void sort(int[] arr, int k){
int[] tmp = new int[arr.length];
int[] c = new int[k+1];
for (int i = 0; i < k + 1; i++){
c[i] = 0;
}
//计算每个数出现的次数
for (int i = 0; i < arr.length; i++){
c[arr[i]] ++;
}
//计算每个数应该保存的位置的最后一个(有多个,则c[i]保存的是最后一个i的位置)
for (int i = 1; i < k + 1; i++){
c[i] = c[i] + c[i - 1];
}

for (int i = 0; i < arr.length; i++){
tmp[--c[arr[i]]] = arr[i];
}

for (int i = 0; i < arr.length; i++){
arr[i] = tmp[i];
}
}


二、基数排序

基数排序就是对n个d位的数进行排序,依次从个位、十位、百位、…、d位进行排序,需要10个辅助队列,i存放某位数为i的队列。最终排好序。也可以是对有多个属性(基数)的对象排序,如对日期排序,可以使用年、月、日分别作一次排序,最终达到排序。

时间复杂度O(d(n+k)),d为位数,n为数组元素个数,k为每一位可能出现的结果(数字为10),当d为常数,k=O(n)时,基数排序是基于线性的排序。这个排序是稳定的排序。

实现:

public static void sort(int[] arr){
if (arr == null || arr.length <= 0) return;
LinkedList<Integer>[] lists = new LinkedList[10];
for (int i = 0; i < 10; i++){
lists[i] = new LinkedList<>();
}
int d = 1;  //第i位
int count = 0; //记录当前位为0的个数,如果全部为0,则结束
while (count != arr.length){
count = 0;
for (int i = 0; i < arr.length; i++){
//计算当前位
int cur = (arr[i] / d) % 10;
if (arr[i] / d == 0) count++;  //说明已经超出该数的位数
lists[cur].addLast(arr[i]);
}
//将数组元素重新排列
int k = 0;
for (LinkedList<Integer> list : lists) {
for (Integer integer : list) {
arr[k++] = integer;
}
list.clear(); //清除当前列表
}
d *= 10; //下一位
}
}


三、桶排序

桶排序:假设输入数据服从均匀分布,平均情况下的时间复杂度为O(n),最坏情况是O(n2)。该排序假设输入数据是由一个随机过程生成的,该过程是将元素均匀、独立地分布在[0,1)区间。

基本思想:桶排序将[0,1)区间划分为n个相同大小的的子区间,或称为桶。然后将n个输入分别放入各个桶中。假设输入数组为n个元素的数组A,0≤A[i]<1,需要一个辅助数组B存放链表。可以将排序扩展(例如要对大小为[1..1000]范围内的n个整数A[1..n]排序,可以把桶设为大小为10的范围,具体而言,设集合B[1]存储[1..10]的整数,集合B[2]存储(10..20]的整数,……,集合B[i]存储((i-1)×10, i×10]的整数,i = 1,2,..100。总共有100个桶。然后对A[1..n]从头到尾扫描一遍,把每个A[i]放入对应的桶B[j]中。 然后再对这100个桶中每个桶里的数字排序,这时可用冒泡,选择,乃至快排,一般来说任何排序法都可以。最后依次输出每个桶里面的数字,且每个桶中的数字从小到大输出,这样就得到所有数字排好序的一个序列了。)

实现:

public static void sort(double[] arr){
if (arr == null || arr.length <= 0) return;
LinkedList<Double>[] lists = new LinkedList[arr.length];
for (int i = 0; i < arr.length; i++){
lists[i] = new LinkedList<>();
}
for (int i= 0; i < arr.length; i++){
int index = (int)(arr.length * arr[i]);
lists[index].add(arr[i]);
}

int k = 0;
for (LinkedList<Double> list : lists) {
Collections.sort(list);   //在桶中选择合适的排序算法排序
for (Double aDouble : list) {
arr[k++] = aDouble; //将桶中元素插入回原数组。
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息