附加题、组链表与通讯录(期末模拟)【S】

11 篇文章 0 订阅

题目描述

组链表是一种常用的数据结构,它由数组加链表组成,往往用于信息检索中。

每个链表由n个链表结点组成,每个链表都有头结点,头结点不存放实际数据,纯粹作为一个索引。

所有链表的头结点组成一个数组,即数组的每个元素都是一个链表头结点,它的后面延伸着一个链表。

例如一个通讯录包含五个联系人,每个联系人都有姓名和电话,每个联系人都对应一个链表结点。

Tom 8111

Any 1222

Ken 2333

Kim 2444

Tim 8222

我们先创建一个数组包含26个链表头结点,对应26个大写字母。因为有五个联系人,因此创建五个链表结点

因为上述联系人的姓名的首字母为A\K\T,因此把五个链表结点分别加入到三个头结点之后,形成三个链表。

其他字母的头结点因为无联系人,所以是空链表。构成组链表如下所示

A--Any.1222

K--Kim.2444--Ken.2333

T--Tim.8222--Tom.8444

现在使用组链表来实现通讯录,通讯录是多个联系人的信息集合,每个联系人都包含姓名和电话属性。

每个联系人对应一个链表结点,姓名首字母相同的联系人放在同一个链表中。联系人的类定义基本写好,如下参考代码

通讯录的类界面如下代码,操作包括:

1、该类没有构造函数,使用输入函数Input实现数据的输入和通讯录的初始化

2、打印函数Print,输出整个通讯录,输出格式参考样本

3、插入新的联系人,重载运算符+=来实现,如果联系人姓名已经存在,则用新的电话覆盖旧电话

注意:插入采用头插法,即新结点直接插入头结点之后

4、查找联系人姓名,重载运算符()来实现,查找成功返回链表结点指针,失败返回NULL

5、合并两个通讯录,重载运算符+来实现,合并结果放在第一个通讯录中,即左操作数。

通讯录的合并实际上是两个相同首字母的链表合并。对于相同首字母的两个链表i和j合并过程如下:

1)第二个链表j从头开始,取出联系人信息,在第一个链表i中查找。

2)如果联系人已存在,则用第二个通讯录的电话覆盖第一个通讯录的电话

3)如果联系人不存在,则把联系人插入到第一个链表i中

程序要求

1、联系人类定义和通讯录的类定义仅供参考,可自行定义

2、主函数代码不能修改

3、必须使用组链表来实现通讯录

4、通讯录类的插入、查找、合并操作都必须基于链表结点来操作。

----参考代码----

const int hmax=26;

class Info { //联系人,用一个链表结点表示

string name; //姓名

int phoneNo; //电话

public:

Info* next;  //指向下一个结点

Info(string tn= "no name", int pno=0)

{name = tn;

phoneNo = pno;

next = NULL;

}

void Print()

{cout<<name<<"--"<<phoneNo<<endl;}

//属性的get和set方法....自行定义

};

class PhoneBook {//组链表方式实现通讯录

//....自行增加一些操作

//提示:把插入和查找先写成内部函数,再被运算符重载调用,会更方便

public:

Info Table[hmax];//链表头结点数组,对应26个大写字母

//以下定义五个操作:输入Input、打印Print、插入、合并、查找

//具体操作看前面说明

};

//...PhoneBook类成员函数,类外实现,自行编写

//----主函数----

int main()

{string tname;

int i, tno;

Info *p;

PhoneBook pb;

pb.Input(); //接收输入数据,初始化第一个通讯录

//两次姓名查找

for (i=0; i<2; i++)

{cin>>tname;

p = pb(tname); //调用()运算符,实现查找

if (p)p->Print(); //查找成功,输出联系人信息

else cout<<"查找失败"<<endl; //查找失败,输出提示信息

}

//一次插入

cin>>tname>>tno;

Info temp(tname, tno);

pb += temp; //调用+=运算符,实现插入新联系人

//通讯录合并

PhoneBook pc;

pc.Input(); //初始化第二个通讯录

pb = pb+pc; //调用+运算符,实现合并

pb.Print(); //输出所有操作后的通讯录

return 0;

}

输入

第一行输入n,表示第一个通讯录有n个联系人

接着n行,每行输入一个联系人的信息:姓名、电话

接着两行,每行输入一个联系人姓名,查找该联系人是否在通讯录中,并输出相应结果

接着一行,输入一个联系人的信息:姓名、电话,执行插入操作

接着一行,输入m,表示第二个通讯录有m个联系人

