分治演算法 求眾數及其重數

2021-08-13 20:35:50 字數 2843 閱讀 7791

問題描述:

給定含有 n 個元素的多重集合 s,每個元素在 s 中出現的次數稱為該元素的重數。多重集合 s 中重數最大的素稱為眾數。例如多重集合 s=,其中眾數是 2,其重數為 3。用分治法設計並實現在多重集合中找眾數及其重數的演算法,要求演算法的時間複雜性在壞情況下不超過 o(nlogn)。

方法一:窮舉

對陣列中的每乙個數計算其個數,最終最終選出最大的。時間複雜度為o(n^2)。**就不貼了,兩重迴圈可以實現。

方法二:分治法

選出第乙個數作為基準,用兩個指標遍歷剩下元素,先從右向左,遇到比基準小的或遇到左指標就停下;再從左向右,遇到比基準大的或遇到右指標就停下。

然後交換左右指標的值。當左右指標相遇時結束迴圈,並且將基準與其交換位置。顯然,我們可以在遍歷時順便統計出基準在此段陣列中元素個數。

因此,遍歷結束後計算出基準左邊和右邊剩下的元素個數。如果左邊或右邊的元素個數比統計得到基準個數多的話,則以左邊或右邊的資料段為引數(因為剩下資料元素小於基準個數時,則不可能出現眾數),遞迴進行以上操作。遞迴邊界條件為資料段中元素剩下乙個或沒有。

由於以上操作和快速排序基本相同,而快速排序的平均時間複雜度為o(nlogn)。所以我推測(僅僅是推測…不能給出證明…)演算法的平均時間複雜度也是為o(nlogn)。並且很可能還要在nlogn的基礎上減去某個常數或變數,因為當左右資料段所剩元素個數小於基準個數時停止遞迴。(望有大神來告訴我這種想法有沒有根據)

最壞情況為o(n^2).因為在選基準時無法保證每次都能選出讓資料段平均分割的基準,所以無法在最壞情況下達到o(nlogn)。

#include

#include

#include

#include

#define maxlen 50

using

namespace

std;

typedef

struct item_sets

sets;

void swap(int &a,int &b)

void divided(sets &s,int keyindex,int start,int rear)

left++;

}while(s.element[right] >= keynum && left < right)

right--;

}if(left < right)

}if(left > right) left--;

if(s.element[keyindex] <= s.element[left])

else

if(cnt>s.times)

if(rear-right>= cnt)

if(left-start>= cnt)

else

if(flag == 0)

}}int main()///生成一組隨機數

for(int i=0;icout

<" ";

}cout

<0,0,n-1);

cout

<<"mode:"

<" times:"

<"pause");

system("cls");

}return

0;}

方法三:分治法加預處理

以上兩種方法都沒能在最壞情況下達到o(nlogn)的時間複雜度。但方法二已經非常接近了,它未能達到要求的原因在於選出的基準不能保證分割時恰好分成兩等分。所以我們需要一些預處理讓選出的基準為當前資料段的中間數。顯然,我們需要先排序。

要時間複雜度為o(nlogn),則預處理的時間複雜度不能超過o(nlogn)。所以我們需要用到歸併排序,因為歸併排序最壞情況下不會超過o(nlogn)。剩下的事情就非常簡單了,每次選擇時選出資料段的中間的資料作為基準,然後從中間向兩邊擴充套件著計算基準個數,遇到不是基準的元素時停下。再計算出剩下左右兩邊的資料段的元素個數,多於基準個數的則遞迴進行以上操作(剩下的不可再排序)。

顯然,排序和求解眾數的演算法時間複雜度都為o(nlogn),並列的o(nlogn)仍為o(nlogn)。

以下**應該用歸併排序的,但我當初寫的時候用了快速排序。

#include

#include

#include

#include

#define maxsize 1000

using

namespace

std;

typedef

struct array

array;

void initialarray(int len,array &arr)

}void displayarray(array arr)

cout

void check(int a,int l,int r)

cout

while(i < j && arr.a[i] <= pivot)

if(i < j)

}swapnum(arr.a[l],arr.a[i]);

quickdivide(arr,l,i-1);

quickdivide(arr,i+1,r);

}void quicksort(array &arr)

void findmode(array &arr,int l,int r)

while(j <= r && arr.a[j] == mode)

}if(times > arr.times)

if(i-l >= times)

if(r-j >= times)

}int main()

c語言分治法求眾數重數 分治法之眾數問題

實驗總結 剛開始我沒有想到可以用分治法來做,用的是陣列來做。做完以後發現演算法太過複雜,而且處理較大的n時,時間複雜度和空間複雜度都比較大。於是我參考了演算法答案那本書,學到了分治法來解決這道題。但是在完成了用分治法的 以後,我發現了問題 輸出應該為 分治法解決這道題有乙個大前提 多重集中的元素是有...

c 找眾數及其重數

問題描述 在乙個由n個元素組成的表中,出現次數最多的元素被稱為眾數。試寫乙個尋找眾數及其重數的有效演算法,並分析其計算時間複雜性。方法 1.首先用快排把資料排個序 2.再使用find方法找出眾數及其重數 注 這裡第一步就跳過了,因為快排可以調庫函式,這裡主要是測試一下find方法的正確性。如下 in...

分治演算法 眾數問題

problem description 給定含有n個元素的多重集合s,每個元素在s 現的次數稱為該元素的重數。多重集s中重數最大的元素稱為眾數。例如,s 多重集s的眾數是2,其重數為3。對於給定的由n 個自然數組成的多重集s,計算s的眾數及其重數。如果出現多個眾數,請輸出最小的那個。input 輸入...