算法專題:Linear Sort

Linear Sort即線性排序震糖,指的是一系列能做到線性時間復雜度即O(n)的排序算法愕贡,這里主要介紹三個:桶排序(bucket sort)穆律,計數(shù)排序(count sort)和基數(shù)排序(radix sort)读慎。
排序算法基于兩類怕品,一類是基于比較的排序野舶,常規(guī)排序一般就是這類秽晚,例如快速排序、歸并排序筒愚、堆排序赴蝇。這種排序方法有著O(nlgn)的下限限制(已有證明比較排序不可能做到比O(nlgn)好)。而非比較排序沒有這個限制巢掺。雖然這些排序方法看上去復雜度比常規(guī)的的時間復雜度O(nlgn)要好句伶,其實都有一些其他方面的限制,所以還是要看情況進行使用陆淀。

  1. 計數(shù)排序
    顧名思義考余,就是通過計算各個元素出現(xiàn)的次數(shù)來排序。 假設出現(xiàn)的元素都在0-k之間轧苫,將這k+1個數(shù)進行頻次計數(shù)楚堤,然后再從小到大把這些數(shù)給排出來。代碼如下:
def countingsort( aList, k ):
    counter = [0] * ( k + 1 )
    for i in aList:
        counter[i] += 1

    ndx = 0
    for i in range( len( counter ) ):
        while 0 < counter[i]:
            aList[ndx] = i
            ndx += 1
            counter[i] -= 1 
整個算法可以分成兩塊含懊,第一塊計數(shù)身冬,時間復雜度O(n),第二塊擺放岔乔,時間復雜度O(k)酥筝,因此總的時間復雜度是O(n+k),空間復雜度也是O(n+k)雏门。很明顯嘿歌,適用的情況,僅限于所需排序的序列是0-k的整數(shù)而且k比較小茁影。
  1. 桶排序
    桶排序自然要用到“桶”宙帝,所謂的“桶”就是一個個容器,其能容納一個區(qū)間內(nèi)未排序的數(shù)值募闲。利用“桶”步脓,將數(shù)值按照區(qū)域分好,然后各自排序,再連到一起沪编,就是桶排序的思想呼盆。桶內(nèi)排序,可以使用比較排序算法蚁廓。

    def bucketsort(A):
        # get hash codes
        code = hashing(A)
        buckets = [list() for _ in range(code[1])]
        # distribute data into buckets: O(n)
        for i in A:
            x = re_hashing(i, code)
            buck = buckets[x]
            buck.append(i)
    
        for bucket in buckets:
            bucket.sort()
    
        ndx = 0
        # merge the buckets: O(n)
        for b in range(len(buckets)):
            for v in buckets[b]:
                A[ndx] = v
                ndx += 1
    
    import math
    def hashing(A):
        m = A[0]
        for i in range(1, len(A)):
            if (m < A[i]):
            m = A[i]
        result = [m, int(math.sqrt(len(A)))]
        return result
    def re_hashing(i, code):
        return int(i / code[0] * (code[1] - 1)) 
    

首先是把數(shù)據(jù)壓縮到01的區(qū)間內(nèi)访圃,這里的代碼是取n^(1/2)個桶。假設數(shù)組內(nèi)的最大值是K相嵌,有M個桶腿时,那么相當于把0-K分成M個區(qū)間,即0M-1號桶饭宾。對于某個數(shù)x批糟,應該分到序號為(M-1)*x/K,因為x=0時分到0號桶看铆,x=K時分到第M-1號桶徽鼎。
然后分完數(shù)之后對桶內(nèi)進行排序,排序完之后連起來弹惦。
稍微分析一下復雜度否淤。最壞情況就是所有數(shù)據(jù)都在一個桶里面,那么相當于白干棠隐,還不如直接常規(guī)排序石抡。
最好情況就是數(shù)據(jù)平均分布,總共N個元素M個桶助泽,每個桶就是N/M個元素啰扛,總時間復雜度就是O(N+Nlog(N/M)),當M越大時總復雜度越小嗡贺,但同時空間復雜度也就更高隐解。
此外,只要桶排序內(nèi)部排序算法是穩(wěn)定的暑刃,那么整個桶排序也就是穩(wěn)定的厢漩。

  1. 基數(shù)排序
    基數(shù)排序屬于多key排序,一般是從最小的key分堆排序岩臣,然后再對較大的key排序,直至對所有key完成排序宵膨。
    網(wǎng)上很常見的一個例子就是對十進制整數(shù)排序架谎,因為每一位的權重不一樣,因此也是對key分次排序的一個例子辟躏。
    例如170, 45, 75, 90, 802, 2, 24, 66谷扣,排序過程如下:
    先對個位進行排序:170,90,802,2,24,45,75,66
    然后進行十位排序:802,2,24,45,66,170,75,90
    最后對百位排序:2,24,45,66,75,90,175,802
    當然,key不止限定于十進制的權重。不過基本上就是這么一個思路会涎。假如有k個key裹匙,那么一共要排k次,如果使用桶排序末秃,那么就是O(nk)概页。
