国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

時(shí)間復(fù)雜度為 O(n) 的排序算法

這篇具有很好參考價(jià)值的文章主要介紹了時(shí)間復(fù)雜度為 O(n) 的排序算法。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

大家好,我是 方圓。本文介紹線性排序,即時(shí)間復(fù)雜度為 O(n) 的排序算法,包括桶排序,計(jì)數(shù)排序和基數(shù)排序,它們都不是基于比較的排序算法,大家重點(diǎn)關(guān)注一下這些算法的適用場(chǎng)景。

桶排序

桶排序是分治策略的一個(gè)典型應(yīng)用。它通過(guò)設(shè)置一些具有大小順序的桶,每個(gè)桶對(duì)應(yīng)一個(gè)數(shù)據(jù)范圍,將數(shù)據(jù)平均分配到各個(gè)桶中;然后,在每個(gè)桶內(nèi)部分別執(zhí)行排序;最終按照桶的順序?qū)⑺袛?shù)據(jù)依次取出合并,組成的序列就是有序的了,如下圖所示:

時(shí)間復(fù)雜度為 O(n) 的排序算法,排序算法,算法,數(shù)據(jù)結(jié)構(gòu)

桶排序的算法流程我將其分成三個(gè)步驟:

  • 初始化桶:以范圍為 0 - 49 的數(shù)據(jù)為例,分為 5 個(gè)桶

  • 分桶:將要排序數(shù)組中的元素加入桶中

  • 出桶:該步驟需要在桶中完成排序后,依次出桶合并

    /**
     * 桶排序:指定數(shù)據(jù)范圍為0 - 49,分桶為5個(gè),每10個(gè)數(shù)為一個(gè)桶
     */
    public void sort(int[] nums) {
        // 聲明5個(gè)桶
        List<ArrayList<Integer>> buckets = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            buckets.add(new ArrayList<>());
        }

        // 數(shù)組元素分桶
        intoBucket(buckets, nums);

        // 出桶
        outOfBucket(buckets, nums);
    }

    /**
     * 分桶
     */
    private void intoBucket(List<ArrayList<Integer>> buckets, int[] nums) {
        for (int num : nums) {
            int bucketIndex = num / 10;
            buckets.get(bucketIndex).add(num);
        }
    }

    /**
     * 出桶
     */
    private void outOfBucket(List<ArrayList<Integer>> buckets, int[] nums) {
        // 出桶覆蓋原數(shù)組值
        int numsIndex = 0;
        for (ArrayList<Integer> bucket : buckets) {
            // 先排序 再出桶
            bucket.sort(Comparator.comparingInt(x -> x));

            for (Integer num : bucket) {
                nums[numsIndex++] = num;
            }
        }
    }

算法特性:

  • 空間復(fù)雜度:O(n + k)

  • 自適應(yīng)排序:與桶劃分情況和桶內(nèi)使用的排序算法有關(guān)

  • 穩(wěn)定排序/非穩(wěn)定排序:與桶內(nèi)使用的排序算法有關(guān)

  • 非原地排序

桶排序比較適用于 外部排序,所謂的外部排序就是數(shù)據(jù)存儲(chǔ)在外部磁盤(pán)中,數(shù)據(jù)量很大,但是內(nèi)存又有限,無(wú)法將所有數(shù)據(jù)全部加載進(jìn)來(lái),比如有 1G 的數(shù)據(jù)需要排序,但是內(nèi)存只有幾百M(fèi)B的情況。我們可以根據(jù)數(shù)據(jù)范圍將其劃分到 N 個(gè)桶中,劃分完成后每個(gè)桶的大小不超過(guò)可用內(nèi)存大小,對(duì)每個(gè)桶內(nèi)的數(shù)據(jù)進(jìn)行排序,排序完成后生成 N 個(gè)小文件,最后我們?cè)賹⑦@ N 個(gè)小文件寫(xiě)入到一個(gè)大文件中即可。如果數(shù)據(jù)在某些范圍內(nèi)并不是均勻分布的話,有些范圍內(nèi)的數(shù)據(jù)特別多,那么這就需要我們?cè)賹?duì)其劃分成更細(xì)粒度的桶,直到滿足內(nèi)存的使用要求,但是這樣我們的桶就不是按照范圍均勻劃分的了。

計(jì)數(shù)排序

