boost::unorder_map如何插入元素_如何使用C++实现单链表

0519d15abf4680eabbd64c40690f45a2.png

线性表——链表

为什么假期也在发文章

//TODO NullGirlfrindException

请忽略以上两行无聊的事实......

如何弥补顺序表的不足之处?

第一次学习线性表一定会马上接触到一种叫做顺序表(顺序存储结构),经过上一篇的分析顺序表的优缺点是很显然的,它虽然能够很快的访问读取元素,但是在解决如插入和删除等操作的时候,却需要移动大量的元素,效率较低,那么是否有一种方法可以改善或者解决这个问题呢?

首先我们需要考虑,为什么顺序表中的插入删除操作会涉及到元素的移动呢?

好家伙,问题就是围绕着顺序表的最大的特点出现的——顺序存储,相邻放置元素,也就是说每个元素都是根据编号一个一个挨着的,这就导致了 插入或删除后,为了仍然呈顺序线性存储,被操作元素后面的元素的位置均需要发生一定的变化,你应该能想象得到,在拥挤的队伍中突然从中插入一个学生的场景,后面浩浩荡荡的人群,口吐芬芳的向后挪了一个空位,如果人群过大,重新排好队也需要一定的时间

好嘛,人与人之间别这么挤在一起,每个人与人之间都流出一点空隙来,留一定的位置出来,好了,这好像是个办法,但是负责一个一个与学生交流填表的老师可就不干了,这意味着我(找人)遍历的时候,需要多跑好多路,浪费好多时间,先不说这个,体院馆又不行了,你们这么个摆法,我这小馆可放不下,这也就意味着空间复杂度增加了很多

我们刚才所围绕的都是在 "排队" 的基本前提下的,但我们能想到的方法并不是很理想,那么我们索性就不排队了,是不是能有更好的解决方式呢?

一个有效的方法:

让同学们(元素)自己找位置随便站,不过你要知道相对于自己下一位同学的位置,这样既解决了空间上的问题,又能通过这种两两联系的方式访问(遍历)到整个队伍(数组),最重要的是,插入和离开同学,由于同学(元素)之间不存在了那种排队,相邻的特点,所以也不会说影响到过多的同学(元素)只需要和你插入位置的前后两位同学沟通好就行了,反正别人也不知道你们之间发生了什么事

好了思路是有了,我们来看一种最常见的链表——单链表

单链表的基本结构

这种链表为什么被称作单链表呢?这是因为它只含有一个地址域,这是什么意思呢?

我们在链表中摈弃了顺序表中那种一板一眼的排队方式,但是我们必须让两个应该相邻的元素之间有一定的相互关系,所以我们选择让每一个元素可以联系对应的下一个元素

而这个时候我们就需要给每个元素安排一个额外的位置,来存储它的后继元素的存储地址,这个存储元素信息的域叫做指针域或地址域,指针域中储存的信息也叫作指针或者链

我们用一张图 看一下他的结构

2678fab099ab8545d29c089b84bbbb34.png

结构中名词解释

  • 头指针:一个指向第一个节点地址的指针变量
    • 头指针具有标识单链表的作用,所以经常用头指针代表单链表的名字
  • 头结点:在单链表的第一个结点之前附设一个结点,它没有直接前驱,称之为头结点
    • 可不存信息,也可以作为监视哨,或用于存放线性表的长度等附加信息
    • 指针域中存放首元结点的地址
  • 首元结点:存储第一个元素的节点

为什么要附设一个头结点

我们来解释一下:

  • 链表如果为空的情况下,如果单链表没有头结点,那么头指针就会指向NULL,如果加上头结点,无论单链表是否为空,头指针都会指向头结点,这样使得空链表与非空链表处理一致
  • 使首元结点前插入或删除元素的时候,与后面操作相同,不需要产生额外的判断分支,使得算法更加简单

8548b14534cebb1ef5037401aff8fe97.png

7d1c8c5664fa87807b319454303f8e5e.png

(以插入为例讲解)在带头结点的情况下,在首元结点前插入或者删除元素仍与在其他位置的操作相同,只需要将前一个元素(在这里是头结点)的指针域指向插入元素,同时将插入元素的指针域指向原来的第二的元素

9965a3ffe354a669eecb861e54786581.png

而无头结点的情况由于,首元结点前没有元素,只能通过修改head的前后关系,所以导致了 与在别的位置插入或删除元素的操作不同,在实现这两个功能的时候就需要额外的写一个判断语句来判断插入的位置是不是首元结点之前的位置,增加了分支,代码不够简洁

总结:头结点的存在使得空链表与非空链表处理一致,也方便对链表首元结点前结点的插入或删除操作

单链表的类型定义

线性表的抽象数据类型定义

我们在给出单链表的定义之前我们还是需要先引入我们线性表的抽象数据类型定义

#ifndef _LIST_H_

单链表的类型定义

#ifndef _SEQLIST_H_

单链表上的基本运算实现

(一) 单链表的初始化-构造函数

