1. 程式人生 > >快速排序過程、partition應用、三種快排四種優化、Java實現

快速排序過程、partition應用、三種快排四種優化、Java實現

快速排序過程

基本思想是分治的思想,說到分治,就應該想到和遞迴是分不開的。

有些書上會使用關鍵字比較的表述,有些書上會直接使用記錄比較表述,這兩種說法是兩個維度上的說法。這裡序列元素的關鍵字屬於記錄的一部分,為了簡化問題,本文的討論並不區分關鍵字和記錄,程式碼實現中使用整數來表示記錄。簡而言之,本文的討論簡化為,對整型陣列的快速排序。

通過一趟排序將要排序的記錄分割成兩部分,一部分的關鍵字值比別一部分的所有關鍵字都小,然後再依次對前後兩部分的記錄進行快速排序,遞迴該過程,直到序列中所有記錄都是有序為止。

步驟

1)分解。選擇第一個元素作為基準數,將輸入序列array[m…n]劃分成兩個非空序列array[m…k]和array[k+1…n],使array[m…k]中任一元素的值不大於array[k+1…n]任一元素值。

2)遞迴求解。通過遞迴呼叫快排演算法分別對array[m…k]和array[k+1…n]進行排序

3)合併。由於對分解出的兩個子序列排序都是原地進行的,所以在array[m…k]和array[k+1…n]都排好序後不需要再執行任何計算,就能將array[m…n]排好序。因此這一步是不需要在程式中體現的。

排序過程分析

初始關鍵字:52 39 67 95 70 8 25 52’ ,下面將列出每一趟執行的結果。

基準52: 52 39 67 95 70 8 25 52’

基準25: 8 25 39 52 70 95 67 52‘

基準70: 8 25 39 52 52’ 67 70 95

基準52‘:8 25 39 52 52’ 67 70 95

演算法分析

快速排序的時間複雜度與關鍵字初始序列有關。

最壞時間複雜度:O(n^2):

以第一個數或最後一個數為基準時,當初始序列整體或區域性有序時,快速排序的效能會下降。若整體有序,此時,每次劃分只能分出一個元素,具有最壞時間複雜度,快速排序將退化成氣泡排序。

最好時間複雜度:

每次選取的基準關鍵字都是待排序列的中間值,也就是說每次劃分可以將序列劃分為長度相等的兩個序列。快速排序的遞迴過程可以用一棵二叉樹來表示,遞迴樹的高度是2為底的對數,每層需要比較的次數是n/2,所以最好時間複雜度是O(n*以2為底n的對數),因為很多時候輸入序列都是亂序的,所以最好時間複雜度也是平均時間複雜度。

三種快排和四種優化方法

三種快排

這裡區分的方式是不同基準的選擇方法:

1)固定位置,取第一個或最後一個元素作為基準。這種選取方法不合適區域性有序的輸入。

2)隨機選取基準,利用隨機演算法,選取待排序序列中任意一個元素作為基準。

3)三數取中,取數列中第一個數,中間位置的數,最後一個數作一個平均值作為基準。

四種優化

1)當排序序列長度分割到一定程度時,使用插入排序

對於N很小或區域性有序的陣列,直接插入排序的效率非常高。

2)在一次分割結束後,可以把與基準數相等的元素聚在一起,下次分割時忽略掉這些元素。

對於含有重複元素比較多的序列,這種優化方法效果比較好,可以減少很多跌代次數。

具本過程:

第一步:在劃分過程,把與所選取的基準數相等的元素放在陣列的兩端。

第二步:劃分結束後,把兩端的與基準數相等的元素移到基準數最終位置的兩側。

3)優化遞迴操作。

4)使用多執行緒並行處理子劃分。

Partition方法在求TopK問題上的應用

TopK問題即求序列中最大或最小的K個數。這裡以求最小K個數為例。

快速排序的思想是使用一個基準元素將陣列劃分成兩部分,左側都比基準數小,右側都比基準數大。

給定陣列array[low…high],一趟快排劃分後的結果有三種:

1)如果基準數左側元素個數Q剛好是K-1,那麼在基準數左側(包含基準數本身),即為TopK的所有元素。

2)如果基準數左側元素個數Q小於K-1,那麼說明基準數左側的Q個數都是TopK裡的元素,只需要在基準數的右側找出剩下的K-Q個元素即可。問題轉化成了以基準數下標為起點,高位(high)為終點的Top(K-Q)。遞迴下去即可。

