眾數問題分析

2021-06-14 14:40:26 字數 3584 閱讀 7977

問題描述

•給定乙個陣列,找出其中出現次數最多的那個元素(即眾數)。

核心思想

•普遍的解決思路。

•如果我們將所有元素的出現次數進行統計,並從中找出次數中的最大值,那麼,這個最大值對應的元素就是眾數。

•從這一思想出發,我總結出以下兩種演算法:

–演算法1:利用排序演算法統計

–演算法2:利用陣列或雜湊表統計

演算法1•演算法思路:首先將陣列元素按照大小排序,然後按順序掃瞄一遍陣列,掃瞄的同時進行統計。這樣,通過一次排序和一遍掃瞄,我們就能夠找到眾數。

•關鍵步驟:排序,掃瞄統計

演算法代價分析

1、時間代價

•由於掃瞄的時間代價是θ(n)的,所以演算法的總時間代價主要依賴於排序演算法的代價。

•如果我們選取θ(nlgn)的排序演算法,最終的時間代價是θ(nlgn)+θ(n)= θ(nlgn)

•θ(nlgn)是基於比較的排序不可逾越的時間下界,也是該演算法能夠達到的最低代價。

2、空間代價

•掃瞄統計時,我們只需要三個輔助變數:乙個用於計數,乙個用於記錄當前出現次數最多的元素的出現次數,乙個用於記錄當前出現次數最多的元素。

•所以,如果排序演算法的輔助空間是o(1)的,那麼整個演算法的輔助空間代價就是o(1)的。

改進想法

•思想:改進排序演算法,使得排序演算法在排序的同時就統計出現次數,並記錄次數最多的元素,以及刪除所有重複的元素。這樣,不僅可以減小排序的規模,並且省去了最後掃瞄的步驟,在一定程度上優化了該演算法。

•然而,雖然改進後的演算法比原始演算法效率高,但是由於其本質仍然是基於比較的排序演算法,所以時間代價還是θ(nlgn)的,並沒有在數量級上取得突破。

演算法2•演算法思路:直接統計各元素出現的次數,用某一種線性資料結構儲存統計結果。

•樸素的實現方法:用乙個輔助陣列儲存統計結果,統計時用陣列下標對應相應元素。

演算法代價分析

1、時間代價

•用下標對應元素,訪問時間o(1)。順序掃瞄一遍原陣列,就可以得到統計結果。

•總的時間代價θ(n)。

演算法代價分析

2、空間代價

•依賴於原陣列中元素的範圍。

•假設我們知道元素集中分布在寬度為m的區間內,那麼我們就可以開闢大小為m的陣列用於統計。這時,最後使用的輔助空間便是o(m)的。

•然而我們一般並不能確切地知道陣列中數的範圍,或者陣列中元素的分布非常稀疏(即陣列中有相當比例的空間儲存的統計數為0)。這時,下標連續分布的、上下界明確的陣列就難以承擔其職責了。

•因此,我們必須改進資料結構,以更加廣泛地適應演算法的需求。

改進想法

•核心思想:採用雜湊表。

•雜湊表的優點:儲存靈活,檢索效率高。

•因此,使用雜湊表能夠有效地替代陣列,實現演算法的功能。

•雜湊表的缺點:空間利用率低。

•據實驗,當雜湊表的負載因子小於0.5時,雜湊表在大部分情況下的檢索長度小於2。但是,如果超過0.5,雜湊表的效能就會急劇下降。

•因此,如果原陣列元素分布稠密,使用雜湊表的空間效率就要低於使用陣列。

改進後演算法的代價分析

•前提假設:雜湊表的效能良好(負載因子小於0.5)

1、時間代價

•同樣是掃瞄一遍,然而每一次的平均探查長度大於1。因此,時間效率要比陣列低。

•但是,由於雜湊表效能良好,平均探查長度小於2,所以時間代價依然是o(n)的。

改進後演算法的代價分析

2、空間代價

•如果原陣列中共有m個不同的元素,那麼,由於負載因子小於0.5,因此雜湊表的大小至少是2m。空間效率低於元素稠密時的陣列,但是可能會遠高於資料稀疏時的陣列。

演算法比較

•這份報告中主要介紹了兩種演算法思想。他們各有利弊,對比如下:

1、基於排序的演算法

•時間代價:θ(nlgn)

•空間代價:o(1)

2、直接統計的演算法

•時間代價:θ(n)