单链表的初始化就是创建一个带头节点空链表,我们不需要设置其指针域,为空即可

template
注意:new 操作符代表申请堆内存空间,上述代码中应该判断是否申请成功,为简单,默认为申请成功,实际上如果系统没有足够的内存可供使用,那么在申请内存的时候会报出一个 bad_alloc exception 异常

(二) 析构函数

当单链表对象脱离其作用域时,系统自动执行析构函数来释放单链表空间,其实也就是清空单链表内容,同时释放头结点

template

(三) 清空单链表

清空单链表的主要思想就是从头结点开始逐步将后面节点释放掉,但是我们又不想轻易的修改头指针head的指向,所以我们引入一个工作指针,从头结点一直移动到表尾,逐步释放节点

template

(四) 求表长

由于我们的代码中已经定义过一个叫做 curLength 的变量用来记录我们的表长

所以我们可以直接返回,我们在定义中已经实现了,也就是这句

//返回单链表的当前实际长度

但是如果我们没有这样一个变量,我们想要实现这样的功能又是什么样的方法呢?

template

(五) 遍历单链表

我们需要从头到尾访问单链表中的每一个节点,并且输出其中数据域的信息

template

(六) 按照位序 i 寻找其元素对应内存地址

设置一个移动工作指针,和一个计数器 count,初始时p指向头结点,每当指针p移向下一个结点的时候,计数器count + 1 ,直到 p指向位序为 i的节点为止。返回 p

template

(七) 按值查询节点位序

设置一个移动工作指针,和一个计数器 count,从单链表的第一个节点开始,开始于给定的值进行比对,如果相等则查找成功,返回节点的位序,否则继续查询知道单链表结束,查询失败返回 -1

template

(八) 插入节点

在位序为 i 出插入值为value 的新节点q,我们需要做的就是找到位序为i - 1 的节点p,让q指针域指向原来p的后继,然后修改p的后继为q即可,说白了也就是修改插入元素位置前后的元素指向关系就可以了

8548b14534cebb1ef5037401aff8fe97.png
template

(九) 删除节点

能看懂添加节点的方法,理解删除节点也是手到擒来

7d1c8c5664fa87807b319454303f8e5e.png
template

单链表整表的创建

回顾我们前面认识的顺序表,它其实可以理解为一个数组,我们声明一个类型,同时给定值,初始化其大小,但是单链表就不一样了,它是一种动态组织,它不需要像顺序表一样元素集中,它可以随着实际的情况来动态生成节点,所以也不需要预先分配空间大小和位置

(一) 头插法创建单链表

头插法的意思就是说,每次新增节点全部插在头结点之后,首元结点之前,你可以这样理解,我先来排队,但是后面来了人,他就会排到我的前面去,我们来借助图看一下

b4b1469706fefb611e69502e7da63352.png

我们一次插入元素 123 但实际上输出的是按照321的顺序存储的,也就是说和我们的逻辑顺序是相反的

我们来看一看怎么实现它

template

逆置单链表

我们知道单链表中元素顺序与读入的顺序是相反的,我们可以通过逆置单链表的算法,帮助我们重新恢复我们的惯有思维顺序

template

(二) 尾插法创建单链表

看完了头插法,但是感觉这样的顺序与我们一贯的思维总是有一点别扭,而尾插法则是一种,逻辑顺序与我们一致的创建方法

还是看一下图

90a9565335c4b8d41d6f9923f41fb42a.png
template

合并单链表

要求:假设我们给出两个仍然是递增的单链表la和lb,我们将其合并为lc 仍保证递增,利用原表空间,但是我们仍在下面将表C称作新表

因为我们的要求是递增的,所以使用尾插法是非常合适的,我们设计三个工作指针,分别指向两个表的首元结点,然后将第三个指针指向新表的头结点,比较前两个指针指向的值,小的就放到新表的表尾,然后后移动两表中较小的那一个的指针,以此类推,直到其中一个表尾空,将剩余的节点全部链接到新表的末尾

template

总结

单链表,采取了链式存储结构,用一组任意的存储单元存放线性表的元素,尤其对于需要频繁的插入和删除数据的时候更加适用,如果需要进行频繁的查找还是推荐使用顺序表,例如对于一个学生成绩管理系统的制作,学生更多的时候是查看自己的成绩,而录入的老师,也只有在考试后录入一次,所以应该使用顺序表,而例如考勤打卡系统,更多的是打卡信息的记录,所以还是选择使用链表,当然例子可能不是很恰当,同时正常的开发中还会有更多复杂的问题需要考虑,举例子只为了利于理解

结尾:

如果文章中有什么不足,或者错误的地方,欢迎大家留言分享想法,感谢朋友们的支持!

如果能帮到你的话,那就来关注我吧!如果您更喜欢微信文章的阅读方式,可以关注我的公众号

在这里的我们素不相识,却都在为了自己的梦而努力 ❤
一个坚持推送原创开发技术文章的公众号:理想二旬不止

d12f6b1ef4f97357ffdbcb541cf5fa66.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值