[Python+Java]-排序算法總結

參考鏈接

附:Java標準庫已經內置了排序功能Arrays.sort(ns);

1.冒泡排序

思想:像氣泡一樣,小的冒上去

每一輪循環後,最小的一個數被交換到開始,因此,下一輪循環就可以“刨除”最開始的數,每一輪循環都比上一輪循環的結束位置靠後一位。

代碼:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
        int tmp;
        // 排序前:
        System.out.println(Arrays.toString(ns));
        for(int i = 0; i < ns.length-1; i++) {//一共要進行n-1次比較
        	for(int j = ns.length-1; j > i; j--) {//每次要比較第ns.length-1到i的數
        		if(ns[j] < ns[j-1]){
        			tmp = ns[j];
        			ns[j] = ns[j-1];
        			ns[j-1] = tmp;
        		}
        	}
        }
        //排序後
        System.out.println(Arrays.toString(ns));
    }
}

算法分析:

  • 平均時間複雜度:o(n^2),嵌套雙循環
  • 最好時間複雜度:o(n),如果數組有序,循環一次就可以了
  • 最壞時間複雜度:o(n^2)
  • 空間複雜度:o(1),只使用了常數空間
  • 穩定性:穩定(相同數字比較過程不會發生交換)

優化: 數據排好序後,冒泡算法仍會進行下一輪的比較,直到ns.length-1次結束。後面的比較是沒有意義的。

可以設置標誌位flag,如果發生了交換就設置flag爲true,否則爲false。

如果一輪交換後flag仍然爲false說明數組已經有序,不需要再進行下去了。

public class Main {
    public static void main(String[] args) {
        int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
        int tmp;
        System.out.println(Arrays.toString(ns));
        for(int i = 0; i < ns.length-1; i++) {
        	boolean flag = false;//優化的地方[1]
        	for(int j = ns.length-1; j > i; j--) {
        		if(ns[j] < ns[j-1]){
        			tmp = ns[j];
        			ns[j] = ns[j-1];
        			ns[j-1] = tmp;
        			flag = true;
        		}
        	}
        	if(!flag) {//優化的地方[2]
        		System.out.println("數組在第"+(i+1)+"次排序後有序");
        		break;
        	}
        }
        System.out.println(Arrays.toString(ns));
    }
}

2.快速排序

思想(分治法):1.設置一個基準值(一般設置爲數組第一個數),標籤low和high。

2.從high開始,當high位置的書比基準值大,high--;比基準值小,把high位置的書放到low的位置,low++

low位置的數比基準值小,low++;比基準值大,把low 位置的數放到high,high--

直到low=high

(最後比基準值小的書都在它左邊,比基準值大的數都在它右邊)

3.對左右兩個小數列重複第二步,直到各個區間都只有一個數

Java代碼:

import java.util.Arrays;

public class Main {
	public static void main(String[] args) {
        int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
        // 排序前:
        System.out.println(Arrays.toString(ns));
        //排序
        QuickSort(0,ns.length-1,ns);
        //排序後
        System.out.println(Arrays.toString(ns));
	}
    public static void QuickSort(int low, int high, int[] ns) {
    	while(low < high) { //所以有傳參的函數一定要先有個判斷條件!!!!!
            int pivo = ns[low];//將第一個值作爲基準賦給pivo暫存
            int slow = low;//記錄本次排序的初始值(後面會發生改變)
            int shigh = high;
            while(low < high) {
                while(low < high && ns[high] >= pivo) {//左邊
                	high--;     	
                }
                ns[low] = ns[high];
                while(low < high && ns[low] <= pivo) {//右邊
                	low++;
                }
                ns[high] = ns[low];
            }
            ns[low] = pivo;
//            System.out.println("初始slow是 = "+slow+" , shigh是 = "+shigh+" ,基準值 = ns[" +slow+"] = "+pivo);
//            System.out.println("排序一趟後的基準位置low=high = ns["+low+"] = "+ns[high]);
//            System.out.println("最終排序結果: "+Arrays.toString(ns)+"\n");
//            System.out.println("上次排序結果: "+Arrays.toString(ns));
            QuickSort(slow,low-1,ns);
            QuickSort(low+1,shigh,ns);
    	}
    }
}

Python代碼:

def partition(arr,low,high):
    pivot = arr[low]
    while (low < high):
        while arr[high] > pivot and low < high:
            high -=1
        arr[low] = arr[high]
        while arr[low] < pivot and low < high:
            low += 1
        arr[high] = arr[low]
    arr[high] = pivot
    return high
def quicksort(arr, low, high):
    if low < high:
        next = partition(arr, low, high);
        quicksort(arr, low, next-1)
        quicksort(arr, next+1, high)

arr = [8,6,1,9,4,5,10,14,3]
length = len(arr)-1
quicksort(arr, 0, length)
print(arr)

算法分析:

先說主定理:  T(n)=aT(\frac{n}{b})+f(n)

(a>=1,b>1) 其中a是劃分後的子問題數,b是劃分後問題的規模。對於快速排序,a=b=2

f(n)=O(n)是劃分問題的時間複雜度,快速排序爲n

所以快速排序公式T(n)=2T(\frac{n}{2})+n然後迭代計算,隨後第\log _2 n次劃分時 = 後的哪一項只有一個T(1)=1了,此時T(n)=n+n*\log _2

所以平均時間複雜度爲O(n*\log _2 n)

 

參考鏈接

最好的情況:快速排序的性能取決於快速排序遞歸樹。遞歸算法執行情況可以用遞歸樹來描述。

下圖是數組{50,10,90,30, 70,40,80,60,20}在快速排序的遞歸過程,樞軸值是50正好遞歸樹是平衡的,性能比較好。

在最優情況下,Partition每次都劃分得很均勻,如果排序n個關鍵字,其遞歸樹的深度就爲.log2n.+1

 

最壞情況:

在最壞的情況下,待排序的序列爲正序或者逆序,每次劃分只得到一個比上一次劃分少一個記錄的子序列,注意另一個爲空。如果遞歸樹畫出來,它就是一棵斜樹。此時需要執行n‐1次遞歸調用,且第i次劃分需要經過n‐i次關鍵字的比較才能找到第i個記錄,也就是樞軸的位置,因此比較次數爲 ,最終其時間複雜度爲O(n2)。

另一種說法:T[n] = T[n-1] + T[1] + O(n),

問題來了,這一次的劃分白玩了,劃分之後一邊是一個,一邊是n-1個,這種極端情況的時間複雜度就是O(n2).

 

3.堆排序

思想:

代碼:

算法分析:

優化:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章