线性时间排序
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; //将桶中元素插入回原数组。 } } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- JavaScript演示排序算法
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序