![054e052901d19370f6c12ccee2382767.png](https://i-blog.csdnimg.cn/blog_migrate/505d0211c1131d3780c0bc6c6ebf5651.jpeg)
今天来讲一下链表大家族:
链表主要分为顺序存储结构以及链式存储结构,其中链式存储结构又可以分为单链表,静态链表,循环链表以及双向链表。
先来讲讲顺序存储结构。
简单来讲,顺序存储结构,就是一段地址连续的存储单元依次存储线性表的数据元素。
那么他又那些优缺点呢?首先是缺点,因为是顺序结构嘛,在插入和删除的时候,前面做插入删除动作时候,后面的元素是否要依次做出后退或者前进一位的当作?是不是很麻烦!
在最糟糕的情况下,第一位插入或者删除一位,那么时间复杂度就会飙到O(n),容易造成存储的碎片。
当然了,优点也是有的,比如无需为表中元素之间的逻辑关系而增加额外的外储空间。同时因为是顺序结构,所以可以快速存取表中任一位置的元素。
再来讲讲链式存储结构。
上面说到了,顺序存储最大的缺点就是插入和删除需要移动大量元素,很浪费时间。呢么有没有好点的办法来解决呢?
这里就是引进链式存储了,我们不必去纠结元素之间的相邻位置了,我们直接告诉上个元素下个元素的位置数据不就行了!
为了表示每个数据元素ai与其直接后继数据元素ai+ 1之间的逻辑关系。对数据元素ai来说,除了存储其本身的信息之外,还需存储一个指示其后继的信息(即直接后继的存储位置)。我们把存储数据元素信息的域称为数据域,把存储后继的位置的域称为指针域.指针域中存储的信息称做指针或链.这两部分信息组成的元素ai的存储映像,称为结点。
n个结点(ai的存储映像)链结成一个链表,即为线性表(a1,a2,...an)的链式存储结构,因为此链表的每个结点中只包含一个指针域,所有叫做单链表。
这里要将一个小tip:单链表插入和删除
插入:s->next = p->next , p->next = s
删除:q = p->next , p->next = q->next
那么问题来了,为什么要这么写呢?如果将两句的顺序调换一下可不可以呢?
我们来对比下单链结构和顺序存储结构的优缺点吧:
存储分配方式
顺序存储用一段连续的存储单元依次存储线性表的数据元素
单链表采用链式存储结构,用一组任意的存储单元存放线性表元素
时间性能
查找:
顺序存储O(1)
单链表O(n)
插入和删除:
顺序存储平均需要移动表长一半的元素 时间为0(n)
单链表在计算出某位置的指针后,插入和删除时间仅为O(1)
空间性能
顺序存储结构需要预分配存储空间,分大了,容易造成空间浪费,分小了,容易发生溢出
单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制
下面简单讲讲其他链式存储方式:
静态链表
用数组描述的链表,即称为静态链表。
优点:再插入和删除时候,只需要修改游标,不需要移动元素,从而改进了顺序存储结构中插入和删除操作需要移动大量元素的缺点。
缺点:没有解决连续存储分配带来的表长难以确定的问题;失去了顺序存储结构随机存取的特性。
链表家族成员差不多就介绍到这里了,下面是真题时间。
160. 相交链表
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
![ae884151ab5c5e74179ec4f8c4936a70.png](https://i-blog.csdnimg.cn/blog_migrate/618ad5f192093e595f742c5f4491b5e5.jpeg)
在节点 c1 开始相交。
![7293871afa57e70039d82b13178b785d.png](https://i-blog.csdnimg.cn/blog_migrate/88ecd984c95cb19ddbbc5bfb9949709f.jpeg)
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
这题比较有趣,我先简单说说。
主要两种思维:
1.先算出A和B的长度,算出长度差n,先让长的跑n步,然后再一起跑,只要是相同就找到intersectVal啦
2.A和B一起走,短的一个,比方说A先到底了,就把指针指向B的头,B走到底后把指针指向A的头,这样走下来两个指针走的路长短都是相同的,而且只要有相同的地方,两个指针必然会C1处相遇。
下面代码选用了第二种思维
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
a = headA
b = headB
while(a != b):
a = headB if a == None else a.next
b = headA if b == None else b.next
return a
206. 反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
p = head
rev = None
while p:
rev, rev.next, p = p, rev, p.next
return rev
这段代码妙不可言,利用了多元赋值的时候,右边的值不会随着赋值而改变的特性,下面有解释可以看看
前置条件:迭代指针:p = head、结果指针:res = none
以1->2->3->4->5为例:
过程:
res:None
第一层循环
res:1->2->3->4->5 res = p
res:1->None res.next = res
p:2->3->4->5 p = p.next
第二层循环
res:2->3->4->5 res = p
res:2->1->None res.next = res
p:3->4->5 p = p.next
第三层循环
res:3->4->5 res = p
res:3->2->1->None res.next = res
p:4->5 p = p.next
第四层循环
res:4->5 res = p
res:4->3->2->1->None res.next = res
p:5 p = p.next
第五层循环
res:5 res = p
res:5->4->3->2->1->None res.next = res
p:None p = p.next
end...
234. 回文链表
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if head == None:
return True
p = head
val = []
while(p != None):
val.append(p.val)
p = p.next
return val == val[::-1]
83. 删除排序链表中的重复元素
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2
示例 2:
输入: 1->1->2->3->3
输出: 1->2->3
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def deleteDuplicates(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
prev = head
curr = head
form = set()
while curr is not None:
if curr.val not in form:
form.add(curr.val)
prev = curr
else:
prev.next = curr.next
curr = curr.next
return head
希望本文能帮到你!~!
最后打个小广告,我的公众号,喜欢写点学习中的小心得,不介意可以关注下!~!
![54cc2afe84fcc3d00ef0cec197f11618.png](https://i-blog.csdnimg.cn/blog_migrate/28238d5d22426bdb4fb0759968048aa4.jpeg)