Algorithm第四版筆記-排序
阿新 • • 發佈:2018-11-01
Algorithm第四版筆記-排序
Table of Contents
1 初級排序演算法
- 排序演算法的模板
- less()方法對元素比較
- exch()方法將元素交換位置
- sort()方法對陣列進行排序
package code; import edu.princeton.cs.algs4.In; import edu.princeton.cs.algs4.StdOut; public class Example { public static void sort(Comparable[] a) {} private static boolean less(Comparable v, Comparable w) { return v.compareTo(w) < 0; } private static void exch(Comparable[] a, int i, int j) { Comparable t = a[i]; a[i] = a[j]; a[j] = t; } private static void show(Comparable[] a) { // 在單行中列印陣列 for (int i = 0; i < a.length; i++) { StdOut.print(a[i] + " "); } StdOut.println(); } public static boolean isSorted(Comparable[] a) { // 測試陣列元素是否有序 for (int i = 0; i < a.length; i++) { if (less(a[i], a[i - 1])) return false; } return true; } public static void main(String[] args) { String[] a = In.readStrings(); sort(a); assert isSorted(a); show(a); } }
1.1 執行時間
- 排序成本模型: 在研究排序演算法時,我們需要計算比較和交換的數量.對於不交換元素的演算法,我們會計算訪問陣列的次數.
1.2 額外的記憶體使用
- 排序演算法可以分為兩類
- 除了函式呼叫所需的棧和固定數目的例項變數之外無需額外記憶體的原地排序演算法.
- 需要額外記憶體空間來儲存另一份陣列副本的其他排序演算法.
1.3 資料型別
- 排序演算法模板適用於任何實現了
Comparable
介面的資料型別. - 對於
v<w
,v=w
,v=>w
三種情況,Java的習慣是在v.compareTo(w)
被呼叫時候分別返回一個負數,零,和一個正整數(-1,0和1). - compareTo必須實現一個完整的比較序列,即:
- 自反性: 對於所有的v,
v=v
- 反對稱性: 對於所有的
v<w
都有w>v
,且v=w
時w=v
- 傳遞性: 對於所有v,w和x,如果
v<=w
且w<=x
,則v<=x
- 自反性: 對於所有的v,
1.4 選擇排序
- 原理: 找到陣列中最小的那個元素,其次,將它和陣列的第一個元素交換位置(如果第一個元素就是最小元素那麼它就和自己交換).
再次,在剩下的元素中找到最小的元素,將它與陣列的第二個元素交換位置,如此往復.
- 對於長度為N的陣列,選擇排序需要大約 \(N^2/2\) 次比較和N次交換.
- 最壞情況下,比較次數為
N-1
到1的等差數列求和.所以是大約 \(N^2/2\) 次比較
- 最壞情況下,比較次數為
- 選擇排序的特點
- 執行時間與輸入無關.
- 資料移動是最小的.
- 選擇排序程式碼如下
package code; import edu.princeton.cs.algs4.In; import edu.princeton.cs.algs4.StdOut; public class Selection { public static void sort(Comparable[] a) { // 將a[]按升序排列 // 陣列的長度 int N = a.length; for (int i = 0; i < N; i++) { int min = i; for (int j = i + 1; j < N; j++) { if (less(a[j], a[min])) min = j; } exch(a, i, min); } } private static boolean less(Comparable v, Comparable w) { return v.compareTo(w) < 0; } private static void exch(Comparable[] a, int i, int j) { Comparable t = a[i]; a[i] = a[j]; a[j] = t; } private static void show(Comparable[] a) { // 在單行中列印陣列 for (int i = 0; i < a.length; i++) { StdOut.print(a[i] + " "); } StdOut.println(); } public static boolean isSorted(Comparable[] a) { // 測試陣列元素是否有序 for (int i = 0; i < a.length; i++) { if (less(a[i], a[i - 1])) return false; } return true; } public static void main(String[] args) { String[] a = In.readStrings(); sort(a); assert isSorted(a); show(a); } }
1.5 插入排序
- 插入排序為了給插入元素騰出空間,需要將其餘所有元素在插入之前都向右移動一位.但是當索引到達陣列的最右端時,陣列排序就完成了.
- 與選擇排序不同,插入排序所需的時間取決於輸入中元素的初始順序.
- 對於隨機排列的長度為N且主鍵不重複的陣列,平均情況下插入排序需要約 \(N^2/4\) 次比較以及 \(N^2/4\) 次交換.
最壞情況下需要 \(N^2/2\) 次比較和 \(N^2/2\) 次交換,最好情況下需要 N-1
次比較和0次交換.
- 插入排序的程式碼如下:
package code; import edu.princeton.cs.algs4.In; import edu.princeton.cs.algs4.StdOut; public class Insertion { public static void sort(Comparable[] a) { // 將a[]按升序排列 int N = a.length; for (int i = 0; i < N; i++) { // 將a[i]插入到a[i-1],a[i-2],a[i-3]...之中 for (int j = i; j > 0 && less(a[j], a[j - 1]); j--) { exch(a, j, j - 1); } } } private static boolean less(Comparable v, Comparable w) { return v.compareTo(w) < 0; } private static void exch(Comparable[] a, int i, int j) { Comparable t = a[i]; a[i] = a[j]; a[j] = t; } private static void show(Comparable[] a) { // 在單行中列印陣列 for (int i = 0; i < a.length; i++) { StdOut.print(a[i] + " "); } StdOut.println(); } public static boolean isSorted(Comparable[] a) { // 測試陣列元素是否有序 for (int i = 0; i < a.length; i++) { if (less(a[i], a[i - 1])) return false; } return true; } public static void main(String[] args) { String[] a = In.readStrings(); sort(a); assert isSorted(a); show(a); } }
- 插入排序對於倒置數量很少的陣列執行時間比較短.
- 插入排序需要的交換操作和陣列中的倒置的數量相同,需要的比較次數大於等於倒置的數量,小於等於倒置的數量加上陣列的大小再減一.
Date: 2018-11-01 21:44
Created: 2018-11-01 四 21:44