def radixSort(a, n, maxLen):
    for x in range(maxLen):
        bins = [[] for i in range(n)]
        for y in a:
            bins[(y // 10 ** x) % n].append(y)
        a = []
        for section in bins:
            a.extend(section)
      return a 

上面的代碼,如果是對十進制排序练慕,那至少要有10個桶來放惰匙,n=10.maxLen是指數(shù)值的最大長度用來確定排序次數(shù)。

總結:線性排序總體來說限制比較多铃将,不夠靈活项鬼,但是在特定場合還是可以用。

例題:maxGap劲阎。給出一個未排序的非負整數(shù)數(shù)組绘盟,找出其排序狀況下的相鄰兩個數(shù)的最大差值。要求線性時間悯仙。
【解】這個題就是線性排序的用武之地奥此。假如不排序,幾乎沒法做雁比。當然也可以用Quick Sort強行線性(其復雜度從O(n)~O(n^2))稚虎,不過用正宗的線性排序顯然更好。
對這道題而言偎捎,計數(shù)排序明顯不靠譜蠢终,基數(shù)排序并沒有多key,所以桶排序是最佳的選擇茴她。事實上寻拂,桶排序時可以不用在桶里面sort,因為題目只是要求max gap丈牢,因此如果能知道每一個桶內(nèi)的max和min祭钉,那么桶與桶之間的gap就知道了。至于桶內(nèi)的呢己沛?平均gap是(max-min)/(N-1)慌核,如果讓每個桶剛好覆蓋平均gap大小,那么極端情況就是每個桶一個元素申尼,桶內(nèi)gap不用考慮垮卓;否則,某些桶多某些桶少师幕,出現(xiàn)分布不均勻的情況時粟按,最大gap也只可能出現(xiàn)在桶與桶之間。

# Time:  O(n)
# Space: O(n)
class Solution:
     # @param numss: a list of integers
     # @return: the maximum difference
    def maximumGap(self, nums):
        if len(nums) < 2:
            return 0
        
        # Init bucket.
        max_val, min_val = max(nums), min(nums)
        gap = max(1, (max_val - min_val) // (len(nums) - 1))
        bucket_size = (max_val - min_val) // gap + 1
        bucket = [{'min': float("inf"), 'max': float("-inf")} for _ in range(bucket_size)]

        # Find the bucket where the n should be put.
        for n in nums:
            # min_val / max_val is in the first / last bucket.
            if n in (max_val, min_val):
                continue      
            i = (n - min_val) // gap
            bucket[i]['min'] = min(bucket[i]['min'], n)
            bucket[i]['max'] = max(bucket[i]['max'], n)
        
        # Count each bucket gap between the first and the last bucket.
        max_gap, pre_bucket_max = 0, min_val
        for i in range(bucket_size):
            # Skip the bucket it empty.
            if bucket[i]['min'] == float("inf") and bucket[i]['max'] == float("-inf"):
                continue
            max_gap = max(max_gap, bucket[i]['min'] - pre_bucket_max)
            pre_bucket_max = bucket[i]['max']
        # Count the last bucket.
        max_gap = max(max_gap, max_val - pre_bucket_max) 
        
        return max_gap 
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市灭将,隨后出現(xiàn)的幾起案子疼鸟,更是在濱河造成了極大的恐慌,老刑警劉巖庙曙,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件空镜,死亡現(xiàn)場離奇詭異,居然都是意外死亡矾利,警方通過查閱死者的電腦和手機姑裂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來男旗,“玉大人舶斧,你說我怎么就攤上這事〔旎剩” “怎么了茴厉?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長什荣。 經(jīng)常有香客問我矾缓,道長,這世上最難降的妖魔是什么稻爬? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任嗜闻,我火速辦了婚禮,結果婚禮上桅锄,老公的妹妹穿的比我還像新娘琉雳。我一直安慰自己,他們只是感情好友瘤,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布翠肘。 她就那樣靜靜地躺著,像睡著了一般辫秧。 火紅的嫁衣襯著肌膚如雪束倍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天盟戏,我揣著相機與錄音绪妹,去河邊找鬼。 笑死抓半,一個胖子當著我的面吹牛喂急,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播笛求,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了探入?” 一聲冷哼從身側響起狡孔,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蜂嗽,沒想到半個月后苗膝,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡植旧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年辱揭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片病附。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡问窃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出完沪,到底是詐尸還是另有隱情域庇,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布覆积,位于F島的核電站听皿,受9級特大地震影響,放射性物質發(fā)生泄漏宽档。R本人自食惡果不足惜尉姨,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吗冤。 院中可真熱鬧又厉,春花似錦、人聲如沸欣孤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽降传。三九已至篷朵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間婆排,已是汗流浹背声旺。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留段只,地道東北人腮猖。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像赞枕,于是被迫代替她去往敵國和親澈缺。 傳聞我的和親對象是個殘疾皇子坪创,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

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

  • 背景 一年多以前我在知乎上答了有關LeetCode的問題, 分享了一些自己做題目的經(jīng)驗。 張土汪:刷leetcod...
    土汪閱讀 12,748評論 0 33
  • 提高溝通效果的三大要素即本能姐赡、情感 和邏輯 莱预,本能就是一個人最直白的簡單的印象,要想提高溝通效果项滑,就需要給人一種可...
    愛學習的小胡同學閱讀 189評論 0 0
  • 微博真的是一個好東西依沮,至少K小姐是這么認為。訪問對方的主頁不會留下痕跡枪狂,有時候為了了解一個人甚至可以一口氣扒完對方...
    李布波閱讀 509評論 2 6
  • 古都長安旗獵獵危喉,渭水河畔書朗朗。 談笑鴻儒表壯志州疾,往來驕子續(xù)新章辜限。 不畏軍營苦與累,自古紅爐出好鋼孝治。 秦皇漢武俱往...
    垚君閱讀 169評論 0 0