欢迎来到study-hard-forever的博客

通讯录管理系统(C++)

通讯录管理系统(C++)

注意事项:

在代码测试之前必须先建立文件并导入内容以供测试使用,系统没有提示内容,用起来可能感到十分晦涩难以理解(可直接参考源代码,源代码还是非常浅显易懂的),这里仅供学习参考,不追求功能完善与实用性,如有问题或错误敬请谅解,欢迎积极指出。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<map>
//int x=0;        //记录删掉联系人个数
using namespace std;

class Phone  //数据类
{
    string name;
    string tel;
public:
    Phone():name("0"),tel("0"){};
    Phone(string name1,string tel1):name(name1),tel(tel1){}
    string getname(){return name;}
    string gettel(){return tel;}
    void setname(string name1){name=name1;}
    void settel(string tel1){tel=tel1;}
    //尝试流输出,输出类对象的形式输出(运算符重载),因此这里去掉print函数(这两个作用一致)
    //void print(){cout<<"name:"<<name<<endl<<"tel:"<<tel<<endl;}
    friend istream&operator>>(istream&is,Phone&X);
    friend ostream&operator<<(ostream&os,Phone&X);
};

istream&operator>>(istream&is,Phone&X)
{
    is>>X.name;
    while(is>>X.tel)      //判断手机号位数
    {
        if(X.tel.size()==11&&X.tel[0]=='1')
            break;
    }
    return is;
}
ostream&operator<<(ostream&os,Phone&X)
{
    os<<"name:"<<X.name<<endl<<"tel:"<<X.tel<<endl;
	return os;
}

class Operation   //操作类
{
    vector<Phone>lianxiren;
    multimap<string,int>m1;     //姓名
    multimap<string,int>m2;    //手机号
public:  //操作函数
    void zengtian();
    void open();
    void chaxun();
    void set();
};

void Operation::zengtian()
{
    /*string name,tel;
    cin>>name;
    while(cin>>tel)      //判断手机号位数
    {
        if(tel.size()==11)
            break;
    }*/
    Phone X;      //改用流输入,直接输入类对象(重载运算符)
    cin>>X;
    m1.insert(make_pair(X.getname(),lianxiren.size()));
    m2.insert(make_pair(X.gettel(),lianxiren.size()));
    //Phone obj(name,tel);
    //lianxiren.push_back(obj);
    lianxiren.push_back(X);
}

void Operation::open()
{
    vector<Phone>::iterator it;
    for(it=lianxiren.begin();it!=lianxiren.end();it++)
    {
        if(it->getname()!="0"&&it->gettel()!="0")          //虚删打开时自动屏蔽“已删除”元素
        //it->print();
        cout<<*it;
        if(it!=lianxiren.end()-1&&it->getname()!="0")
        cout<<"-------------------------"<<endl;   //不同联系人之间的分割线,但是只有一位联系人时不必显示(最后一位联系人后不显示)
    }

    //由该multimap测试数据得出联系人数据不能删,因为联系人信息删掉后下标前移,
    //但是此时multimap中第二个值并没有发生改变,这样指向的值就会指向vector中下一个值,造成序号对应错误,修改时会产生问题。
    //或许我们可以进行在multimap中find该删掉后的序号下标值(通过key值),然后进行从该值到结束遍历对multimap的second值减一,但是这样数据多时效率会大大降低。(像重建索引)
    //另一种解决方法是假装删除实际不删除(不显示而已),那样可以对vector进行特殊处理,只是在“删掉后”不输出,但实际存在占一个内存值,这样multimap中又可以与vector的下标一一对应了。
    //另外我们可以尝试对删除次数进行计数(这样每次操作时都通过该数使vector下标与multimap的second值进行对应)(需要定义全局变量为之计数,但是全局变量也不好。。。)
    //这里我采用的是最后这种方法(最后我用了一下,发现其中的问题,就是当我们删除之后我们总是记录该最大值,却忘了当我们删数之前的那些下标处理,这样下标永远是无法对应的,因此思路错误。。。)
    //最后我还是用的虚删的方式。
    /*
    multimap<string,int>::iterator m1i;
    for(m1i=m1.begin();m1i!=m1.end();m1i++)
    {
        cout<<m1i->first<<"   "<<m1i->second<<endl;
    }
    */
}

/*
int main()
{
    Operation op;
    string caozuo;
    while(1)
    {
        cin>>caozuo;
        if(caozuo=="zengtian") {op.zengtian();}
        if(caozuo=="open") {op.open();}
        if(caozuo=="end") break;
    }
    return 0;
}
*/

/*
void Operation::chaxun()
{
    string caozuo,name,tel;
    cin>>caozuo;
    if(caozuo=="name")
    {
        cin>>name;
        multimap<string,int>::iterator m1i;
        m1i=m1.find(name);
        if(m1i!=m1.end())
        lianxiren[m1i->second].print();
        else cout<<"No Found!"<<endl;
    }
    if(caozuo=="tel")
    {
        cin>>tel;
        multimap<string,int>::iterator m2i;
        m2i=m2.find(tel);
        if(m2i!=m2.end())
        lianxiren[m2i->second].print();
        else cout<<"No Found!"<<endl;
    }
}
*/

/*
int main()
{
    Operation op;
    string caozuo;
    while(1)
    {
        cin>>caozuo;
        if(caozuo=="zengtian") {op.zengtian();}
        if(caozuo=="open") {op.open();}
        if(caozuo=="chaxun") {op.chaxun();}
        if(caozuo=="end") break;
    }
    return 0;
}
*/

