大二上 数据结构课设--双链表通讯录

一、前言

其实这次的数据结构课设写的不太好,因为学校提前放假,写课设和考试在一周之内了,本来想写飞机订票系统的,但是还是只能把综合实验改了改就交上去了。

1、运行环境

本程序使用c++编写,在vs2019上运行通过,最初使用vscode编写,但是由于设置控制台标题的函数有问题,就换到vs2019上用了

二、 实验内容

设计一个简单个人电话号码查询系统

1. 问题描述

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

2、基本要求

(1)在外存上,用文件保存电话号码信息;
(2)在内存中,设计数据结构存储电话信息;
(3)提供查询功能;根据姓名实现快速查询;
(4)提供其他功能,例如插入、删除、修改等;

三、本程序实现的功能

1.主要功能

(1)利用双向循环带头链表存储记录
(2)实现了简单的控制台记录列表翻页效果
(3)实现了增加、依据序号删除的功能
(4)实现了根据任意关键字查找记录的功能(注:目前只返回第一个匹配结果)
(5)实现了根据序号修改任意单条记录的功能
(6)实现了存储/读取的功能
(7)实现了根据任意关键字进行排序(升序/降序)的功能 —//使用冒泡排序

2.其他功能

(1)进行了对输入的一般检测,保证在一般情况下不会出问题
(2)使用控制台相关函数修改了界面大小和控制台文字颜色,比较好看
(3)写了记录的拷贝函数
(4)重载了结构体的输入运算符,方便读取信息和后续修改
(5)重载了输出运算符,方便修改,用了left/right/setw进行控制输出格式
(6)进行了一些边界值的测试,保证一般情况下不会出现问题

四、实验源码与运行结果

1.源代码

(1)funcs.h


#pragma once
#include<iostream>
#include<Windows.h>
using namespace std;

int ckerror()
{
    if (cin.fail())
    {
        cin.clear();
        cin.ignore(99999, '\n');
        return 1;
    }
    return 0;
}
void setCursorPos(COORD curpos)
{//固定点位输出

    HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);//获得窗口句柄
    SetConsoleCursorPosition(screen, curpos);//两个参数分别是指定哪个窗体,具体位置
}

void setCursorPos(short x,short y)
{//固定点位输出
    COORD curpos = { x,y };
    setCursorPos(curpos);
}

(2)main.cpp

#include<iostream>//输入输出
#include<iomanip>
#include<fstream>//文件
#include<Windows.h>

#include<stdlib.h>//调用system("cls")
#include<string.h>//需要使用string,strcmp();
#include<conio.h>//getch()
#include"funcs.h"
using namespace std;

const int g_max_record_per_page = 10;

struct TelNumber
{//电话存储结构体
    TelNumber();
    TelNumber(const TelNumber& newtel);
    string name;//
    string phone_number;
    string mobile_number;
    string email;
    TelNumber* prev, * next;
};

TelNumber::TelNumber()
{
    name = "0";
    phone_number = "0";
    mobile_number = "0";
    email = "0";
    prev = NULL;
    next = NULL;
}

TelNumber::TelNumber(const TelNumber& newtel)
{
    name = newtel.name;
    phone_number = newtel.phone_number;
    mobile_number = newtel.mobile_number;
    email = newtel.email;
    prev = NULL;
    next = NULL;
}

istream& operator>>(istream& sin, TelNumber& telnum)
{//重载输入运算符
    sin >> telnum.name
        >> telnum.phone_number
        >> telnum.mobile_number
        >> telnum.email;
    return sin;
}

ostream& operator<<(ostream& sout, TelNumber& telnum)
{//输出电话号码
    if (telnum.name.compare("0") == 0)
        sout <<left<<setw(20)<< "无名";
    else
        sout << left << setw(20)<<telnum.name;

    if (telnum.phone_number.compare("0") == 0)
        sout << left <<setw(20)<< "无";
    else
       sout << left << setw(20) << telnum.phone_number ;

    if (telnum.mobile_number.compare("0") == 0)
        sout << left << setw(19)<<"无";
    else
        sout << left << setw(19) << telnum.mobile_number ;

    if (telnum.email.compare("0") == 0)
        sout << left << setw(25) <<"无";
    else
        sout << left << setw(25) << telnum.email;
    sout << right;
    return sout;
}

class TelManager
{
public:
    TelManager();
    ~TelManager();
    int readData();//读取数据
    int saveData();
    int getMaxpage();
    int getRecordNum() { return tel_saved_num; }
    void showTelNumber(int record_id);
    void showTelNumberList(int page);//
    int addTelNumber(const TelNumber& newtel);//添加记录
    int getTelNumberBy(int search_type, string search_key, TelNumber& search_result);//搜索记录,返回待查数据的序号 search——key:搜索的值,search_type:搜索的数据的类型 search_result:搜索的结果
    int deleteTelNumber(int record_id);//删除记录,返回是1否0成功 record_id:待删除记录的序号
    