•空間代價:ω(m)

•從以上對比,我們可以看出:演算法2是利用空間換時間,雖然使用了大量的輔助空間,但是時間代價要遠低於演算法1。

•我們的演算法設計,就是乙個權衡利弊的過程。很多時候,時間和空間不可兼得,那麼,我們就要根據使用者的需求選擇合適的演算法,以實現時間更快或者空間更省。

•而對於演算法2,我們同樣面臨著選擇:使用陣列還是使用雜湊表。這一選擇基於陣列元素的分布:如果陣列元素分布稠密,使用陣列自然是又快又省;可是,如果分布稀疏或是不確定,雜湊表的靈活性就派上了用場。

•因此,除了使用者需求,我們面對的資料本身也左右著我們的選擇。

•在實際應用中,眾數問題一般用於對大量資料的統計。

•下面舉一些例項,來**實際問題中眾數問題的解決方案。

例項1•選票統計

•data*+=,「張三」,「李四」,「李四」,「張三」,「李四」,「李四」,「棄權」,「李四」,「張三」,「李四」,「張三」,「棄權」,「張三」……-

•資料規模大,資料範圍有限,顯然用陣列更為方便。

例項2•在一些科學實驗中,我們要對實驗資料進行統計和分析,這時眾數只是我們研究的一部分,還有其他方面(例如分布情況)需要研究。這時,我們希望一次運算得到的資訊量更多。

•這時我們也需要用陣列。

010203040506070809010~2020~3030~4040~50資料:23.1,14.6,39.7,32.0,12.2……

範圍10~20

20~30

30~40

40~50

分布數20

2890

21例項3

•假設1:有海量的資料需要統計,如果要排序只能通過外排序。

•假設2:硬碟空間足夠用(操作過程中不必考慮空間開銷)

•這時有乙個使用者需求,要得到這些資料的眾數。

•如果用排序,我們必須考慮外排序可怕的時間代價。

•如果用陣列或雜湊表,雖然會占用額外的硬碟儲存空間。但是,如果這些資料需要經常增刪,並且需要經常呼叫取眾數操作,那麼,儲存這些統計結果將帶來極大的方便。

總結•解決眾數問題主要有兩種演算法思想,其中演算法2可以使用兩種不同的輔助資料結構。這三者本身都是解決眾數問題的很好的辦法,他們之間並無優劣。具體實現時,我們選擇哪種方法,要依賴於我們對時空的權衡,以及資料本身的性質。

•眾數問題雖然很簡單,但是從中折射出的關於時空權衡的考慮,是演算法設計時會普遍遇到的問題,值得大家討論和思考。

//眾數問題

/*問題描述:

給定含有n個元素的多重集合s,每個元素在s中出現的次數成為該元素的重數。多重

集s中重數最大的元素稱為眾數。

例如, s = 。

多重集s的眾數是2,其重數為3。

程式設計任務:

對於給定的由n個自然數組成的多重集s,程式設計計算s的眾數及其重數。

*/#include #include #include #include using namespace std;

int main()

map::iterator map_it = number_count.begin();

map_it++;

int key = map_it->first;

int maxcount = map_it->second;

while(map_it != number_count.end())

++map_it;

} output<

演算法 眾數問題

眾數問題 description 給定含有n個元素的多重集合s,每個元素在s中出現的次數稱為該元素的重數。多重 集s中重數最大的元素稱為眾數。例如,s 多重集s的眾數是2,其重數為3。程式設計任務 對於給定的由n 個自然數組成的多重集s,程式設計計算s 的眾數及其重數。input 輸入資料第1行多重...

95 眾數問題

時間限制 3000 ms 記憶體限制 65535 kb 難度 3 描述 所謂眾數,就是對於給定的含有n個元素的多重集合,每個元素在s中出現次數最多的成為該元素的重數,多重集合s重的重數最大的元素成為眾數。例如 s 則多重集s的眾數是2,其重數為3。現在你的任務是 對於給定的由m個自然數組成的多重集s...

YTUOJ 眾數問題

給定含有n個元素的多重集合s,每個元素在s中出現的次數稱為該元素的重數。多重集s中重數最大的元素稱為眾數。例如,s 多重集s的眾數是2,其重數為3。對於給定的由n 個自然數組成的多重集s,計算s的眾數及其重數。輸入資料的第1行是多重集s中元素個數n n 1300000 接下來的n行中,每行有乙個最多...