分治法之眾數問題


東 華 大 學

《算法分析設計與綜合實踐》實驗報告

   

 

學生姓名:曹晨 學號:171310402 指導教師:章昭輝

實驗時間:2019-3-13 實驗地點:圖文信息樓三號機房

請勿轉載!!!

 

  1.  實驗名稱

眾數問題

  1. 實驗目的

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

  2. 實驗內容

    給定含有n個元素的多重集合S,每個元素在S中出現的次數稱為該元素的重數。多重集合S中重數最大的元素稱為眾數。例如{1,2,2,2,3,5}。多重集合S的眾數為2,其重數為3。

    數據輸入:

    輸入第一行為多重集S中元素的個數n;在接下來的n行中,每行有一個自然數。

    結果輸出:

    輸出由兩行,第一行為眾數,第二行時重數

  3. 實驗過程

    自己的思路:

    創建一個數組b[][2],遍歷一遍數組,b中的結果如下

     

    元素

    個數

    b[0]

    1

    1

    b[1]

    2

    3

    b[2]

    3

    1

    b[3]

    5

    1

    在數組b中找到個數最多的值為重數,對應的元素為眾數,輸出即可

    參考答案及網上的思路:

1

2

2

2

3

5

                      l                                                         med                                                                                      r

                                                                                                     👇

1

2

2

2

3

5

                        l                          l1                          med                           r1                                                        r

                                                                                                       左子集                                                       右子集

1

 

3

5

                                                                                                                            l,r                                                  l                    r

 

‧‧‧‧‧‧‧‧‧

 

每做完一次上述的操作,都要更新一下眾數和重數。當重數的大小大於左(或右)子集的大小時,就不用在左(或右)子集中再做一次上述操作。

  1. 結果分析

    這個結果是我用數組的辦法編寫的。所用的時間為9.683s

    這個結果是我用分治法的辦法編寫的。所用的的時間為5.352s

    由此可見,用分治法解這道題效率更高

       

       

       

  2. 實驗總結

    剛開始我沒有想到可以用分治法來做,用的是數組來做。做完以后發現算法太過復雜,而且處理較大的n時,時間復雜度和空間復雜度都比較大。於是我參考了算法答案那本書,學到了分治法來解決這道題。但是在完成了用分治法的代碼以后,我發現了問題:

    輸出應該為:

    2

    4

    分治法解決這道題有一個大前提:多重集中的元素是有序的(遞增或者遞減),所以很有必要給多重集加入一個排序的算法.

    附錄:(要求代碼里各行要有注釋

    自己的代碼(性能不夠好,太過復雜)

    int main()

    {

    int n;

    cin>>n;

    int a[n];

    for(int i=0;i<n;i++)

    {

    cin>>a[i];

    }

    f(n,a);

    return 0;

    }

    void f(int n,int *a)//n為多重集元素的個數,a是存放數組的元素

    {

    int b[n][2];//b[][0]存放元素的種類,B[][1]存放每種元素的個數

    b[0][0]=a[0];

    b[0][1]=1;

    int h=0;//數組b中已初始化的行的標號

    int flag=0;//判斷b中是否已經有該元素了

    for(int i=1;i<n;i++)

    {

    for(int j=0;j<=h;j++)

    {

    if(a[i]==b[j][0])//判斷元素a[i]是否已經在數組b中存在

    {

    b[j][1]++;

    flag=1;

    }

    }//存在的話,把b[j][1]加1,flag變為1,否則不做操作

    if(flag==0)

    {

    h++;

    b[h][0]=a[i];

    b[h][1]=1;

    }

    flag=0;

    }//不存在的話,flag為0,此時把a[i]加入到數組之中,並把個數變為1

    int temp=b[0][1];

    int t=0;

    for(int i=0;i<=h;i++)//尋找b中數目最多的那個元素

    {

    if(temp<b[i][1])

    {

    temp=b[i][1];

    t=i;

    }

    }

    cout<<b[t][0]<<endl<<temp<<endl;//輸出眾數和重數

    }

    參照答案和csdn博客所改的代碼:

    https://www.cnblogs.com/yangykaifa/p/7162192.html

    https://blog.csdn.net/chencong3139/article/details/52863629

    int main()

    {

    int n;

    cin>>n;//元素個數

    int a[n];

    for(int i=0;i<n;i++)

    {

    cin>>a[i];

    }//數組用於存放元素

    int l=0;//數組的首個標號

    int r=n-1;//數組的最后一個標號

    int largest=0;//重數的初始化

    int elem=-1;//眾數的初始化

    mode(a,l,r,largest,elem);//調用函數

    cout<<elem<<endl<<largest<<endl;//輸出眾數和重數

    return 0;

    }

    //用於求數組的中位數的函數

    int median(int *a,int l,int r)

    {

    return a[(l+r)/2];

    }

    //以med來划分數組↓ !!!關鍵函數

    void split(int *a,int med,int l,int r,int &l1,int &r1)

    {

    for(l1=l;l1<=r;l1++)

    {

    if(a[l1]==med)

    break;

    }//l1表示首個等於med的數組下標

    for(r1=l1+1;r1<=r;r1++)

    {

    if(a[r1]!=med)

    break;

    }

    r1--;

    }//r1表示最后一個等於med的數組下標

    void mode(int *a,int l,int r,int &largest,int &elem)

    {

    int l1,r1;//分割后左邊子數組的右界和右邊子數組的左界

    int med=median(a,l,r);//midian函數用於找到數組的中位數

    split(a,med,l,r,l1,r1);//以med中位數來分割數組

    if(largest<r1-l1+1)

    {

    largest=r1-l1+1;

    elem=med;

    }//每次遞歸更新眾數和重數的值

    if(l1-l>largest)

    mode(a,l,l1-1,largest,elem);//判斷左邊是否值得遞歸(只有l1-1大於largest才有必要搜尋)

    if(r-r1>largest)

    mode(a,r1+1,r,largest,elem);//判斷右邊是否值得遞歸

    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM