(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
    • 在线调试帮助:
      • 如何执行

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



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

如果输出不正常,或者没有输入输出,或者不知道如何输入,可以按下图执行
(Boolan)STL与泛型编程作业一_第1张图片
:方法一代码
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

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

int main()
{
    int count;
    multiset s = {};   //创建一个空的容器,用于存放记录
    queue resultSet;    //创建一个空队列,用于存放输出记录
    set 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 &s, queue &resultSet, set &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 &s, queue &rs, set &record, const int &content)
{
    s.insert(content);//在集合中加入元素
    ask(rs, s, record, content);//输出操作后集合中x的个数
    record.insert(content);
    return 0;
}

int ask(queue &rs, multiset &target, set &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 &s, queue &rs, set &record, const int &content)
{
    //删除前需要查询情况
    ask(rs, s, record, content);
    s.erase(content);//删除元素
    return 0;
}

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

方法二:

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

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

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


    (Boolan)STL与泛型编程作业一_第2张图片
    分装后如何使用
  • 为了方便您批改作业,我特地制作了在线测试的程序,程序的在线测试地址:http://rextester.com/SRG5586

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

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



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

如果输出不正常,或者没有输入输出,或者不知道如何输入,可以按下图执行
(Boolan)STL与泛型编程作业一_第3张图片
#ifndef __SET_TEST__HEADER__
#define __SET_TEST__HEADER__

#include 
#include 
#include 
#include 
#include 

using namespace std;

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

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

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

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

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

template
Recorder* Recorder::recorder = NULL;

ControllerLog* ControllerLog::cl = NULL;

#endif // !__SET_TEST__HEADER__



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

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

template
inline string Multiset::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
inline void Multiset::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
inline void Multiset::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
inline Multiset::~Multiset()
{   //析构函数释放指针的内存
    if (s) delete s;
    if (log) delete log;
    if (recorder) delete recorder;
    if (ms) delete ms;//最后释放自己
}

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

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

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

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

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

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

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

template
inline int Recorder::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();    //单例(饿汉模式)
}

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* s = Multiset::getInstance();//单例模式获取对象
    s->run();//调用方法执行

    system("pause");
    return 0;
}

你可能感兴趣的:((Boolan)STL与泛型编程作业一)