void Operation::set()      //先导入查询功能
{
    string caozuo,name,tel,name_tel;  //用name_tel来合并操作
    string name1,tel1;         //用来记录查找时最初的量(很重要的一步)
    int ii;
    //cin>>caozuo;
    //if(caozuo=="name")
    //{
        cin>>name_tel;
        multimap<string,int>::iterator m1i,m2i;
        m1i=m1.end();m2i=m2.end();
        m1i=m1.find(name_tel);
        m2i=m2.find(name_tel);
        if(m1i!=m1.end()||m2i!=m2.end())
        {
            if(m1i!=m1.end())
            ii=m1i->second;    //这里记录vector序号,以后用到时其实都可用ii表示,这样可以简化m1i->second,并且会避免m1i->second值的变化带来的问题
            if(m2i!=m2.end())
            ii=m2i->second;
            //ii=ii-x;
            //ii值-x变化了,但是这样每修改一次压入的ii值也会改变下标值,因此需要再定义一下值来记录该下标值使其保持不变,这样就可以使修改后下标依然对应
            //lianxiren[ii].print();
            cout<<lianxiren[ii];
            cin>>caozuo;
            while(1){           //这里允许多次修改与一次删除
            name1=lianxiren[ii].getname();   //这里永远是首次操作时记录的序号,因此这里的name1,tel1与联系人信息绑定(不能说联系人信息不会变,这里的联系人信息随修改的变化而变化,是变量)
            tel1=lianxiren[ii].gettel();
            m1i=m1.find(name1);             //每次操作后m1i,m2i的指向应该改变
            m2i=m2.find(tel1);
            if(caozuo=="operation")
            {
                int i=1,j=1;
                cin>>caozuo;
                while(1)
                {
                    if(caozuo=="name")
                    {
                        i=0;
                        cin>>name;
                        lianxiren[ii].setname(name);
                    }
                    if(caozuo=="tel")
                    {
                        j=0;
                        cin>>tel;
                        lianxiren[ii].settel(tel);
                    }
                    if(caozuo=="end")
                    break;
                    cin>>caozuo;
                }
                if(i==0) {m1.insert(make_pair(name,ii));}
                if(j==0)
                {
                    /*
                    //当初测的是这样,这样会导致一个问题,每次修改完数据,lianxiren[ii].gettel()其实已经变了
                    //但是我们要删除修改之前的数据并补充新数据,如果用下面的代码测出的将会是删掉新的,保留原来的,相当于这一步没有执行任何操作
                    m2.insert(make_pair(tel,ii));
                    m2i=m2.find(lianxiren[ii].gettel());
                    m2.erase(m2i);
                    */
                    m2.insert(make_pair(tel,ii));
                    m2i=m2.find(tel1);    //删除原数据(每次while循环后都记录改变后的值,删除的是改变后的新值)
                    m2.erase(m2i);
                }
                if(i==0) {m1.erase(m1i);}
            }
            if(caozuo=="delete")
            {
                vector<Phone>::iterator it;
                it=lianxiren.begin();
                it=it+ii;               //这里删除用ii(起初的常值不会变)
                //lianxiren.erase(it);
                it->setname("0");
                it->settel("0");
                m1i=m1.find(name1);
                m1.erase(m1i);
                m2i=m2.find(tel1);
                m2.erase(m2i);
                //x++;
                break;
            }
            if(caozuo=="return")
            break;
            cin>>caozuo;
          }
        }
        else cout<<"No Found!"<<endl;
   // }

    /*
    if(caozuo=="tel")
    {
        cin>>tel;
        multimap<string,int>::iterator m2i;
        m2i=m2.find(tel);
        if(m2i!=m2.end())
        lianxiren[m2i->second].print();
        else cout<<"No Found!"<<endl;
    }
    */
}

int main()
{
    Operation op;
    //string caozuo;
    freopen("1.txt","r",stdin); //操作记录从文件1.txt中输入数据
    if(freopen("1.txt","r",stdin)==NULL)//(这里与fopen读取是否成功的判断方式不同)
    {
        cout<<"Can't read!"<<endl;
        return 0;
    }
	freopen("2.txt","w",stdout); //操作输出结果输出到自动创建的文件2.txt中
    /*
    while(1)           //最后去掉“菜单”
    {
        cin>>caozuo;
        if(caozuo=="zengtian") {op.zengtian();}
        if(caozuo=="open") {op.open();}
        //if(caozuo=="chaxun") {op.chaxun();}
        if(caozuo=="set") {op.set();}
        if(caozuo=="end") break;
    }
    */
    op.zengtian();
    op.zengtian();
    op.open();
    op.set();
    op.zengtian();
    op.set();
    op.open();
    fclose(stdin);
    fclose(stdout);
    freopen("小光的通讯录.txt","w",stdout);//操作最后的通讯录结果(所有联系人)输出到"通讯录.txt"中
    op.open();
    fclose(stdout);
    return 0;
}

需要的文件:

1.txt
ma 12345678900
li 12345654321
ma delete 
guang 15275882925
li operation tel 12312312312 end return
2.txt
name:ma
tel:12345678900
-------------------------
name:li
tel:12345654321
name:ma
tel:12345678900
name:li
tel:12345654321
name:li
tel:12312312312
-------------------------
name:guang
tel:15275882925
小光的通讯录.txt
name:li
tel:12312312312
-------------------------
name:guang
tel:15275882925

部分功能测试:

输入电话合法性判断(必须为11位)
在这里插入图片描述
文件输入合理性(是否首位电话号码为“1”:)
在这里插入图片描述
打开(输出操作:)
在这里插入图片描述
删除操作:
在这里插入图片描述

改名操作:
在这里插入图片描述

文件无法读取操作:
在这里插入图片描述
最终结果:
在这里插入图片描述
(有些功能截图可能并不全面,具体可测试代码)

posted @ 2021-02-01 23:13  study-hard-forever  阅读(489)  评论(0编辑  收藏  举报