算法 | 最坏复杂度 | 平均复杂度 | 最好复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
选择排序(Selection) | O( n2 ) | O( n2 ) | O( n2 ) | O(1) | 不稳定 |
插入排序(insertion) | O( n2 ) | O( n2 ) | O( n ) | O(1) | 稳定 |
希尔排序(Shell) | O( nlog(n)) ~O( n2 ) | O( n1.3 ) | O( n ) | O(1) | 不稳定 |
冒泡排序(Bubble) | O( n2 ) | O( n2 ) | O(n)(用交换flag改进) | O(1) | 稳定 |
快速排序(Quick) | O( n2 ) | O( nlog(n) ) | O( nlog(n) ) | O(log(n))~O(n) | 不稳定 |
堆排序(heap) | O( nlog(n) ) | O( nlog(n) ) | O( nlog(n) ) | O(1) | 不稳定 |
归并排序(merge) | O( nlog(n) ) | O( nlog(n) ) | O( nlog(n) ) | O(n) | 稳定 |
//选择排序:每次遍历找到数组中的最小值,放到剩余数组最前面,以此类推,直到所有元素被排好
public static void select_sort(int[] arr){
int len=arr.length;
long start=System.currentTimeMillis();
for(int i=0;ifor(int j=i+1;jif(arr[i]>arr[j]){
swap(arr,i,j);
}
}
}
long end=System.currentTimeMillis();
System.out.println("选择排序耗时(秒):"+(end-start));
//toPrint(arr);
}
//插入排序:用新的元素去与已经排序好的元素数组从尾部开始比较,若比对应元素小,则下标继续往前走,直到找到比新元素小的元素,然后将比新元素小的元素后面的全部元素后移,插入新元素。
public static int[] insert_sort(int[] arr){
long start=System.currentTimeMillis();
for(int i=0;iint temp=arr[i];
for(int j=i;j>0 && arr[j-1]>arr[j];j--){
arr[j]=arr[j-1];
arr[j-1]=temp;
}
}
long end=System.currentTimeMillis();
System.out.println("插入排序耗时(秒):"+(end-start));
return arr;
//toPrint(temparr);
}
//希尔排序:以arr.length/2为开始间隔,并不断/2缩小间隔的插入排序,最后一次的循环比较e就是插入排序,但是数组的绝大部分元素已经处于相对有序状态。
public static int[] shell_sort(int arr[]){
for(int gap=arr.length; gap>0 ; gap/=2){
for(int i=gap;iint temp=arr[i];
for(int j=i;j>=gap && arr[j-gap]>arr[j];j-=gap){
arr[j]=arr[j-gap];
arr[j-gap]=temp;
}
}
}
return arr;
}
//冒泡排序:比较相邻两个元素的大小,决定是否交换位置,每次循环可将一个最大值元素一直交换到最后面(或者将最小值一直交换到最前面),以此类推。用一个交换flag作优化可以将最优情况时间复杂度降到O(n),即只比较一轮。
public static void bubble_sort(int[] arr){
int len=arr.length;
long start=System.currentTimeMillis();
boolean swapFlag=true;
for(int i=0;iif(swapFlag==false)
break;
swapFlag=false;
for(int j=1;jif(arr[j-1]>arr[j]){
swap(arr,j-1,j);
swapFlag=true;
}
}
}
//思路:每一次排序,将首元素(arr[0])交换到这样的位置,即它所在位置往右的所有元素都不小于它,且它所在位置往左的所有元素都不大于它。完成这一步,只需要将首元素不断地从右往左遍历找比它小的,然后从左往右找比它大的,找到即交换位置,一直到从两个方向都再也找不到一个可以交换的元素,一轮排序结束。接着用递归的方式排序剩下的两半。
public static void quickSort(int[] arr,int start,int end){
if(start>=end)
return;
boolean leftFlag=false,rightFlag=false;
int pivot=start;
System.out.println("hehe");
while(!(leftFlag && rightFlag)){
leftFlag=true;rightFlag=true;
//第一轮:第一个元素从右边开始找第一个比它小的元素,与之交换位置
for(int i=end;i>=start;i--){
if(arr[pivot]false;
}
}
System.out.println("循环");
for(int i=start;i<=end;i++){
if(arr[pivot]false;
}
}
}
quickSort(arr, start, pivot-1);
quickSort(arr, pivot+1,end);
}
具体原理可以参考这里
//堆排序:
/*
* 思路:
* 先将传入的数组做成一个最大二叉堆,然后取出堆顶元素,再调整剩余的二叉堆,重复上述过程。
*/
public static void heap_sort(int[] arr){
buildMaxHeap(arr);
for(int i=arr.length-1;i>=0;i--){
swap(arr, 0, i);
maxHeapify(arr, 0, i);
}
}
//从下至上,对所有拥有子结点的根节点进行maxHeapify,保证整个堆的最大堆属性
private static void buildMaxHeap(int[] arr){
int iParent=(int) (Math.floor(arr.length/2))-1;
for(int i=iParent;i>=0;i--){
maxHeapify(arr, i,arr.length);
}
}
private static void maxHeapify(int[] arr,int index,int heapSize){
//iMax:最大元素的数组下标
int iMax=index;
while(true){
int iLeft=2*index+1,iRight=2*(index+1);
//比较当前元素与左子节点值孰大孰小,当然注意判断左子节点是否存在
if(iLeftarr[iMax])
iMax=iLeft;
//比较当前最大元素与右子节点值孰大孰小,当然注意判断右子节点是否存在
if(iRightarr[iMax])
iMax=iRight;
//判断完毕,将最大元素挪移到根节点位置
if(index!=iMax){
swap(arr, index, iMax);
index=iMax;
}
else
break;
}
}
//思路:将数组不断划分为更小的两个数组的组合(递归),当划分到最小的粒度时,即两个数之间的比较与位置交换,然后不断将两个小的数组融合成大的数组(merge方法)。
public static void merge_sort(int[] arr,int low,int high){
if(high>low){
int pivot=(high+low)/2;
merge_sort(arr,low,pivot);
merge_sort(arr,pivot+1,high);
merge(arr,low,pivot,high);
}
}
private static void merge(int[] arr,int low,int pivot,int high){
int[] temp=new int[high-low+1];
int i=low,j=pivot+1;
int count=0;
while(i<=pivot && j<=high){
if(arr[i]>arr[j]){
temp[count++]=arr[j];
j++;
}
else{
temp[count++]=arr[i];
i++;
}
}
while(i<=pivot){
temp[count++]=arr[i];
i++;
}
while(j<=high){
temp[count++]=arr[j];
j++;
}
for(int x=0;x