(Boolan)STL与泛型编程作业一

题目:一个整数集 , 该整数集可以有重复元素, 初始为空集合 。可以指定如下指令:

  1. add x 将x加入整数集
  2. del x 删除整数集中所有与x相等的元素
  3. ask x 对整数集中元素x的情况询问
    下面为指令解释,并要求进行如下输出:
  4. add 输出操作后集合中x的个数
  5. del 输出操作前集合中x的个数
  6. ask 先输出0或1表示x是否曾被加入集合(0表示不曾加入),再输出当前集合中x的个数,中间用空格格开。
    提示
    请使用STL中的 set 和multiset 来完成该题

输入
第一行是一个整数n,表示命令数。0<=n<=100000。
后面n行命令。
输出
共n行,每行按要求输出。

样例输入( //第一行是整数,表示为命令数目)
7
add 1
add 1
ask 1
ask 2
del 2
del 1
ask 1
样例输出
1
2
1 2
0 0
0
2
1 0

对于该题目我提供了两个方法来解决问题

方法一:

说明:
  • 该程序是通过一组函数直接实现题目要求的结果
  • 为了保证结果能一次性输出,在程序中采用了queue来暂存操作的输出结果,最后统一输出
  • 为了方便您批改作业,我特地制作了在线测试的程序,程序的在线测试地址:http://rextester.com/VYZSW2883
    • 在线调试帮助:
      • 如何执行

点击链接进入页面,点击按钮



即可执行程序了
- 执行不正确,没有输出(如何输入)

如果输出不正常,或者没有输入输出,或者不知道如何输入,可以按下图执行
:方法一代码
#include <set>
#include <queue>
#include <iostream>
#include <string>
#include <algorithm>
#include <sstream>

using namespace std;

void controller(multiset<int> &s, queue<string> &rs, set<int> &record); //通过该函数协调流程
int add(multiset<int> &s, queue<string> &rs, set<int> &record, const int &content); //添加数据
int del(multiset<int> &s, queue<string> &rs, set<int> &record, const int &content); //删除数据
int ask(queue<string> &s, multiset<int> &rs, set<int> &record, const int &content, int type = 0);   // 查询数据,type用于区分是否为查询
template<class T>
void printMultiset(queue<T>);   //打印输出结果

int main()
{
    int count;
    multiset<int> s = {};   //创建一个空的容器,用于存放记录
    queue<string> resultSet;    //创建一个空队列,用于存放输出记录
    set<int> record = {};       //创建一个空set,用于存放保存记录
    //cout << "请输入需要操作的步数: \n";
    cin >> count;
    if (count <= 0) count = 1;
    //cout << "还需要输入 " << count << "步操作\n";

    while (count)   //依据输入,循环执行,通过controller调度顺序
    {
        //cout << "还需要输入 " << count << "步操作\n";
        
        controller(s, resultSet,record);
        count--;
    }

    cout << "\n\n*****************************************\n\n";
    printMultiset(resultSet);   //打印日志

    return 0;
}

void controller(multiset<int> &s, queue<string> &resultSet, set<int> &record)
{
    string cmd;     //命令
    int content;    //内容
    cin >> cmd >> content;
    if ("add" == cmd) {
        add(s, resultSet, record, content);
    }
    else if("del" == cmd)
    {
        del(s, resultSet, record, content);
    }
    else if("ask" == cmd)
    {
        ask(resultSet, s, record, content, 1);//由controller调用
    }
    else 
    {
        cout << "输入错误,请重新输入\n";
    }
}

int add(multiset<int> &s, queue<string> &rs, set<int> &record, const int &content)
{
    s.insert(content);//在集合中加入元素
    ask(rs, s, record, content);//输出操作后集合中x的个数
    record.insert(content);
    return 0;
}

int ask(queue<string> &rs, multiset<int> &target, set<int> &record, const int &content, int type)//type用于区分是否为存入双参数
{
    int count = target.count(content);
    int history = count ? count: record.count(content);//如果count为0,检测该元素是否被删除
    stringstream result;
    result << count;
    string s, scount;
    result >> scount;   //通过stringstream来构造字符串
    if (type) 
    {   //需要存入双参数
        const string a = "1 ", b = "0 ";
        s = (history ? a : b) + scount;
    }
    else 
    {   //存入查询结果即可
        s = scount;
    }

    rs.push(s);//ask的结果保存
    
    return count;
}

int del(multiset<int> &s, queue<string> &rs, set<int> &record, const int &content)
{
    //删除前需要查询情况
    ask(rs, s, record, content);
    s.erase(content);//删除元素
    return 0;
}

template<class T>
void printMultiset(queue<T> s)
{
    while (!s.empty()) 
    {   //打印日志
        cout << s.front() << endl;
        s.pop();//弹出打印完的日志  
    }
}

方法二:

说明:
  • 这个方法主要是采用了面向对象和泛型编程的思路来实现题目的要求

  • 这个方法,分别有三个单例的class,来封装了multiset、set、queue三个容器,分别来实现保存数据,保存插入记录和输出信息的功能

  • 封装后的最大优势就是,使用者极其简单可以使用封装的过程


    分装后如何使用
  • 为了方便您批改作业,我特地制作了在线测试的程序,程序的在线测试地址:http://rextester.com/SRG5586

    • 在线调试帮助:
      • 如何执行

点击链接进入页面,点击按钮



即可执行程序了
- 执行不正确,没有输出(如何输入)

如果输出不正常,或者没有输入输出,或者不知道如何输入,可以按下图执行
#ifndef __SET_TEST__HEADER__
#define __SET_TEST__HEADER__

#include <set>
#include <string>
#include <queue>
#include <iostream>
#include <sstream>

using namespace std;

template<typename T>
class Multiset;     //包装了multiset,用于存放数据
template<typename T>
class Recorder;     //记录器,存放记录不会重复,所以包装了set,如果存入了某个数据,在此记录,如果修改了原始数据,此处还有记录,说明该数据被添加过
class ControllerLog;//日志器,包装了queue,用于存放输出信息

template<typename T>
class Multiset  //multiset的包装类
{
private:
    multiset<T>* s; //实际的容器的指针,用于存放数据
    static Multiset<T>* ms; //单例模式自己的指针
    Recorder<T>* recorder;  //记录器指针,将添加的数据放入在此
    ControllerLog* log;     //用于控制日志的存储,以便一次输出
    Multiset();//单例
public:
    void add(const T&); //添加的方法
    void del(const T&); //删除的方法
    void ask(const T&); //查询的方法
    static Multiset<T>* getInstance();  //单例模式
    ~Multiset();//析构函数流程
    string geneLog(const T& content, int type = 0);//生成日志,type用于控制不同的日至需求(查询的日志和其他不同)
    void controller();//控制器,用于控制
    void run();//对外的方法,直接调用该方法即可
};

template<typename T>
class Recorder  //记录器,set的包装类
{
private:
    static Recorder<T>* recorder;//单例
    set<T>* s;  //被包装的set
    Recorder(); //单例
public:
    static Recorder<T>* getInstance();//单例
    void addRecord(const T&);//添加一条记录
    int count(const T&) const;//统计数量
    ~Recorder();//析构函数
};

class ControllerLog //日志器,queue的包装类
{
private:
    queue<string>* q; //被包装对象的指针
    static ControllerLog* cl;//单例
    ControllerLog();//单例
public:
    static ControllerLog* getInstance();//单例
    void addLog(const string &log);//添加一条日至
    void print();//输出所有的日志
    ~ControllerLog();//析构函数
};

template<typename T>
Multiset<T>* Multiset<T>::ms = NULL;//静态成员,需要赋值

template<typename T>
Recorder<T>* Recorder<T>::recorder = NULL;

ControllerLog* ControllerLog::cl = NULL;

#endif // !__SET_TEST__HEADER__



template<typename T>
inline Multiset<T>::Multiset()
{   //构造对象时,构造指针指向的对象
    if (!s)
        s = new multiset<T>();
    if (!log)
        log = ControllerLog::getInstance();
    if (!recorder)
        recorder = Recorder<T>::getInstance();
}

template<typename T>
inline Multiset<T>* Multiset<T>::getInstance()
{   //单例(饿汉模式)
    if (!ms)
        ms = new Multiset<T>();
    return ms;
}

template<typename T>
inline string Multiset<T>::geneLog(const T& content, int type)
{   
    int count = s->count(content);  //查询数据表格中的数量
    int history = count ? count : recorder->count(content); //如果查询到的count为0,则在Recorder中查询是否存入过
    stringstream result;    //通过stringstream来将得到的int转换为string
    result << count;
    string sresult, scount;
    result >> scount;
    if (type) {     //如果是查询,则依此拼接字符串
        const string a = "1 ", b = "0 ";
        sresult = (history ? a : b) + scount;
    }
    else {      //非查询,依此拼接字符串
        sresult = scount;
    }
    return sresult;
}

template<typename T>
inline void Multiset<T>::controller()
{
    //控制器接受控制台输入
    string cmd;
    T content;
    cout << "请依次输入命令:\n";
    cin >> cmd >> content;
    //依据输入执行不同的方法
    if ("add" == cmd) {
        add(content);
    }
    else if ("del" == cmd)
    {
        del(content);
    }
    else if ("ask" == cmd)
    {
        ask(content);
    }
    else
    {
        cout << "输入错误,请重新输入\n";
    }
}

template<typename T>
inline void Multiset<T>::run() {
    //对外方法,直接调用即可
    int count = 0;
    cout << "请输入命令的条数: ";
    cin >> count;
    count = count >= 0 ? count : 7;
    string x;
    int content;
    //循环接收输入
    while (count) {
        controller();
        count--;
    }
    //打印结果
    cout << "\n\n输出:**************************************\n\n";
    log->print();
}

template<typename T>
inline Multiset<T>::~Multiset()
{   //析构函数释放指针的内存
    if (s) delete s;
    if (log) delete log;
    if (recorder) delete recorder;
    if (ms) delete ms;//最后释放自己
}

template<typename T>
inline void Multiset<T>::add(const T &content)
{   //添加到容器中
    s->insert(content);
    recorder->addRecord(content);//通过记录器,添加一条记录
    log->addLog(geneLog(content));//添加一条输出日志
}

template<typename T>
inline void Multiset<T>::del(const T &content)
{   //通过日志器添加一条日志
    log->addLog(geneLog(content));
    s->erase(content);//数据容器中,清除内容
}

template<typename T>
inline void Multiset<T> ::ask(const T &content)
{
    //添加一条查询记录,以便输出
    log->addLog(geneLog(content, 1));
}

template<typename T>
inline Recorder<T>::Recorder() {
    if (!s)s = new set<T>();//构造对象时,构造指针指向的对象
}

template<typename T>
inline Recorder<T>* Recorder<T>::getInstance()
{
    if (!recorder) recorder = new Recorder<T>();//单例(饿汉模式)
    return recorder;
}

template<typename T>
inline Recorder<T>::~Recorder()
{   // 释放指针指向的对象
    if (s) delete s;
    if (recorder) delete recorder;//最后释放自己
}

template<typename T>
inline void Recorder<T>::addRecord(const T& content)
{
    s->insert(content);//在记录表中添加一个记录
}

template<typename T>
inline int Recorder<T>::count(const T& content) const
{
    return s->count(content);//返回记录表中的数目
}

inline void ControllerLog::addLog(const string &log)
{
    q->push(log);//加入一条日志
}

inline void ControllerLog::print() {
    while (!q->empty())
    {   //遍历打印全部日至
        cout << q->front() << endl;
        q->pop();//将打印完的条目弹出队列
    }
}

inline ControllerLog::ControllerLog() {
    if (!q) q = new queue<string>();    //单例(饿汉模式)
}

inline ControllerLog* ControllerLog::getInstance()
{
    if (!cl) cl = new ControllerLog();  //单例
    return cl;
}

inline ControllerLog::~ControllerLog()
{
    if (q) delete q;
    if (cl) delete cl;  //最后释放自己
}


int main()
{
    Multiset<int>* s = Multiset<int>::getInstance();//单例模式获取对象
    s->run();//调用方法执行

    system("pause");
    return 0;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,639评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,884评论 25 707
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,604评论 18 399
  • 高中的暑假总是那么少,只有短短的8天。有时候陈小凡会想到为什么自己没有生在战争时期,那样就可以不用上学了。但也就只...
    道滁阅读 202评论 0 1