课堂练习-找水王
三人行设计了一个灌水论坛。
信息学院的学生都喜欢在上面交流灌水,传说在论坛上有一个“水王”,他不但喜欢发帖,还会回复其他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的,所以第二种方法寻找水王的速度会快很多。