(Vi) Data Structure - Quick Sort

Quick Sort

Quicksort is a high sorting efficiency sorting algorithm, which uses divide and conquer treated ordered sequence sorting partition, which is mainly thought to be sorted by row trip records divided into separate two portions, wherein smaller than a portion of keywords, keywords than the large rear portion, then these two respectively front and rear parts of the sort this manner, the recursive computation ultimately the entire ordered sequence.

main idea

Quick Sort (English: Quicksort), also known as the exchange Sort division (partition-exchange sort), a trip by ordering the data to be sorted into separate two parts, one part of all of the data than the other part of all of the data to be smaller and then this method for two parts are quickly sort the data, the entire sorting process can be recursively, in order to achieve the whole data into an ordered sequence.

 

Code development

Realization of ideas

Step 1-从数组中挑选一个元素作为基准值(从左边和右边开始都可以)
Step 2-将两个变量分别指向数组的左侧和右侧(不包括基准值)
Step 3-左指向低索引
Step 4-右指向高索引
Step 5-比基准值小的放置在基准值前面
Step 6-比基准值大的放置在基准值后面(相同数据可以放置任意一边)
Step 7-递归(其中包括确定新的基准值)把小于基准值元素的子数列和大于基准值元素的子数列排序

Fake code

package com.paal.demo.c01SortingBasic;

import com.paal.demo.Sort;
import com.paal.demo.utils.SortTestHelper;

/**
 * <p/>
 * <li>title: 快速排序-基础版</li>
 * <li>@author: li.pan</li>
 * <li>Date: 2019/12/10 22:50 下午</li>
 * <li>Version: V1.0</li>
 * <li>Description: todo</li>
 */
public class QuickSort implements Sort {

    /**
     * 快速排序入口
     *
     * @param arr 数组
     */
    @Override
    public void sort(Integer[] arr) {

        int n = arr.length;
        sort(arr, 0, n - 1);
    }

    /**
     * 递归使用快速排序,对arr[l...r]的范围进行排序
     *
     * @param arr 无序集合
     * @param l   低索引
     * @param r   高索引
     */
    public static void sort(Integer[] arr, int l, int r) {

        // 递归到底
        if (l >= r)
            return;
        int p = partition(arr, l, r);
        sort(arr, l, p - 1);
        sort(arr, p + 1, r);
    }

    /**
     * 比基准值小的放置在基准值前面,比基准值大的放置在基准值后面(相同数据可以放置任意一边)
     * 返回p, 使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
     *
     * @param arr 无序数组
     * @param l   低索引
     * @param r   高索引
     * @return
     */
    private static int partition(Integer[] arr, int l, int r) {

        Integer v = arr[l];

        int j = l; // arr[l+1...j] < v ; arr[j+1...i) > v
        for (int i = l + 1; i <= r; i++)
            if (arr[i] < v) {
                j++;
                SortTestHelper.swap(arr, j, i);
            }

        SortTestHelper.swap(arr, l, j);
        return j;
    }
}
/**
     * 快速排序测试方法
     */
    @Test
    public void quickSortTest() {

        Integer[] integers0 = SortTestHelper.generateRandomArray(100, 0, 1000000);
        Integer[] integers1 = SortTestHelper.generateRandomArray(10000, 0, 1000000);
        Integer[] integers2 = SortTestHelper.generateRandomArray(100000, 0, 1000000);
        System.out.println("------------------------------随机数组--------------------------------");
        System.out.println("插入排序测试1数据量为100" + SortTestHelper.testSort(integers0, new InsertionSort()));
        System.out.println("插入排序测试2数据量为10000" + SortTestHelper.testSort(integers1, new InsertionSort()));
        System.out.println("插入排序测试3数据量为100000" + SortTestHelper.testSort(integers2, new InsertionSort()));
        System.out.println("归并排序优化测试1数据量为100" + SortTestHelper.testSort(integers0, new MergeSortOptimize()));
        System.out.println("归并排序优化测试2数据量为10000" + SortTestHelper.testSort(integers1, new MergeSortOptimize()));
        System.out.println("归并排序优化测试3数据量为100000" + SortTestHelper.testSort(integers2, new MergeSortOptimize()));
        System.out.println("快速排序测试1数据量为100" + SortTestHelper.testSort(integers0, new QuickSort()));
        System.out.println("快速排序测试2数据量为10000" + SortTestHelper.testSort(integers1, new QuickSort()));
        System.out.println("快速排序测试3数据量为100000" + SortTestHelper.testSort(integers2, new QuickSort()));

    }

