Tian Jiale's Blog

排序算法

插入排序

Java

public class Insertion {
    private Insertion() { }

    public static void sort(Comparable[] a) {
        int n = a.length;
        for (int i = 1; i < n; i++) {
            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(Object[] a, int i, int j) {
        Object swap = a[i];
        a[i] = a[j];
        a[j] = swap;
    }
}

Go

func InsertionSort(A []int) {
    for i := 1; i < len(A); i++ {
        for j := i; j > 0 && A[j] < A[j-1]; j-- {
            A[j], A[j-1] = A[j-1], A[j]
        }
    }
}

自顶向下归并排序

Java

public class Merge {
    private Merge() { }

    private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
        for (int k = lo; k <= hi; k++) {
            aux[k] = a[k];
        }

        int i = lo, j = mid+1;
        for (int k = lo; k <= hi; k++) {
            if      (i > mid)              a[k] = aux[j++];
            else if (j > hi)               a[k] = aux[i++];
            else if (less(aux[j], aux[i])) a[k] = aux[j++];
            else                           a[k] = aux[i++];
        }
    }

    private static void sort(Comparable[] a, Comparable[] aux, int lo, int hi) {
        if (hi <= lo) return;
        int mid = lo + (hi - lo) / 2;
        sort(a, aux, lo, mid);
        sort(a, aux, mid + 1, hi);
        merge(a, aux, lo, mid, hi);
    }

    public static void sort(Comparable[] a) {
        Comparable[] aux = new Comparable[a.length];
        sort(a, aux, 0, a.length-1);
    }

    private static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }
}

Go

func MergeSort(A []int) {
    if len(A) <= 1 {
        return
    }
    mid := len(A) / 2
    L := A[:mid]
    R := A[mid:]
    MergeSort(L)
    MergeSort(R)
    merge(L, R, A)
}

func merge(L, R, A []int) {
    C := make([]int, len(A))
    i := 0
    j := 0
    for k := 0; k < len(C); k++ {
        if i >= len(L) {
            C[k] = R[j]
            j++
        } else if j >= len(R) {
            C[k] = L[i]
            i++
        } else if L[i] < R[j] {
            C[k] = L[i]
            i++
        } else {
            C[k] = R[j]
            j++
        }
    }
    copy(A, C)
}

自底向上归并排序

Java

public class MergeBU {
    private MergeBU() { }

    private static void merge(Comparable[] a, Comparable[] aux, int lo, int mid, int hi) {
        for (int k = lo; k <= hi; k++) {
            aux[k] = a[k];
        }

        int i = lo, j = mid+1;
        for (int k = lo; k <= hi; k++) {
            if      (i > mid)              a[k] = aux[j++];
            else if (j > hi)               a[k] = aux[i++];
            else if (less(aux[j], aux[i])) a[k] = aux[j++];
            else                           a[k] = aux[i++];
        }

    }

    public static void sort(Comparable[] a) {
        int n = a.length;
        Comparable[] aux = new Comparable[n];
        for (int len = 1; len < n; len *= 2) {
            for (int lo = 0; lo < n-len; lo += len+len) {
                int mid  = lo+len-1;
                int hi = Math.min(lo+len+len-1, n-1);
                merge(a, aux, lo, mid, hi);
            }
        }
    }

    private static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }
}

Go

func MergeBUSort(A []int) {
    for length := 1; length < len(A); length *= 2 {
        for lo := 0; lo < len(A)-length; lo += length * 2 {
            mid := lo + length
            var hi int
            if lo+length*2-1 < len(A)-1 {
                hi = lo + length*2
            } else {
                hi = len(A)
            }
            merge(A[lo:mid], A[mid:hi], A[lo:hi])
        }
    }
}
func merge(L, R, A []int) {
    C := make([]int, len(A))
    i := 0
    j := 0
    for k := 0; k < len(C); k++ {
        if i >= len(L) {
            C[k] = R[j]
            j++
        } else if j >= len(R) {
            C[k] = L[i]
            i++
        } else if L[i] < R[j] {
            C[k] = L[i]
            i++
        } else {
            C[k] = R[j]
            j++
        }
    }
    copy(A, C)
}

随机快速排序

Java

public class Quick {
    private Quick() { }

    public static void sort(Comparable[] a) {
        shuffle(a);
        sort(a, 0, a.length - 1);
    }

    private static void sort(Comparable[] a, int lo, int hi) {
        if (hi <= lo) return;
        int j = partition(a, lo, hi);
        sort(a, lo, j-1);
        sort(a, j+1, hi);
    }

