当前位置: 首页 > news >正文

C++课设:通讯录管理系统(vector、map协作实现)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》
创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)
专栏介绍:《编程项目实战》

目录

    • 一、为什么选择C++开发通讯录系统?
      • 1. C++的现状
      • 2. STL标准模板库的威力
    • 二、系统架构设计与STL容器选型
      • 1. 三层架构设计
      • 2. STL容器选型的智慧
      • 3. 系统架构图解
    • 三、完整代码及功能详解
      • 1. 完整代码
      • 2. 核心功能详解
    • 四、STL容器的巧妙运用
      • 1. vector:动态数组的艺术
      • 2. map:红黑树的高效查找
      • 3. 双容器协作的设计模式
      • 4. STL算法的强大助力
    • 五、用户体验与界面优化
      • 1. 美观的界面设计
      • 2. 智能的错误处理
      • 3. 数据展示的艺术
    • 六、总结与建议
      • 1. 项目亮点总结
      • 2. 性能优化建议
      • 3. 学习收获与启发

在移动互联网时代,通讯录管理系统看似简单,但背后蕴含着丰富的数据结构与算法知识。本文将带你从零构建一个现代化的C++通讯录系统,重点探索STL容器的巧妙运用,让你的代码既高效又优雅!

一、为什么选择C++开发通讯录系统?

在这个Python、JavaScript满天飞的时代,为什么我们还要用C++来开发通讯录系统呢?答案很简单:因为它依然是性能之王!

1. C++的现状

根据最新的JetBrains开发者调查报告显示,C++作为一门有40多年历史的"老将",依然在关键战场上发光发热。特别是在嵌入式系统、游戏开发、金融科技等对性能要求极高的领域,C++始终占据着不可替代的地位。

2. STL标准模板库的威力

STL(Standard Template Library) 是C++的核心优势之一。STL提供了一套功能强大的模板类和函数集合,包括容器、算法、迭代器等六大组件,让我们可以:

  • 高效管理数据vectormap等容器经过高度优化
  • 简化开发流程:不用重复造轮子,专注业务逻辑
  • 保证代码质量:经过无数项目验证的稳定性

二、系统架构设计与STL容器选型

想象一下,你要设计一座图书馆,你需要考虑:书籍怎么存放?如何快速找到某本书?同样,设计通讯录系统也需要巧妙的架构。

1. 三层架构设计

我们的系统采用经典的三层架构

  • 用户界面层:负责与用户交互,处理输入输出
  • 业务逻辑层:核心功能实现,包含AddressBookContact
  • 数据存储层:基于STL容器的高效数据管理

2. STL容器选型的智慧

这里是最关键的设计决策!我们选择了双剑合璧的方案:

1️⃣vector<Contact> - 主存储容器

vector<Contact> contacts;  // 存储所有联系人

为什么选择vector?

  • 连续内存存储,访问速度快如闪电
  • 动态扩容,不用担心容量限制
  • 支持随机访问,可以直接通过下标操作

2️⃣map<string, int> - 快速索引

map<string, int> nameIndex;   // 姓名索引
map<string, int> phoneIndex;  // 电话索引  

为什么用map做索引?

  • 红黑树实现,查找复杂度O(log n)
  • 自动排序,key值始终有序
  • 高效插入删除,维护成本低

3. 系统架构图解

通过下面的架构图,你可以直观地看到各个组件是如何协作的:

在这里插入图片描述

三、完整代码及功能详解

现在进入最激动人心的部分——看看这些功能是如何一步步实现的!

