什么是链表?
链表是在内存上不连续的,通过另外保存指针来描述结点地址的,以空间换时间的一种数据结构。
这种内存上不连续的数据结构对缓存不友好。
大体可以分为3种类型:单链表,循环链表和双向链表。
单链表
单链表,顾名思义,只有一条链。以头结点和尾节点特殊。头结点记录链表的基地址,尾节点的指针指向空地址NULL。
由于并没有连续地址的特性,不能够按照寻址公式的方式进行随机读取,只能顺序读取,所以单链表的读取数据的时间复杂度是O(n)。
不过也胜在这种方式,链表的删除和添加异常的方便。只需要改动指针next即可。
举个?(只为了说明),m.next = n,n.next = z,
现在要插入一个w结点在m和n中间,只需要
m.next = w,w.next = n
更新n为w,m.next =w,w.next = z
删除n,m.next = z
可以看到单链表的插入删除的时间复杂度是O(1)。
循环链表
根据单链表指针的定义,尾指针指向头指针就可以了
双向链表
看名字就知道了,这是个啥玩意儿。两个结点比如说A,B结点。单链表就只有一条,A->B,现在双链表又加了一个B->A。总的来说,由单链表的data,next形式变成了prev,data,next的形式。双向链表的作用在于,当我要删除一个值的时候,以上面为例,我要删除n,但是在单链表中我并不知道n的前面是谁,在双向链表中的prev给我们提供了答案。
双向链表的插入删除时间复杂度是O(1),查询是O(n)。
对于一个有序链表来说,在已知一个结点值的情况下,我们可以很方便的根据大小查找下一个我们需要的值。单向链表因为没有提供前结点的地址所以得重新遍历。
那么问题来了,双向链表是不是百利而无一害?答案当然是错的。双向链表以空间换时间,在消耗更多内存的基础上提供更快的速度。像手机端的应用大多采用时间换空间的策略。
Java中的LinkedHashMap容器底层就使用了这种双向链表。
补充
由于指针的存在,链表是一个很考验逻辑的数据结构。
手写下述链表的功能。
单链表反转,
链表中环的检测,
两个有序的链表合并,
删除链表倒数第n个结点,
求链表的中间结点。