計(jì)數(shù)排序是桶排序的一種特殊情況,只是它定義的“桶”的粒度更細(xì),每個(gè)桶中只包含一個(gè)單位范圍的數(shù)字,那么每個(gè)“桶”內(nèi)的數(shù)值都是相等的。它適合數(shù)據(jù)范圍不大,但數(shù)據(jù)量很大的排序場(chǎng)景,比如高考考生成績(jī)排名,86 萬(wàn)考生,滿分 750 分,需要?jiǎng)澐?751 個(gè)桶,將這些考生的成績(jī)劃分到各個(gè)桶中后,依次取出即可。

看到這里你可能會(huì)覺(jué)得這不就是桶排序嗎?計(jì)數(shù)排序的計(jì)數(shù)體現(xiàn)在哪里呢?別急,我們看下下面這個(gè)排序的例子,簡(jiǎn)單起見(jiàn),假設(shè)有 8 個(gè)考生,他們的分?jǐn)?shù)為 [2, 5, 3, 0, 2, 3, 0, 3],分?jǐn)?shù)范圍為 0 ~ 5,那么我們需要?jiǎng)?chuàng)建 6 個(gè)桶,規(guī)定桶中保存的不是對(duì)應(yīng)的元素,而是對(duì)應(yīng)分?jǐn)?shù)元素出現(xiàn)的數(shù)量,并根據(jù)分?jǐn)?shù)將桶中的計(jì)數(shù)值累加,如下圖所示:

時(shí)間復(fù)雜度為 O(n) 的排序算法,排序算法,算法,數(shù)據(jù)結(jié)構(gòu)

我們先看分?jǐn)?shù) 0 的桶,它是該數(shù)據(jù)范圍內(nèi)最小的分?jǐn)?shù),它的計(jì)數(shù)為 2,根據(jù)計(jì)數(shù)值我們可以確定分?jǐn)?shù)為 0 的兩個(gè)元素占用該數(shù)據(jù)范圍的前兩個(gè)索引位置,所以計(jì)數(shù)表示的是對(duì)應(yīng)數(shù)值的索引位置。我們?cè)倏纯雌渌耐皝?lái)驗(yàn)證一下:可以發(fā)現(xiàn)分?jǐn)?shù) 2 的桶計(jì)數(shù)也為 2,但是前兩個(gè)索引位置已經(jīng)被分?jǐn)?shù) 0 占用了呀,分?jǐn)?shù) 2 的計(jì)數(shù)應(yīng)該是 4 才對(duì),所以,我們還需要一步操作:疊加前面分?jǐn)?shù)出現(xiàn)的次數(shù),這樣分?jǐn)?shù) 2 的計(jì)數(shù)值便為 4,可以發(fā)現(xiàn)計(jì)數(shù)值其實(shí)表示的是某數(shù)字占用的第 N 個(gè)索引,如果我們想知道其中分?jǐn)?shù) 2 的索引位置,將計(jì)數(shù)值 4 進(jìn)行減 1 即可,即它的索引值為 3,而且每取完某數(shù)字一次,需要將該計(jì)數(shù)值減 1。排序流程如下:

時(shí)間復(fù)雜度為 O(n) 的排序算法,排序算法,算法,數(shù)據(jù)結(jié)構(gòu)

這樣一步步操作完成之后,最終數(shù)組是有序的。計(jì)數(shù)排序的代碼如下:

    /**
     * 計(jì)數(shù)排序的計(jì)數(shù)體現(xiàn)在小于等于某個(gè)數(shù)出現(xiàn)的次數(shù) - 1 即為該數(shù)在原數(shù)組排序后的位置
     */
    public void sort(int[] nums) {
        if (nums.length <= 1) {
            return;
        }

        // 尋找數(shù)組中的最大值來(lái)以此定義max + 1個(gè)桶
        int max = Arrays.stream(nums).max().getAsInt();

        // 定義桶,索引范圍即數(shù)組值的最大范圍,每個(gè)桶中保存的是該數(shù)字出現(xiàn)的次數(shù),計(jì)數(shù)排序的計(jì)數(shù)概念出現(xiàn)
        int[] bucket = new int[max + 1];

        // 計(jì)算每個(gè)數(shù)的個(gè)數(shù)在桶中累加
        Arrays.stream(bucket).forEach(x -> bucket[x]++);
        // 依次累加桶中的數(shù),該數(shù)表示小于等于該索引值的數(shù)量
        for (int i = 1; i < bucket.length; i++) {
            bucket[i] += bucket[i - 1];
        }

        // 創(chuàng)建臨時(shí)數(shù)組來(lái)保存排序結(jié)果值
        int[] res = new int[nums.length];
        // 倒序遍歷原數(shù)組,不改變相同元素的相對(duì)順序
        for (int i = nums.length - 1; i >= 0; i--) {
            // 根據(jù)桶中的 計(jì)數(shù) 找出該數(shù)的索引
            int index = bucket[nums[i]] - 1;
            // 根據(jù)索引在結(jié)果數(shù)組中賦值
            res[index] = nums[i];
            // 該數(shù)分配完成后,需要將桶中的計(jì)數(shù)-1
            bucket[nums[i]]--;
        }

        // 結(jié)果數(shù)組覆蓋原數(shù)組
        System.arraycopy(res, 0, nums, 0, res.length);
    }