1. 完整代码

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <iomanip>
#include <cctype>using namespace std;// 联系人类
class Contact {
private:string name;        // 姓名string phone;       // 电话号码string email;       // 邮箱string address;     // 地址public:// 构造函数Contact() {}Contact(const string& n, const string& p, const string& e = "", const string& a = "") : name(n), phone(p), email(e), address(a) {}// 获取器string getName() const { return name; }string getPhone() const { return phone; }string getEmail() const { return email; }string getAddress() const { return address; }// 设置器void setName(const string& n) { name = n; }void setPhone(const string& p) { phone = p; }void setEmail(const string& e) { email = e; }void setAddress(const string& a) { address = a; }// 显示联系人信息void display() const {cout << left << setw(15) << name << setw(15) << phone << setw(25) << email << setw(30) << address << endl;}// 详细显示void displayDetailed() const {cout << "姓名: " << name << endl;cout << "电话: " << phone << endl;cout << "邮箱: " << email << endl;cout << "地址: " << address << endl;cout << string(40, '-') << endl;}
};// 通讯录管理类
class AddressBook {
private:vector<Contact> contacts;           // 存储所有联系人map<string, int> nameIndex;        // 姓名索引map<string, int> phoneIndex;       // 电话索引// 更新索引void updateIndexes() {nameIndex.clear();phoneIndex.clear();for (size_t i = 0; i < contacts.size(); ++i) {nameIndex[contacts[i].getName()] = i;phoneIndex[contacts[i].getPhone()] = i;}}// 字符串转小写(用于不区分大小写的搜索)string toLowerCase(const string& str) const {string result = str;transform(result.begin(), result.end(), result.begin(), ::tolower);return result;}public:// 添加联系人bool addContact(const Contact& contact) {// 检查是否已存在相同姓名或电话if (nameIndex.find(contact.getName()) != nameIndex.end()) {cout << "错误: 姓名 '" << contact.getName() << "' 已存在!" << endl;return false;}if (phoneIndex.find(contact.getPhone()) != phoneIndex.end()) {cout << "错误: 电话号码 '" << contact.getPhone() << "' 已存在!" << endl;return false;}contacts.push_back(contact);updateIndexes();cout << "联系人添加成功!" << endl;return true;}// 根据姓名查找联系人Contact* findByName(const string& name) {map<string, int>::iterator it = nameIndex.find(name);if (it != nameIndex.end()) {return &contacts[it->second];}return NULL;}// 根据电话查找联系人Contact* findByPhone(const string& phone) {map<string, int>::iterator it = phoneIndex.find(phone);if (it != phoneIndex.end()) {return &contacts[it->second];}return NULL;}// 模糊搜索(按姓名)vector<Contact*> searchByName(const string& keyword) {vector<Contact*> results;string lowerKeyword = toLowerCase(keyword);for (size_t i = 0; i < contacts.size(); ++i) {string lowerName = toLowerCase(contacts[i].getName());if (lowerName.find(lowerKeyword) != string::npos) {results.push_back(&contacts[i]);}}return results;}// 删除联系人(根据姓名)bool deleteByName(const string& name) {map<string, int>::iterator it = nameIndex.find(name);if (it != nameIndex.end()) {contacts.erase(contacts.begin() + it->second);updateIndexes();cout << "联系人删除成功!" << endl;return true;}cout << "未找到姓名为 '" << name << "' 的联系人!" << endl;return false;}// 删除联系人(根据电话)bool deleteByPhone(const string& phone) {map<string, int>::iterator it = phoneIndex.find(phone);if (it != phoneIndex.end()) {contacts.erase(contacts.begin() + it->second);updateIndexes();cout << "联系人删除成功!" << endl;return true;}cout << "未找到电话为 '" << phone << "' 的联系人!" << endl;return false;}// 按姓名排序void sortByName() {sort(contacts.begin(), contacts.end(), NameComparator());updateIndexes();cout << "已按姓名排序!" << endl;}// 按电话排序void sortByPhone() {sort(contacts.begin(), contacts.end(), PhoneComparator());updateIndexes();cout << "已按电话号码排序!" << endl;}// 显示所有联系人void displayAll() const {if (contacts.empty()) {cout << "通讯录为空!" << endl;return;}cout << "\n" << string(85, '=') << endl;cout << "                           通讯录列表" << endl;cout << string(85, '=') << endl;cout << left << setw(15) << "姓名" << setw(15) << "电话" << setw(25) << "邮箱" << setw(30) << "地址" << endl;cout << string(85, '-') << endl;for (size_t i = 0; i < contacts.size(); ++i) {contacts[i].display();}cout << string(85, '=') << endl;cout << "总计: " << contacts.size() << " 个联系人" << endl;}// 获取联系人数量int getContactCount() const {return contacts.size();}// 比较器类(用于排序)struct NameComparator {bool operator()(const Contact& a, const Contact& b) const {return a.getName() < b.getName();}};struct PhoneComparator {bool operator()(const Contact& a, const Contact& b) const {return a.getPhone() < b.getPhone();}};
};// 显示主菜单
void showMenu() {cout << "\n" << string(50, '=') << endl;cout << "           通讯录管理系统" << endl;cout << string(50, '=') << endl;cout << "1. 添加联系人" << endl;cout << "2. 查找联系人" << endl;cout << "3. 删除联系人" << endl;cout << "4. 显示所有联系人" << endl;cout << "5. 按姓名排序" << endl;cout << "6. 按电话排序" << endl;cout << "7. 模糊搜索" << endl;cout << "0. 退出系统" << endl;cout << string(50, '-') << endl;cout << "请选择操作 (0-7): ";
}// 添加联系人
void addContactMenu(AddressBook& book) {string name, phone, email, address;cout << "\n=== 添加联系人 ===" << endl;cout << "请输入姓名: ";cin.ignore();getline(cin, name);cout << "请输入电话: ";getline(cin, phone);cout << "请输入邮箱 (可选): ";getline(cin, email);cout << "请输入地址 (可选): ";getline(cin, address);Contact newContact(name, phone, email, address);book.addContact(newContact);
}// 查找联系人菜单
void searchContactMenu(AddressBook& book) {int choice;cout << "\n=== 查找联系人 ===" << endl;cout << "1. 按姓名查找" << endl;cout << "2. 按电话查找" << endl;cout << "请选择查找方式: ";cin >> choice;if (choice == 1) {string name;cout << "请输入姓名: ";cin.ignore();getline(cin, name);Contact* contact = book.findByName(name);if (contact) {cout << "\n找到联系人:" << endl;contact->displayDetailed();} else {cout << "未找到姓名为 '" << name << "' 的联系人!" << endl;}} else if (choice == 2) {string phone;cout << "请输入电话: ";cin.ignore();getline(cin, phone);Contact* contact = book.findByPhone(phone);if (contact) {cout << "\n找到联系人:" << endl;contact->displayDetailed();} else {cout << "未找到电话为 '" << phone << "' 的联系人!" << endl;}} else {cout << "无效的选择!" << endl;}
}// 删除联系人菜单
void deleteContactMenu(AddressBook& book) {int choice;cout << "\n=== 删除联系人 ===" << endl;cout << "1. 按姓名删除" << endl;cout << "2. 按电话删除" << endl;cout << "请选择删除方式: ";cin >> choice;if (choice == 1) {string name;cout << "请输入要删除的姓名: ";cin.ignore();getline(cin, name);book.deleteByName(name);} else if (choice == 2) {string phone;cout << "请输入要删除的电话: ";cin.ignore();getline(cin, phone);book.deleteByPhone(phone);} else {cout << "无效的选择!" << endl;}
}// 模糊搜索菜单
void fuzzySearchMenu(AddressBook& book) {string keyword;cout << "\n=== 模糊搜索 ===" << endl;cout << "请输入搜索关键词: ";cin.ignore();getline(cin, keyword);vector<Contact*> results = book.searchByName(keyword);if (results.empty()) {cout << "没有找到包含 '" << keyword << "' 的联系人!" << endl;} else {cout << "\n搜索结果 (共 " << results.size() << " 个):" << endl;cout << string(85, '-') << endl;cout << left << setw(15) << "姓名" << setw(15) << "电话" << setw(25) << "邮箱" << setw(30) << "地址" << endl;cout << string(85, '-') << endl;for (size_t i = 0; i < results.size(); ++i) {results[i]->display();}}
}// 主函数
int main() {AddressBook book;int choice;// 添加一些示例数据book.addContact(Contact("张三", "13800138000", "zhangsan@email.com", "北京市朝阳区"));book.addContact(Contact("李四", "13900139000", "lisi@email.com", "上海市浦东新区"));book.addContact(Contact("王五", "13700137000", "wangwu@email.com", "广州市天河区"));cout << "欢迎使用通讯录管理系统!" << endl;cout << "已预置 " << book.getContactCount() << " 个示例联系人" << endl;while (true) {showMenu();cin >> choice;switch (choice) {case 1:addContactMenu(book);break;case 2:searchContactMenu(book);break;case 3:deleteContactMenu(book);break;case 4:book.displayAll();break;case 5:book.sortByName();break;case 6:book.sortByPhone();break;case 7:fuzzySearchMenu(book);break;case 0:cout << "感谢使用通讯录管理系统,再见!" << endl;return 0;default:cout << "无效的选择,请重新输入!" << endl;break;}cout << "\n按任意键继续...";cin.ignore();cin.get();}return 0;
}

