幾個經典排序算法自己手寫一下練習練習
1、冒泡排序
private static int[] bubleSort(int[] arr) {
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){
int tmp=arr[j+1];
arr[j+1]=arr[j];
arr[j]=tmp;
}
}
}
return arr;
}
最簡單的冒泡排序,沒什麼多說的,兩個for循環,每次循環把最大的數排到後面。
冒泡排序最好的時間複雜度爲O(n),最差的時間複雜度爲O(n²),平均時間複雜度爲O(n²);
2、插入排序
給定一個數組{8,7,9,5,6,4,0,1,2,3},for循環,從7遍歷到3,從第2個元素7開始,與前面各個元素比較,將它插入到前面數組中相應的位置。比如5插入到{1,2,3,4,6,10}中的4和6之間。
private static int[] insertSort(int[] arr) { //插入排序
for(int i=1;i<arr.length;i++){
int tmp=arr[i];
for(int j=i-1;j>=0;j--){
if(tmp<arr[j]){
arr[j+1]=arr[j];
arr[j]=tmp;
}
if(tmp>arr[j]){
break;
}
}
}
return arr;
}
空間複雜度O(1)
時間複雜度O(n2)
最差情況:反序,需要移動n*(n-1)/2個元素
最好情況:正序,不需要移動元素
數組在已排序或者是“近似排序”時,插入排序效率的最好情況運行時間爲O(n);
插入排序最壞情況運行時間和平均情況運行時間都爲O(n²)。
3、希爾排序
基於插入排序的思想,增加了步長,一般先取array.length/2,然後依次二分直到爲1。每次對第i個,i+step,i+2step等等元素進行插入排序。
例:{6,3,4,5,1,7,2,9,10,8}
第一次排序,step爲10/2=5,第一次分爲5組,每組爲{6,7}{3,2}{4,9}{5,10}{1,8}
排序之後爲{6,2,4,5,1,7,3,9,10,8}
第二次排序,step爲5/2=2,分2組,每組爲{6,4,1,2,10}{3,5,7,9,8}
排序之後爲{1,3,2,5,4,7,6,8,10,9}
最後一次排序,step爲1,插入排序。
private static int[] shellSort(int[] array) {
int step=array.length/2;
while(step>0){
System.out.println("step="+step);
for(int i=0;i<step;i++){
for(int j=i+step;j<array.length;j=j+step){
int k=j;
int tmp=array[k];
while(k>=0){
if(tmp<array[k]){
array[k+step]=array[k];
array[k]=tmp;
}
if(tmp>array[k]){
break;
}
k=k-step;
}
}
}
step=step/2;
}
return array;
}
平均時間複雜度O(n的1.3次方)(這個牛逼了,居然還有1.3次方)
最好情況O(n),最壞情況O(n²)。
4、簡單選擇排序
從i=0開始循環,每次選出最小或者最大的元素與第 i個元素交換,跟冒泡排序有點像。
private static int[] selectSort(int[] array) { //選擇排序
for(int i=0;i<array.length;i++){
int min=Integer.MAX_VALUE;
int minJ=0;
for(int j=i;j<array.length;j++){
if(array[j]<min){
min=array[j];
minJ=j;
}
}
array[minJ]=array[i];
array[i]=min;
}
return array;
}
時間複雜度爲O(n²)。
5、歸併排序
分治法的經典例子,先把數組二分二分再二分,直到分爲只剩一個元素,然後再兩兩比較大小,歸併。
public class mergeSort {
public static void main(String[] args) {
int[] array={6,3,4,5,1,7,2,9,10,8};
mergeSort(array,0,array.length-1);
for(int i=0;i<array.length;i++){
System.out.print(array[i]+" ");
}
}
private static void mergeSort(int[] array,int left,int right) { //歸併排序
if (left >= right) return;
int mid=(left+right)/2;
System.out.println("mid = "+mid);
mergeSort(array,left,mid); //對左半邊二分
mergeSort(array,mid+1,right); //對右半邊二分
merge(array,left,mid,mid+1,right); //左右合併
}
private static int[] merge(int[] array,int leftS,int leftE,int rightS,int rightE) { //歸併排序
System.out.println("sort "+"leftS="+leftS+" leftE="+leftE+" to "+"rightS="+rightS+ "rightE="+rightE);
int[] temp = new int[rightE-leftS+ 1];
int i=leftS;
int j=rightS;
int k=0;
while(i<=leftE&&j<=rightE){
if(array[i]<array[j]){
temp[k++] = array[i++];
}
else{
temp[k++] = array[j++];
}
}
while (i <= leftE) {
temp[k++] = array[i++];
}
while (j <= rightE) {
temp[k++] = array[j++];
}
k = leftS;
// 將臨時數組中的內容拷貝回原數組中 // (原left-right範圍的內容被複制回原數組)
for (int element : temp) {
array[k++] = element;
System.out.println("element = "+element);
}
for(int z=0;z<array.length;z++){
System.out.print(array[z]+" ");
}
System.out.println(000);
return array;
}
}
時間複雜度無論是在最好情況下還是在最壞情況下均是O(nlgn),開闢了一個temp空間去暫存數組,所以空間複雜度爲O(n)。
6、快速排序
每次選擇數組的第一個數爲基準數,與後面的數比較,大的放基準數後面,小的放前面。具體實現是設定一個low和high,從高位開始與基準比較,小的話將array[high]與基準數交換,然後從array[low]開始比較,大於基準數的話就和array[high]交換。這樣運行到low=high時,基準數被交換到了array[low],對左右數組array[l],array[low-1],繼續遞歸進行排序。
public class quickSort {
public static void main(String[] args) {
int[] array={6,3,4,5,1,7,2,9,10,8};
quickSort(array,0,array.length-1);
for(int i=0;i<array.length;i++){
System.out.print(array[i]+" ");
}
}
private static void quickSort(int[] array, int l, int h) {
int low =l;
int high=h;
int target=array[low];
while(low<high){
while(low<high&&array[high]>target){
high--;
}
if(array[high]<target){
int temp = array[low];
array[low]=array[high];
array[high]=temp;
low++;
}
while(low<high&&array[low]<target){
low++;
}
if(array[low]>target){
int temp = array[low];
array[low]=array[high];
array[high]=temp;
high--;
}
}
//當low==high時,本次排序結束,對low前後各半邊再排序
if(low>l) quickSort(array,l,low-1);
if(high<h) quickSort(array,high+1,h);
}
}
平均時間複雜度爲O(nlogn),最差爲O(n²)7、堆排序
堆頂元素爲最大,左右孩子節點都小於父節點。每次調整時比較孩子節點和父節點,將最大值放在父節點。
(1)構建大根堆
(2)堆頂元素放到最後
(3)對剩下元素重新構建大根堆
(4)重複(2)(3)步直到全部輸出
public class HeapSort {
public static void main(String[] args) {
int[] array = {6,3,4,5,1,7,2,9,10,8};
System.out.println("Before heap:");
printArray(array);
heapSort(array);
System.out.println("After heap sort:");
printArray(array);
}
public static void printArray(int[] array) {
System.out.print("{");
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]);
if (i < array.length - 1) {
System.out.print(", ");
}
}
System.out.println("}");
}
public static void exchangeElements(int[] array, int index1, int index2) {
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
public static void heapSort(int[] array) {
if (array == null || array.length <= 1) {
return;
}
buildMaxHeap(array);
for (int i = array.length - 1; i >= 1; i--) {
exchangeElements(array, 0, i);
maxHeap(array, i, 0);
}
}
private static void buildMaxHeap(int[] array) {
if (array == null || array.length <= 1) {
return;
}
int half = array.length / 2;
for (int i = half; i >= 0; i--) {
maxHeap(array, array.length, i);
}
}
private static void maxHeap(int[] array, int heapSize, int index) {
int left = index * 2 + 1;
int right = index * 2 + 2;
int largest = index;
if (left < heapSize && array[left] > array[index]) {
largest = left;
}
if (right < heapSize && array[right] > array[largest]) {
largest = right;
}
if (index != largest) {
exchangeElements(array, index, largest);
maxHeap(array, heapSize, largest);
}
}
}