快速選擇Java實現(xiàn)

快速選擇算法

一盛霎、基本原理: 從一個數(shù)組中,快速找到一個排名第K大或者第K小的元素耽装。

二愤炸、實現(xiàn)思路:依據(jù)快排的思路,找到軸樞元素的索引與排名k之間的關(guān)系掉奄。

三规个、具體分析:

舉例1:

問題: 假如現(xiàn)在有6個學(xué)生的體重,想知道6個學(xué)生中體重第二輕的是多少kg挥萌?

抽象成如下問題:

在未排序的數(shù)組中绰姻,找到排名第K的元素。

給定一個數(shù)組: [30,83,56,76,21,95] 和 k = 2

輸出: 30

結(jié)合之前學(xué)習(xí)過的快速排序引瀑,我們只需要保證軸樞元素(X)前的元素均比X小狂芋,X后的元素均比X大即可。且比X小的元素為k-1個憨栽,那么此時的X就是我們需要找的第K位元素帜矾。

即沒必要對原數(shù)組進(jìn)行整體的排序,只需要找到滿足條件的元素X即可屑柔。

參照快速排序的partion過程屡萤,在第一輪結(jié)束后,軸樞元素X的位置為ind

import java.util.Arrays;

public class quick_sort_test {


    public static void main(String[] args) {
        int[] arr = new int[] {30,83,56,76,21,95};
        quickSort(arr, 0 ,arr.length-1);

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


    public void swap(int[] nums, int i, int j) {
        if(i == j) {
            return;
        }
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;

    }

    public static void quickSort(int[] nums, int left, int right) {
        int middle;
        if(left < right) {
            middle = partition(nums, left, right);
            System.out.println("軸樞元素的下標(biāo):" + middle);
            System.out.println("軸樞元素的值:" + nums[middle]);
//          對分界值分隔的兩個數(shù)組掸宛,繼續(xù)遞歸該方法死陆。
//            quickSort(nums, left, middle-1);
//            quickSort(nums, middle+1, right);
        }

    }
    //執(zhí)行完一次后,輸出分界值的坐標(biāo)
    public static int  partition(int[] nums, int left, int right) {
        if (left > right) {
            return 0;
        }

        int pivot = nums[left];

        while(left < right) {
            while (left < right && nums[right] >= pivot) {
                right--;
            }
            nums[left] = nums[right];
            while (left < right && nums[left] <= pivot) {
                left++;
            }

            nums[right] = nums[left];

        }
        nums[left] = pivot;

        return left;
    }

}

將測試數(shù)組傳入,軸樞的元素的下標(biāo)ind為1(即為排名第k=2的元素)措译, X的值為30

問題中的k=2(當(dāng)k=3, k = 1是分別得出以下結(jié)論:)

  • 當(dāng) ind = k -1 時别凤,此時的ind對應(yīng)的元素X就是要求解的值。
  • 當(dāng) ind < k -1 時领虹,此時需要從軸樞元素分隔的后部分?jǐn)?shù)組開始尋找规哪,范圍為:[ind+1, nums.length-1]
  • 當(dāng) ind > k - 1時,測試需要從軸樞元素分隔的前部分?jǐn)?shù)組開始尋找塌衰,范圍為: [0诉稍, ind-1]
image-20220404121847456.png

落到具體的代碼上:

import java.util.Arrays;

public class quick_select {
    public static void main(String[] args) {
        int[] arr = {30,83,56,76,21,95};

//      快速選擇算法:從數(shù)組中找出排名第k位的元素,并輸出最疆。
//      eg: 從數(shù)據(jù)中找出排名第2的元素杯巨。
        int k = 2;
//      int k = 3;
//      int k = 1;

        int result = quickSelect(arr, 0, arr.length-1, k);

        System.out.println("排名第" +k +  "位的元素值為:" + result + "\n");

        System.out.println("此時數(shù)組的內(nèi)容為:" + Arrays.toString(arr
        ));
    }

    public static void swap(int[] nums, int i, int j ) {
        if(i == j) {
            return;
        }

        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }

    /**
     * 快速排序的核心思想是找到排名第k位置的元素, 所以僅需保證前k-1的元素比k位置的元素小即可肚菠,
     * 沒有必要對整個數(shù)組進(jìn)行全部的排序
     * @param nums
     * @param left
     * @param right
     * @param k
     * @return  返回的是排名第K位置的元素值舔箭。
     */

    public static int quickSelect(int[] nums, int left, int right, int k) {
        if(left > right) {
            return 0;
        }

        while (left < right) {
            int privot = nums[left];

            while (left < right && nums[right] >= privot) {
                right--;
            }

            nums[left] = nums[right];

            while (left < right && nums[left] <= privot) {
                left++;
            }

            nums[right] = privot;
        }

//      完成了第一輪比較,此時left和right相等蚊逢,均指向第一個軸樞元素层扶。即ind = left = right
        int ind = left;
        if(ind == k - 1) {
            return nums[ind];
        } else if (ind < k - 1) {
            return quickSelect(nums, ind + 1, nums.length-1, k);
        } else {
            return  quickSelect(nums, 0, ind-1, k);
        }
    }



}

①、當(dāng)k = 2(ind == k - 1)烙荷,執(zhí)行結(jié)果如下:


ind == k - 1

②镜会、當(dāng)k = 3(ind < k - 1), 執(zhí)行結(jié)果如下:


ind < k - 1

③终抽、當(dāng)k = 1(inx > k - 1)戳表,執(zhí)行結(jié)果如下:

inx > k - 1

觀察該測試數(shù)據(jù),可以發(fā)現(xiàn)在一輪排序的過程中昼伴,剛好將所有的數(shù)據(jù)排序完成了匾旭,此時難以驗證快速選擇算法的。所以我們更換一組測試數(shù)據(jù)圃郊,執(zhí)行后觀察:符合預(yù)期

        int[] arr = {8,2,3,5,10,7,19,4,14};
更換測試數(shù)據(jù)后
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末价涝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子持舆,更是在濱河造成了極大的恐慌色瘩,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逸寓,死亡現(xiàn)場離奇詭異居兆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)竹伸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門泥栖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事聊倔』薇校” “怎么了生巡?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵耙蔑,是天一觀的道長。 經(jīng)常有香客問我孤荣,道長甸陌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任盐股,我火速辦了婚禮钱豁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疯汁。我一直安慰自己牲尺,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布幌蚊。 她就那樣靜靜地躺著谤碳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪溢豆。 梳的紋絲不亂的頭發(fā)上蜒简,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機(jī)與錄音漩仙,去河邊找鬼骇钦。 笑死娱节,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播仗岸,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼忧勿!你這毒婦竟也來了睬澡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤磕谅,失蹤者是張志新(化名)和其女友劉穎私爷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膊夹,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡衬浑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了放刨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片工秩。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出助币,到底是詐尸還是另有隱情浪听,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布眉菱,位于F島的核電站迹栓,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏俭缓。R本人自食惡果不足惜克伊,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望华坦。 院中可真熱鬧愿吹,春花似錦、人聲如沸惜姐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歹袁。三九已至坷衍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宇攻,已是汗流浹背惫叛。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留逞刷,地道東北人嘉涌。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像夸浅,于是被迫代替她去往敵國和親仑最。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容