Results of the

------------------------------随机数组--------------------------------
插入排序测试1数据量为100排序时长为: 0.005s
插入排序测试2数据量为10000排序时长为: 0.089s
插入排序测试3数据量为100000排序时长为: 5.728s
归并排序优化测试1数据量为100排序时长为: 0.0s
归并排序优化测试2数据量为10000排序时长为: 0.001s
归并排序优化测试3数据量为100000排序时长为: 0.005s
快速排序测试1数据量为100排序时长为: 0.0s
快速排序测试2数据量为10000排序时长为: 0.046s
快速排序测试3数据量为100000排序时长为: 6.721s

Code optimization

  • Optimization of a: small amount of data for the array using insertion sort but faster performance, the bottom layer can be smaller when the amount of data, the use of alternative rapid insertion sort partition ordering

  • Optimization II: Because the array may be nearly ordered array, so we can not take every head of the queue elements, you can take a time to take a random element

  • Optimization of three ( three-way fast row ): Array for a large number of repetitive elements, we can not only be part of the array is divided into two, but may be divided into an array of V is less than, equal to V, V is greater than three parts, then less than V and V is greater than the two portions of the sorting is performed recursively

Fake code

package com.paal.demo.c01SortingBasic.optimize;

import com.paal.demo.Sort;
import com.paal.demo.utils.SortTestHelper;

/**
 * <p/>
 * <li>title: 快速排序优化</li>
 * <li>@author: li.pan</li>
 * <li>Date: 2019/12/10 22:50 下午</li>
 * <li>Version: V1.0</li>
 * <li>Description:
 * 优化1: 对于小规模数组, 使用插入排序,效率更佳
 * 优化2: 对于arr[l...r]可能近乎有序的数组,采用获取随机值的方式随机获取基准值位置
 * 优化3: 对于arr[l...r]可能存在大量元素的数组,可以将数组分割为小于V,等于V,大于V的三部分,然后对小于V和大于V部分进行递归
 * </li>
 */
public class QuickSortOptimize implements Sort {

    /**
     * 快速排序入口
     *
     * @param arr 数组
     */
    @Override
    public void sort(Integer[] arr) {

        int n = arr.length;
        sort(arr, 0, n - 1);
    }

    /**
     * 递归使用快速排序,对arr[l...r]的范围进行排序
     *
     * @param arr 无序集合
     * @param l   低索引
     * @param r   高索引
     */
    private static void sort(Integer[] arr, int l, int r) {

        /**
         *  优化1: 对于小规模数组, 使用插入排序,效率更佳
         */
        if (r - l <= 15) {
            insertionSort(arr, l, r);
            return;
        }

        /**
         * 优化2: 对于arr[l...r]可能近乎有序的数组,采用获取随机值的方式随机获取基准值位置
         * (int) (Math.random() * (r - l + 1)) + l
         */
        SortTestHelper.swap(arr, l, (int) (Math.random() * (r - l + 1)) + l);

        Integer v = arr[l];

        /**
         * 优化3: 对于arr[l...r]可能存在大量元素的数组,可以将数组分割为小于V,等于V,大于V的三部分,然后对小于V和大于V部分进行递归
         * 简称"三路快排"
         */
        int lt = l;     // arr[l+1...lt] < v
        int gt = r + 1; // arr[gt...r] > v
        int i = l + 1;    // arr[lt+1...i) == v
        while (i < gt) {
            if (arr[i] < v) {
                SortTestHelper.swap(arr, i, lt + 1);
                i++;
                lt++;
            } else if (arr[i].compareTo(v) > 0) {
                SortTestHelper.swap(arr, i, gt - 1);
                gt--;
            } else { // arr[i] == v
                i++;
            }
        }
        SortTestHelper.swap(arr, l, lt);

        sort(arr, l, lt - 1);
        sort(arr, gt, r);
    }

