数据结构与算法之非比较排序【Java】
比较排序与非比较排序的对比
常见的快速排序、归并排序、堆排序、冒泡排序等属于比较排序。在排序的最终结果里,元素之间的次序依赖于它们之间的比较。每个数都必须和其他数进行比较,才能确定自己的位置。在冒泡排序之类的排序中,问题规模为n,又因为需要比较n次,所以平均时间复杂度为O(n²)。在归并排序、快速排序之类的排序中,问题规模通过分治法消减为logN次,所以时间复杂度平均O(nlogn)。比较排序的优势是,适用于各种规模的数据,也不在乎数据的分布,都能进行排序。可以说,比较排序适用于一切需要排序的情况。
计数排序、基数排序、桶排序则属于非比较排序。非比较排序是通过确定每个元素之前,应该有多少个元素来排序。针对数组arr,计算arr[i]之前有多少个元素,则唯一确定了arr[i]在排序后数组中的位置。
非比较排序只要确定每个元素之前的已有的元素个数即可,所有一次遍历即可解决。算法时间复杂度O(n)。非比较排序时间复杂度底,但由于非比较排序需要占用空间来确定唯一位置。所以对数据规模和数据分布有一定的要求。
非比较排序
常见的比较排序主要有以下几种:基数排序、计数排序、桶排序。
基数排序
1、基本思想:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。
2、算法实现
package com.allSorts; import java.util.ArrayList;
import java.util.List; /**
* Created by Demrystv.
*/
public class Ji1Shu {
public static void main(String[] args) {
int[] a = {23,45,67,88,90,21,42,52,73,61};
System.out.println("排序前:");
for(int i=0;i<a.length;i++){
System.out.print(a[i]+" ");
} //基数排序
sort(a); System.out.println("");
System.out.println("排序后:");
for(int i=0;i<a.length;i++){
System.out.print(a[i]+" ");
}
} private static void sort(int[] a){ //找到最大值,看最大值有几位,从而确定要比较几次,个十百千万。。。
int max = 0;
for(int i=0;i<a.length;i++){
if(max<a[i]){
max = a[i];
}
} //找到最大值后,确定要比较几次
int times = 0;
while (max>0){
max = max/10;
times++;
} //建立从0到9十个队列
List<ArrayList> list1 = new ArrayList<>();
for(int i=0;i<10;i++){
ArrayList list2 = new ArrayList();
list1.add(list2);
} //进行times次分配和收集,不断的重复即可。
for(int i=0;i<times;i++){ //分配,按照比较的所在的位的大小将其放入list1 中,类似于数组链表中的链表
for(int j=0;j<a.length;j++){
int x = a[j] % (int)Math.pow(10,i+1) / (int)Math.pow(10,i);
ArrayList list3 = list1.get(x);
list3.add(a[j]);
list1.set(x,list3);
} //收集,然后以此从数组的从左到右,链表的从上到下进行收集,将其重新放进一个新的数组中
int count = 0 ;
for(int j=0;j<10;j++){
while (list1.get(j).size()>0){
ArrayList<Integer> list4 = list1.get(j);
a[count] = list4.get(0);
list4.remove(0);
count++;
}
}
} }
}
3、分析
基数排序是稳定的排序算法。
基数排序的时间复杂度为O(k*n),空间复杂度为O(m),k为数组中数值的最大位数,m为桶的的个数。
计数排序
package com.allSorts; /**
* Created by Demrystv.
*/
public class Ji4Shu {
public static void main(String[] args) {
int[] a = {23,42,53,64,63,32,13,52,97,94,26};
System.out.println("排序前:");
for(int i=0;i<a.length;i++){
System.out.print(a[i]+" ");
} //计数排序
sort(a); System.out.println("");
System.out.println("排序后:");
for(int i=0;i<a.length;i++){
System.out.print(a[i]+" ");
}
} private static void sort(int[] a){ if(a==null || a.length==0){
return;
} int max=0,min=0;
for(int i=0;i<a.length;i++){
max = Math.max(max,a[i]);
min = Math.min(min,a[i]);
} int[] help = new int[max-min+1];
int pos; for(int i=0;i<a.length;i++){
pos = a[i]-min;
help[pos]++;
} int index=0;
for(int i=0;i<help.length;i++){
while (help[i]>0){
a[index] = i + min;
index++;
help[i]--;
}
}
}
}
3、分析
计数排序是稳定的排序算法。
计数排序的时间复杂度为O(k+n),空间复杂度为O(m),k为数组中最大数与最小数差值,m为桶的的个数。
桶排序
package com.allSorts; import java.util.ArrayList;
import java.util.Collections; /**
* Created by Demrystv.
*/
public class Tong {
public static void main(String[] args) {
int[] a = {32,45,42,51,53,86,95,53,93,55,59};
System.out.println("排序前:");
for(int i=0;i<a.length;i++){
System.out.print(a[i]+" ");
} //桶排序
sort(a); System.out.println("");
System.out.println("排序后:");
for(int i=0;i<a.length;i++){
System.out.print(a[i]+" ");
}
} private static void sort(int[] a){ if(a==null || a.length==0){
return;
} int max=0,min=0;
for(int i=0;i<a.length;i++){
max = Math.max(max,a[i]);
min = Math.min(min,a[i]);
} //确定桶数,并且建立一系列的桶
int bucketNum = (max-min)/a.length+1;
ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
for (int i=0;i<bucketNum;i++){
bucketArr.add(new ArrayList<Integer>());
} //将每个元素放入桶
for(int i=0;i<a.length;i++){
int num = (a[i]-min)/a.length;
bucketArr.get(num).add(a[i]);
} //对每个桶进行排序
for(int i=0;i<bucketArr.size();i++){
Collections.sort(bucketArr.get(i));
} int index = 0;
for(int i=0;i<bucketArr.size();i++){
while (bucketArr.get(i).size()>0){
a[index++] = bucketArr.get(i).get(0);
bucketArr.get(i).remove(0);
}
}
}
}
3、分析
数据结构与算法之非比较排序【Java】的更多相关文章
- 数据结构和算法(Golang实现)(25)排序算法-快速排序
快速排序 快速排序是一种分治策略的排序算法,是由英国计算机科学家Tony Hoare发明的, 该算法被发布在1961年的Communications of the ACM 国际计算机学会月刊. 注:A ...
- 数据结构和算法(Golang实现)(23)排序算法-归并排序
归并排序 归并排序是一种分治策略的排序算法.它是一种比较特殊的排序算法,通过递归地先使每个子序列有序,再将两个有序的序列进行合并成一个有序的序列. 归并排序首先由著名的现代计算机之父John_von_ ...
- 数据结构和算法(Golang实现)(24)排序算法-优先队列及堆排序
优先队列及堆排序 堆排序(Heap Sort)由威尔士-加拿大计算机科学家J. W. J. Williams在1964年发明,它利用了二叉堆(A binary heap)的性质实现了排序,并证明了二叉 ...
- 数据结构和算法(Golang实现)(18)排序算法-前言
排序算法 人类的发展中,我们学会了计数,比如知道小明今天打猎的兔子的数量是多少.另外一方面,我们也需要判断,今天哪个人打猎打得多,我们需要比较. 所以,排序这个很自然的需求就出来了.比如小明打了5只兔 ...
- 数据结构和算法(Golang实现)(19)排序算法-冒泡排序
冒泡排序 冒泡排序是大多数人学的第一种排序算法,在面试中,也是问的最多的一种,有时候还要求手写排序代码,因为比较简单. 冒泡排序属于交换类的排序算法. 一.算法介绍 现在有一堆乱序的数,比如:5 9 ...
- 数据结构和算法(Golang实现)(20)排序算法-选择排序
选择排序 选择排序,一般我们指的是简单选择排序,也可以叫直接选择排序,它不像冒泡排序一样相邻地交换元素,而是通过选择最小的元素,每轮迭代只需交换一次.虽然交换次数比冒泡少很多,但效率和冒泡排序一样的糟 ...
- 数据结构和算法(Golang实现)(21)排序算法-插入排序
插入排序 插入排序,一般我们指的是简单插入排序,也可以叫直接插入排序.就是说,每次把一个数插到已经排好序的数列里面形成新的排好序的数列,以此反复. 插入排序属于插入类排序算法. 除了我以外,有些人打扑 ...
- 数据结构和算法(Golang实现)(22)排序算法-希尔排序
希尔排序 1959 年一个叫Donald L. Shell (March 1, 1924 – November 2, 2015)的美国人在Communications of the ACM 国际计算机 ...
- Python数据结构与算法(几种排序)
数据结构与算法(Python) 冒泡排序 冒泡排序(英语:Bubble Sort)是一种简单的排序算法.它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.遍历数列的工作是 ...
随机推荐
- 罗德里格斯旋转公式(Rodrigues' rotation formula)推导
本文综合了几个相关的维基百科,加了点自己的理解,从比较基础的向量投影和叉积讲起,推导出罗德里格斯旋转公式.公式比较繁杂,如有错误,欢迎评论区指出. 对于向量的三维旋转问题,给定旋转轴和旋转角度,用罗德 ...
- 突破CRUD | 万能树工具类封装
0.学完本文你或许可以收获 感受一个树工具从初始逐步优化完善的过程 树工具封装的设计思考与实现思路 最后收获一款拿来即用的树工具源代码 对于前端树组件有一定了解和使用过的同学可直接跳跃到第3章节开始. ...
- logstash 安装插件multiline
一.安装multiline 在使用elk 传输记录 java 日志时,如下 一个java的报错 在elk中会按每一行 产生多条记录,不方便查阅 这里修改配置文件 使用 multiline 插件 ...
- awk sed 命令
awk awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大. 简单来说awk就是把文件逐行的读入,以 空格或TAB 为默认分隔符 将每行 ...
- href的几个特殊值
a href ="" :默认打开的还是当前页面,会刷新一下重新打开. a href ="#": 浏览器地址栏网址后面会多显示1个#.不会刷新页面,会回到页面顶部 ...
- AJAX优势、跨域方案及JSON数据格式和浏览器中JSON对象
ajax 不重新加载整个网页的情况下,更新部分网页的技术 注意:ajax只有在服务器上运行才能生效,我在本地一般用phpstudy 优点: 1.优化用户体验 2.承担了一部分本该服务器端的工作,减轻了 ...
- cesium结合geoserver实现地图空间查询(附源码下载)
前言 cesium 官网的api文档介绍地址cesium官网api,里面详细的介绍 cesium 各个类的介绍,还有就是在线例子:cesium 官网在线例子,这个也是学习 cesium 的好素材. 内 ...
- 软链接和硬链接——Linux中的文件共享
硬链接(Hard Link)和软链接也称为符号链接(Symbolic Link)的目的是为了解决文件的共享使用问题.要阐明其原理,必须先理解Linux的文件存储方式. 索引结点 Linux是一个UNI ...
- C#里面低消耗获取当前时间的思路
Linux下有vsyscall来优化一些例如time(NULL), gettimeofday这种调用的消耗; 但是Windows下, 没有类似的东西, 但是思路还是有的 1. 程序启动的时候, 获取一 ...
- JS中let、var、const的区别
先看let和var: 1. console.log(a); // undefined var a = 3; console.log(a); // Uncaught ReferenceError: Ca ...