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

[Java]各种排序算法整理(更新中。。。)

2018-03-25 21:41 351 查看

一、冒泡排序

Java源码

V1版本

/**
* 冒泡排序基础版本
* @param a 待排序的数组
*/
public static void bubbleSortV1(int[] a){
// 边界条件判断
if(a==null || a.length<2){
return;
}

int j = 0;
int tmp = 0;
for(int i=0; i<a.length-1; i++){
for(j=a.length-1; j>i; j--){
// 一次交换将最小的值移动到最左边
if(a[j]<a[j-1]){
tmp = a[j];
a[j] = a[j-1];
a[j-1] = tmp;
}
}
}
}


V2版本

/**
* 优化后的冒泡排序,此处可能减少冒泡的轮数
* @param a
*/
public static void bubbleSortV2(int[] a){
// 边界条件判断
if(a==null || a.length<2){
return;
}
int j = 0;
int tmp = 0;
boolean flag = false;  // 表示是否会交换
for(int i=0; i<a.length-1; i++){
if(flag){
// 如果标志为为true,表示上次未发生交换,也就是已经是有序的了,这样的话就不需要再进行交换了
break;
}
flag = true;
for(j=a.length-1; j>i; j--){
if(a[j]<a[j-1]){
tmp = a[j];
a[j] = a[j-1];
a[j-1] = tmp;
}
}
}
}


性能总结

版本最坏时间复杂度平均时间复杂度最好时间复杂度空间复杂度是否稳定是否为本地排序是否为外地排序
V1O(n2)O(n2)O(n2)O(n2)O(n2)O(n2)O(1)O(1)
V2O(n2)O(n2)O(n2)O(n2)O(n)O(n)O(1)O(1)
最坏的情况是输入逆序数组,最要好的应该是输入为排好序的数组

二、选择排序

Java源码

V1版本

/**
* 选择排序,本地排序,无需额外数组
* @param a
*/
public static void selectionSortLocal(int[] a){
if(a==null || a.length<=1){
return;
}

int minIndex = 0;
int j = 0;
int tmp = 0;
for(int i=0; i<a.length-1; i++){
minIndex = i;
// 一次遍历选取剩余数字的最小值的索引
for(j=i; j<a.length; j++){
if(a[j]<a[minIndex]){
minIndex = j;
}
}
if(minIndex!=i) {
// 交换最小值和第一个的位置
tmp = a[i];
a[i] = a[minIndex];
a[minIndex] = tmp;
}
}
}


性能总结

版本最坏时间复杂度平均时间复杂度最好时间复杂度空间复杂度是否稳定是否为本地排序是否为外地排序
V1O(n2)O(n2)O(n2)O(n2)O(n2)O(n2)O(1)O(1)
对于选择排序,因为每次都要去找最小值,做n次比较,所以最好的情况是输入排序好的,可以减少n次交换,但是比较次数不会减少;但他最坏的情况并不是输入逆序数组,因为逆序再一次交换后刚好将最大的交换至末尾了。

三、插入排序

Java源码

V1版本

/**
* 插入排序,本地排序
* @param a
*/
public static void insertionSortLocal(int[] a){
if(a==null || a.length<2){
return;
}

int j = 0;
int tmp = 0;
for(int i=1; i<a.length; i++){
tmp = a[i];
if(tmp>=a[i-1]){
// 如果该值已经是排好序的数的最大值
continue;
}
for(j=i-1; j>=0; j--){
if(a[j]>tmp){
a[j+1] = a[j];
}else{
// 找到插入位置后即退出
break;
}
}
a[j+1] = tmp;
}
}


V2版本

/**
* 插入排序,外地排序
* @param a
*/
public static int[] insertionSortOuter(int[] a){
if(a==null || a.length==0){
return null;
}
int[] b = new int[a.length];
b[0] = a[0];
if(a.length==1){
return b;
}

int j = 0;

for(int i=1; i<a.length; i++){
if(a[i]>=b[i-1]){
b[i] = a[i];
}else{
for(j=i-1; j>=0; j--){
if(b[j]>a[i]){
b[j+1] = b[j];
}else{
break;
}
}
b[j+1] = a[i];
}
}

return b;
}


