软件工程个人项目——寻找水王

寻找水王

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

      据说这是一道微软软件工程师面试的试题……老师上课让我们作为课堂练习思考的时候我们都不约而同的想到了遍历所有id号,然后排序找到水王。可是老师对我们的时间复杂度和算法的执行时间作了要求,因此我们苦苦思索优化的算法。上课时由于时间匆忙,老师简单介绍了一种“两两相消”的思想:就是从第一个id号码开始,与其相邻的两个号码如果不相同则消掉;如果相同则保留。这样,最后剩下的序号就是水王的id号。但是课下我和同学讨论了一下(其实是没弄明白算法的含义),发现这种思路有的时候是不能计算出正确的结果的,比如发帖的总数为奇数的时候……后来回到宿舍我还是想不出什么更好的解决办法(。﹏。*),于是百度查阅了一下微软面试的思路解析,并与同学讨论了他上面提到的算法,编写了下面的程序。
一、设计思想
      首先我准备用文件存取各个发帖id(相当于题目中说的“论坛帖子列表”)。
      其次,我认为本题的关键是:水王发帖的总数(也就是id号码)超过总帖子数量的一半。抓住这个条件,我们可以假设第一个id为水王,在依次遍历剩下的帖子时会出现两种情况:下一个id号还是这个“假设水王”的,那么记录发帖次数的值+1;如果id号发生变化,则相应的次数-1。如此下去,就会出现到某个位置,记录次数的变量值为0(就意味着这个id号号出现的次数没有超过一半),那么就假设下一个id号为新的水王,然后从新开始上面的记录。因为水王的id数大于一半,所以到最后总会有一个id使得记录次数的值>0,那么这个就是真正的“水王”。
 
附:参考的网页地址链接:编程之美--寻找发帖水王
     
二、代码实现
      本次实验我是把水王发帖的id存入文件,程序读取文件并寻找水王,代码如下:
 1 //Zhao Ziyin 2016/5/18  寻找水王
 2 
 3 #include<iostream>
 4 #include<fstream>
 5 using namespace std;
 6 #define MAX 50
 7 
 8 void Find(int id[], int lenth, int &water)
 9 {
10     int i = 0, count = 0;               //count用来记录某id发帖次数
11     for (i = 0; i<lenth; i++)
12     {
13         if (count == 0)                //次数为零
14         {
15             water = id[i];            //假设当前的id为水王
16             count++;
17         }
18         else
19         {
20             if (water == id[i])        //若前后id相同,水王的id不变,次数加1
21                 count++;          
22             else
23                 count--;
24         }
25     }
26 }
27 int main(int argc, char* argv[])
28 {
29     int ID[MAX];                //发帖记录表
30     int in[MAX+1];                //从文件中读出的数组
31     int i , num, King;              //发帖数目、水王
32     /*cout << "请输入帖子的数量:";
33     cin >> num;
34     cout << "请输入发帖ID:";
35     for (int i = 0; i<num; i++)
36     {
37         cin >> ID[i];
38     }*/
39 
40     //读取文件中的id号
41     ifstream infile("id_form.txt", ios::in);
42     if (infile.is_open() == false)
43     {
44         cerr << "open error!" << endl;
45         exit(1);
46     }
47     infile >> in[0];//读取帖子总数
48     num = in[0];
49     cout << "帖子的总数为:"<<in[0]<<endl;
50 
51     cout << "发帖的id号分别为:" << endl;
52     for (i = 0; i < num; i++)
53     {
54         infile >> in[i+1];
55         ID[i] = in[i+1];
56         cout << ID[i]<<" ";
57     }
58     cout << endl;
59 
60     Find(ID, num, King);
61     cout << endl << "找到水王!!!" << endl;
62     cout << "发帖水王的id为:" << King << endl;
63     infile.close();
64     return 0;
65 }
三、实现截图
以下是几种不同情况的测试用例。
1、只有一个id号发帖
2、帖子的总数为奇数
 
3、帖子的总数为偶数
4、前后id号码都有重复几次出现的
 
四、个人总结
      通过这次实验,让我意识到程序员不应该只想着问题怎样解决,有的时候我们虽然能够解决问题,但是我们花费的时间或者代价却往往是不值得或者是浪费的。面对问题,我们应该先想到最基本的解决办法,然后不吝惜花费时间去思考到底怎样才能简化算法。这样不仅能够使我们在更短的时间完成该做的事,提高效率,还能够锻炼我们的逻辑思维,对于以后的工作发展有很多积极的影响。还有就是我希望有时间可以阅读以下《编程之美》这本书,并且希望我能够看懂里面的算法,最后达到提升编程能力的效果。
原文地址:https://www.cnblogs.com/2016helen/p/5507279.html