    private static int partition(Comparable[] a, int lo, int hi) {
        int i = lo;
        int j = hi + 1;
        Comparable v = a[lo];
        while (true) {
            while (less(a[++i], v)) {
                if (i == hi) break;
            }
            while (less(v, a[--j])) {
                if (j == lo) break;
            }

            if (i >= j) break;

            exch(a, i, j);
        }

        exch(a, lo, j);

        return j;
    }

    private static boolean less(Comparable v, Comparable w) {
        if (v == w) return false;
        return v.compareTo(w) < 0;
    }

    private static void exch(Object[] a, int i, int j) {
        Object swap = a[i];
        a[i] = a[j];
        a[j] = swap;
    }

    private static void shuffle(Object[] a) {
        validateNotNull(a);
        int n = a.length;
        for (int i = 0; i < n; i++) {
            int r = i + uniform(n-i);     // between i and n-1
            Object temp = a[i];
            a[i] = a[r];
            a[r] = temp;
        }
    }

    private static void validateNotNull(Object x) {
        if (x == null) {
            throw new IllegalArgumentException("argument must not be null");
        }
    }

    private static int uniform(int n) {
        if (n <= 0) throw new IllegalArgumentException("argument must be positive: " + n);
        return random.nextInt(n);
    }
}

Go

func QuickSort(A []int) {
    shuffle(A)
    quickSort(A)
}

func quickSort(A []int) {
    j := partition(A, 0, len(A))
    if j > 0 {
        quickSort(A[:j])
    }
    if j < len(A)-1 {
        quickSort(A[j+1:])
    }
}

func partition(A []int, lo, hi int) int {
    pivot := A[lo]
    i := lo + 1
    for j := lo + 1; j < hi; j++ {
        if A[j] < pivot {
            A[i], A[j] = A[j], A[i]
            i++
        }
    }
    A[lo], A[i-1] = A[i-1], A[lo]
    return i - 1
}

func shuffle(slice []int) {
    r := rand.New(rand.NewSource(time.Now().Unix()))
    for len(slice) > 0 {
        n := len(slice)
        randIndex := r.Intn(n)
        slice[n-1], slice[randIndex] = slice[randIndex], slice[n-1]
        slice = slice[:n-1]
    }
}

Dijkstra 3-路划分快速排序

Java

public class Quick3way {
    private Quick3way() { }

    public static void sort(Comparable[] a) {
        shuffle(a);
        sort(a, 0, a.length - 1);
    }

    private static void sort(Comparable[] a, int lo, int hi) {
        if (hi <= lo) return;
        int lt = lo, gt = hi;
        Comparable v = a[lo];
        int i = lo + 1;
        while (i <= gt) {
            int cmp = a[i].compareTo(v);
            if      (cmp < 0) exch(a, lt++, i++);
            else if (cmp > 0) exch(a, i, gt--);
            else              i++;
        }

        sort(a, lo, lt-1);
        sort(a, gt+1, hi);
    }

    private static void exch(Object[] a, int i, int j) {
        Object swap = a[i];
        a[i] = a[j];
        a[j] = swap;
    }

    private static void shuffle(Object[] a) {
        validateNotNull(a);
        int n = a.length;
        for (int i = 0; i < n; i++) {
            int r = i + uniform(n-i);     // between i and n-1
            Object temp = a[i];
            a[i] = a[r];
            a[r] = temp;
        }
    }

    private static void validateNotNull(Object x) {
        if (x == null) {
            throw new IllegalArgumentException("argument must not be null");
        }
    }

    private static int uniform(int n) {
        if (n <= 0) throw new IllegalArgumentException("argument must be positive: " + n);
        return random.nextInt(n);
    }
}

Go

func Quick3WaySort(A []int) {
    shuffle(A)
    quick3WaySort(A, 0, len(A))
}

func quick3WaySort(A []int, lo, hi int) {
    if hi-lo < 2 {
        return
    }
    lt := lo
    gt := hi - 1
    i := lo
    pivot := A[lo]
    for i <= gt {
        if A[i] < pivot {
            A[lt], A[i] = A[i], A[lt]
            lt++
            i++
        } else if A[i] > pivot {
            A[i], A[gt] = A[gt], A[i]
            gt--
        } else {
            i++
        }
    }
    quick3WaySort(A, lo, lt)
    quick3WaySort(A, gt+1, hi)
}

func shuffle(slice []int) {
    r := rand.New(rand.NewSource(time.Now().Unix()))
    for len(slice) > 0 {
        n := len(slice)
        randIndex := r.Intn(n)
        slice[n-1], slice[randIndex] = slice[randIndex], slice[n-1]
        slice = slice[:n-1]
    }
}