性能总结

版本最坏时间复杂度平均时间复杂度最好时间复杂度空间复杂度是否稳定是否为本地排序是否为外地排序
V1O(n2)O(n2)O(n2)O(n2)O(n)O(n)O(1)O(1)
V2O(n2)O(n2)O(n2)O(n2)O(n)O(n)O(n)O(n)
最坏情况是输入逆序数字,那么每次查找位置时都需要比较和移动n次值;最好情况是输入排序好的数组,此时每次要插入的值都是最大值,直接与已排好序的数字的最大值比较即可获得位置,只需要遍历一次即可。

四、希尔排序

希尔排序的时间复杂度分析好像比较复杂,博主这里也是摘自网上资料的分析。所以欢迎各位在底下讨论。。。

Java源码

V1版本

public void localSort(Item[] items) {
// 边界条件检测
if(items==null || items.length<2){
return;
}

int k = items.length/2;  // 初始增量为元素总数的一半
while (k>=1){
for(int i=0; i<k; i++){
for(int j=i+k; j<items.length; j+=k){
Item key = items[j];
int m = j-k;
if(key.compareTo(items[m])<0){
for(; m>=i; m-=k){
if(items[m].compareTo(key)>=0){
items[m+k] = items[m];
}else{
break;
}
}
items[m+k] = key;
}
}
}
k--;
}
}


V2版本

public void localSort(Item[] items) {
// 边界条件检测
if(items==null || items.length<2){
return;
}

int k = items.length/2;  // 初始增量为元素总数的一半
while (k>=1){
for(int i=0; i<k; i++){
for(int j=i+k; j<items.length; j+=k){
Item key = items[j];
int m = j-k;
if(key.compareTo(items[m])<0){
for(; m>=i; m-=k){
if(items[m].compareTo(key)>=0){
items[m+k] = items[m];
}else{
break;
}
}
items[m+k] = key;
}
}
}
k/=2;
}
}


V3版本

public void localSort(Item[] items) {
// 边界条件检测
if(items==null || items.length<2){
return;
}

int n = (int)Math.floor(Math.log(items.length+1));
int k = (int)Math.pow(2, n)-1;  // 初始增量为元素总数的一半
while (k>=1){
for(int i=0; i<k; i++){
for(int j=i+k; j<items.length; j+=k){
Item key = items[j];
int m = j-k;
if(key.compareTo(items[m])<0){
for(; m>=i; m-=k){
if(items[m].compareTo(key)>=0){
items[m+k] = items[m];
}else{
break;
}
}
items[m+k] = key;
}
}
}
n--;
k = (int)Math.pow(2, n)-1;
}
}


性能分析

版本最坏时间复杂度平均时间复杂度最好时间复杂度空间复杂度是否稳定是否为本地排序是否为外地排序
V1−−−−−−O(1)O(1)
V2O(n2)O(n2)O(n2)O(n2)O(n2)O(n2)O(1)O(1)
V3O(n32)O(n32)O(n32)O(n32)O(n32)O(n32)O(1)O(1)
希尔排序是插入排序的一种改进,因为插入排序每次插入时所有元素向后最多移动一位,这样的话加入一个元素距离它排序后的位置较远的话需要移动很多次,而希尔排序过程中每次移动的步幅由大变小,对于一些数据可能更快的移动到正确位置。希尔排序是第一批打破O(n2)O(n2)的排序方式,它的时间复杂度与增量序列的选取有关:如上第二个版本的增量序列为{gap,gap2,gap4,...,1}{gap,gap2,gap4,...,1},其中gap=数组长度2gap=数组长度2,该序列称为希尔增量,它的时间复杂度为O(n2)O(n2),而第三个版本的增量序列为1,3,...,2k−11,3,...,2k−1,它的时间复杂度为O(n32)O(n32)。希尔排序的时间复杂度下限为nlog22nnlog22n。它在中小规模表现良好,但是对于大规模数据不是一个好选择。另外,它在最好和最坏的情况下执行效率差不多,但是快排在最坏情况下却会性能下降好多。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: