数据结构(C++)——电话号码查询系统实现

报告内容开始

一、数据结构课程设计目标

《数据结构》是计算机专业一门重要的专业技术基础课程,是一门关键性核心课程。《数据结构》课程的目标是使学生学会分析研究计算机加工对象的特性,选择合适的数据结构和存储表示,以及编制相应的实现算法,培养和提高学生程序设计的能力。《数据结构》课程也是一门实践性较强的课程,设置实践环节是十分重要的。本课程设计的目标就是要达到理论与实际应用相结合,提高学生组织数据及编写大型程序的能力,并培养基本的、良好的程序设计技能以及合作能力。

二、问题描述

人们在日常生活中经常需要查找某个人或某个单位的电话号码,本实验将实现一个简单的个人电话号码查询系统,根据用户输入的信息(例如姓名等)进行快速查询。

三、需求分析

1. 需求

人们在日常生活中经常需要查找某个人或某个单位的电话号码,通过纸质记录或是电子文档记录会显得杂乱,并且难于管理维护。因此设计一个电话号码查询系统。

电话号码查询系统需要做到:

  1. 通过姓名进行电话号码查找
  2. 电话号码信息的插入
  3. 电话号码的删除
  4. 电话信息的修改
  5. 电话号码查询系统信息的排序

2. 对需求进行算法分析

电话号码查询系统程序运行结束会释放内存,导致插入信息丢失。如果要在程序运行结束后仍然保存电话号码信息,就需要将电话号码信息采用文件的形式存放到外存中。在系统运行时,需要将电话号码信息从文件调入内存来进行查找等操作就需要创建一个结构体接收文件数据。完成对电话号码的插入删除等操作使用对单链表的增删改查算法实现。利用起泡排序法对电话号码信息进行排序。

四、概要设计

如果要建立电话号码查询系统需要输入多个类型信息,例如姓名,电话号,邮箱等。所要求定义的数据类型不同,所以定义一个结构体封装各类型数据。将各个功能函数定义在一个类中。需要完成的功能有:插入,排序,删除,查找,修改,保存。要显示这些功能结果还需要有显示功能。

因为电话号码查询系统需要记录用户信息,即对输入的信息进行保存。所以在程序运行时应当有对外部数据处理的函数,即文件输入输出函数,需要在系统执行功能之前对外部内存进行检索,查找是否有记录信息的文件,如果有,则导入,如果没有,在程序运行保存数据后,应当建立一个外部存储文件用以存放用户输入信息,方便下次直接进行信息的读入、检索、阅览。

对程序进行概括设计,建立函数模块图,以及程序流程图。

函数模块思维导图如下:
主程序思维导图
程序流程图如下:
程序流程图

五、详细设计

1.结构体的定义

定义所需要的的结构变量,以及一些结构体函数,
具体算法实现及注释信息如下:

struct TeleNumber // 定义结构体类型;封装电话号码查询系统的信息
{
    char name[10]; // 姓名
    long long phoneNumber; // 固定电话号码
    long long mobileNumber; // 移动电话号码
    char email[30]; // 个人邮箱
    int s;
    TeleNumber* Next;//定义结构体指针
    void ReadFile(istream& in);//读入文件数据
    void input();      //键盘输入信息
    void display();    //DOS窗口信息显示
};
void TeleNumber::ReadFile(istream& in) // 从文件把数据读入到程序
{
    in >> name >> phoneNumber >> mobileNumber >> email;
}
void TeleNumber::input() // 信息输入
{
    cout << " 请输入姓名 " << endl;
    cin >> name;
    cout << " 请输入固定电话号码 " << endl;
    cin >> phoneNumber;
    cout << " 请输入移动电话号码 " << endl;
    cin >> mobileNumber;
    cout << " 邮箱 " << endl;
    cin >> email;
    s = j++;

}
void TeleNumber::display() // 在命令窗口显示信息
{
    cout << " 姓名 :" << name << '\t' << " 固定号码 :" << phoneNumber << '\t'
        << " 移动电话号码 :" << mobileNumber << " 邮箱 :" << email << '\t' << endl;
}

2.建立单链表,读取外部文件数据

使用头插法建立单链表
头插法是将新增结点插入到第一个结点之前,示意图如下:
头插法图解

使用到iostream、fstream头文件,定义读写操作

程序代码及注释如下:

TeleQuerySystem::TeleQuerySystem()
{
    Head = new TeleNumber; // 头插法建立单链表
    Head->Next = new TeleNumber;
    End = Head->Next;
    in.open("TeleNumber.txt"); // 打开外存文件,看是否有数据存在
    if (!in)
        cout << " 电话查询系统中没有任何信息,请输入信息 " << endl;
    else
    {
        while (!in.eof()) // 如果有,则打开,并将数据读取到程序
        {
            End->ReadFile(in);
            if (End->name[0] == '\0')break;
            End->Next = new TeleNumber;
            End = End->Next;
        }
        in.close();
        cout << " 读取电话号码查询系统成功 !" << endl;
    }
    cout << " 输入任意字符继续 " << endl;
    cin >> a;
}
TeleQuerySystem::~TeleQuerySystem() // 释放单链表
{
    TeleNumber* temp;
    while (Head->Next != End)
    {
        temp = Head->Next;
        Head = Head->Next;
        delete temp;
    }
    delete Head, End; // 删除头尾指针
}

3.主函数部分设计(查询系统首页菜单)

利用switch语句实现输入代号调用函数
程序代码及注释信息如下:

int main()
{
    bool flag = true;
    TeleQuerySystem tele;
    char name[20];
    while (flag)
    {
        system("cls");
        cout << "添加信息请按 1 " << endl;
        cout << "显示信息请按 2 " << endl; 
		cout << "排序信息请按 3 " << endl;
        cout << "查找信息请按 4 " << endl;
        cout << "删除信息请按 5 " << endl;
        cout << "修改信息请按 6 " << endl;
        cout << "保存信息请按 7 " << endl;
        cout << " 请输入代号: ";
        cin >> x;
        switch (x)//利用switch语句实现输入代号调用函数
        {
        case 0:flag = false; break;
        case 1:tele.Insert(); break;
        case 2:tele.Show(); break;
        case 3:tele.BubbleSort(); break;
        case 4:
            cout << " 请输入欲查找人的姓名 " << endl;
            cin >> name;
            tele.Search(name); break;
        case 5:tele.Delete(); break;
        case 6:tele.Change(); break;
        case 7:tele.FileSave(); break;
        }
        cout << " 输入任意字母返回 " << endl;
        cin >> a;
    }
    return 0;
}

4.子函数调用(各个功能的具体实现函数)

(1) 链表插入函数Insert()【实现新信息的添加】

调用结构体内封装函数input实现键入信息插入链表结点
程序代码以及注释信息如下:

void TeleQuerySystem::Insert() // 插入
{
    End->input(); // 从单链表尾部插入
    End->Next = new TeleNumber;
    End = End->Next;
    cout << endl << " 插入信息成功 " << endl;
}

(2) 显示函数Show()

调用结构体内封装函数display实现键入信息插入链表结点
程序代码及注释信息如下:

void TeleQuerySystem::Show()//显示
{
    TeleNumber* p = Head->Next;

    if (p != End) {
        printf("\n电话查询系统内所有信息如下:\n\n");
        for (; p != End; p = p->Next)
            p->display();
    }
    else cout << " 没有信息,请先输入 " << endl;
}

(3) 排序函数BubbleSort()

排序函数我使用起泡排序法。通过比较电话号码进行排序。排序方法是对一个结点A的电话号码信息与下一个结点B电话号码信息进行比较,若A>B,则进行信息交换。再与下一个结点C进行比较,如此往复比较n-1趟结束。
对信息交换,需要定义一个数据域交换函数进行两个结点间的数据交换,我们使用函数 strcpy

程序代码及注释信息如下:

void TeleQuerySystem::BubbleSort() // 起泡排序主体
{
    TeleNumber* p = NULL, * q = NULL;
    int exchange = j - 1;
    int bound;
    int i;
    while (exchange)
    {
        bound = exchange;
        exchange = 0;
        for (p = Head->Next, i = 1; i < bound; i++, p = p->Next)
            if (p->mobileNumber > p->Next->mobileNumber)
            {
                Swap(p, p->Next); // 调用交换函数
                exchange = p->s;
            }
    }
    Show();//调用显示函数显示结果
}
void TeleQuerySystem::Swap(TeleNumber* p1, TeleNumber* p2) // 两个类对象数据域进行交换
{
    TeleNumber* temp = new TeleNumber;
    strcpy_s(temp->name, p1->name);
    temp->mobileNumber = p1->mobileNumber;
    temp->phoneNumber = p1->phoneNumber;
    strcpy_s(temp->email, p1->email);
    temp->s = p1->s;
    strcpy_s(p1->name, p2->name);
    p1->mobileNumber = p2->mobileNumber;
    p1->phoneNumber = p2->phoneNumber;
    strcpy_s(p1->email, p2->email);
    p1->s = p2->s;
    strcpy_s(p2->name, temp->name);
    p2->mobileNumber = temp->mobileNumber;
    p2->phoneNumber = temp->phoneNumber;
    strcpy_s(p2->email, temp->email);
    p2->s = temp->s;
}

(4) 信息查询函数Search()

信息查询函数是对姓名进行查询,对单链表所有结点,从头结点开始进行遍历。用strcmp字符串比较函数对名字这个字符数组进行比较,若相等,则调用display输出该结点p对应的信息。不存在则输出“查无此人”。

程序代码及注释信息如下:

TeleNumber* TeleQuerySystem::Search(char* name)
{
    for (TeleNumber* p = Head->Next; p != End; p = p->Next)
        if (!strcmp(p->name, name))
        {
            if (x == 4)
            {
                p->display();
                return p;
            }
            else
                return p;
        }
    if (x == 4)
        cout << " 查无此人 " << endl;
    return 0;

}

(5) 删除函数Delete()

