题目:通信录查询系统(查找应用)

【问题描述】

设计散列表(哈希表)实现通讯录查找系统。

(1) 设每个记录有下列数据项:电话号码、用户名、地址;

(2) 从键盘输入各记录,分别以电话号码为关键字建立散列表;

(3) 采用任意方法解决冲突;

(4) 查找并显示给定电话号码的记录;

(5) 通讯录信息文件保存;

【实现功能】

主函数:根据选单的选项调用各函数,并完成相应的功能。

Create()的功能:创建新的通讯录。

Append()的功能:在通讯录的末尾写入新的信息,并返回选单。

Find():查询某人的信息,如果找到了,则显示该人的信息,如果没有则提示通讯录中没有

此人的信息,并返回选单。

Alter()的功能:修改某人的信息,如果未找到要修改的人,则提示通讯录中没有此人的信息,

并返回选单。

Delete()的功能:删除某人的信息,如果未找到要删除的人,则提示通讯录中没有此人的信

息,并返回选单。

List()的功能:显示通讯录中的所有记录。

Save()的功能:保存通讯录中的所有记录到指定文件中。

设计思路

自顶向下拆解任务:

  1. 接收输入数据;
  2. 创建HTable;
  3. 实现各个功能。
  1. 接收输入数据:

    a)       输入数据包括姓名 + 联系电话 + 地址,可以考虑用一个Class打包

 1 // 联系人 类
2 class Contact {
3 public:
4 string tel; // 电话号码
5 string name; // 姓名
6 string addr; // 地址
7 Contact* next;
8
9 Contact() : next(nullptr) {}
10 Contact(const string &_tel, const string &_name, const string &_addr)
11 : tel(_tel), name(_name), addr(_addr), next(nullptr) {}
12 ~Contact() {}
13
14 void print() {
15 printf("%s, %s, %s\n", name.c_str(), tel.c_str(), addr.c_str());
16 // std::cout << name << " " << tel << " " << addr << "\n";
17 }
18 };

Contact class

    b)      输入数据不定长,以 ‘@’ 作为结束标志

 1 第一种方式(行输入,比较好看):
2 string line;
3 string name, tel, addr;
4
5 // 行获取数据,'@'作为结束标志
6 while (true) {
7 getline(cin, line);
8 if (line == "@") {
9 break;
10 }
11 std::istringstream iss(line);
12 iss >> tel >> name >> addr;
13 // 插入至HTable
14 }
15
16 第二种方式(逐词输入,比较简单):
17 string tel, name, addr;
18 do {
19 cin >> tel >> name >> addr;
20 // 插入至HTable
21 } while(cin.get() != '\n');

不定长数据输入

   2. 创建HTable:

    a)       我的哈希表使用的是数字分析法确定地址,具体来说是电话号码后三位;再使用链接法处理冲突;

    b)      哈希表的基本操作有三,分别是:插入(insert) + 查找(search) + 删除(remove)。我将这三个基本操作和存放数据的数组打包起来,作为HashTable类(详见下文“代码实现”部分);

    c)       存储输入数据时,将它们作为一个个联系人插入进HTable即可。

   3. 实现各个功能:

    a)       说到底,这些功能的实现实际上是基本操作按某种顺序的组合,比如修改Alter() == 查找search() + 删除remove() + 插入insert();

    b)      因此,我编写了一些入口函数,并将它们设置为public供外界调用,而其他关键部分比如 Hash() 与 存储数据的数组 与 HTable基本操作 则设置为private隐藏起来。

代码实现

贴一下HTable及其基本操作的实现吧,入口函数就不贴了:

 1 // HashTable类
