时间复复杂度 | 空间复杂度 | 是否稳定 | 存储方式 | 备注 | |
---|---|---|---|---|---|
冒泡 | On2 | O1 | 稳定 (相邻交换) | 可链式存储 | 移动次数较多,时间性能差于插入算法。 初始值无序,n 较大时不宜采用。 |
选择 | On2 | O1 | 不稳定 (跳跃交换) | 可链式存储 | 移动次数较少,当每个数据占空间较大时,比插入排序快。 |
插入 | On2 | O1 | 稳定 (单方向交换) | 可链式存储 | 适合初始值基本有序。 若无序,n 较大,此算法时间复杂度较高,不宜采用。 |
快排 | Onlog2n | Olog2n~On | 不稳定 (跳跃交换) | 不可链式存储。 排序过程需要定位表的上下界 | n 较大,初始值无序时,是所有内部排序中最快的。 很小的数组(N<=20)快排不如插入排序。 |
归并 | Onlog2n | On | 稳定 (相邻交换) | 可链式存储,不需要附加存储空间 | Java类库泛型排序所使用的算法 |
测试代码
import java.util.Arrays;
import java.util.Random;
//多种排序测试
public class SortTest {
public static void main(String[] args) {
Random rd = new Random();
int[] array = new int[21];
int index=0;
for(int i=21; i>0;i--){
array[index++] = i;
}
System.out.println("排序前:");
System.out.println(Arrays.toString(array));
//BubbleSort(array);
//QSort(array);
//SelectSort(array);
//InsertSort(array);
//MergeSort(array);
System.out.println("排序后:");
System.out.println(Arrays.toString(array));
}
//冒泡排序--网上
private static void BubbleSort(int[] array){
if(null==array || array.length<2) return ;
//每一轮规则:前后两两比较,前者比后者大,调换,否则不换。 一直保持后者更大,前者更小。
//一轮下来,最大值换到最后面。
//第二轮的时候就不需要比较最后一位了
//第三轮就不需要比较最后2位
//最后一轮只需要第一跟第二比就可以
//所以外循环控制轮数,一共需要比 n-1轮
//内存换控制每一轮比较次数,是变化的,n-1-i 次
for(int i=0; i<array.length-1; i++){
for(int j=0; j<array.length-1-i; j++){
if(array[j]>array[j+1]){
int t=array[j];
array[j] = array[j+1];
array[j+1] = t;
}
}
}
}
//选择排序--严蔚敏
public static void SelectSort(int[] array){
if(null==array||array.length<2) return;
//第一轮 i0 轮流和 i1,i2,i3...ileng比较,如果遇到比自己小的就交换,一轮下来保证 i0最小
//第二轮 i1 轮流和 i2,i3...ileng 比较,遇到比自己小的就交换,一轮下来保证 i1最小
//。。。
//最后一轮 ileng-2和 ileng-1 比较,遇到比自己小的就交换,结果排序完成
//i一共比较 leng-1次;j 从 i+1开始,最多是 leng-1
for(int i=0; i<array.length-1; i++){
int pMin=i;
for(int j=i+1; j<array.length; j++)
if(array[pMin]>array[j]) pMin=j; //pMin 指向此趟排序中最小值
if(i!=pMin){ //如果最小值发生变动,则交换
int t = array[i];
array[i] = array[pMin];
array[pMin] = t;
}
}
}
//插入排序--数据结构与算法分析
//时间复杂度On2 空间复杂度 O1
//稳定排序(因为是一位一位移动(交换)的,所以不会像选择排序那样跳跃交换导致不稳定)
//适合初始值基本有序情况,当初始值无序且 n 较大时,时间复杂度校稿,不适合。
public static void InsertSort(int[] array){
if(null==array||array.length<2) return;
//数组 12 22 3 4 1 40
//下标 0 1 2 3 4 5
//第一轮 i0(12)作为排序后数组,其它都是未排序数据。前面的数如果比待插入数大,则把前面元素往后移动一位。前面没了,就把待插入数插入当前位置。
//第n轮 i0,i1(12 22)作为排序后数据,其它都是未排序数据。前面数如果比待插入数大,就把前面元素往后移动一位,直到前面元素不大于位置,把待插入数插入到当前位置。
//外循环一共需要比较 n-1轮
int j,i;
int t;
for(i=1; i< array.length; i++){
t=array[i];
for(j=i; j>0 && array[j-1]>t; j--){ //如果是引用数据类型,则需要用 compareTo 比较大小
array[j] = array[j-1];
}
array[j] = t;
}
}
//快速排序--严蔚敏
//对循序表 array 做快速排序
public static void QSort(int[] array){
if(null==array || array.length<2) return;
quickSort(array,0,array.length-1);
}
//对顺序表 array 中的序列 array[low,high]做快速排序
public static void quickSort(int[] array, int low, int high){
if(low<high){ //隐含判断长度大于1
int pivotLoc= partition(array,low,high); //将子序列一分为二,pivotLoc 是枢轴位置
quickSort(array,low,pivotLoc-1); //对左子表递归排序
quickSort(array,pivotLoc+1,high); //对右子表递归排序
}
}
//对顺序表 array 中的子表array[low,high]进行一趟排序,返回枢轴位置
public static int partition(int[] array, int low, int high){
int pivotKey=array[low]; //用子表第一个记录做枢轴值
while(low<high){ //从表的两端交替向中间扫描
while(low<high && array[high]>=pivotKey)
high--;
array[low] = array[high]; //将比枢轴值小的值移动到低端
while(low<high && array[low]<=pivotKey)
low++;
array[high] = array[low]; //将比枢轴值大的值移动到高端
} //while 结束时 low==high,已到达枢轴在排序中的位置
array[low] = pivotKey; //枢轴值到位
return low; //返回枢轴位置
}
//归并排序--数据结构与算法分析
//需要一份与待排序数据相等的额外存储空间
public static void MergeSort(int[] array){
if(null==array||array.length<2)return;
int[] tmpArray = new int[array.length];
mSort(array,tmpArray,0,array.length-1);
}
//归并算法递归部分
//分治思想,一组分两半,其中一半再分两半,再分,再分,直到剩1个值分不开了,开始回溯
//回溯就是往上 merge,先归左边最小的,左边归并完,归并右边最小的,右边归并完,归并总体,完成
public static void mSort(int[] array, int[] tmpArray, int low, int high){
if(low < high) {
int mid = (low+high)/2;
mSort(array,tmpArray,low,mid);
mSort(array,tmpArray,mid+1,high);
merge(array,tmpArray,low,mid,high);
}
}
//归并算法核心
//将一组数据分成两半,两半的数据从左到右一对一对比较大小,小的先放到临时数组,大的后放,剩余的直接放
//最后将临时数组的值再倒回原始数组
public static void merge(int[] a,int[] t,int low,int mid,int high){
int p1=low;
int p2=mid+1;
int k=low;
while(p1<=mid&&p2<=high){ //将 a[low,mid] a[mid+1,high] 中的值比较大小并入 t[] 中,从小到大
if(a[p1]<=a[p2])t[k++]=a[p1++];
else t[k++]=a[p2++];
}
while(p1<=mid)t[k++]=a[p1++]; //将a[low,mid]中剩余的值直接放入 t[]中
while(p2<=high)t[k++]=a[p2++]; //将a[mid+1,high]中剩余的值直接放入 t[]中
for(int i=low;i<=high;i++){ //将 t 中的值倒回 a 中
a[i]=t[i];
}
}
}