    // 对arr[l...r]的区间使用InsertionSort排序
    public static void insertionSort(Integer[] arr, int l, int r) {

        for (int i = l + 1; i <= r; i++) {
            Integer e = arr[i];
            int j = i;
            for (; j > l && arr[j - 1] > e; j--)
                arr[j] = arr[j - 1];
            arr[j] = e;
        }
    }
}

    /**
     * 快速排序测试优化方法
     */
    @Test
    public void quickOptimizeSortTest() {

        Integer[] integers0 = SortTestHelper.generateRandomArray(100, 0, 1000000);
        Integer[] integers1 = SortTestHelper.generateRandomArray(10000, 0, 1000000);
        Integer[] integers2 = SortTestHelper.generateRandomArray(100000, 0, 1000000);
        System.out.println("------------------------------随机数组--------------------------------");
        System.out.println("插入排序测试1数据量为100" + SortTestHelper.testSort(integers0, new InsertionSort()));
        System.out.println("插入排序测试2数据量为10000" + SortTestHelper.testSort(integers1, new InsertionSort()));
        System.out.println("插入排序测试3数据量为100000" + SortTestHelper.testSort(integers2, new InsertionSort()));
        System.out.println("归并排序优化测试1数据量为100" + SortTestHelper.testSort(integers0, new MergeSortOptimize()));
        System.out.println("归并排序优化测试2数据量为10000" + SortTestHelper.testSort(integers1, new MergeSortOptimize()));
        System.out.println("归并排序优化测试3数据量为100000" + SortTestHelper.testSort(integers2, new MergeSortOptimize()));
        System.out.println("快速排序测试1数据量为100" + SortTestHelper.testSort(integers0, new QuickSort()));
        System.out.println("快速排序测试2数据量为10000" + SortTestHelper.testSort(integers1, new QuickSort()));
        System.out.println("快速排序测试3数据量为100000" + SortTestHelper.testSort(integers2, new QuickSort()));
        System.out.println("快速排序测试1数据量为100" + SortTestHelper.testSort(integers0, new QuickSortOptimize()));
        System.out.println("快速排序测试2数据量为10000" + SortTestHelper.testSort(integers1, new QuickSortOptimize()));
        System.out.println("快速排序测试3数据量为100000" + SortTestHelper.testSort(integers2, new QuickSortOptimize()));

        System.out.println("------------------------------近乎有序的数组--------------------------------");
        Integer[] integers00 = SortTestHelper.generateNearlyOrderedArray(100, 10);
        Integer[] integers11 = SortTestHelper.generateNearlyOrderedArray(10000, 100);
        Integer[] integers22 = SortTestHelper.generateNearlyOrderedArray(100000, 1000);
        System.out.println("插入排序测试1数据量为100" + SortTestHelper.testSort(integers00, new InsertionSort()));
        System.out.println("插入排序测试2数据量为10000" + SortTestHelper.testSort(integers11, new InsertionSort()));
        System.out.println("插入排序测试3数据量为100000" + SortTestHelper.testSort(integers22, new InsertionSort()));
        System.out.println("归并排序优化测试1数据量为100" + SortTestHelper.testSort(integers00, new MergeSortOptimize()));
        System.out.println("归并排序优化测试2数据量为10000" + SortTestHelper.testSort(integers11, new MergeSortOptimize()));
        System.out.println("归并排序优化测试3数据量为100000" + SortTestHelper.testSort(integers22, new MergeSortOptimize()));
        System.out.println("快速排序测试1数据量为100" + SortTestHelper.testSort(integers00, new QuickSort()));
        System.out.println("快速排序测试2数据量为10000" + SortTestHelper.testSort(integers11, new QuickSort()));
        System.out.println("快速排序测试3数据量为100000" + SortTestHelper.testSort(integers22, new QuickSort()));
        System.out.println("快速排序测试1数据量为100" + SortTestHelper.testSort(integers00, new QuickSortOptimize()));
        System.out.println("快速排序测试2数据量为10000" + SortTestHelper.testSort(integers11, new QuickSortOptimize()));
        System.out.println("快速排序测试3数据量为100000" + SortTestHelper.testSort(integers22, new QuickSortOptimize()));

        Integer[] integers000 = SortTestHelper.generateRandomArray(100, 0, 10);
        Integer[] integers111 = SortTestHelper.generateRandomArray(10000, 0, 100);
        Integer[] integers222 = SortTestHelper.generateRandomArray(100000, 0, 1000);
        System.out.println("------------------------------大量重复的数组--------------------------------");
        System.out.println("插入排序测试1数据量为100" + SortTestHelper.testSort(integers000, new InsertionSort()));
        System.out.println("插入排序测试2数据量为10000" + SortTestHelper.testSort(integers111, new InsertionSort()));
        System.out.println("插入排序测试3数据量为100000" + SortTestHelper.testSort(integers222, new InsertionSort()));
        System.out.println("归并排序优化测试1数据量为100" + SortTestHelper.testSort(integers000, new MergeSortOptimize()));
        System.out.println("归并排序优化测试2数据量为10000" + SortTestHelper.testSort(integers111, new MergeSortOptimize()));
        System.out.println("归并排序优化测试3数据量为100000" + SortTestHelper.testSort(integers222, new MergeSortOptimize()));
        System.out.println("快速排序测试1数据量为100" + SortTestHelper.testSort(integers000, new QuickSort()));
        System.out.println("快速排序测试2数据量为10000" + SortTestHelper.testSort(integers111, new QuickSort()));
        System.out.println("快速排序测试3数据量为100000" + SortTestHelper.testSort(integers222, new QuickSort()));
        System.out.println("快速排序测试1数据量为100" + SortTestHelper.testSort(integers000, new QuickSortOptimize()));
        System.out.println("快速排序测试2数据量为10000" + SortTestHelper.testSort(integers111, new QuickSortOptimize()));
        System.out.println("快速排序测试3数据量为100000" + SortTestHelper.testSort(integers222, new QuickSortOptimize()));

    }