    int changeData(int record_id, TelNumber new_record);//修改数据,返回是1否0成功 record_id:待修改记录的序号,new_record:要修改为什么
    int sortData(int sort_key_type, int order_type);//以~排序数据 sort_key_type:排序依据 order_type:排序方向,1.升序 2降序      排序方法:
    int clearData();
private:
    void swap(TelNumber*& pnow, TelNumber*& pnext)
    {//冒泡交换
        pnow->prev->next = pnext;
        pnext->next->prev = pnow;//外接内
        pnow->next = pnext->next;
        pnext->prev = pnow->prev;//内接外
        pnext->next = pnow;
        pnow->prev = pnext;//自己接自己
        pnow = pnow->prev;
        pnext = pnext->next;//指针复位
    }
    TelNumber* head;//存储结构第一个数据的指针
    int tel_saved_num;//已保存数量
    int max_page;

    //SMALL_RECT
}Book;

TelManager::TelManager()
{//无参构造函数
    head = new TelNumber;
    head->prev = head;
    head->next = head;
    tel_saved_num = 0;
    readData();
}

TelManager::~TelManager()
{//析构函数
    head->prev->next = NULL;//断开连接
    TelNumber* pnow = head, * pt;
    while (pnow)
    {
        pt = pnow;
        pnow = pnow->next;
        delete pt;
    }
}

int TelManager::readData()
{//读取数据
    ifstream hasdata("telNumber.txt");//验证是否是第一次运行---验证telNumber.txt有没有
    int telnumber_count;
    TelNumber ttelnum;
    if (!hasdata.is_open())
    {//没有数据,重新创建文件
        ofstream newfile("telNumber.txt");
        newfile << 0;                         //输入记录个数
        newfile.close();
        return 0;
    }
    else
    {//有文件
        hasdata.close();
    }
    ifstream fin("telNumber.txt");
    fin >> telnumber_count;                   //读取记录个数
    for (int i = 0; i < telnumber_count; i++)
    {
        fin >> ttelnum;
        addTelNumber(ttelnum);
    }
    getMaxpage();
    return 1;
}

int TelManager::saveData()
{
    ofstream fout("telNumber.txt");
    fout << tel_saved_num << endl;
    if (tel_saved_num == 0)
    {
        fout.close();
        return 1;
    }

    TelNumber* pnow = head->next;
    while (pnow != head)
    {
        fout << pnow->name << ' '
            << pnow->phone_number << ' '
            << pnow->mobile_number << ' '
            << pnow->email << endl;
        pnow = pnow->next;
    }
    fout.close();
    return 1;
}

int TelManager::getMaxpage()
{
    if (tel_saved_num % g_max_record_per_page != 0)
    {
        max_page = tel_saved_num / g_max_record_per_page + 1;
    }
    else
    {
        max_page = tel_saved_num / g_max_record_per_page;
    }
    return max_page;
}

void TelManager::showTelNumber(int record_id)
{
    if (record_id > tel_saved_num)
        return;
    TelNumber* pnow = head->next;
    for (int i = 1; i < record_id; i++)
    {
        pnow = pnow->next;
    }
    cout << *pnow;
}

void TelManager::showTelNumberList(int current_page)
{
    int record_no = 0;
    cout << "----------------------------------------------------------------------------------------@" << endl;
    cout << "   姓名                  电话号码              手机号码                邮箱地址" << endl;
    cout << "---------------------------------------------------------------------------------------@ |" << endl;
    if (tel_saved_num == 0)
    {
        cout << "无数据...";
        return;
    }
    for (int i = (current_page - 1) * g_max_record_per_page + 1; i <= current_page * g_max_record_per_page; i++)
    {
        if (i > tel_saved_num)
            cout << endl;
        else
        {
            cout << setw(2) << record_no + 1 << '.';
            Book.showTelNumber(i);
            cout << '|'<<endl;
            cout << setw(90)<<'|'<<endl;
        }
        record_no++;
    }
    if (current_page > 1)
        cout << "<上一页(8)                           ";
    else
    {
        cout << "                                     ";
    }
    cout << "第" << current_page << '/' << max_page << "页";
    if (current_page < max_page)
        cout << "                           (9)下一页>";
    else
    {
        cout << "                                     ";
    }
}

int TelManager::addTelNumber(const TelNumber& newtel)
{//于末尾添加电话号
    TelNumber* pnow = head->prev;
    pnow->next = new TelNumber(newtel);
    pnow->next->prev = pnow;
    pnow->next->next = head;
    head->prev = pnow->next;
    tel_saved_num++;
    getMaxpage();
    return 1;
}

int TelManager::getTelNumberBy(int search_type, string search_key, TelNumber& search_result)
{
    if (tel_saved_num == 0)
    {
        return 0;
    }
    TelNumber* pnow = head->next;
    while (pnow != head)
    {
        switch (search_type)
        {
        case 1:
            if (pnow->name.compare(search_key) == 0)
            {
                search_result = *pnow;
                return 1;
            }
            break;
        case 2:
            if (pnow->phone_number.compare(search_key) == 0)
            {
                search_result = *pnow;
                return 1;
            }
            break;
        case 3:
            if (pnow->mobile_number.compare(search_key) == 0)
            {
                search_result = *pnow;
                return 1;
            }
            break;
        case 4:
            if (pnow->email.compare(search_key) == 0)
            {
                search_result = *pnow;
                return 1;
            }
            break;
        default:
            break;
        }
        pnow = pnow->next;
    }
    return 0;
}

int TelManager::deleteTelNumber(int record_id)
{//删除记录,依照序号record_id
    TelNumber* pnow = head->next;
    for (int i = 1; i < record_id; i++)
    {//找到要修改的数据,数据必存在,故不会删掉head
        pnow = pnow->next;
    }
    pnow->prev->next = pnow->next;
    pnow->next->prev = pnow->prev;
    delete pnow;
    tel_saved_num--;
    getMaxpage();
    return 1;
}

int TelManager::changeData(int record_id, TelNumber new_record)
{
    TelNumber* pnow = head->next;
    for(int count = 1;count < record_id;count++)
    {
        pnow = pnow->next;
    }
    if (new_record.name.compare("0") != 0)
    {
        pnow->name = new_record.name;
    }
    if (new_record.phone_number.compare("0") != 0)
    {
        pnow->phone_number = new_record.phone_number;
    }
    if (new_record.mobile_number.compare("0") != 0)
    {
        pnow->mobile_number = new_record.mobile_number;
    }
    if (new_record.email.compare("0") != 0)
    {
        pnow->email = new_record.email;
    }
    return 1;
}

int TelManager::sortData(int sort_key_type, int order_type)
{
    if (tel_saved_num < 2)
        return 1;
    bool need_sort = 1;
    int rest = tel_saved_num;
    TelNumber* pnow = head->next, * pnext = head->next->next;
    for (int i = 0; i < tel_saved_num -1; i++)
    {
        if (!need_sort)
            break;
        need_sort = 0;
        pnow = head->next, pnext = head->next->next;
        for (int j = 0; j < tel_saved_num - i - 1; j++)
        {
            switch (sort_key_type)
            {//处理当前数据
            case 1:
                if ((pnow->name.compare(pnext->name) > 0 && order_type == 1) ||
                    (pnow->name.compare(pnext->name) < 0 && order_type == 2))
                {//交换
                    swap(pnow, pnext);
                    need_sort = 1;
                }
                break;
            case 2:
                if ((pnow->phone_number.compare(pnext->phone_number) > 0 && order_type == 1) ||
                    (pnow->phone_number.compare(pnext->phone_number) < 0 && order_type == 2))
                {//交换
                    swap(pnow, pnext);
                    need_sort = 1;
                }
                break;
            case 3:
                if ((pnow->mobile_number.compare(pnext->mobile_number) > 0 && order_type == 1) ||
                    (pnow->mobile_number.compare(pnext->mobile_number) < 0 && order_type == 2))
                {//交换
                    swap(pnow, pnext);
                    need_sort = 1;
                }
                break;
            case 4:
                if ((pnow->email.compare(pnext->email) > 0 && order_type == 1) ||
                    (pnow->email.compare(pnext->email) < 0 && order_type == 2))
                {//交换
                    swap(pnow, pnext);
                    need_sort = 1;
                }
                break;
            default:
                break;
            }
            pnow = pnow->next;
            pnext = pnext->next;
        }
    }
    return 1;
}

int TelManager::clearData()
{
    TelNumber* pnow = head->next, * pt;
    while (pnow != head)
    {
        pt = pnow;
        pnow = pnow->next;
        delete pt;
    }
    head->next = head;
    head->prev = head;
    tel_saved_num = 0;
    getMaxpage();
    return 1;
}

