通讯录管理系统(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”:)
打开(输出操作:)
删除操作:
改名操作:
文件无法读取操作:
最终结果:
(有些功能截图可能并不全面,具体可测试代码)
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文链接,否则保留追究法律责任的权利。