3)如果基準數左側元素個數Q大於K-1,說明第K個位置,在基準數的左側,需要縮小搜尋範圍,在低位(low)至基準數位置重複遞迴即可,最終問題會轉化成上面兩種情況。

快排java實現

在手寫快排演算法時,最好先把一趟排序的過程寫出來。

package sort;



public class QuickSort {



    // 暴露只一個引數的公共介面

    public void quickSort(int a[]) {

        sort(a, 0, a.length - 1);

    }



    // 快排演算法的真正實現

    private void sort(int[] a, int low, int high) {

        if (low >= high)

            return;

        int i = low, j = high; // 設定這兩個變數的目的是為了保持low和high不變

        int pivotNum = a[i]; // 基準數

        while (i < j) {

            while (a[j] >= pivotNum && j > i) { // 迴圈結束的條件有二:一是找到比支點小的數,二是j==i

                j--;

            }

            if (j > i) {    // 由於上面迴圈結束的功能性有兩個,對於找到比支點小的數,即j!=i,要進行位置的交換,下同

                a[i] = a[j];

                i++;

            }



            while (a[i] < pivotNum && i < j) { 

                i++;

            }

            if (i < j) {

                a[j] = a[i];

                j--;

            }

        }

        a[i] = pivotNum;



        sort(a, low, i - 1);

        sort(a, i + 1, high);

    }



    public static void main(String[] args) {

        int[] a = { 52, 39, 67, 95, 70, 8, 25, 52 };

        new QuickSort().quickSort(a);

        for (int i : a) {

            System.out.print(i + " ");

        }



    }



}

參考資料:

相關推薦

快速排序過程partition應用優化Java實現

快速排序過程 基本思想是分治的思想,說到分治,就應該想到和遞迴是分不開的。 有些書上會使用關鍵字比較的表述,有些書上會直接使用記錄比較表述,這兩種說法是兩個維度上的說法。這裡序列元素的關鍵字屬於記錄的一部分,為了簡化問題,本文的討論並不區分關鍵字和記錄,程式

