==> 学习汇总(持续更新)
==> 从零搭建后端基础设施系列(一)-- 背景介绍
**基本思想:**在单链表的基础上加一个前驱指针域,存放前一个节点的地址。所以现在节点结构一共有三个字段,数据域,两个指针域(前驱和后继)。
**优点:**拥有单链表的所有优点(动态增长),也拥有循环链表的优点(能够在任何位置访问到所有节点),增加尾指针后,头添加和尾添加的时间复杂度都变为0(1),逆转表不再需要牺牲空间换时间,时间复杂度只有0(n/2),打印表的时候,可以正着打印,还可以逆着打印。
**缺点:**就是代码上的实现较为复杂,还有查询还是没有数组快(时间复杂度为0(n/2))。
综合以上所述,如果对于效率有比较高的要求,那最好用双向链表,其代码量只比单链表多了100行,但是功能效率却高了许多。
C代码实现下载
C++代码实现下载
java代码实现下载
(备用下载地址)
实现的功能:
1.bool IsEmpty(); 判断表是否为空
2.int Size(); 获取元素个数
3.void AddFromHead(Node* node); 添加数据(头添加)
双向链表,所以两个节点之间相当于有两根线,可以先连接正的,再连接负的。一共分为三步。
1).判断表是否为空 (这一步是必须的,不然当表为空的时候,按照正常的添加,会有解引用空指针的风险)
2).如果为空则让尾指针指向这个新的节点,然后把该节点挂在头节点后面,最后让该节点指向头节点。
3).如果不为空,则进行正常的添加操作。
如图:
表为空的时候
4.void AddFromTail(Node* node); 添加数据(尾添加)
尾添加和头添加的第二步一样,也需要判断是否是第一次添加,共分为三步。
1).判断表是否为空
2).如果为空则调用AddFromHead函数
3).如果不为空,则进行正常的添加操作。
如图:
5.void Insert(int local, Node* node); 插入数据(指定位置)
插入操作,和头添加的第三步是一样的。
6.void DeleteFromLocal(int local); 删除数据 (指定位置)
这和单链表相比,只是多了一个步骤,就是最后把后一个节点指向删除后的前一个节点
如图:
7.void DeleteFromElement(T e); 删除数据 (指定元素)
8.int SearchFromElmemt(T e); 根据指定元素查找,返回位置
9.T SearchFromLocal(int local); 根据位置查找指定元素
10.void Reverse(); 逆转表
因为是双向链表,所以可以同时从头和尾遍历到中间,这样就不需要每次都遍历一次链表才能得到指定的节点。所以,这次逆转会相当之快,时间复杂度只有0(n/2),经过我的测试,逆转1000W个元素只需0.3s左右。这个方法趋近于顺序表逆转的那个方法。
11.void Print(bool bReverse = false); 遍历元素(可以正遍历,也可以倒着遍历)
12.void CopyList(DoubleLinkList& sl); 复制表
13.void Rewrite(int local, T e); 修改元素
14.void ClearLinkList(); 清空链表
15.Node* GetNode(int local); 获取指定位置的节点
16.void SortByAsc(); 升序排序
17.void SortByDesc(); 降序排序
18.Node* GetTailNode(); 获取最后一个节点
19.void MergeList(DoubleLinkList& sl); 合并链表(无序),会改变原表
20.void MergeListOrder(DoubleLinkList& sl, bool bAsc = true); 合并链表(有序)
21.void MergeListNoChange(DoubleLinkList& sl); 合并链表(无序),不会改变原表
22.void MergeListNoChangeOrder(DoubleLinkList& sl, bool bAsc = true); 合并链表(有序),不会改变原表
线性表之循环链表
线性表之单链表
线性表之顺序表