删除函数使用单链表删除操作完成。思想:为找出要删除的结点p(2结点),将前驱结点pre(1结点)的下一结点指向所要删除的结点p的下一结点temp(3结点)。
示意图如下:
链表删除图解

程序代码及注释信息如下:

void TeleQuerySystem::Delete() // 删除
{
    char name[20];
    TeleNumber* p = new TeleNumber, * temp = NULL;
    cout << " 请输入要删除人的姓名 :" << endl;
    cin >> name;
    p->Next = Search(name); // 先进行查找,找到所要删除的结点
    if (Search(name))
    {
        temp = p->Next;
        p->Next = p->Next->Next; // 摘链
        delete temp;
        cout << "\t\t 删除成功 !" << endl;
    }
    else
    {
        cout << "\t\t 没有找到 !" << endl;
    }
}

(6) 修改函数Change()

修改信息的函数是使用查询函数对需要修改的姓名进行查询,查询到的链表结点(姓名所对应信息)调用input函数重新输入信息。

程序代码及注释信息如下:

void TeleQuerySystem::Change() // 修改信息
{
    char name[20];
    cout << " 请输入要修改的人的姓名 :";
    cin >> name;
    if (Search(name))
    {
        cout << "\t\t 已找到个人的信息,请输入新的信息 !" << endl;
        Search(name)->input();
        cout << " 修改成功! " << endl;
    }
    else
    {
        cout << "\t\t 没有找到 !" << endl;
    }
}

(7) 文件保存函数FileSave()

文件保存函数即利用iostream和fstream头文件将链表信息值循环依次导入到外部存储文件中。
程序代码及注释信息如下:

void TeleQuerySystem::FileSave() // 保存文件
{
    out.open("TeleNumber.txt"); // 建立外存文件 TeleNumber.txt 
    for (TeleNumber* p = Head->Next; p != End; p = p->Next)
        out << p->name << "\t" << p->phoneNumber << "\t" << p->mobileNumber << "\t" << p->email << endl; // 将数据存到外存文件里
    out.close();
    cout << " 保存成功! " << endl;
}

六、软件说明书(给出软件如何使用,使用时的注意事项)

软件使用过程: 使用集成编译软件运行TeleQuerySystem.cpp文件 程序运行成功后首页显示
  • 初次运行该程序会显示如下字段:
电话查询系统中没有任何信息,请输入信息
请输入任意字段继续:
  • 对电话号信息进行保存后再次运行程序会显示如下:
读取电话号码查询系统成功!
请输入任意字段继续:
  • 出现“输入任意字符继续”后随意输入一个字符跳转到主页菜单栏

主页菜单栏的使用

主页菜单栏显示如下:

	添加信息请按1
	显示信息请按2
	排序信息请按3
	查找信息请按4
	删除信息请按5
	修改信息请按6
 	保存信息请按7
 输入代号:
  • 使用主页菜单栏需要根据所需要使用的功能,键入对应的数字。
    例如:我们需要插入信息,就使用键盘键入1,进入信息添加模块,根据提示输入信息即可,信息输入完成后键入回车(Enter键)完成插入信息操作。操作过程图如下:
  • 在显示插入信息成功,显示“输入任意字符返回”字段后键入一个字符后返回主页菜单栏。
    其他功能实现同理。
  • 最后键入7,以文件形式保存数据至外存中,文件名为“TeleNumber.txt”。

注意事项

  • 这里我使用的是Visual Stdio
    2019,使用VC6.0需要将代码第146、149、151、154、156、159行的strcpy_s改为strcpy。这是因为在VC++2005和VS2013版本后引入了函数后缀” _s ” 使得原函数更加安全,老版本编译器没有引入该后缀会导致编译出错。
  • 在显示“输入任意字符继续”字段时切忌输入大于单个字符的字符串,否则会出现异常
  • 在对数据信息进行增删改查后如果没有保存信息而关闭程序,会导致本次信息修改数据丢失

七、测试报告

八、心得体会

参考文献:《数据结构(C语言版)清华大学出版社.严蔚敏》

报告内容结束

因为疫情原因,所以课程设计原本时限一周压缩至一天。很多功能实现有欠缺。可以适量更改一下。例如:

  • 电话号码可以定义为字符数组类型,这样对排序功能实现会很方便。至今我排序功能实现都有问题,原因不明,只怪自己学艺不精,不过你们帮我提出来我也不会介意,哎嘿…
  • 在插入信息时,需要重复退回主页菜单栏,重新选择插入功能再进行插入,每插入一条数据都要重复进行此操作,删除操作亦是如此。操作过于繁杂。
  • 在插入信息时,需要重复退回主页菜单栏,重新选择插入功能再进行插入,每插入一条数据都要重复进行此操作,删除操作亦是如此。操作过于繁杂。
  • 当进行信息删除时,依然只能删除多个同名结点的最靠前结点的数据。
  • 当信息出现重复时,没有良好的查重算法进行约束。

源码文件+论文报告:源文件下载

  • 48
    点赞
  • 335
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值