基數(shù)排序

基數(shù)排序?qū)Υ判驍?shù)據(jù)是有特殊要求的,需要數(shù)據(jù)可以分割出獨(dú)立的“位”,并且位與位之間要有遞進(jìn)關(guān)系,根據(jù)遞進(jìn)關(guān)系對(duì)每一位進(jìn)行排序,獲得最終排序結(jié)果。

我們先來(lái)看一下使用基數(shù)排序處理 [3, 4, 100, 11, 33] 數(shù)組的過(guò)程:

時(shí)間復(fù)雜度為 O(n) 的排序算法,排序算法,算法,數(shù)據(jù)結(jié)構(gòu)

因?yàn)檎麛?shù)每位取數(shù)范圍為 0 ~ 9,所以創(chuàng)建了 10 個(gè)桶,這 10 個(gè)桶已經(jīng)有了從大到小的順序。排序時(shí)從整數(shù)的個(gè)位開(kāi)始,到最高位終止,排序的輪次為最大整數(shù)的位數(shù),在每輪排序中,根據(jù)當(dāng)前位數(shù)值大小入桶,完成后再按順序出桶,最終結(jié)果即為排序結(jié)果。代碼如下:

    private void sort(int[] nums) {
        if (nums.length <= 1) {
            return;
        }

        // 1. 整數(shù)的每位取值范圍為 0-9,因此需要?jiǎng)?chuàng)建10個(gè)桶
        Queue<Integer>[] buckets = createBuckets();

        // 2. 獲取基數(shù)排序的執(zhí)行輪次
        int radixRounds = getRadixRounds(nums);

        // 3. 根據(jù)執(zhí)行輪次處理各個(gè)"位",eg: 第一輪處理個(gè)位...
        for (int round = 1; round <= radixRounds; round++) {
            for (int num : nums) {
                // 獲取所在桶的索引
                int bucketIndex = getBucketIndex(num, round);
                // 進(jìn)桶
                buckets[bucketIndex].offer(num);
            }

            // 出桶賦值,當(dāng)前結(jié)果為根據(jù)當(dāng)前位排序的結(jié)果
            int numsIndex = 0;
            for (Queue<Integer> bucket : buckets) {
                while (!bucket.isEmpty()) {
                    nums[numsIndex++] = bucket.poll();
                }
            }
        }
    }

    /**
     * 創(chuàng)建大小為10的數(shù)組作為桶,每個(gè)桶都是一個(gè)隊(duì)列
     */
    @SuppressWarnings("unchecked")
    private Queue<Integer>[] createBuckets() {
        Queue<Integer>[] buckets = new Queue[10];
        for (int i = 0; i < buckets.length; i++) {
            buckets[i] = new LinkedList<>();
        }

        return buckets;
    }

    /**
     * 獲取基數(shù)排序的執(zhí)行輪次
     */
    private int getRadixRounds(int[] nums) {
        return String.valueOf(Arrays.stream(nums).max().getAsInt()).length();
    }

    /**
     * 獲取該數(shù)所在桶的索引
     */
    private int getBucketIndex(int num, int round) {
        int bucketIndex = 0;

        while (round != 0) {
            bucketIndex = num % 10;
            num /= 10;

            round--;
        }

        return bucketIndex;
    }

基數(shù)排序比較適用于數(shù)據(jù)范圍比較大且位數(shù)相對(duì)均勻的數(shù)據(jù)排序,比如排序手機(jī)號(hào)或者學(xué)號(hào),它的時(shí)間復(fù)雜度接近于 O(n)。


巨人的肩膀

  • 《數(shù)據(jù)結(jié)構(gòu)與算法之美》:第 3.6 章 線性排序:如何根據(jù)年齡給 100 萬(wàn)個(gè)用戶排序

  • 《Hello 算法》:第 11.8、11.9 和 11.10 章

  • 《算法導(dǎo)論》:第 8 章 線性時(shí)間排序文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-832559.html

