java 八大排序算法详解
2016-05-20 13:35
369 查看
首先介绍一下排序的概念,排序是这样一个过程,即基于某一标准,要么升序要么降序将某一组项目按照某个规定的顺序排列。在java 中排序基本排序有八中,我习惯按排序算法的效率来分类。
对数排序:它对nn个元素排序通常需要大约nlog2nnlog_{2^n},即时间复杂度为O(nlog2n)O(nlog_{2^n}),例如,快速排序,归并排序。
希尔排序:时间复杂度为O(n1.3)O(n^{1.3})
堆排序:堆排序的时间复杂度为O(nlogn)O(nlogn) 。
基数排序:基数排序的时间复杂度为O(n)O(n) 。
从上到下时间复杂度依次降低,即算法的效率依次提高。
算法的稳定性:通俗地讲就是能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。在简单形式化一下,如果Ai = Aj, Ai原来在位置前,排序后Ai还是要在Aj位置前。
其次,说一下稳定性的好处。排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。基数排序就 是这样,先按低位排序,逐次按高位排序,低位相同的元素其顺序再高位也相同时是不会改变的。
选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,
冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
一.算法的时间复杂度和稳定性
顺序排序:它通常使用一对嵌套循环对nn个元素进行排序,大概需要n2n^2次比较,即时间复杂度为O(n2)O(n^2),例如,选择排序,插入排序,冒泡排序。对数排序:它对nn个元素排序通常需要大约nlog2nnlog_{2^n},即时间复杂度为O(nlog2n)O(nlog_{2^n}),例如,快速排序,归并排序。
希尔排序:时间复杂度为O(n1.3)O(n^{1.3})
堆排序:堆排序的时间复杂度为O(nlogn)O(nlogn) 。
基数排序:基数排序的时间复杂度为O(n)O(n) 。
从上到下时间复杂度依次降低,即算法的效率依次提高。
算法的稳定性:通俗地讲就是能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。在简单形式化一下,如果Ai = Aj, Ai原来在位置前,排序后Ai还是要在Aj位置前。
其次,说一下稳定性的好处。排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。基数排序就 是这样,先按低位排序,逐次按高位排序,低位相同的元素其顺序再高位也相同时是不会改变的。
选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,
冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
二.排序算法的实现
这里将所有的排序方法都写成静态方法,由于使用了泛型,所以所有的静态方法都要使用泛型静态方法,即在 static 后面加上泛型<T extends Comparable<T>>,表示要排序的元素必须要Comparable的子类。
public class SortMethod { /** * 公用方法 * 数组中两个元素位置对调 * @param data 要操作的数组 * @param index1 要操作的元素的角标 * @param index2 要操作的元素的角标 */ private static <T extends Comparable<T>> void swap(T[] data,int index1,int index2){ T temp = data[index1]; data[index1] = data[index2]; data[index2] = temp; } //============================================================== /** * 选择排序:首先选择改组元素最小的放到第一位,然后选择剩下的元素中最小的放在第二位 * 以此类推 * @param data */ public static <T extends Comparable<T>> void selectionSort(T[] data){ for(int index=0;index<data.length;index++){ int scan = index; for(int i=index+1;i<data.length;i++){ if(data[i].compareTo(data[scan])<0){ scan = i; } } swap(data,index,scan); } } //============================================================== /** * 插入排序:通过反复的将某一特定的值插入到该列表某个已排序的子集中, * 即先将列表前两个元素排序,然后将剩余的元素插入到这个已排序的列表中。 * @param data */ public static <T extends Comparable<T>> void insertionSort(T[] data){ //下面称已排序好的元素列表 为 sorted //index 为sorted 中元素的个数 for(int index = 1;index < data.length;index++){ T key = data[index];//要插入的元素 int position = index; while(position>0 && data[position-1].compareTo(key)>0){ data[position] = data[position-1]; position--; } data[position] = key; } } //============================================================== /** * 冒泡排序:通过重复地比较相邻的元素且在必要时将他们互换。 * @param data */ public static <T extends Comparable<T>> void bubbleSort(T[] data){ for(int i=0;i<data.length;i++){ for(int index=0;index<data.length-1;index++){ if(data[index].compareTo(data[index+1])>0){ swap(data, index, index+1); } } } } //============================================================== /** * 快速排序:选取一个元素A,将比A大的放在右边,比A小的放在左边。 * 然后对左右两边的列表在进行相同的处理,直到排序完成。 * @param data */ public static <T extends Comparable<T>> void quickSort(T[] data){ quickSort(data, 0, data.length-1); } /** * 递归式的排序方法 * @param data 数组对象 * @param min 列表最小索引 * @param max 列表最大索引 */ private static <T extends Comparable<T>> void quickSort(T[] data,int min,int max){ if(min<max){ int indexOfPartition = partition(data, min, max); quickSort(data, min, indexOfPartition-1); quickSort(data, indexOfPartition+1, max); } } /** * 将列表分为两个分区,左边分区元素小于 中间值 ,右边分区元素大于中间值,并返回中间值索引 * partition 方法的两个内循环用于寻找位于错误分区的交换元素。第一个循环从左边扫描到右边, * 以寻找大于分区元素的元素。第二个循环从右边扫描到左边,以寻找小于分区元素的元素。在找 * 到这俩个元素的时候,则将他们互换。该过程会一直继续下去,直至右索引和左索引在该列表的 * “中间”相遇。他们相遇的位置同样也表明了该分区元素最终会驻留在那个地方。 * @param data 数组对象 * @param min 列表最小索引 * @param max 列表最大索引 * @return */ private static <T extends Comparable<T>> int partition(T[] data,int min,int max){ T partitionElement ; int left , right; int middle = (min+max)/2; partitionElement = data[middle];//中间元素 swap(data, middle, min);//现将 中间元素移动到最左边,等找到中间位置后在将中间元素换回去 left = min; right = max; while(left<right){ //从min开始到,找出比 partitionElement 大的元素 while(left<right && data[left].compareTo(partitionElement)<=0) left++; //从max开始,找出比 partitionElement 小的元素 while(data[right].compareTo(partitionElement)>0) right--; if(left<right) swap(data, left, right); } swap(data, min, right); return right; } //==============================================================
相关文章推荐
- 第十九章 springboot + hystrix(1)
- SpringBoot中通过配置文件控制路径和变量(三)
- 通用DAO之MyBatis封装,封装通用的增删改查(一)
- SpringMVC深度探险(二) —— SpringMVC概览
- java中数字转化为中文大写(类似一,十,二十一,一百零一)
- Spring-IOC
- 学习SpringMVC(十二)之mvc:view-controller标签
- Android逆向之旅---动态方式破解apk前奏篇(Eclipse动态调试smail源码)
- spring 自定义标签实现传递list属性
- 关于使用运算符"||"、"&&"的小例子
- 如何解决eclipse android开发中的R cannot be resolved 的错误
- struts2中的几个技术
- spring boot集成data-jpa
- Java遍历文件夹下所有文件,并且将数据保存在数据库当中
- JavaSE入门学习44:文件传输基础之I/O流(三)
- Spring DATA JPA 中findAll 进行OrderBy
- Spring的父子容器问题
- java中void
- Spring 源码解析之HandlerAdapter源码解析(二)
- springmvc与struts2的区别