接着m行,每行输入一个联系人的信息:姓名、电话

输入完毕后,把第一个通讯录和第二个通讯录合并

假定联系人姓名都是英文字母,且首字母大写。

输出

按照主函数执行过程输出

示例输入1

4
Tom 8111
Any 1222
Ken 2333
Kim 2444
Any
Ben
Tim 8222
2
Tom 8444
Ann 1333

示例输出1

Any--1222
查找失败
A--Ann.1333--Any.1222--
K--Kim.2444--Ken.2333--
T--Tim.8222--Tom.8444--

CODE

#include <iostream>
using namespace std;

const int hmax=26;

class Info { //联系人,用一个链表结点表示
    string name; //姓名
    int phoneNo; //电话
public:
    Info* next;  //指向下一个结点
    Info(string tn= "no name", int pno=0)
    {
        name = tn;
        phoneNo = pno;
        next = NULL;
    }
    void setphone(int op){
        phoneNo=op;
    }
    string getname(){
        return name;
    }
    int getphone(){
        return phoneNo;
    }
    void Print()
    {cout<<name<<"--"<<phoneNo<<endl;}
//属性的get和set方法....自行定义
};

class PhoneBook {//组链表方式实现通讯录
//....自行增加一些操作
//提示:把插入和查找先写成内部函数,再被运算符重载调用,会更方便
public:
    Info Table[hmax];//链表头结点数组,对应26个大写字母
//以下定义五个操作:输入Input、打印Print、插入、合并、查找
    void Input(){
        for(int i=0;i<hmax;i++){
            Table[i]=Info();
        }
        int t;
        cin>>t;
        while(t--){
            string a;
            int b;
            cin>>a>>b;
            Info *res;
            res=new Info(a,b);
            res->next=Table[a[0]-'A'].next;
            Table[a[0]-'A'].next=res;
        }
    }
    Info* find(string op){
        Info *res;
        res=Table[op[0]-'A'].next;
        while(res!=NULL){
            if(res->getname()==op){
                return res;
            }
            res=res->next;
        }
        return res;
    }
    Info* operator()(string op){
        return find(op);
    }
    PhoneBook add(Info &r){
        Info *res= find(r.getname());
        if(res){
            res->setphone(r.getphone());
        }
        else{
            string qwe=r.getname();
            r.next=Table[qwe[0]-'A'].next;
            Table[qwe[0]-'A'].next=&r;
        }
        return *this;
    }
    PhoneBook operator+=(Info &r){
        return add(r);
    }
    void Print(){
        for(int i=0;i<hmax;i++){
            if(Table[i].next){
                Info *res=Table[i].next;
                cout<<res->getname()[0]<<"--";
                while(res){
                    cout<<res->getname()<<"."<<res->getphone()<<"--";
                    res=res->next;
                }
                cout<<endl;
            }
        }
    }
    PhoneBook operator+(PhoneBook &r){
        for(int i=0;i<hmax;i++){
            if(r.Table[i].next==NULL)
                continue;
            Info *res=r.Table[i].next;
//            cout<<res->getname()<<endl;
            while(res){
//                cout<<res->getname()<<endl;
                Info *tmp=find(res->getname());
                if(tmp){
                    tmp->setphone(res->getphone());
                }
                else {
                    //注意插入的变量需要重新new
                    Info *asd;
                    asd=new Info(res->getname(),res->getphone());
                    add(*asd);
                }
                res=res->next;
            }
//            cout<<endl;
        }
        return *this;
    }
//具体操作看前面说明
};

//...PhoneBook类成员函数,类外实现,自行编写
//----主函数----
int main()
{
    string tname;
    int i, tno;
    Info *p;
    PhoneBook pb;
    pb.Input(); //接收输入数据,初始化第一个通讯录
//两次姓名查找
    for (i=0; i<2; i++)
    {
        cin>>tname;
        p = pb(tname); //调用()运算符,实现查找
        if (p)p->Print(); //查找成功,输出联系人信息
        else cout<<"查找失败"<<endl; //查找失败,输出提示信息
//        else cout<<"9999999"<<endl; //查找失败,输出提示信息
    }
//一次插入
    cin>>tname>>tno;
    Info temp(tname, tno);
    pb += temp; //调用+=运算符,实现插入新联系人
//通讯录合并
    PhoneBook pc;
    pc.Input(); //初始化第二个通讯录
//    pc.Print();
//    cout<<endl;
    pb = pb+pc; //调用+运算符,实现合并
    pb.Print(); //输出所有操作后的通讯录
    return 0;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值