java中的排序
排序是数据结构中重要的一个部分,也是在实际开发中最易遇到的问题之一,当然了,你也可以不考虑这些排序的算法,直接把要排序的数据insert到数据库中,用数据库的order by再select一下,也能产生排序结果,不过,开发一个好的系统,性能同样很重要。
在一堆数据中,是比较的执行耗时多,还是复制交换的执行耗时比较多,大量数据比较时,是否会有内存限制等等,在综合这些因素后,我们选择适当的排序算法,常常会让系统性能提升数倍,当然了,如果你的系统中没有任何需要数据排序的,那就不考虑了。
所有的排序算法,都是在大数据量时才会显示出其运行差别,所以,在下面的讨论中,大家了解各特性,按需选用。注:以下的排序,均以int或long型来比较,其实,比较的元素可以是除这以外的任何对象,要对象实现比较功能,可参考jdk的compareable接口,这个后面再讨论。
所有的问题,都会有一个简单的解决方法,但它往往并不是最佳的方法。
一,冒泡排序
Java代码
public void bubbleSort(int[] array) {
int temp;
for(int i=0;i<array.length-1;i++){
for(int j=i+1;j<array.length;j++){
if (array[i]>array[j]){
temp=array[i];
array[i]=array[j];
array[j]=temp;
}
}
}
public void bubbleSort(int[] array) {
int temp;
for(int i=0;i<array.length-1;i++){
for(int j=i+1;j<array.length;j++){
if (array[i]>array[j]){
temp=array[i];
array[i]=array[j];
array[j]=temp;
}
}
}
这个是最简单,最易理解的排序算法。从队列的最左边开始,比较0号位置和1号位置的元素,如果左边的元素(0号)大,就让两个元素交换;如果右边的元素大,就什么也不做。然后右移一个位置比较1号位置和2号位置;沿着这个队列照这样比较下去,一直比较到队列的最右端,虽然没有把所有元素排好充,但是最大的那个元素已经在最右边了,也就像是在水底下冒泡一样,冒上来了。然后再从左边的1号开始,再循环前面的操作。。。。
可以看出,冒泡排序运行需要O(N^2)时间级别,其速度是很慢的,比较次数:N*(N-1)/2,交换次数最坏的情况也是:N*(N-1)/2。
2,选择排序
选择排序与冒泡排序有点相似,但是,选择排序对冒泡排序做了些许优化:减少元素交换的次数。
从下面的代码中,我们可以看出,通过每一次循环,标识出当前最小的元素,再做交换。
选择排序和冒泡排序执行了相同的比较次数:N*(N-1)/2,对于100个数据项就是要4950次比较,但选择排序只进行了不到100次交换。当N值很大时,比较的次数是主要的。所以,当N比较小,特别是如果交换的性能消耗比比较的性能消耗大得多时,用选择排序是相当快的。
Java代码
public void selectionSort(int[] array)
{
int out, in, min,nElems=array.length;
for(out=0; out<nElems-1; out++) // 外层循环
{
min = out; // 最小值
for(in=out+1; in<nElems; in++) // 内层循环
if(a[in] < a[min] ) // 如果有比最小值还小的
min = in; // 得到新最小值
swap(out, min); // 交换
} // end for(out)
} // end selectionSort()
private void swap(int one, int two)
{
long temp = a[one];
a[one] = a[two];
a[two] = temp;
}
public void selectionSort(int[] array)
{
int out, in, min,nElems=array.length;
for(out=0; out<nElems-1; out++) // 外层循环
{
min = out; // 最小值
for(in=out+1; in<nElems; in++) // 内层循环
if(a[in] < a[min] ) // 如果有比最小值还小的
min = in; // 得到新最小值
swap(out, min); // 交换
} // end for(out)
} // end selectionSort()
private void swap(int one, int two)
{
long temp = a[one];
a[one] = a[two];
a[two] = temp;
}
三,插入排序
插入排序的特点是局部有序,通过循环,在(局部)有序组中的适当位置插入元素进行排序。然而要做到这一点,就需要把部分已排序的队员右移以让出空间。当把最后一个要比较的元素移位之后,这个移动的过程就结束了。
Java代码
public void insertionSort(int a[]){
int in, out,nElems=a.length;
for(out=1; out<nElems; out++) { // 外层循环
long temp = a[out]; // 先把要插入有序队列中的元素取出
in = out; // 要从这个元素的左边开始依次比较了
while(in>0 && a[in-1] >= temp){ // 比较条件,
a[in] = a[in-1]; // 比temp大的元素,就要右移了
--in; // 再比较左边的
}
a[in] = temp; // 找到合适的位置了
} // end for
} // end insertionSort()
public void insertionSort(int a[]){
int in, out,nElems=a.length;
for(out=1; out<nElems; out++) { // 外层循环
long temp = a[out]; // 先把要插入有序队列中的元素取出
in = out; // 要从这个元素的左边开始依次比较了
while(in>0 && a[in-1] >= temp){ // 比较条件,
a[in] = a[in-1]; // 比temp大的元素,就要右移了
--in; // 再比较左边的
}
a[in] = temp; // 找到合适的位置了
} // end for
} // end insertionSort()
在外层的for循环中,out变量从1开始,向右移动。它标记了未排序部分的最左端的数据。而在内层的while循环中,in变量从out变量开始,向左移动,直到temp变量小于in所指的数组数据项,或者它已经不能再往左移动了。while循环的每一趟都向右移动了一个已排序的数据项。
这个算法需要多少次比较和复制呢?在第一趟排序中,它最多比较一次,在第二趟中最多比较两次,依此类推了,最后一趟最多,N-1次.所以:
1+2+3+......+N-1=N*(N-1)/2
然而,在每一趟排序发现插入点之前,平均只有全体数据项的一半真的进行了比较,所以实际上大约是N*(N-1)/4 次 (这个值不是精确值,只是一个概率的估算值,学过数理统计的朋友就不要太过计较了)
复制的次数大致等于比较的次数,由于一次复制与一次交换的时间耗费不同,所以相对于随机数据,这个算法比冒泡排序快一倍,比选择排序略快。
如果数据基本有序,插入排序几乎只需要O(N)的时间;然后对于逆序排列的数据,每次比较和移动都会执行,所以这时插入排序并不比冒泡快。
大家在选择算法时,要注意了,在事先估算待排序数据的状况下,再选择相应的算法。
四,有序链表排序
这里存储数据的方式就不是前面讨论的用数组来存储了,而是用链表这一个数据结构。
有序链表排序是一种高效的排序机制。所设有一个无序数组,如果从这个数组中取出数据,然后一个一个地插入有序链表,它们自动地按序排列,把它们从链表中删除重新放入数组,那么数组就会排好序了。
建立链表类Link.java:
Java代码
class Link
{
public long dData;
public Link next;
public Link(long dd)
{ dData = dd; }
}
class Link
{
public long dData;
public Link next;
public Link(long dd)
{ dData = dd; }
}
建立有序链表SortedList.java
Java代码
class SortedList
{
private Link first;
public SortedList()
{ first = null; }
public SortedList(Link[] linkArr)
{
first = null;
for(int j=0; j<linkArr.length; j++)
insert( linkArr[j] );
}
public void insert(Link k)
{
Link previous = null;
Link current = first;
while(current != null && k.dData > current.dData)
{
previous = current;
current = current.next;
}
if(previous==null)
first = k;
else
previous.next = k;
k.next = current;
} // end insert()
public Link remove()
{
Link temp = first;
first = first.next;
return temp;
}
}
class SortedList
{
private Link first;
public SortedList()
{ first = null; }
public SortedList(Link[] linkArr)
{
first = null;
for(int j=0; j<linkArr.length; j++)
insert( linkArr[j] );
}
public void insert(Link k)
{
Link previous = null;
Link current = first;
while(current != null && k.dData > current.dData)
{
previous = current;
current = current.next;
}
if(previous==null)
first = k;
else
previous.next = k;
k.next = current;
} // end insert()
public Link remove()
{
Link temp = first;
first = first.next;
return temp;
}
}
测试类ListInsertionSortApp.java:
Java代码
class ListInsertionSortApp
{
public static void main(String[] args)
{
int size = 10;
// 建立一个随机数组
Link[] linkArray = new Link[size];
for(int j=0; j<size; j++)
{
int n = (int)(java.lang.Math.random()*99);
Link newLink = new Link(n); // 建立链表
linkArray[j] = newLink;
}
System.out.print("Unsorted array: ");
for(int j=0; j<size; j++)
System.out.print( linkArray[j].dData + " " );
System.out.println("");
SortedList theSortedList = new SortedList(linkArray);
for(int j=0; j<size; j++)
linkArray[j] = theSortedList.remove();
System.out.print("Sorted Array: ");
for(int j=0; j<size; j++)
System.out.print(linkArray[j].dData + " ");
System.out.println("");
}
}
class ListInsertionSortApp
{
public static void main(String[] args)
{
int size = 10;
// 建立一个随机数组
Link[] linkArray = new Link[size];
for(int j=0; j<size; j++)
{
int n = (int)(java.lang.Math.random()*99);
Link newLink = new Link(n); // 建立链表
linkArray[j] = newLink;
}
System.out.print("Unsorted array: ");
for(int j=0; j<size; j++)
System.out.print( linkArray[j].dData + " " );
System.out.println("");
SortedList theSortedList = new SortedList(linkArray);
for(int j=0; j<size; j++)
linkArray[j] = theSortedList.remove();
System.out.print("Sorted Array: ");
for(int j=0; j<size; j++)
System.out.print(linkArray[j].dData + " ");
System.out.println("");
}
}
这种排序方式总体上比在数组中用常用的插入排序效率更高一些,因为这种方式进行的复制次数少一些,但它仍然是一个时间级为O(N^2)的过程,因为在有序链表中每插入一个新的链结点,平均要与一半已存在数据进行比较。如果插入N个新数据,就进行了N*N/4次比较。每一个链结点只进行两次复制:一次从数组到链表,一次从链表到数组。在数组中进行插入排序需要N*N次移动,相比之下,2*N次移动更好。
java中的排序的更多相关文章
- Java中的排序算法(2)
Java中的排序算法(2) * 快速排序 * 快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists). * 步骤为: * 1. 从数 ...
- Comparable与Comparator,java中的排序与比较
1:比较和排序的概念 比较:两个实体类之间按>,=,<进行比较. 排序:在集合类中,对集合类中的实体进行排序.排序基于的算法基于实体类提供的比较函数. 基本型别都提供了默认的比较算法,如s ...
- Java中中文排序器
在Java中使用Collator类按照汉字拼音排序字符串 public static void main(String[] args) throws Exception{ String[] strs ...
- [个人原创]关于java中对象排序的一些探讨(三)
这篇文章由十八子将原创,转载请注明,并标明博客地址:http://www.cnblogs.com/shibazijiang/ 对对象排序也可以使用Guava中的Ordering类. 构造Orderin ...
- Java中选择排序,冒泡排序,插入排序,快速排序
一:冒泡法排序 //冒泡排序 注:从小到大排 //特点:效率低,实现简单 //思想:每一趟将待排序序列中最大元素移到最后,剩下的为新的待排序序列,重复上述步骤直到排完所有元素. 这只是冒泡排序 ...
- java中的排序--排序容器_TreeSet与TreeMap
1.TreeSet:数据元素可以排序且不可重复. 对比: (1)Set接口:HashSet,元素必须重写hashcode和equals方法. (2)TreeSet:只要可以排序即可.去重:比较等于0即 ...
- java中的排序(自定义数据排序)--使用Collections的sort方法
排序:将一组数据按相应的规则 排列 顺序 1.规则: 基本数据类型:日常的大小排序. 引用类型: 内置引用类型(String,Integer..),内部已经指定规则,直接使用即可.---- ...
- Java中List排序的3种方法
在某些特殊的场景下,我们需要在 Java 程序中对 List 集合进行排序操作.比如从第三方接口中获取所有用户的列表,但列表默认是以用户编号从小到大进行排序的,而我们的系统需要按照用户的年龄从大到小进 ...
- JAVA中List 排序
第一种方法,就是list中对象实现Comparable接口,代码如下: public class SortEntity implements Comparable<SortEntity>{ ...
随机推荐
- Android7.0 拨号盘应用源码分析(一) 界面浅析
前言 android拨号盘的源码目录在package/app/Dialer 自7.0以后Incallui的源码直接放到了Dialer目录下,虽然在7.0以前incallui有自己独立的目录,但实际编译 ...
- Guid.NewGuid().ToString()的几种格式
1.Guid.NewGuid().ToString("N") 结果为: 38bddf48f43c48588e0d78761eaa1ce6 2.Guid.NewGuid() ...
- Crystal Report 处理当前系统时间
Changed the print date format to HH/yy/MM/mm/SS/dd (For Example:2014/01/23 16:30:45= 161430014523) ...
- CentOS安装 Docker
系统的要求64 位操作系统,内核版本至少为 3.10. Docker 目前支持 CentOS 6.5 及以后的版本,推荐使用 CentOS 7 系统. cat /proc/version 首先,也是要 ...
- c语言描述简单的线性表,获取元素,删除元素,
//定义线性表 #define MAXSIZE 20 typedef int ElemType; typedef struct { ElemType data[MAXSIZE]; //这是数组的长度, ...
- WIN32 DLL中使用MFC
最近用WIN32 DLL,为了方便要用到MFC的一些库,又不想转工程,就网上找了很多方法,发现没有详细的介绍,有的也行不通,现在成功在WIN32 DLL中使用了MFC,记录一下以防以后用到忘记 一.修 ...
- java 个人总结
每周课程总结链接: 第一周 第二周 第三周 第四周 第五周 第六周 第七周 第八周 第九周 第十周 java实验报告链接: 实验一 实验二 实验三 实验四 实验五 代码托管链接 课程收获: 学习任何语 ...
- Android IOS WebRTC 音视频开发总结(三六)-- easyRTC介绍
本文主要介绍easyRTC,文章来自博客园RTC.Blacker,支持原创,转载请说明出处. 先看看人家官网的介绍,然后再来解释,这样您可能更容易理解: 以下部分内容属个人看法,如有异议,欢迎探讨: ...
- 浅谈Bootstrap自适应功能在Web开发中的应用
随着移动端市场的强势崛起,web的开发也变得愈发复杂,对于个体开发者来说,自己开发的网站,在电脑.手机.Pad等上面都要有正常的显示以及良好的用户体验.如果每次都要自己去调整网页去匹配各个不同的客户端 ...
- 自定义Attribute 服务端校验 客户端校验
MVC 自定义Attribute 服务端校验 客户端校验/* GitHub stylesheet for MarkdownPad (http://markdownpad.com) *//* Autho ...