界面预览:

在这里插入图片描述

2. 核心功能详解

1️⃣联系人类设计

首先,我们需要一个Contact类来表示联系人:

class Contact {
private:string name;        // 姓名string phone;       // 电话号码  string email;       // 邮箱string address;     // 地址public:// 构造函数Contact(const string& n, const string& p, const string& e = "", const string& a = "") : name(n), phone(p), email(e), address(a) {}// 获取器方法string getName() const { return name; }string getPhone() const { return phone; }// ... 其他方法
};

设计亮点:

  • 使用私有成员变量保证数据封装
  • 提供公有访问器方法确保接口清晰
  • 默认参数让构造更灵活

2️⃣添加联系人

防重复的智慧

bool addContact(const Contact& contact) {// 检查重复:姓名和电话都不能重复if (nameIndex.find(contact.getName()) != nameIndex.end()) {cout << "错误: 姓名已存在!" << endl;return false;}contacts.push_back(contact);updateIndexes();  // 更新索引return true;
}

核心思路:

  • 先检查,再添加:避免数据重复
  • 双重索引验证:姓名和电话都要唯一
  • 原子操作:要么成功,要么失败,不存在中间状态

3️⃣快如闪电的查找功能

Contact* findByName(const string& name) {auto it = nameIndex.find(name);if (it != nameIndex.end()) {return &contacts[it->second];  // 通过索引直接定位}return nullptr;
}

技术解析:

  • 利用mapO(log n)查找效率
  • 索引映射:map存储的是在vector中的位置
  • 一次查找定位:不需要遍历整个容器

4️⃣模糊搜索的人性化体验

vector<Contact*> searchByName(const string& keyword) {vector<Contact*> results;string lowerKeyword = toLowerCase(keyword);for (size_t i = 0; i < contacts.size(); ++i) {string lowerName = toLowerCase(contacts[i].getName());if (lowerName.find(lowerKeyword) != string::npos) {results.push_back(&contacts[i]);}}return results;
}

用户体验优化:

  • 大小写不敏感:输入"zhang"也能找到"Zhang"
  • 子串匹配:输入"李"可以找到"李明"、"李华"等
  • 返回指针集合:避免不必要的对象拷贝

四、STL容器的巧妙运用

这一章是技术含金量最高的部分,让我们深入探索STL的精妙之处!

1. vector:动态数组的艺术

为什么不用传统数组?

传统的C风格数组有诸多限制:

  • 固定大小,无法动态扩容
  • 没有边界检查,容易越界
  • 缺乏STL算法支持

vector就像是超级进化版的数组

vector<Contact> contacts;  // 自动管理内存
contacts.push_back(newContact);  // 自动扩容
contacts.size();  // 获取实际大小
contacts[index];  // 支持下标访问

内存管理的智慧:

  • 自动扩容:当容量不足时,vector会申请更大空间(通常是原来的2倍)
  • 连续存储:所有元素在内存中连续排列,缓存友好
  • RAII机制:析构时自动释放内存,避免内存泄漏

2. map:红黑树的高效查找

map在C++ STL中是一个关联容器,基于自平衡二叉搜索树(特别是红黑树)实现,这保证了:

  • 查找效率:O(log n)时间复杂度
  • 自动排序:键值始终保持有序
  • 稳定性能:无论数据如何插入,性能都很稳定
map<string, int> nameIndex;
// 插入:O(log n)
nameIndex["张三"] = 0;
// 查找:O(log n)  
auto it = nameIndex.find("张三");
// 删除:O(log n)
nameIndex.erase("张三");

3. 双容器协作的设计模式

这是我们系统的核心创新

class AddressBook {
private:vector<Contact> contacts;           // 主存储map<string, int> nameIndex;        // 姓名索引map<string, int> phoneIndex;       // 电话索引void updateIndexes() {nameIndex.clear();phoneIndex.clear();for (size_t i = 0; i < contacts.size(); ++i) {nameIndex[contacts[i].getName()] = i;phoneIndex[contacts[i].getPhone()] = i;}}
};

设计优势:

  • vector负责存储:利用连续内存的高效访问
  • map负责索引:提供快速查找能力
  • 智能同步:修改时自动更新所有索引

4. STL算法的强大助力

STL不仅提供容器,还有丰富的算法库:

// 排序算法
sort(contacts.begin(), contacts.end(), NameComparator());// 查找算法  
auto it = find_if(contacts.begin(), contacts.end(), [&](const Contact& c) { return c.getName() == name; });// 转换算法
transform(name.begin(), name.end(), name.begin(), ::tolower);

算法优势:

  • 高度优化:经过无数次优化的高效实现
  • 泛型设计:适用于所有符合条件的容器
  • 标准化:代码更易读、易维护

五、用户体验与界面优化

好的系统不仅要技术过硬,还要有出色的用户体验。让我们看看如何让用户爱上我们的通讯录!

1. 美观的界面设计

void showMenu() {cout << "\n" << string(50, '=') << endl;cout << "           通讯录管理系统" << endl;cout << string(50, '=') << endl;cout << "1. 添加联系人" << endl;cout << "2. 查找联系人" << endl;// ... 更多选项cout << string(50, '-') << endl;cout << "请选择操作 (0-7): ";
}

界面设计理念:

  • 视觉层次:用分隔线区分不同区域
  • 信息对称:选项排列整齐美观
  • 操作引导:清晰的提示和说明

在这里插入图片描述

2. 智能的错误处理

bool deleteByName(const string& name) {auto it = nameIndex.find(name);if (it != nameIndex.end()) {contacts.erase(contacts.begin() + it->second);updateIndexes();cout << "联系人删除成功!" << endl;return true;}cout << "未找到该联系人!" << endl;  // 友好的错误提示return false;
}

错误处理策略:

  • 预防性检查:操作前先验证
  • 友好提示:用自然语言告知结果
  • 优雅降级:失败时不崩溃,给出建议

3. 数据展示的艺术

void displayAll() const {cout << left << setw(15) << "姓名" << setw(15) << "电话" << setw(25) << "邮箱" << setw(30) << "地址" << endl;cout << string(85, '-') << endl;for (const auto& contact : contacts) {contact.display();}
}

展示优化技巧:

  • 表格对齐:使用setw()控制列宽
  • 分隔美化:用横线分割标题和内容
  • 信息层次:重要信息突出显示

六、总结与建议

经过这一路的探索,我们成功构建了一个功能完整、性能优异的通讯录管理系统。让我们回顾一下这个项目的亮点和未来的扩展可能。

1. 项目亮点总结

技术架构方面:

  • STL容器双剑合璧:vector + map的完美组合
  • 面向对象设计:清晰的类层次和职责分离
  • 高效算法应用:O(log n)查找,O(n log n)排序

用户体验方面:

  • 操作简便:直观的菜单导航
  • 功能完整:增删改查一应俱全
  • 错误友好:完善的异常处理机制

代码质量方面:

  • 兼容性强:支持Dev-C++ 5.11等多种编译器
  • 扩展性好:模块化设计便于功能扩展
  • 维护性佳:代码结构清晰,注释完善

2. 性能优化建议

对于追求极致性能的开发者,还可以考虑以下优化:

// 使用unordered_map提升查找速度(O(1)平均时间复杂度)
unordered_map<string, int> fastIndex;// 预留容器空间,减少重新分配
contacts.reserve(1000);// 使用移动语义减少拷贝开销
contacts.push_back(std::move(newContact));

3. 学习收获与启发

通过这个项目,我们不仅掌握了C++和STL的核心概念,更重要的是学会了:

  • 系统性思考:如何设计一个完整的软件系统
  • 性能意识:时间复杂度和空间复杂度的权衡
  • 用户视角:从技术实现转向用户体验

正如《C++ 语言超详细系统学习路线》中提到的,C++最大的特点就是语法复杂,学习难度大,但一旦掌握,就能写出高性能的优秀程序。

在这个AI蓬勃发展的时代,C++依然是系统底层开发的不二选择。正如技术报告所显示的,C++在嵌入式系统、游戏开发、金融科技等关键领域依然发挥着不可替代的作用。

希望这个项目能激发你对编程的热情,让你在C++的世界里越走越远。每一行代码不单是对更好的追求,也是成长的阶梯

参考资料:

  • C++ STL 教程 | 菜鸟教程
  • STL教程:C++ STL快速入门 - C语言中文网

创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)
如果这篇文章对你有帮助,请不要忘记点赞👍和收藏⭐!有任何问题欢迎在评论区交流讨论~

