【练手小项目】简易通讯录:单链表实现

My Blog / 2024-07-19 / 原文

简易通讯录:单链表实现

结构描述:

#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;

class PeoNode {
private:
    string name;
    string sex;
    int age;
    string tele;
    string addr;

    PeoNode * next;

    //Provide Contact access;
    friend class Contact;
};

class Contact {
public:
    //初始化通讯录信息
    void initContact();
    //判空
    bool isEmpty();
    //添加联系人
    void addPeople();
    //打印通讯录信息
    void printContact();
    //根据联系人的姓名删除联系人
    void deleteByName(string & name);
    //根据姓名查找联系人
    PeoNode * searchByName(string & name);
    //根据姓名修改联系人的信息
    void modifyByName(string & name);
    //分配节点
    PeoNode * buyNode();
    //销毁
    void makeEmpty();
private:
    PeoNode * head;
};

初始化通讯录

把链表的头指针置空:

void Contact::init() {
    head = nullptr;
}

添加联系人

使用头插法添加联系人至链表中:

void Contact::addPeople() {
    PeoNode * newNode = buyNode();
    newNode->next = head;
    head = newNode;
}

分配节点

根据用户输入创建一个联系人节点,并返回节点。

PeoNode * Contact::buyNode() {
    //分配节点并判断是否成功
    PeoNode * newNode = new PeoNode();
    if (newNode == nullptr) {
        cout << "New Failed!\n";
        exit(-1);
    }
    
    //输入信息
    cout << "Please enter name:> "; getline(cin, newNode->name);
    cout << "Please enter sex:> "; getline(cin, newNode->sex);
    //cin.ignore()方法忽略掉在读取整数后可能残留在输入缓冲区中的换行符
    cout << "Please enter age:> "; cin >> newNode->age; cin.ignore();
    cout << "Please enter telephone:> "; getline(cin, newNode->tele);
    cout << "Please enter address:> "; getline(cin, newNode->addr);
	
    newNode->next = nullptr;
    
    return newNode;
}

打印通讯录

  • 表空:不允许操作

  • 非空:遍历并打印每一个元素

void Contact::printContact() {
    if (isEmpty()) {
        cout << "List Is Empty!\n";
        exit(-1);
    }
    
    //表头
    cout << "name" << "\t"
         << "sex" << "\t"
         << "age" << "\t"
         << "tele" << "\t"
         << "addr" << "\n";
    PeoNode * cur = head;
    while (cur != nullptr) {
        cout << cur->name << "\t"
             << cur->sex << "\t"
             << cur->age << "\t"
             << cur->tele << "\t"
             << cur->addr << "\n";
        cur = cur->next;
    }
}

查找联系人

根据联系人的名字查找。

  • 表空:报错
  • 非空:遍历查找,找到第一个名字匹配的,并返回节点指针,若到表尾还没有找到,则联系人不存在
PeoNode * Contact::searchByName(string & name) {
    if (isEmpty()) {
        cout << "List Is Empty!\n";
        exit(-1);
    }
    
    PeoNode * cur = head;
    while (cur != nullptr) {
        if (cur->name == name) {
            return cur;
        }
        //向后遍历
        cur = cur->next;
    }
    
    //没找到返回nullptr
    return nullptr;
}

删除联系人

  1. 根据名字查找
  2. 找到:删除
  3. 找不到:报告不存在
void Contact::deleteByName(string & name) {
    PeoNode * ret = searchByName(name);
    if (ret == nullptr) {
        cout << "People is Not Exist!\n";
        exit(-1);
    }

    //调整链表的关系
    PeoNode * cur = head;
    while (cur->next != ret) {
        cur = cur->next;
    }
    cur->next = ret->next;
    
    //释放节点
    delete ret;
    ret = nullptr;
}

修改联系人信息

  1. 根据名字查找
  2. 查找成功:修改
  3. 查找失败:返回错误
void Contact::modifyByName(string & name) {
    PeoNode * ret = searchByName(name);
    if (ret == nullptr) {
        cout << "Search Failed!\n";
        exit(-1);
    }
    
        //输入信息
    cout << "Please enter name:> "; getline(cin, ret->name);
    cout << "Please enter sex:> "; getline(cin, ret->sex);
    //cin.ignore()方法忽略掉在读取整数后可能残留在输入缓冲区中的换行符
    cout << "Please enter age:> "; cin >> ret->age; cin.ignore();
    cout << "Please enter telephone:> "; getline(cin, ret->tele);
    cout << "Please enter address:> "; getline(cin, ret->addr);
}

销毁

  • 表空:返回错误
  • 非空:一直头删,直至表空