2 class HashTable {
3 private:
4 vector<Contact*> HTable;
5 int size;
6
7 // Hash函数: 数字分析法,tel作为key,取其后三位
8 // 注:应当来说,取tel后四位比较合理,但如此一来HTable的size应为10000,vscode的调试里装不下了
9 int Hash(const string &key) {
10 // 输入检查 没写。
11
12 string sstr = key.substr(key.length() - 3); // 取key后三位作为子串
13 int num = std::stoi(sstr); // 字符串按字面量转为数字
14 return num;
15 }
16
17 // 插入键值对:
18 void insert(const string &tel, const string &name, const string &addr) {
19 int index = Hash(tel);
20 Contact* newContact = new Contact(tel, name, addr);
21
22 // 如果该位置为空,则直接插入
23 if (HTable[index] == nullptr) {
24 HTable[index] = newContact;
25 } else {
26 // 否则,新节点头插法入链表
27 newContact->next = HTable[index];
28 HTable[index] = newContact;
29 }
30 }
31
32 // 查找键对应的值
33 Contact* search(const string &tel) {
34 int index = Hash(tel);
35 Contact* curr = HTable[index];
36
37 // 在链表中查找键对应的值(顺序查找可优化成AVL 或 RBT什么的)
38 while (curr != nullptr) {
39 if (curr->tel == tel) {
40 return curr;
41 }
42 curr = curr->next;
43 }
44
45 return nullptr;
46 }
47
48 // 删除键值对
49 void remove(const string &tel) {
50 int index = Hash(tel);
51 Contact* curr = HTable[index];
52 Contact* prev = nullptr;
53
54 // 在链表中查找并删除键值对
55 while (curr != nullptr) {
56 if (curr->tel == tel) {
57 if (prev == nullptr) {
58 HTable[index] = curr->next;
59 } else {
60 prev->next = curr->next;
61 }
62 delete curr;
63 return;
64 }
65 prev = curr;
66 curr = curr->next;
67 }
68 return;
69 }
70
71 public:
72 HashTable(int s) : size(s) {
73 HTable.resize(size, nullptr);
74 }
75
76 ~HashTable() {
77 // 释放哈希表中的所有节点
78 for (int i = 0; i < size; ++i) {
79 Contact* curr = HTable[i];
80 while (curr != nullptr) {
81 Contact* temp = curr;
82 curr = curr->next;
83 delete temp;
84 }
85 }
86 }
 // 。。。。。。
// 。。。。。。。。。。

87 };

运行结果

杂谈

- 为什么选择链接法处理冲突?
  - 删除操作上,在找到目标节点后,链接法可以通过修改指针直接删除它,而开放定址法则需要在当前位置留下“删除标记”,顺带着在插入操作上也需要特别处理,略显麻烦;
  - 插入操作上,链接法可以很方便地完成:计算Hash(key),在目标位置利用头插法入链表,而开放定址法需要不断的寻找空位,比较麻烦。另外比如线性探测法的堆积现象也会使得ASL大大增加;
  - 查找操作上,二者差别不大,在各种情况下,二者应该算是有来有回(随口一说,没具体计算过)
  - 补充:链接法的某个链的元素超过10个后,可以改用红黑树来存储,这虽然增加了插入与删除的时间复杂度,但也使得查找的时间复杂度降低到了O(h),h是红黑树的树高。

最后,希望这篇博客不会误人子弟,如果你有任何问题,欢迎留言!