void drawMenu()
{
    int page = 1;
    int option = -1;
    int search_type = 1, sort_type = 1, sort_order = 1;
    int change_no = 1,delete_no = 1;
    int clear_option = 1;
    string search_key;
    TelNumber newtel,search_result,changetel;
    while (1)
    {
        system("cls");
        
        cout << "---------------电话管理菜单-----------------@" << endl;
        cout << "1.添加记录                        2.搜索记录|" << endl;
        cout << "3.排序记录                        4.修改记录|" << endl;
        cout << "5.保存记录                        6.删除记录|" << endl;
        cout << "7.清空记录                        0.退出程序|" << endl;
        cout << "--------------------------------------------@" << endl;
        cout << "\n\n\n\n\n";
        Book.showTelNumberList(page);
        setCursorPos(0, 6);
        cout << "请输入您的选择:";
        cin >> option;
        cin.sync();//防止输入过多
        if (ckerror())
        {
            cout << "您的输入有误";
            continue;
        }
        switch (option)
        {
        case 1:
            cout << "请输入新记录的姓名,电话号码,手机号码和邮箱地址,如无请输入0:" << endl;
            cin >> newtel;
            cin.sync();//防止输入过多
            if (ckerror())
            {
                cout << "您的输入有误";
                continue;
            }
            if (Book.addTelNumber(newtel))
                cout << "添加成功";
            else
            {
                cout << "添加失败";
            }
            break;
        case 2:
            cout << "请选择您想搜索的关键词:1.姓名 2.电话号码 3.手机号码 4.邮箱:";
            cin >> search_type;
            cin.sync();//防止输入过多
            if (ckerror())
            {
                cout << "您的输入有误";
                continue;
            }
            if (search_type < 1 || search_type >4)
            {
                cout << "您输入的数字有误";
                break;
            }
            cout << "请输入您要查找的内容:";
            cin >> search_key;
            cin.sync();//防止输入过多
            if (ckerror())
            {
                cout << "您的输入有误";
                continue;
            }
            if (Book.getTelNumberBy(search_type, search_key, search_result))
            {
                cout << "找到记录:" << endl;
                cout << search_result;
            }
            else
            {
                cout << "没有找到记录";
            }
            break;
        case 3:
            cout << "请输入您想按照什么排序:1.姓名 2.电话号码 3.手机号码 4.邮箱:";
            cin >> sort_type;
            cin.sync();//防止输入过多
            if (ckerror())
            {
                cout << "您的输入有误";
                continue;
            }
            if (sort_type < 1 || sort_type >4)
            {
                cout << "您输入的数字有误";
                break;
            }
            cout << "请输入排序方式:1.升序 2.降序:";
            cin >> sort_order;
            cin.sync();//防止输入过多
            if (ckerror())
            {
                cout << "您的输入有误";
                continue;
            }
            if (sort_order < 1 || sort_order >2)
            {
                cout << "您输入的数字有误";
                break;
            }
            if (Book.sortData(sort_type, sort_order))
            {
                cout << "排序完成";
            }
            else
            {
                cout << "排序失败";
            }
            break;
        case 4:
            cout << "请输入想要修改的人的序号:";
            cin >> change_no;
            cin.sync();//防止输入过多
            if (ckerror())
            {
                cout << "您的输入有误";
                continue;
            }
            if (change_no < 1 || change_no > 20)
            {
                cout << "您输入的数字有误";
                break;
            }
            cout << "请输入新的数据,如果不需要修改就输入0,例如:0 0 10133224422 qwerrty@qqq.com意为修改后两项为给的值" << endl;;
            cin >> changetel;
            cin.sync();//防止输入过多
            if (ckerror())
            {
                cout << "您的输入有误";
                continue;
            }
            Book.changeData(change_no + (page - 1) * g_max_record_per_page, changetel);
            break;
        case 5:
            Book.saveData();
            break;
        case 6:
            cout << "请输入您想删除的数据的序号:";
            cin >> delete_no;
            cin.sync();//防止输入过多
            if (ckerror())
            {
                cout << "您的输入有误";
                continue;
            }
            if (delete_no < 1 || delete_no > 20|| (delete_no + (page - 1) * g_max_record_per_page) > Book.getRecordNum())
            {
                cout << "取消删除"<< endl;
                break;
            }
            if (Book.deleteTelNumber(delete_no + (page - 1) * g_max_record_per_page))
            {
                cout << "删除成功";
                if (Book.getMaxpage() < page)//若在最后一页删除后该页没有记录,翻到上一页
                    page = Book.getMaxpage();
            }
            else
            {
                cout << "删除失败";
            }
            break;
        case 7:
            cout << "您真的要清空吗?是1/否0";
            cin >> clear_option;
            cin.sync();//防止输入过多
            if (ckerror())
            {
                cout << "您的输入有误";
                continue;
            }
            if (clear_option == 1)
            {
                if (Book.clearData())
                {
                    cout << "删除成功";
                    page = 1;
                }
                else
                {
                    cout << "删除失败";
                }
            }
            break;
        case 8:
            page = page - 1 < 1 ? 1 : page - 1;
            break;
        case 9:
            page = page + 1 > Book.getMaxpage() ? Book.getMaxpage() : page + 1;
            break;
        case 0:
            return;
        default:
            break;
        }
        if (option != 8 && option != 9)
            _getch();
    }
}

