標籤:log 快速 一個 其他 建立 while index 行合并 使用
排序演算法是一個最基本的演算法,經常會被問到,有些公司的面試也可能會考到,這裡特意將所有的排序演算法做一個總結
1. 冒泡排序
//冒泡排序,兩個迴圈都從0開始冒泡 public int[] MaoPao(int [] array){ int len = array.length; for(int i=0;i<len-1;i++){ for(int j=0;j<len-i-1;j++){ if(array[j]>array[j+1]){ int temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; } } } return array; }
最基本的一個排序演算法,總是將最大的往右進行冒泡,總是比較兩個相鄰的元素。
平均時間複雜度O(n^2),最好時間O(n),最壞時間O(n^2),空間複雜度O(1),不需要另外開闢空間
穩定的演算法,因為冒泡排序總是比較相鄰的兩個元素,所以是穩定的。
2. 直接插入排序
//直接插入排序 public int[] ChaRu(int [] array){ int len = array.length; for(int i=1;i<len;i++){ int temp = array[i]; int j=i-1; while(j>=0 && temp<array[j]){ //所有元素後移 array[j+1]=array[j]; j--; } array[j+1] = temp; //出入元素 } return array; }
第一個元素認為排序好的,之後的每一個元素往排好順序的數組裡插入,其他所有的元素向後移動一位
平均時間複雜度O(n^2),最好時間O(n),最壞時間O(n^2),空間複雜度O(1),不需要另外開闢空間
穩定的演算法,因為出入排序每次也是相鄰的比較並且後移,因此也是穩定的
3. 選擇排序
//選擇排序,每次找到最小的排過去就好 public int[] selectSort(int [] array){ int len = array.length; for(int i=0;i<len;i++){ int index = i; for(int j=len-1;j>i;j--){ if(array[j]<array[index]){ index=j; } } int temp = array[i]; array[i] = array[index]; array[index] = temp; } return array; }
每次迴圈,找到最小的一個元素,放在每一次迴圈的位置
平均時間複雜度O(n^2),最好時間O(n^2),無論如何都需要迴圈完才能確定最小元素,最壞時間O(n^2),空間複雜度O(1),不需要另外開闢空間
不穩定的排序演算法,因為每次都需要選擇來進行,而且是選擇位置插入的。
4. 快速排序
//快速排序思想,每次第一個為base,然後小的放左邊,大的放右邊,遞迴兩邊 public int[] quickSort(int[] array, int left, int right){ if(left<right){ int base = array[left]; int temp; int i=left, j=right; do{ while(array[i]<base && i<right){ i++; } while(array[j]>base && j>left){ j--; } if(i<=j){ temp = array[i]; array[i] = array[j]; array[j] = temp; i++; j--; } }while(i<=j); if(left<j){ quickSort(array,left,j); } if(right>i){ quickSort(array,i,right); } } return array; }
每次,將首個left元素作為基礎base,然後從left和right兩邊開始,小的放在左半部分,大的放在右半部分。然後遞迴排序左邊和右邊,直到left==right停止
平均時間複雜度O(nlog(n)),最好時間O(nlog(n)),最壞時間O(n^2),空間複雜度一般是O(log(n)),但是也可以到達O(1),如上述代碼,是沒有額外開闢空間的。
快速排序也是一個不穩定的排序演算法
5. 歸併排序
//歸併排序 public int[] mergeSort(int[] array, int left, int right){ int mid = (left+right)/2; if(left<right){ mergeSort(array,left,mid); mergeSort(array,mid+1,right); merge(array,left,mid,right); } return array; } public void merge(int[] array, int left, int mid, int right){ int[] temp = new int[right-left+1]; int k = 0; int i=left; //左 int j=mid+1; //右 //合并 while(i<=mid && j<=right){ if(array[i]<array[j]){ temp[k]=array[i]; k++; i++; }else{ temp[k]=array[j]; i++; j++; } } //左邊剩餘 while(i<=mid){ temp[k]=array[i]; k++; i++; } //右邊剩餘 while(j<=right){ temp[k]=array[j]; k++; i++; } //複製到原數組中 for(int ii=0;ii<temp.length;ii++){ array[left+ii]=temp[ii]; } }
採用了分治法的思想,首先把一個數組不斷地拆分,一直拆分到每個都只有一個元素為止,然後調用merge演算法,不斷地合并兩個已經排好序的數組,知道最後排好順序
平均時間複雜度O(nlog(n)),最好時間O(nlog(n)),最壞時間O(nlog(n)),空間複雜度一般是O(log(n)),歸併排序是需要額外的申請空間的,每次是需要產生新的數組的。
歸併排序是穩定的,因為是總是先分治到最小的數組,然後進行合并的。
6. 希爾排序
本質是分治思想和直接插入排序演算法的結合
平均時間複雜度O(n^(1.3)),最好時間O(n),最壞時間O(n^(2)),空間複雜度一般是O(1)
不穩定的排序演算法
7. 堆排序
本質是使用最小堆或者最大堆進行排序(二叉樹),首先需要建立堆,之後每次拿出一個最小元素或者最大元素,需要重新地調整堆
平均時間複雜度O(nlog(n)),最好時間O(nlog(n)),最壞時間O(nlog(n)),空間複雜度一般是O(l)
不穩定的排序演算法
8. 基數排序,基於桶排序的演算法
(1) 首先根據個位元進行桶排序,然後按照0-9得到桶中的元素
(2) 根據十位元進行桶排序,然後按照0-9得到桶中的元素
(3) .......
(4) 一直達到最高位位置,得到的結果即為最終的排序結果
9. 桶排序
用空間換取時間的做法,給定一個很大範圍的桶,每個元素放在一個桶中,只用一遍迴圈便可
時間複雜度O(n)
排序演算法匯總