数据结构实验代码分享 - 5 (HashTable - 链接法)的更多相关文章

  1. Python与数据结构[4] -> 散列表[1] -> 分离链接法的 Python 实现

    分离链接法 / Separate Chain Hashing 前面完成了一个基本散列表的实现,但是还存在一个问题,当散列表插入元素冲突时,散列表将返回异常,这一问题的解决方式之一为使用链表进行元素的存 ...

  2. JAVA数据结构--哈希表的实现(分离链接法)

    哈希表(散列)的定义 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度 ...

  3. Python与数据结构[4] -> 散列表[2] -> 开放定址法与再散列的 Python 实现

     开放定址散列法和再散列 目录 开放定址法 再散列 代码实现 1 开放定址散列法 前面利用分离链接法解决了散列表插入冲突的问题,而除了分离链接法外,还可以使用开放定址法来解决散列表的冲突问题. 开放定 ...

  4. 分离链接法(Separate Chaining)

    之前我们说过,对于需要动态维护的散列表 冲突是不可避免的,无论你的散列函数设计的有多么精妙.因此我们解决的重要问题就是:一旦发生冲突,我们该如何加以排解? 我们在这里讨论最常见的两种方法:分离链接法和 ...

  5. SDUT OJ 1479 数据结构实验之栈:行编辑器

    数据结构实验之栈:行编辑器 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述  一个简单的行编辑程序的功能是:接受用户从终端输入的程 ...

  6. 20145205 java语言实现数据结构实验一

    数据结构实验要求 综合类实验设计3 已知有一组数据a1a2a3a4--anb1b2b3b4--bm,其中ai均大于bj,但是a1到an和b1到bm不是有序的,试设计两到三个算法完成数据排序,且把bj数 ...

  7. .net之工作流工程展示及代码分享(四)主控制类

    现在应该讲主控制类了,为了不把系统弄得太复杂,所以就用一个类作为主要控制类(服务类),作为前端.后端.业务逻辑的控制类. WorkflowService类的类图如下: 该类的构造函数: public ...

  8. SDUT 3344 数据结构实验之二叉树五:层序遍历

    数据结构实验之二叉树五:层序遍历 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 已知一个按 ...

  9. vue项目微信分享之后路由链接被破坏怎么办

    异常现象: 多页面应用,路由采用hash模式,链接带有"#". 在微信中分享到朋友圈或好友时,分享出去的路由被破坏,打开分享的链接,路由中的“#”会被去掉并追加?fromTimel ...

  10. 解决hash冲突之分离链接法

    解决hash冲突之分离链接法 分离链接法:其做法就是将散列到同一个值的所有元素保存到一个表中. 这样讲可能比较抽象,下面看一个图就会很清楚,图如下 相应的实现可以用分离链接散列表来实现(其实就是一个l ...

随机推荐

  1. mikumikudance 和 pmxEditor 都可以打开 pmx

    mikumikudance 和 pmxEditor 都可以打开 pmx 模型下载 https://www.bilibili.com/blackboard/activity-5hkwDIRkBv.htm ...

  2. [VueJsDev] 其他知识 - NestJS 学习内容

    [VueJsDev] 目录列表 https://www.cnblogs.com/pengchenggang/p/17037320.html NestJS 学习内容 NestJS 学习总结 Step. ...

  3. printJS 打印 无头无尾 style 加 @page { margin: 0; } body { padding: 100px;}

    // 使用npm模块 print-js printJS({ printable: this.printData, type: 'json', documentTitle: ' ', propertie ...

  4. 新版idea配置maven注意点!!

    1. maven配置 首先是按要求配置了maven,关闭所有项目->自定义->所有设置 配置完成之后发现新建项目下方还是显示从官方源下载maven包装器,而且在项目中出现这个配置文件 可以 ...

  5. 日常办公——Excel中重复打印标题的设置

    打印预览时,所在数据行或列不能显示在同一页,在打印区域之外还有内容,为了方便阅读,可使用顶端标题行重复或左端标题行重复,具体方法如下: 按顺序操作,完成后点击确定即完成操作.

  6. stm32L4xx串口日志配置解析

    前言: st这两年推出了一款超低功耗的芯片,stm32l4xx系列,该系列芯片有着功耗低,尺寸小等特点,非常适合应用在可穿戴式设备. 团队在这一领域深耕,所以不可避免的要用到这款芯片,这里就针对该芯片 ...

  7. 关于api的表优化及代码优化小结

    提示:近期有空整理下mysql设计注意点吧 文章目录 一.表设计方面 二.代码设计方面 总结 一.表设计方面 建表要求三范式 5个必须字段is_del,create_time(CURRENT_TIME ...

  8. [503. 下一个更大元素 II] 单调栈

    import java.util.ArrayDeque; import java.util.Deque; class Solution { public static void main(String ...

  9. 记录--用Echarts打造自己的天气预报!

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 最近刚刚学习了Echarts的使用,于是想做一个小案例来巩固一下.项目效果如下图所示: 话不多说,开始进入实战. 创建项目 这里我们 ...

  10. 记录--详解 XSS(跨站脚本攻击)

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言:我们知道同源策略可以隔离各个站点之间的 DOM 交互.页面数据和网络通信,虽然严格的同源策略会带来更多的安全,但是也束缚了 Web. ...