第一次大作业
目的 :
(1)综合运用之前所学知识(选择控制 循环控制,数组,函数,指针,结构体和 文件等)来完成一个简单的信息管理程序的设计。
(2) 充分体现和体会函数在程序设计中的必要性和实用性,并反映主函数main ()在程序设计中的实现思路和方法。
实训内容和原理
①添加记录:输入联系人的序号、姓名、电话号码等相关信息;(在此基础上我们还添加了加入的时间显示与储存)
②显示记录:显示联系人的序号、姓名、电话号码等相关信息,在此基础上,还增加了录入时间的显示和存储;
③删除记录:根据联系人的任意信息,查找并删除联系人的信息;
④查询记录:根据联系人的序号,查找联系人的其他信息;
⑤修改记录:根据联系人的任意信息,查找并修改联系人的信息;
⑥清空记录:清空电话簿数据;
class CData //定义数据基类
{
public:
CData() {};
virtual int Compare(CData&) = 0;
virtual void Show() = 0;
virtual ~CData() {};
};
class CNode
{
private:
CData* pData; //用于指向数据类的指针
CNode* pNext; //用于指向链表的后向指针
public:
CNode()//结点构造函数
{
pData = 0;
pNext = 0;
}
CNode(CNode& node)//用于拷贝的构造函数
{
pData = node.pData;
pNext = node.pNext;
}
void InputData(CData* pdata)//输入数据
{
pData = pdata;
}
void ShowNode()
{
pData->Show();
}
CData* GetData()
{
return pData;
}
friend class CList;//定义链表类为友元类
};
class CList
{
CNode* pHead;//链表头结点指针
public:
CList()
{
pHead = 0;
}
~CList()
{
DeleteList();
}
void AddNode(CNode* pnode);//在首部添加结点
CNode* DeleteNode(CNode*);//删除一个指定的结点,返回该结点的指针
CNode* LookUp(CData&);
//查找一个指定的数据,返回该数据所在的结点在链表中的指针,若未找到返回0
void ShowList();//打印整个链表
void DeleteList();//删除整个链表
CNode* GetListHead()
{
return pHead;//返回链表首结点
}
CNode* GetListNextNode(CNode* pnode);//返回链表指定结点的下一个结点
};
//电话簿类
#include<iostream>
#include<ctime>
#include<string.h>
#include<iomanip>
#include<fstream>
using namespace std; //用命名空间std中的定义
CNode* CList::GetListNextNode(CNode* pnode)//返回链表指定结点的下一个结点
{
CNode* p1 = pnode;
return p1->pNext;
};
void CList::AddNode(CNode* pnode)//在首部添加结点
{
if (pHead == 0) //如果是空链表,插入的结点是唯一的结点
{
pHead = pnode;
pnode->pNext = 0;
return;
}
else //否则,插入到链表首部
{
pnode->pNext = pHead;
pHead = pnode;
}
};
CNode* CList::DeleteNode(CNode* pnode)//删除一个指定的结点,返回该结点的指针
{
CNode* p1, *p2;
p1 = pHead;//指向首结点
while (p1 != pnode && p1->pNext != 0)//寻找要删除的结点
{
p2 = p1;//结点指针p2始终在p1的后面
p1 = p1->pNext;
}
if (p1 == pHead) //如果要删除的是首结点
{
pHead = pHead->pNext;//将首结点后移
return pnode;
}
p2->pNext = p1->pNext;//p1指向被删除的结点,将p2结点与p1后面的结点连接起来
return pnode;
}
CNode* CList::LookUp(CData& data)
//查找一个指定的数据,返回该数据所在结点在链表中的指针,若未找到返回0
{
CNode* p1 = pHead;
while (p1) //从头结点开始查找
{
if (p1->pData->Compare(data) == 0)
return p1; //找到返回结点指针
p1 = p1->pNext;
}
return 0;//搜索完整个链表之后,如果找不到,返回空指针0
}
void CList::ShowList()//打印整个链表数据
{
CNode* p1 = pHead;
while (p1)
{
p1->pData->Show();
p1 = p1->pNext;
}
}
void CList::DeleteList() //删除整个链表结点
{
CNode* p1, *p2;
p1 = pHead;
while (p1)
{
delete p1->pData;
p2 = p1;
p1 = p1->pNext;
delete p2;
}
pHead=NULL;
}
class CTelRecord :public CData//电话簿记录,为数据基类的公有派生类
{
private:
char szName[20];//电话簿的数据:姓名和电话号码
char szNumber[20];
time_t etime;
public:
CTelRecord()//构造函数
{
strcpy(szName, "\0");
strcpy(szNumber, "\0");
time(&etime);
}
CTelRecord(char* name, char* number)//构造函数
{
strcpy(szName, name);
strcpy(szNumber, number);
time(&etime);
}
void SetRecord(char* name, char* number)//输入数据函数
{
strcpy(szName, name);
strcpy(szNumber, number);
time(&etime);
}
int Compare(CData&);//比较函数,比较姓名
void Show();
//打印数据函数
};
int CTelRecord::Compare(CData& data) //比较姓名,供查找用,比较结果为1、0、-1
{
CTelRecord& temp = (CTelRecord&)data;
return strcmp(szName, temp.szName);
}
void CTelRecord::Show()//打印一个结点的数据
{
cout << setw(15) << szName << setw(15) << szNumber<< setw(30)<<ctime(&etime) << endl;
}
void AddRecord(CList& TelList) //将记录添加到链表中
{
CNode* pNode;
CTelRecord* pTel;
char szName[20], szNumber[20];
cout << "输入名字(输入0结束):";
cin.getline(szName, 20);
while (strcmp(szName, "0"))
{
cout << "输入电话号码:";
cin.getline(szNumber, 20);
pTel = new CTelRecord;//生成新的数据类对象
pTel->SetRecord(szName, szNumber);//数据类对象赋值
pNode = new CNode;//生成新的结点
pNode->InputData(pTel);//结点赋值
TelList.AddNode(pNode);//结点加入链表
cout << "输入姓名(输入0结束):";
cin.getline(szName, 20);
}
cout << endl << endl;
}
void DisplayRecord(CList& TelList) //显示全部链表数据
{
cout << setw(15) << "姓名" << setw(15) << "电话号码" << setw(15) << "录入时间" << endl;
TelList.ShowList();
cout << endl << endl;
}
void LookUpRecord(CList& TelList) //按照姓名查找电话簿数据
{
CNode* pLook;
char szName[20];
cout << "输入您需要查找的姓名(输入0结束):";
cin.getline(szName, 20);
while (strcmp(szName, "0"))
{
CTelRecord tele(szName, "0");//生成结点
pLook = TelList.LookUp(tele);//查找指定结点的数据
if (pLook)
{
cout << "在电话簿中找到" << szName << ",内容是" << endl;
pLook->ShowNode();
}
else
cout << "在电话簿中查找不到" << szName << "." << endl;
cout << "输入您需要查找的姓名(输入0结束):";
cin.getline(szName, 20);
}
cout << endl << endl;
system("pause");
}
void ModifyRecord(CList& TelList) //按照姓名查找电话簿数据
{
CNode* pLook;
char szName[20]="hello";
char tel[20];
while (strcmp(szName, "0"))
{
cout << "输入您需要修改的姓名(输入0结束):";
cin.getline(szName, 20);
if(!strcmp(szName, "0"))break;
CTelRecord tele(szName, "0");//生成结点
pLook = TelList.LookUp(tele);//查找指定结点的数据
if (pLook)
{
cout << "在电话簿中找到" << szName << ",内容是:" << endl;
pLook->ShowNode();
printf("输入新的姓名:\n");
cin.getline(szName, 20);
printf("输入电话号码:\n");
cin.getline(tel, 20);
CData*tmp = new CTelRecord(szName, tel);//创建更新数据
pLook->InputData(tmp);
cin.getline(tel, 20);
cout << "修改成功!\n";
}
else
{
cout << "在电话簿中查找不到" << szName << "." << endl;
}
}
cout << endl << endl;
system("pause");
}
void DeleteRecord(CList& TelList) //在链表中删除指定节点的数据
{
CNode* pLook;
char szName[20];
cout << "输入您需要删除的姓名(输入0结束):";
cin.getline(szName, 20);
while (strcmp(szName, "0"))
{
CTelRecord tele(szName, "0");
pLook = TelList.LookUp(tele);
if (pLook) //删除时应先查找出结点
{
cout << "在电话簿中找到" << szName << ",内容是:" << endl;
pLook->ShowNode();
TelList.DeleteNode(pLook);
cout << szName << "的资料已删除" << endl;
delete pLook;
}
else
cout << "在电话簿中查找不到" << szName << "." << endl;
cout << "输入您需要删除的名字(输入0结束):";
cin.getline(szName, 20);
}
cout << endl << endl;
}
void DestoryRecord(CList& TelList) //在清除链表数据
{
TelList.DeleteList();
fstream ifs("TELEPHONE.txt", ios::trunc);//删除文件重新创建
ifs.close();
cout << "清除成功!\n";
}
void StoreFile(CList& TelList)//将链表中的数据保存在文件中
{
ofstream outfile("TELEPHONE.txt", ios::binary);
if (!outfile)
{
cout << "数据文件打开错误,没有将数据存入文件!\n";
return;
}
CNode* pnode;
CTelRecord* pTel;
string strName, strNumber;
pnode = TelList.GetListHead();//取出链表首结点指针
while (pnode)
{
pTel = (CTelRecord*)pnode->GetData();//返回结点指向的数据域指针
outfile.write((char*)pTel, sizeof(CTelRecord));//将数据域写入文件
pnode = TelList.GetListNextNode(pnode);//去下一节点的指针
}
outfile.close();
}
void Operate(string& strChoice, CList& TelList)//根据主菜单选项进行操作
{
if (strChoice == "1")
AddRecord(TelList);
else if (strChoice == "2")
DisplayRecord(TelList);
else if (strChoice == "3")
LookUpRecord(TelList);
else if (strChoice == "4")
DeleteRecord(TelList);
else if (strChoice == "0")
StoreFile(TelList);
else if (strChoice == "5")
ModifyRecord(TelList);
else if (strChoice == "6")
DestoryRecord(TelList);
else
cout << "输入错误,请重新输入您的选择:";
}
void LoadFile(CList& TelList)//在程序开始首先查找有无数据文件,找到后读取文件数据
{
ifstream infile("TELEPHONE.txt", ios::binary);
if (!infile)
{
cout << "没有数据文件!\n\n";
}return;
CNode* pNode;
CTelRecord* pTel;
while (!infile.eof())
{
pTel = new CTelRecord; //定义数据域对象
infile.read((char*)pTel, sizeof(CTelRecord));
pNode = new CNode;
pNode->InputData(pTel);//数据域对象内容生成结点
TelList.AddNode(pNode);//将结点加入链表
}
TelList.DeleteNode(pNode);//由于文件的关系,多读了一次,所以将首结点删除
infile.close();
}
int main(void)
{
CList TelList; //定义链表类的对象
system("cls");
cout << "\t欢迎进入电话簿数据系统\n";
LoadFile(TelList); //从文件中输入数据
string strChoice; //接受主菜单选项
do
{
cout << "\t1.添加电话簿记录\n";
cout << "\t2.显示电话簿内容\n";
cout << "\t3.根据姓名查询电话簿数据\n";
cout << "\t4.根据姓名删除电话簿数据\n";
cout << "\t5.根据姓名修改电话簿数据\n";
cout << "\t6.清空电话簿数据\n";
cout << "\t0.退出系统\n";
cout << "请输入您的选择:";
cin >> strChoice;
cin.ignore();
Operate(strChoice, TelList);
} while (strChoice != "0");
cout << "\n\n\t欢迎再次使用电话簿数据系统\n\n";
return 0;
}