到了這里,關(guān)于時(shí)間復(fù)雜度為 O(n) 的排序算法的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 數(shù)據(jù)結(jié)構(gòu)與算法-時(shí)間復(fù)雜度與空間復(fù)雜度

    數(shù)據(jù)結(jié)構(gòu)與算法-時(shí)間復(fù)雜度與空間復(fù)雜度

    數(shù)據(jù)結(jié)構(gòu)是計(jì)算機(jī)存儲(chǔ)、組織數(shù)據(jù)的方式,指相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合。 算法就是定義良好的計(jì)算過(guò)程,他取一個(gè)或一組的值為輸入,并產(chǎn)生一個(gè)或一組值作為輸出。簡(jiǎn)單來(lái)說(shuō)算法就是一系列的計(jì)算步驟,用來(lái)將輸入數(shù)據(jù)轉(zhuǎn)化成輸出結(jié)果。 算法在

    2024年02月07日
    瀏覽(21)
  • 【數(shù)據(jù)結(jié)構(gòu)和算法】時(shí)間復(fù)雜度和空間復(fù)雜度

    【數(shù)據(jù)結(jié)構(gòu)和算法】時(shí)間復(fù)雜度和空間復(fù)雜度

    目錄 ? 一、前言 二、時(shí)間復(fù)雜度 2.1時(shí)間復(fù)雜度表示形式 2.1.1規(guī)則: 3.1如何計(jì)算時(shí)間復(fù)雜度 3.1.1線性階 3.1.2平方階 3.1.3對(duì)數(shù)階 常見(jiàn)的時(shí)間復(fù)雜度排序: 三、空間復(fù)雜度 3.1Java的基本類型內(nèi)存占用 數(shù)據(jù)結(jié)構(gòu)和算法是程序的靈魂,這是某位程序員大佬所言,學(xué)習(xí)了這門,我們便可

    2023年04月09日
    瀏覽(24)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法】1.時(shí)間復(fù)雜度和空間復(fù)雜度

    【數(shù)據(jù)結(jié)構(gòu)與算法】1.時(shí)間復(fù)雜度和空間復(fù)雜度

    ??博客主頁(yè):愛(ài)敲代碼的小楊. ?專欄:《Java SE語(yǔ)法》 ??感謝大家點(diǎn)贊????收藏?評(píng)論???,您的三連就是我持續(xù)更新的動(dòng)力?? ??小楊水平有限,歡迎各位大佬指點(diǎn),相互學(xué)習(xí)進(jìn)步! 算法效率分為兩種:第一種是時(shí)間效率;第二種是空間效率。時(shí)間效率又稱為時(shí)間

    2024年01月20日
    瀏覽(23)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法篇】時(shí)間復(fù)雜度與空間復(fù)雜度

    【數(shù)據(jù)結(jié)構(gòu)與算法篇】時(shí)間復(fù)雜度與空間復(fù)雜度

    ?? 目錄 一、數(shù)據(jù)結(jié)構(gòu)和算法 1.什么是數(shù)據(jù)結(jié)構(gòu)?? 2.什么是算法? 3.數(shù)據(jù)結(jié)構(gòu)和算法的重要性 二、算法的時(shí)間復(fù)雜度和空間復(fù)雜度 1.算法效率 2.算法的復(fù)雜度 3.復(fù)雜度在校招中的考察 4.時(shí)間復(fù)雜度 5.空間復(fù)雜度? 6.常見(jiàn)復(fù)雜度對(duì)比 7.復(fù)雜度的OJ練習(xí) ? ??內(nèi)容專欄:《數(shù)據(jù)結(jié)

    2023年04月24日
    瀏覽(44)
  • 數(shù)據(jù)結(jié)構(gòu) | 算法的時(shí)間復(fù)雜度和空間復(fù)雜度【詳解】

    數(shù)據(jù)結(jié)構(gòu) | 算法的時(shí)間復(fù)雜度和空間復(fù)雜度【詳解】

    數(shù)據(jù)結(jié)構(gòu)(Data Structure)是計(jì)算機(jī)存儲(chǔ)、組織數(shù)據(jù)的方式,指相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合。 算法(Algorithm):就是定義良好的計(jì)算過(guò)程,他取一個(gè)或一組的值為輸入,并產(chǎn)生出一個(gè)或一組值作為輸出。簡(jiǎn)單來(lái)說(shuō)算法就是一系列的計(jì)算步驟,用來(lái)將輸入數(shù)據(jù)轉(zhuǎn)

    2024年02月08日
    瀏覽(30)
  • 學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu):算法的時(shí)間復(fù)雜度和空間復(fù)雜度

    學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu):算法的時(shí)間復(fù)雜度和空間復(fù)雜度

    衡量一個(gè)算法的好壞,一般是從時(shí)間和空間兩個(gè)維度來(lái)衡量的,即時(shí)間復(fù)雜度和空間復(fù)雜度。 時(shí)間復(fù)雜度主要衡量一個(gè)算法的運(yùn)行快慢,而空間復(fù)雜度主要衡量一個(gè)算法運(yùn)行所需要的額外空間。 算法的時(shí)間復(fù)雜度 算法中的基本操作的執(zhí)行次數(shù),為算法的時(shí)間復(fù)雜度。 算法的

    2024年04月11日
    瀏覽(23)
  • 【數(shù)據(jù)結(jié)構(gòu)初階】算法的時(shí)間復(fù)雜度和空間復(fù)雜度

    【數(shù)據(jù)結(jié)構(gòu)初階】算法的時(shí)間復(fù)雜度和空間復(fù)雜度

    1.1 如何衡量一個(gè)算法的好壞 如何衡量一個(gè)算法的好壞呢? 比如對(duì)于以下斐波那契數(shù)列: 斐波那契數(shù)列的遞歸實(shí)現(xiàn)方式非常簡(jiǎn)潔,但簡(jiǎn)潔一定好嗎?那該如何衡量其好與壞呢? 1.2 算法的復(fù)雜度 算法在編寫(xiě)成可執(zhí)行程序后,運(yùn)行時(shí)需要耗費(fèi)時(shí)間資源和空間(內(nèi)存)資源 。因此

    2024年02月08日
    瀏覽(18)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法篇】之時(shí)間復(fù)雜度與空間復(fù)雜度

    【數(shù)據(jù)結(jié)構(gòu)與算法篇】之時(shí)間復(fù)雜度與空間復(fù)雜度

    ??博客主頁(yè): 小鎮(zhèn)敲碼人 ?? 歡迎關(guān)注:??點(diǎn)贊 ????留言 ??收藏 ??友友們暑假快樂(lè),好久不見(jiàn)呀?。?!?????? ?? 有人曾經(jīng)問(wèn)過(guò)我這樣一個(gè)問(wèn)題,“人終其一身,執(zhí)著追求的東西究竟是什么?”我是這樣回答的,”我們終其一生都在尋找著那個(gè)和我們靈魂極其契合

    2024年02月12日
    瀏覽(27)
  • 從頭開(kāi)始:數(shù)據(jù)結(jié)構(gòu)和算法入門(時(shí)間復(fù)雜度、空間復(fù)雜度)

    從頭開(kāi)始:數(shù)據(jù)結(jié)構(gòu)和算法入門(時(shí)間復(fù)雜度、空間復(fù)雜度)

    ? ? 目錄 文章目錄 前言 1.算法效率 1.1 如何衡量一個(gè)算法的好壞 1.2 算法的復(fù)雜度 2.時(shí)間復(fù)雜度? 2.1 時(shí)間復(fù)雜度的概念 2.2 大O的漸進(jìn)表示法 2.3常見(jiàn)時(shí)間復(fù)雜度計(jì)算 3.空間復(fù)雜度 4.常見(jiàn)復(fù)雜度對(duì)比 總結(jié) 前言 ????????C語(yǔ)言的學(xué)習(xí)篇已經(jīng)結(jié)束,今天開(kāi)啟新的篇章——數(shù)據(jù)結(jié)構(gòu)

    2024年02月14日
    瀏覽(28)
  • 數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之路--算法的時(shí)間復(fù)雜度與空間復(fù)雜度(精講)

    數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)之路--算法的時(shí)間復(fù)雜度與空間復(fù)雜度(精講)

    ? ? ?嗨嗨大家!本期帶來(lái)的內(nèi)容是:算法的時(shí)間復(fù)雜度與空間復(fù)雜度。 目錄 前言 一、算法效率 算法效率的衡量標(biāo)準(zhǔn) 二、時(shí)間復(fù)雜度 1 時(shí)間復(fù)雜度的定義 2 求解時(shí)間復(fù)雜度的步驟 2.1 找出算法中的基本語(yǔ)句:? 2.2計(jì)算基本語(yǔ)句執(zhí)行次數(shù)的數(shù)量級(jí): 2.3大O階的漸進(jìn)表示法:

    2024年04月09日
    瀏覽(26)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包