CCh99

分治法之众数问题

东 华 大 学

《算法分析设计与综合实践》实验报告

   

 

学生姓名:曹晨 学号: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);//判断右边是否值得递归

    }

posted on 2019-03-25 17:50  CCh99  阅读(4140)  评论(0编辑  收藏  举报

导航