课堂练习-找水王

三人行设计了一个灌水论坛。
信息学院的学生都喜欢在上面交流灌水,传说在论坛上有一个“水王”,他不但喜欢发帖,还会回复其他ID发的每个帖子。
坊间风闻该“水王”发帖数目超过了帖子数目的一半。
如果你有一张当前论坛的帖子(包括回帖)列表,其中帖子的作者的ID也在其中,你能快速的找到这个传说中的水王吗?

程序实现的是第一种方法!!!

第一种方法:
基于的原理是:“水王”在这个论坛中的帖子数是最多的,只要找出最多帖子的id,即为“水王”。
假如有10个id,依次为a b c a b d c b a c
将第一个id即a放入b【0】,num【0】=1;然后把第二个id即b和b【0】比较,不相同,则把b放入b【1】,num【1】=1;将c和b【0】,b【1】比较,
发现都不同,则将c放入b【2】,num【2】=1;将第四个id即a和前面的b【i】比较,发现和b【0】相同,则将num【0】++;然后依次比较后面的id值,
若和前面有相同的,则对应的num【】++;若都不相同,则另外放入一个b【】,对应一个num【】。
最后将所有的num【i】进行大小比较,找出最大的num【】,即为“水王”。

对应的流程如下:

1。输入帖子数量int型,变量为number,然后依次输入帖子的id,string id【number】类型。
2。定义一个string b【number】数组,用来放相同种类id的名称。定义一个int num【number】数组,用来记录相同种类id出现的次数。定义一个int add=1,用于记录有几种id出现,初始化为1,是因为第一个id已经是第一种了,再出现的话就是第二种id了。
3。将第一个id【0】放入b【0】,num【0】=1;表示id【0】出现,并且出现了1次。
4。循环运算后面的id,依次和前面种类的id进行比较。如果有相同种类的id,则这种id的num【】++,如果比较完之后发现没有相同种类的id,则将这种id设为新种类的id即b【add】,同时num【add】,然后add++,准备作为下一种新种类的id。
5。在比较的过程中,如果发现有哪种id的次数大于等于了总数的一半,则将这种id打印,即为“水王”,同时结束整个程序。
6。如果一直没有哪种id满足一半的条件,则按照过程4执行。最后将num【】比较,找出最大的num【】,即为“水王”。

第二种方法:
基于的原理是:题目中有一句“水王”会回复其他ID发的每个帖子,则表示每个发帖的回帖中都有“水王”的id,则把每组回帖进行比较,找出相同的id即可。
假如每个发帖id和若干回帖id是一组对应关系,即liming发帖,然后回帖id有a,b,c,d,假如把liming和abcd看作是对应的一组,
则从第二组回帖id开始,与第一组中的回帖id进行比较,取出相同的id;然后将第三组回帖id与前面取出的相同id进行比较,再取出相同id值。
往后依次循环,直到只取出一个相同id值,即为“水王”。

源代码:

#include <iostream>
#include <string>
#define N 100
using namespace std;
void main()
{
    int number = 1; //number为帖子的数量
    cout << "请输入帖子数量:";
    cin >> number;

    string id[N];  //id【】为各帖子的id值
    cout << "请依次输入帖子的id:" << endl;
    for(int i = 0; i < number; i++)
        cin >> id[i];

    string b[N];  //b[N]用来存放相同id的名称,用于进行比较。
    int num[N] = {1}; //num[N]用来记录相同id出现的次数,第一个id第一次出现时,出现了1次
    int add = 1; //add计数变量,用于当后面id比较不相同时,新添放入b【】时,
    //进行计数.后面比较的时候,从第二个id开始比较的,所以add初值为1

    b[0] = id[0]; //用于后面进行比较。
    for(int i = 1; i < number; i++)
    {
        int x = 0; //用于下面两个if,当下一个id和前面所有id比较完,没有一个相同的时候,
        //则将此id新添入b【】;假如只要有一个相同的id,则不加入
        for(int j = 0; j < add; j++)
        {
            if(id[i] == b[j]) //后面的id和前面每种id比较的时候,如果相同,那么这种id就++,表示出现次数加1
            {
                num[j]++;
                //根据水王帖子数大于等于总数的一半,如果有哪种id的出现次数满足这个条件,则程序终止,同时也不需要全部遍历了。
                //如果没有超过一半的,则全部遍历,按出现次数最多的id为水王
                if(num[j]>=(int)((number+1)/2))
                {
                    cout<<"水王是:"<<b[j]<<endl;
                    exit(1);
                }
                x = 1; //设置x是监视哨,只要比较过程中有一次相同的,那么就不能把当前的id设为新种类的id
            }
        }
        if(x == 0) //如果比较之后,发现都不同,那么将这个id设为新一种id,同时新种类的id出现次数自动为1
        {
            b[add] = id[i];
            num[add] = 1;
            add++;
        }
    }
    for(int k = 0; k < add; k++)
    {
        cout << "" << k + 1 << " 个id为:" << b[k] << ",出现次数为:" << num[k] << endl;
        //将得出的所有种类id出现的次数进行比较,最大的即为水王
        if(num[k + 1] > num[0])
        {
            num[0] = num[k+1];
            id[0] = b[k + 1];
        }
    }
    cout << "所以水王为:" << id[0] << endl;
}

总结:

修改之后的程序好处在于,加了

if(num[j]>=(int)((number+1)/2))
                {
                    cout<<"水王是:"<<b[j]<<endl;
                    exit(1);
                }

这样一个判断,当某种id数满足一半这个条件时,程序就会终止,不需要全部遍历。
而如果一直没有哪种id满足一半,程序会遍历全部id,找到出现次数最多的id,即为“水王”。
但是博客一开始写的第二种方法是不需要遍历全部id的,所以第二种方法寻找水王的速度会快很多。

原文地址:https://www.cnblogs.com/diyunfei/p/5511821.html