深入理解快速排序(隨機雙路

快速排序可以說是20世紀最偉大的演算法之一了。相信都有所耳聞,它的速度也正如它的名字那樣,是一個非常快的演算法了。當然它也後期經過了不斷的改進和優化,才被公認為是一個值得信任的非常優秀的演算法。 本文將結合快速排序的三方面進行比較和深入解析。 快速排

Python 多執行緒多程序 ()之 執行緒程序對比多程序

Python 多執行緒、多程序 (一)之 原始碼執行流程、GIL Python 多執行緒、多程序 (二)之 多執行緒、同步、通訊 Python 多執行緒、多程序 (三)之 執行緒程序對比、多執行緒 一、多執行緒與多程序的對比 在之前簡單的提過,CPython中的GIL使得同一時刻只能有一個執行緒執行,即併

快速排序中的partition.

div ati 排序 span [] 一個數 代碼 等於 圖片 經典快速排序中的partition, 將最後一個元素作為劃分點。 維護兩個區域。 <= x 的, >x 的區域。 劃分過程中還有個待定的區域。 [L,less] 區域小於x, [less+1,c

深入淺出之 TCP協議(次握手與次揮手超時重發流量控制擁塞控制與UDP區別)

TCP/IP 中有兩個具有代表性的傳輸層協議,分別是TCP、UDP。TCP提供可靠的通訊傳輸,而UDP則常被用於讓廣播和細節控制交給應用的通訊傳輸。 要知道TCP為了這簡單描述“可靠的通訊傳輸”背後所做的努力,你會深感佩服其強大性。TCP的特徵:序列化+確認應

MySqlOracle(通用方法)遞迴查詢生成檔案目錄樹(JAVA實現 遞迴過程中不訪問資料庫,遞迴之前只訪問兩次 進行遞迴前資料準備)

查詢檔案樹 實體類 public class TradeInfoFile { ​ // 檔案編碼(子) private String fileCode; // 所屬檔案編碼(父) private String belongFileCode; // 交易

我見過最通俗易懂的快速排序過程講解,轉自《坐在馬桶上看演算法:快速排序

如果以上C程式碼看不懂,請看下面java程式碼: public static int Partition(int[] a,int p,int r){   int x=a[r-1];   int i=p-1;   int temp;   for(int j=p;j<=

通俗易懂的快速排序過程講解,轉自《坐在馬桶上看演算法:快速排序

注:1.關於ij相遇時,該數和基準交換的說法,不認同;要是相遇時這個數(比如9)比基準6大,交換不久錯了? 2.while(i!=j)裡面,當i=3,j=4,i++,j--還是會錯開,你寫while(i<j)只能保證不進入當下迴圈,但不會從while(i!=j)出來,所以有可能死迴圈的情況; 3.建議到

java算法面試題:排序都有哪幾方法?請列舉。用JAVA實現一個快速排序。選擇冒泡快速集合至少4方法排序

算法 err div println rda print 算法面試 ++ 快速排序 package com.swift; import java.util.ArrayList; import java.util.Collections; import java.util

LeetCode—75—Sort Colors(思想應用)

題目 Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors

二叉樹的先序遍歷(遞迴和非遞迴)中序遍歷(遞迴和非遞迴)後序遍歷(非遞迴)及層次遍歷java實現

二叉樹的先序遍歷,遞迴實現: public List<Integer> preorderTraversal(TreeNode root) { //用棧來實現 List<Integer> list = new ArrayList&l

X軸Y軸label文字過長的處理方式

1、傾斜顯示 2、換行顯示  3、豎直顯示 4、隔兩行顯示   5、原始碼 var axisLabel1 = { // 方法1:傾斜顯示 interval: 0, //強制全部顯示,1表示隔一個;2隔兩個 rotate: "45

CRC16算法之:CRC16-CCITT-MODBUS算法的java實現

targe func tag art pub gui itl 實現 oct CRC16算法系列文章: CRC16算法之一:CRC16-CCITT-FALSE算法的java實現 CRC16算法之二:CRC16-CCITT-XMODEM算法的java實現

與兩歸併和堆和插入排序 大資料量執行時間比較

#include"iostream" #include"iomanip" #include"stdlib.h" #include"time.h" #include"string" /*由於我電腦記憶體有限所以資料量最大能執行在20w*/ //三路快排適用於有大量重複值的資

方式列印楊輝三角形(JAVA實現

  1 //採用一個二維陣列列印楊輝三角 2 class Yanghui1 { 3 public static void main(String[] args) 4 { 5 //設定楊輝三角的行數 6 int num = 10

三路快排也是用來解決序列中存在大量重複元素的問題,比雙路快排更高效 將序列分為三個部分,小於pivot、等於pivot、大於pivot 等於pivot的部分不遞迴,這樣在存在大量重複元素時,將大大縮小遞迴的資料規模 from random import shuffle, randint def quick

交換兩個變數的值,不借助第個變數的方法(學習)

缺點:是隻能用於數字型別,字串之類的就不可以了。a+b有可能溢位(超出int的範圍),溢位是相對的, +了溢位了,-回來不就好了,所以溢位不溢位沒關係,就是不安全。2) 指標地址操作         因為對地址的操作實際上進行的是整數運算,比如:兩個地址相減得到一個整數,表示兩個變數在記憶體中的儲存位置隔了

基本解法以及兩優化

/*  快速排序  基本思想    選定每次排序的基準資料 在剩下的位置將小於基準值的資料放在基準值得左邊,大於基準值的資料放到基準值的右邊    一次劃分之後 如果此基準值的左右兩邊仍存在大於兩個資料  則繼續劃分排序 直至每個數字都有序   遞迴實現Quick_Sort1

一個數如果恰好等於它的因子之和,這個數就稱為完數,編寫應用程式求1到1000的完數(java實現

package vb;public class abcd { public static void main(String args[]){   int i,j;  for(i=1;i<=1000;i++){   int sum=0;   for(j=1;j<i;

分散式系統應用中生成全域性唯一ID的演算法(snowflake)----java 實現,單例模式

概述 在分散式系統中,有很多的地方需要生成全域性id的場景,比方說,訂單模組,使用者id等。這種情況下大多數的做法是通過UUID來做處理。首先,UUID是36位的一個字串,相對來說是比較長的,一般我們採用的資料庫會是MySQL,因為大多數的情況下,我們都希望我們的資料是可以