void initWnd()
{//初始化窗口
    SetConsoleTitleW(L"电话查询系统<^-^>      ------by 计算机19-1张逸豪");      //设置标题,LPCWSTR Long Pointer to Const Wide_char String
    system("mode con cols=100 lines=35");   //26行,每行100字符
    system("color 0B");                     //设置
    HWND hwnd = GetConsoleWindow();
    LONG style = GetWindowLongPtrW(hwnd, GWL_STYLE);    //取得窗口类型 (define long LONG,类型是长整数)
    style &= ~(WS_MAXIMIZEBOX);                         /*位与去掉最大化按钮,WS意为WindowStyle,WS_MAXIMIZE = 0x00010000L
                                                        *此处是以16进制存储longint,longint 是32字节,最大值是2^31-1加一位符号,2^32正是16^8
                                                        *以longint的每一位存储窗口样式选项
                                                        */
                                                        //?如果同位存0x08000000L和0x02000000L不冲突吗,在二进制是不同的位吗
    style &= ~(WS_SIZEBOX);                             //去掉拖动修改大小,防止破坏结构,比较方便 WS_SIZEBOX = 0x00040000L
    SetWindowLong(hwnd, GWL_STYLE, style);
    ReleaseDC(hwnd, NULL);                              //释放空间
}

int main()
{
    initWnd();
    drawMenu();
    return 0;
}

(3)测试数据

注:测试数据属于虚构

telNumber.txt

33
TirRal 28853412 11122235123 OrIWillx_x@tt.com
杨静晨 28779493 10549631188 SilenTMoorn@tt.com
田馨婷 51396575 10432411575 seenTea@sqr4.com
乔岚风 22123405 10524558275 mtnWindY@jio.com
戴昕靓 86651842 10734669335 CyanDawn@dai.com
慎啸 15881436 10846156162 CareYel@msg.com
高叔 74464893 10458465682 mnSealw@qqw.com
浦辈 33349628 10145648958 shuiche@me.com
毛示 86213374 10855655878 Mosssss@ao.com
刘浩广 72144016 10374296783 Howgone@yui.com
周景铄 22941669 10757683235 SunFunz@zzz.com
江天瑞 32396731 10320981991 TerryJTR@mso.com
马英耀 46899638 10632297190 YueYouUM@mma.com
许致远 32165089 10967987285 PreMiss2FAr@qwa.com
高可心 51540484 10645688888 Hicocox@wel.com
张之双 28027814 10655964888 shellTwozZ@mms.com
杨馥 39871919 10156484887 fufuYanf@waw.com
黄可 79490088 10156489887 KingNok@mms.com
朱姝 34403188 10998766555 facepowder@zzz.com
史鸾 48030475 10488985499 sheLoved@waw.com
养嘉悦 51810455 10489785698 YoungJerry@wat.com
文思雁 91898380 10459898578 TK_spArrow@wel.com
逢春桃 62833858 10778489566 xhsNoCore@hh.com
宁生文 71589247 10145898656 whyBeme@haw.com
储村 82920192 10564884872 SavaLLAge@ww.com
从泉 84745558 10156482978 1supona_Spring@qqw.com
逯茗 45842515 10484858878 hardtoread@name.com
林汉 87482592 10548487897 Linkeeee@wqw.com
彭晋 56521132 10486455212 PenGUI@pg.com
孟评 15213564 10548479887 PaoMain@ww.com
方荷 15656222 10100010659 VeFor_Her@msg.com
秦梦泽 39826327 10646898447 QinMengZe8447@ww.com
曹鸿 42255895 10548654174 YanCC2000@waw.com

2、运行结果:

初始状态
如图,是程序运行的初始状态

在这里插入图片描述
如图,是有数据时进行查找的情况

五、总结

双链表这样用在查找太多数据的时有问题,其实可以记录当前的记录,直接传入最近10条数据之前的数据就能避免这种很慢的情况,但是因为时间有限,而且只是一次实验,所以就先不写出来了,这次实验里我做了一些尝试,感觉还不错。。
就是这样。

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值