Results of the

------------------------------随机数组--------------------------------
插入排序测试1数据量为100排序时长为: 0.001s
插入排序测试2数据量为10000排序时长为: 0.08s
插入排序测试3数据量为100000排序时长为: 5.66s
归并排序优化测试1数据量为100排序时长为: 0.0s
归并排序优化测试2数据量为10000排序时长为: 0.005s
归并排序优化测试3数据量为100000排序时长为: 0.003s
快速排序测试1数据量为100排序时长为: 0.0s
快速排序测试2数据量为10000排序时长为: 0.045s
快速排序测试3数据量为100000排序时长为: 6.748s
快速排序测试1数据量为100排序时长为: 0.0s
快速排序测试2数据量为10000排序时长为: 0.004s
快速排序测试3数据量为100000排序时长为: 0.033s
------------------------------近乎有序的数组--------------------------------
插入排序测试1数据量为100排序时长为: 0.0s
插入排序测试2数据量为10000排序时长为: 0.001s
插入排序测试3数据量为100000排序时长为: 0.097s
归并排序优化测试1数据量为100排序时长为: 0.0s
归并排序优化测试2数据量为10000排序时长为: 0.0s
归并排序优化测试3数据量为100000排序时长为: 0.0s
快速排序测试1数据量为100排序时长为: 0.0s
快速排序测试2数据量为10000排序时长为: 0.031s
快速排序测试3数据量为100000排序时长为: 3.459s
快速排序测试1数据量为100排序时长为: 0.0s
快速排序测试2数据量为10000排序时长为: 0.0s
快速排序测试3数据量为100000排序时长为: 0.008s
------------------------------大量重复的数组--------------------------------
插入排序测试1数据量为100排序时长为: 0.0s
插入排序测试2数据量为10000排序时长为: 0.039s
插入排序测试3数据量为100000排序时长为: 5.454s
归并排序优化测试1数据量为100排序时长为: 0.0s
归并排序优化测试2数据量为10000排序时长为: 0.0s
归并排序优化测试3数据量为100000排序时长为: 0.0s
快速排序测试1数据量为100排序时长为: 0.0s
快速排序测试2数据量为10000排序时长为: 0.034s
快速排序测试3数据量为100000排序时长为: 7.021s
快速排序测试1数据量为100排序时长为: 0.0s
快速排序测试2数据量为10000排序时长为: 0.001s
快速排序测试3数据量为100000排序时长为: 0.005s

 

Published 87 original articles · won praise 69 · views 130 000 +

Guess you like

Origin blog.csdn.net/lp284558195/article/details/103486398