C++复习:一个小例子复习基础
来源:互联网 发布:mac如何下载阿里旺旺 编辑:程序博客网 时间:2024/06/08 19:28
前言
经过两周的学习,C++基础部分基本已经有了一定的了解。正好前两天在群里看到一个哥们问了一个很有代表性的需求,于是决定以这个需求为例子,对现阶段所学知识做一个复习巩固。
需求
需求内容
游戏中有一个推荐好友的功能,每推荐成功一个玩家自己都会获得奖励,并且推荐自己的玩家也会获得一定比率的分成,同时推荐他的玩家也会获得他分成的一定比率分成,直至没有推荐者或者最小分成为止。恩,你想的没错,就是传销模式。
需求要求推荐信息以文本保存,格式如下:
1001 1002
1001 1003
1003 1004
……
每一行的前一个是推荐者的编号,后一个是被推荐者的编号。
输出信息要求如下:
1003推荐了1004 1003获得了10金币 1001获得了2金币
也就是说每一行先输出推荐信息,然后从自身开始逐级输出获得的奖励,直至结束
最后,还要求输出所有奖励的金币总数。
需求分析
这个例子虽然简单,但是包含了读取数据,存储,输出,并且数据之间还有一定的关系,并不是简单的一个容器存起来那么简单(当然,一定要这么做也可以,但是使用关联容器可能用起来更顺手)。
数据读取:比较简单,fstream可以实现。
数据存储:由于玩家人数并不固定,并且玩家需要通过编号查询,所以建立一个字典是必须的,C++中是map。当然,在这之前还需要建立一个玩家类。由于玩家可能有一个推荐者(上线),和若干个被推荐者(下线),所以上线用一个string存储,下线用一个string的vecotr容器存储,使用的时候通过该tring去字典里面获取。当然通常我们还需要保存玩家的姓名,id,由于涉及到奖励,还可以将该玩家获得的总金币数保存下来。
数据输出:这一点有点绕。由于输出的时候需要输出玩家及其所有上线的获得的奖励,而玩家有几级上线我们并不清楚,所以可以考虑使用递归来让系统自动追踪最顶级的上线,而系统的上线分成按比率逐级递减也符合这一条件。
实现
静态数据
由上述需求分析可知,推荐者获得的金币数量是固定的,上线递减比率也是固定的,金币递归的最小额度也是固定的,于是可以将其用常量存储起来方便修改。
而所有玩家(people类,下面会给出)需要通过名字进行查询,于是通过一个map<string, people>
来实现。
static const int award = 25;//最大金币获得量static const double discount = 0.2;//金币获得递减比率static const int minimum = 1;//最小金币获得数量static map<string, people> AllPeople = {};//玩家字典
玩家类
玩家类中需要包含姓名,上线下线,添加下线的方法(上线在构造函数中添加,无序动态改变),以及一个递归获取金币的方法:
此处用struct,与c#中struct不同的是,c++中struct与class的唯一区别是在遇到第一个访问控制符之前,struct成员是public的,而class成员是private的,所以怎么方便怎么来,无需考虑性能的区别。
struct people{//玩家 people() = default; people(string n) :name(n){ money = 0; } people(string n, string p) :name(n), upPeople(p){ money = 0; } string name;//姓名 int money;//该玩家总金币数 string upPeople;//上线 vector<string> downPeople;//下线 void addDownPeople(string p){//添加下线 downPeople.push_back(p); } int addMoney(int m){//递归获得金币 money += m; cout << name << "获得了:" << m << "金币 "; if (upPeople!=""&&(m*discount >= minimum))//递归条件 return m + AllPeople[upPeople].addMoney(static_cast<int>(m*discount)); else{//终结条件 cout << endl; return m; } }};
玩家管理器类
直接调用玩家数据当然可以实现需求,但是为了方便客户端使用,降低耦合并尽量少的暴露类信息,通常使用一个管理器来对数据进行管理,客户端只需要调用管理器中对应的接口来处理数据即可。
目前管理器仅包含两个方法:添加玩家和输出金币,由于需要统计金币的总消耗量,所以需要返回一个金币值
struct peopleManager//玩家操作管理器{public:static void addPeople(string s){//根据行添加玩家int f = s.find(" ");addPeople(string(s,0,f),string(s,f+1));}static void addPeople(string up, string down){//根据玩家姓名添加玩家if (AllPeople.find(up) == AllPeople.end())AllPeople.insert({ up, people(up) });AllPeople.insert({ down, people(down, up) });AllPeople[up].addDownPeople(down);}static int appMoney(int money){//按玩家关系给予奖励int num=0;for (auto p : AllPeople)for (auto s : p.second.downPeople){cout << p.second.name << "推荐了" << s<<" ";num += p.second.addMoney(money);//递归调用}return num;}};
数据文件
由于只是练习测试用,创建一个test.txt保存在程序的根目录下,文件内容如下:
1001 1002
1001 1003
1001 1004
1002 1005
1002 1006
1003 1007
1005 1008
使用
现在准备工作做好了,我们可以使用了。
读取文件:
ifstream inFile("test.txt");//文件读取流
录入玩家数据:
string line;while (getline(inFile, line))//读取一行文件 peopleManager::addPeople(line);inFile.close();
输出金币数据:
cout <<"总金币数量为:"<< peopleManager::appMoney(award) << endl;
运行结果:
转载请注明出处:http://blog.csdn.net/ylbs110/article/details/50984578
其他
到此为止,需求已经实现了,但是实现需求本身不是目的,目的是为了在实现需求的时候巩固所学知识。
在目前的代码中,对类,函数,语句,关联容器,文件读取都有所涉及,但是对C++中具有特色的引用,指针,迭代器却并未涉及到,于是需要对代码做一些修改。
修改一:
for (auto s : p.second.downPeople){ cout << p.second.name << "推荐了" << s<<" "; num += p.second.addMoney(money);//递归调用}
改为
//for_each使用,迭代器使用,lambda使用,引用,指针for_each(p.second.downPeople.begin(),p.second.downPeople.end(),[&p, &num, money](string s){cout << p.second.name << "推荐了" << s << " "; num += p.second.addMoney(money); });
这么一改,复习了泛型方法,迭代器,指针,引用。具体用法我就不细细分析了,自己查询一下也可以加深印象。
修改二:
由于每个玩家的下线玩家不会重复,所以可以采取set而不是vector。
vector<string> downPeople;//下线 void addDownPeople(string p){//添加下线 downPeople.push_back(p); }
改为
set<string> downPeople;//下线 void addDownPeople(string p){//添加下线 downPeople.insert(p); }
修改三:
将people除默认构造方法外改为私有,通过友元来让玩家管理器调用,这样复习了友元,代码也更加符合开闭原则:
struct people{//玩家 friend class peopleManager;//友元使用 people() = default;private: people(string n) :name(n){ money = 0; } people(string n, string p) :name(n), upPeople(p){ money = 0; } string name;//姓名 int money;//该玩家总金币数 string upPeople;//上线 vector<string> downPeople;//下线 void addDownPeople(string p){//添加下线 downPeople.push_back(p); } int addMoney(int m){//递归获得金币 money += m; cout << name << "获得了:" << m << "金币 "; if (upPeople!=""&&(m*discount >= minimum))//递归条件 return m + AllPeople[upPeople].addMoney(static_cast<int>(m*discount)); else{//终结条件 cout << endl; return m; } }};
所有代码
#include "stdafx.h"#include <iostream>#include <string>#include <map>#include <set>#include <vector>#include <fstream>#include <algorithm>using namespace std;struct people;struct peopleManager;static const int award = 25;//最大金币获得量static const double discount = 0.2;//金币获得递减比率static const int minimum = 1;//最小金币获得数量static map<string, people> AllPeople = {};//玩家字典struct people{//玩家 friend struct peopleManager;//友元使用 people() = default; ~people(){}private: people(string n) :name(n){ money = 0; } people(string n, string p) :name(n), upPeople(p){ money = 0; } string name;//姓名 int money;//该玩家总金币数 string upPeople;//上线 set<string> downPeople;//下线 void addDownPeople(string p){//添加下线 downPeople.insert(p); } int addMoney(int m){//递归获得金币 money += m; cout << name << "获得了:" << m << "金币 "; if (upPeople!=""&&(m*discount >= minimum))//递归条件 return m + AllPeople[upPeople].addMoney(static_cast<int>(m*discount)); else{//终结条件 cout << endl; return m; } }};struct peopleManager//玩家操作管理器{public: static void addPeople(string s){//根据行添加玩家 int f = s.find(" "); addPeople(string(s,0,f),string(s,f+1)); } static void addPeople(string up, string down){//根据玩家姓名添加玩家 if (AllPeople.find(up) == AllPeople.end()) AllPeople.insert({ up, people(up) }); AllPeople.insert({ down, people(down, up) }); AllPeople[up].addDownPeople(down); } static int appMoney(int money){//按玩家关系给予奖励 int num=0; for (auto p : AllPeople) for_each(p.second.downPeople.begin(),p.second.downPeople.end(),//for_each使用,迭代器使用 [&p, &num, money](string s){cout << p.second.name << "推荐了" << s << " "; num += p.second.addMoney(money); }//lambda使用 ); //for (auto s : p.second.downPeople){ // cout << p.second.name << "推荐了" << s<<" "; // num += p.second.addMoney(money);//递归调用 //} return num; }};int _tmain(int argc, _TCHAR* argv[]){ string line; ifstream inFile("test.txt");//文件读取流 while (getline(inFile, line))//读取一行文件 peopleManager::addPeople(line); inFile.close(); cout <<"总金币数量为:"<< peopleManager::appMoney(award) << endl; return 0;}
- C++复习:一个小例子复习基础
- 一个小复习
- C基础的复习
- C语言基础复习
- C指针基础复习
- C语言基础复习
- java 基础复习 --小知识点
- 复习潭浩强的c基础
- 前几天复习的c基础
- c语言基础复习一
- C++Primer Plus 基础复习
- c语言的基础复习
- C++(基础班)上机复习
- 基础复习
- 基础复习
- 基础复习
- 基础复习
- Java基础复习:StringBuilder小练习
- display:none与visible:hidden的区别
- Oracle11g release2数据导出到Oracle10g release2方法
- 实习 - 纪念第一次被腾讯虐
- SVM(2)-算法
- (第1讲)java 的基本类型及其范围
- C++复习:一个小例子复习基础
- Oracle-03-初次连接数据库
- Enumernation pk iterator
- 最快最简单的排序——桶排序
- Ubuntu 屏幕分辨率设置
- ERROR 1366 (HY000): Incorrect string value: '\xE5\xB8\x82' for column 'address' at row 1
- how many positive integers are divisible by a number d in range [x,y]?
- java基础知识点总结
- Nginx学习笔记——提供静态内容