http://www.xdnf.cn/news/871795.html

相关文章:

  • 在VSCode中开发一个uni-app项目
  • 企业级网络安全攻防全景指南:从渗透测试到防御体系建设
  • 基于深度学习(Unet和SwinUnet)的医学图像分割系统设计与实现:超声心脏分割
  • 6. MySQL基本查询
  • Elasticsearch集群状态为RED且存在未分配分片问题排查诊断
  • GitHub 趋势日报 (2025年06月03日)
  • 小白的进阶之路系列之十四----人工智能从初步到精通pytorch综合运用的讲解第七部分
  • Delphi中实现批量插入数据
  • 5分钟了解,Mysql事务事务隔离级别
  • tensorflow image_dataset_from_directory 训练数据集构建
  • 使用 Python 的 psutil 库进行系统资源监控
  • Webpack搭建本地服务器
  • Unity3D 逻辑代码性能优化策略
  • Linux kill 暂停命令
  • 跟着deepseek浅学分布式事务(2) - 两阶段提交(2PC)
  • 人工智能:网络安全的“智能守护者”
  • 录制mp4
  • Kali Linux 安全工具解析
  • Ros(控制机器人运动)
  • .NET 原生驾驭 AI 新基建实战系列(四):Qdrant ── 实时高效的向量搜索利器
  • JVMTI 在安卓逆向工程中的应用
  • 【Oracle】存储过程
  • 纹理压缩格式优化
  • OpenCV 自带颜色表实现各种滤镜
  • 【Netty源码分析总结】
  • 使用 Unstructured 开源库快速入门指南
  • 机器学习:聚类算法
  • Python爬虫:trafilatura 的详细使用(快速提取正文和评论以及结构,转换为 TXT、CSV 和 XML)
  • Day44打卡 @浙大疏锦行
  • 01-Redis介绍与安装