小橙書閱讀指南(六)——快速排序和三向切分快速排序

算法描述:快速排序是一種分治的排序算法。它將數組分爲兩個子數組,並將兩部分獨立的排列。快速排序和歸併排序是互補的:歸併排序將數組分紅兩個子數組分別排序,並將子數組歸併以將整個數組排序;而快速排序將數組排序的方式則是當兩個子數組都有序時整個數組也就天然有序了。java

算法圖示:git

算法解釋:選擇標的元素(5)而且便利數組,將素有小於5的元素都安排在它的左側,而大於5的元素都安排在它的右側。以後再經過遞歸的方法分別處理左邊的子數組和右邊的子數組。算法

快速排序的算法難點在於儘可能不要使用額外的存儲空間(即保證原地切分)以及如何處理與標的元素(5)相等的元素。數組

Java代碼示例:ide

package algorithms.sorting;

import algorithms.Sortable;
import algorithms.common.Arrays;
import algorithms.common.ArraysGenerator;

/**
 * Created by learnhow on 2018/8/17.
 */
public class Quick extends Arrays<Integer> implements Sortable<Integer> {
    @Override
    public void sort(Integer[] array) {
        sort(array, 0, array.length - 1);
    }

    // 遞歸體
    private void sort(Integer[] array, int lo, int hi) {
        if (lo >= hi) {
            return;
        }

        int part = partition(array, lo, hi);
        sort(array, lo, part - 1);
        sort(array, part + 1, hi);
    }

    // 切分算法
    private int partition(Integer[] array, int lo, int hi) {
        // 限制數組的遍歷範圍 array(lo, hi];
        int i = lo;
        int j = hi + 1;
        int temp = array[lo];
        while (true) {
            while (array[++i] < temp) {
                if (i == hi) {
                    break;
                }
            }
            while (array[--j] > temp) {
                if (j == lo) {
                    break;
                }
            }
            if (i >= j) {
                break;
            }
            exchange(array, i, j);
        }
        exchange(array, lo, j);
        return j;
    }

    public static void main(String[] args) {
        Integer[] arr = ArraysGenerator.generate(10, 0, 10);
        Quick quick = new Quick();
        quick.sort(arr);

        System.out.println(java.util.Arrays.toString(arr));
    }
}

Qt/C++代碼示例:性能

void Quick::sort(int *arr, int lo, int hi)
{
    if (lo >= hi) {
        return;
    }
    int part = partition(arr, lo, hi);
    sort(arr, lo, part - 1);
    sort(arr, part + 1, hi);
}

int Quick::partition(int *arr, int lo, int hi)
{
    int i = lo;
    int j = hi + 1;
    int targetValue = arr[lo];
    while (true) {
        while (arr[++i] < targetValue) {
            if (i == hi) {
                break;
            }
        }
        while (arr[--j] > targetValue) {
            if (j == lo) {
                break;
            }
        }
        if (i >= j) {
            break;
        }
        // 交換元素位置
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    int temp = arr[lo];
    arr[lo] = arr[j];
    arr[j] = temp;

    return j;
}

算法性能分析:ui

快速排序速度優點子啊與它的比較次數不多,可是排序效果仍是依賴切分數組的狀況,而且若是在數組中存在大量重複元素。算法性能還能夠大幅度提高。下面咱們給出三向切分的快速排序算法。你們做爲了解便可。spa

算法圖示:指針

算法解釋:在三向切分快速排序算法中咱們定義了三個指針變量:gt 小於 V 的數組的上界,i 等於 V 的數組的上界,gt 大於 V 的數組的下界。以及一段中間數組array[i, gt]。一次遍歷的判斷過程以下:code

  • array[i]小於V,將array[lt]和array[i]交換,並將lt和i分別加1;
  • array[i]大於V,將array[gt]和array[i]交換,並將gt減1;
  • array[i]等於V, 將i單獨加1;

Java代碼示例:

package algorithms.sorting;

import algorithms.Sortable;
import algorithms.common.Arrays;
import algorithms.common.ArraysGenerator;

public class Quick3way extends Arrays<Integer> implements Sortable<Integer> {
    @Override
    public void sort(Integer[] array) {
        sort(array, 0, array.length - 1);
    }

    private void sort(Integer[] array, int lo, int hi) {
        if (hi <= lo) {
            return;
        }
        int temp = array[lo]; // 比較標的
        int lt = lo; // 小於temp的index記錄
        int eq = lo + 1; // 等於temp的index記錄
        int gt = hi; // 大於temp的index記錄

        while (eq <= gt) {
            if (array[eq] < temp) {
                exchange(array, lt++, eq++);
            } else if (array[eq] > temp) {
                exchange(array, eq, gt--);
            } else {
                eq++;
            }
        }
        sort(array, lo, lt - 1);
        sort(array, gt + 1, hi);
    }

    public static void main(String[] args) {
        Integer[] arr = ArraysGenerator.generate(10, 0, 10);
        Quick3way quick3way = new Quick3way();
        quick3way.sort(arr);

        System.out.println(java.util.Arrays.toString(arr));
    }
}

Qt/C++代碼示例(略)

三向切分快速排序針對特定數組可以起到很是優秀的效果,可是在處理下標越界的事情每每容易弄錯。所以在考慮算法性能的同時,保證正確應該優先考慮。

 

相關連接:

Algorithms for Java

Algorithms for Qt

相關文章
相關標籤/搜索