void Contact::makeEmpty() {
    if (isEmpty()) {
        cout << "List Is Empty!\n";
        exit(-1);
    }
    
	while (!isEmpty()) {
        cout << head->name;
        //头删
        PeoNode * tmp = head;
        head = head->next;
        free(tmp);
        tmp = nullptr;
        
        cout << "has been poped!\n";
    }
    
    cout << "Make Empty Successfully!\n";
}

综上

Contact.hpp

#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;

class PeoNode {
private:
    string name;
    string sex;
    int age;
    string tele;
    string addr;

    PeoNode * next;

    //Provide Contact access;
    friend class Contact;
};

class Contact {
public:
    //初始化通讯录信息
    void initContact();
    //判空
    bool isEmpty();
    //添加联系人
    void addPeople();
    //打印通讯录信息
    void printContact();
    //根据联系人的姓名删除联系人
    void deleteByName(string & name);
    //根据姓名查找联系人
    PeoNode * searchByName(string & name);
    //根据姓名修改联系人的信息
    void modifyByName(string & name);
    //分配节点
    PeoNode * buyNode();
    //销毁
    void makeEmpty();
private:
    PeoNode * head;
};

Contact.cpp

#include "Contact.hpp"

void Contact::initContact() {
    head = nullptr;
}

bool Contact::isEmpty() {
    return head == nullptr;
}

void Contact::addPeople() {
    PeoNode * newNode = buyNode();
    newNode->next = head;
    head = newNode;
}

PeoNode * Contact::buyNode() {
    //分配节点并判断是否成功
    PeoNode * newNode = new PeoNode();
    if (newNode == nullptr) {
        cout << "New Failed!\n";
        exit(-1);
    }
    
    //输入信息
    cout << "Please enter name:> "; getline(cin, newNode->name);
    cout << "Please enter sex:> "; getline(cin, newNode->sex);
    //cin.ignore()方法忽略掉在读取整数后可能残留在输入缓冲区中的换行符
    cout << "Please enter age:> "; cin >> newNode->age; cin.ignore();
    cout << "Please enter telephone:> "; getline(cin, newNode->tele);
    cout << "Please enter address:> "; getline(cin, newNode->addr);
	
    newNode->next = nullptr;
    
    return newNode;
}

void Contact::printContact() {
    if (isEmpty()) {
        cout << "List Is Empty!\n";
        exit(-1);
    }
    
    //表头
    cout << "name" << "\t"
         << "sex" << "\t"
         << "age" << "\t"
         << "tele" << "\t"
         << "addr" << "\n";
    PeoNode * cur = head;
    while (cur != nullptr) {
        cout << cur->name << "\t"
             << cur->sex << "\t"
             << cur->age << "\t"
             << cur->tele << "\t"
             << cur->addr << "\n";
        cur = cur->next;
    }
}

PeoNode * Contact::searchByName(string & name) {
    if (isEmpty()) {
        cout << "List Is Empty!\n";
        exit(-1);
    }
    
    PeoNode * cur = head;
    while (cur != nullptr) {
        if (cur->name == name) {
            return cur;
        }
        //向后遍历
        cur = cur->next;
    }
    
    //没找到返回nullptr
    return nullptr;
}

void Contact::deleteByName(string & name) {
    PeoNode * ret = searchByName(name);
    if (ret == nullptr) {
        cout << "People is Not Exist!\n";
        exit(-1);
    }

    //调整链表的关系
    PeoNode * cur = head;
    while (cur->next != ret) {
        cur = cur->next;
    }
    cur->next = ret->next;
    
    //释放节点
    delete ret;
    ret = nullptr;
}

void Contact::modifyByName(string & name) {
    PeoNode * ret = searchByName(name);
    if (ret == nullptr) {
        cout << "Search Failed!\n";
        exit(-1);
    }
    
        //输入信息
    cout << "Please enter name:> "; getline(cin, ret->name);
    cout << "Please enter sex:> "; getline(cin, ret->sex);
    //cin.ignore()方法忽略掉在读取整数后可能残留在输入缓冲区中的换行符
    cout << "Please enter age:> "; cin >> ret->age; cin.ignore();
    cout << "Please enter telephone:> "; getline(cin, ret->tele);
    cout << "Please enter address:> "; getline(cin, ret->addr);
}

void Contact::makeEmpty() {
    if (isEmpty()) {
        cout << "List Is Empty!\n";
        exit(-1);
    }
    
	while (!isEmpty()) {
        cout << head->name;
        //头删
        PeoNode * tmp = head;
        head = head->next;
        free(tmp);
        tmp = nullptr;
        
        cout << "has been poped!\n";
    }
    
    cout << "Make Empty Successfully!\n";
}

踩坑

C++处理字符串输入用 std::getline() 方法

C++中 new 关键字为对象分配空间,并返回该对象的指针。