"Algorithm" notes 5 - Quick Sort

  • The basic algorithm
    • Code
    • Segmentation
    • Features
  • Algorithm Improvement
    • Insertion sort to the switching
    • Three sampling segmentation
    • Optimized for repeating elements - three-way segmentation

This section will learn quick sort, arguably the most widely used sorting algorithm, many languages such as Java, C # sort of system is used in quick sort. Quick sort simple, but for a variety of different input data, and other sorting algorithms much faster than in a typical application. Quicksort advantage that as compared with the previous several sorting algorithm, it is not only place sorting algorithm (requires only a small auxiliary stack), and the length of time required to sort the array and N is proportional NlgN, and several algorithms are not before both of these two characteristics. Merge sort Although very fast, but it's the cost of space is linear growth.
Quick Sort by CAR Hoare invention in 1960, one of the ten algorithm known as the 20th century, Hoare himself for achievements fast sorting and other computer science obtained in 1980 Turing Award.

The basic algorithm

Quick sort is a sorting algorithm based on divide and conquer, its basic idea is that the array is divided into two halves, the left is always less than half an element, the right is always greater than half an element, the process continues to recursively continue until the entire array becomes orderly.

Code

code show as below:

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

    private static void sort(Comparable[] a, int lo, int hi) {
        if (lo >= hi)
            return;
        int j = partition(a, lo, hi);  //切分方法,待实现
        sort(a, lo, j - 1);  //将左边子数组排序
        sort(a, j + 1, hi);  //将右边边子数组排序
    }

    ...
}

Quick sort and merge sort are complementary, but also merge sort the array are sorted into two sub-arrays, sub-array and ordered merge to the entire array is sorted, the recursive call occurs prior to processing the entire array; and sort the array quicksort it is less than by way let segmented subarray elements on both sides of the left and right, respectively, greater than the splitting element, eventually the whole array is ordered nature, and its recursive call occurs after processing the entire array.

Segmentation

Segmentation effect Partition () is to segmentation element a [j] into the position it should stay, and segmentation based element, of the sort will recursively left subarray sort. Will first array upset before ordering, which would allow the performance of the algorithm from the effects of the input feature.

Segmentation is the code:

private static int partition(Comparable[] a, int lo, int hi) {
    int i = lo, j = hi + 1;
    Comparable v = a[i];
    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;
}

FIG segmentation procedure:

Take a [lo] slicing element is v, the pointer i, j, respectively, start scanning from the left and right ends of the array, the elements found a greater than v from left to right, right to left to find an element v is less than two elements are not scheduled, so the exchange Talia position, and then continue scanning, exchange, until the left "pointer" i and right "pointer" j meet, they completed a segmentation process for the element v while v It has been scheduled to the appropriate position. Every time segmentation can always schedule an element, all the elements will eventually routed to the correct location.
When scanning with less (a [++ i], v) rather than less (a [i ++], v), because i just came in is assigned lo, lo is the segmentation element, a start scanning from under ; and the right "pointer" j comparison code less (v, a [- j ]), instead j--, because j is initially assigned hi + 1.
In the face of border elements, this code can schedule it.

Features

Performance characteristics for the rapid sorting can be assumed that an ideal situation, both the slicing each array can be divided in half, so that similar binary merge sort, each N comparisons are required, the total NLgN times.

In my books, when 100,000 random integer sort, merge sort and quick sort of speed comparison is as follows:

Merge, 0.249
Quick, 0.195

Algorithm Improvement

Insertion sort to the switching

Quick sort and merge sort are the same as the use of recursion, then switch to insertion sort algorithm can improve the performance of the small-scale arrays.

public class QuickX {
    private static int CUTOFF = 7;
    ...
    private static void sort(Comparable[] a, int lo, int hi) {
        if (lo + CUTOFF >= hi) {
            insertionSort(a, lo, hi);
            return;
        }
        int j = partition(a, lo, hi);
        sort(a, lo, j - 1);
        sort(a, j + 1, hi);
    }

    private static void insertionSort(Comparable[] a, int lo, int hi) {
        for (int i = lo; i <= hi; i++) {
            for (int j = i; j > lo && less(a[j], a[j - 1]); j--) {
                exch(a, j, j - 1);
            }
        }
    }
}

Three sampling segmentation

Effect sliced ​​quick sort a great impact on performance, an ideal front envisaged a case, each array segmentation can be divided in half; but if the first time-slicing cut from the smallest elements, the second cut from the second smallest element points, and so on, each call will only remove an element, in this case the performance will be very poor. First be upset before the start of the sort, it is to avoid a similar situation. Cut three sample points is a method for increasing the balance of slicing, when selecting segmentation element array select the leftmost, rightmost, the median three intermediate elements.

Three sample code is as follows:

public class QuickX {
    private static int partition(Comparable[] a, int lo, int hi) {
        int n = hi - lo + 1;
        int m = median3(a, lo, lo + n / 2, hi);  //三取样切分
        exch(a, lo, m);
        int i = lo, j = hi + 1;
        Comparable v = a[i];
        while (true) {
            while (less(a[++i], v)) { // less(a[i++], v)
                if (i == hi)
                    break;
            }
            while (less(v, a[--j])) { // less(v, a[j--])
                if (j == lo)
                    break;
            }
            if (i >= j)
                break;
            exch(a, i, j);
        }
        exch(a, lo, j);
        return j;
    }

    private static int median3(Comparable[] a, int i, int j, int k) {
        return (less(a[i], a[j]) ? (less(a[j], a[k]) ? j : less(a[i], a[k]) ? k : i)
                : (less(a[k], a[j]) ? j : less(a[k], a[i]) ? k : i));
    }
}

When after insertion sort optimized segmentation and three samples, and then try to 100,000 random integer sort, the sorting and optimization fast speed comparison quick sort:

Quick, 0.203
QuickX, 0.159

Optimized for repeating elements - three-way segmentation

Often there will be an array contains a lot of repeating elements in practical applications, such as date of birth, gender, etc. When this type of input, if the element sub-array has all repeat, and then continue to run its segmentation algorithm, row given only a waste of time, this situation can be further optimized.
Three-segmentation array is cut into three parts, respectively less than, equal to, greater than splitting element array elements, code:

public class Quick3Way {
    ...

    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++;
        }

        // a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi]. 
        sort(a, lo, lt-1);
        sort(a, gt+1, hi);
    }
}

Respectively and maintains two pointers lt gt, sequentially scanning the array, such that a [lo..lt-1] are less than v, a [lt..i-1] is equal to v, a [gt + 1..hi] are greater than v, a [i..gt] element is not yet in the comparison of the elements.

Finally, the 100 integers, each repeated data 1,000,000 10,000 try the effect obtained as inputs:

Quick, 0.408
Quick3Way, 0.03

Guess you like

Origin www.cnblogs.com/zhixin9001/p/11502945.html