链表
链表基础知识
单链表
1.逻辑结构:数据元素之间的逻辑关系
集合、线性结构(一对一)、树形结构(一对多)、图结构(多对多)
2.存储结构:顺序存储、链式存储、索引存储、散列存储
- 顺序存储(顺序表):逻辑上相邻的元素物理位置也相邻
- 链式存储(单链表):逻辑上相邻的元素物理位置不一定相邻。
3.数据操作:
- 单链表定义
- 单链表在指定位置插入元素
- 删除指定位置元素
- 头插法创建单链表
- 尾插法创建单链表
4.单链表的定义
-
带头结点的单链表:head没有实际意义。
-
不带头结点的单链表:第一个结点就是头结点。
4.单链表的插入元素
- 带头结点的单链表插入
def Insert(head, i, elem):
assert i >= 0
cur = head
while i != 0:
i -= 1
cur = cur.next
if not cur:
return False
temp = cur.next
cur.next = elem
elem.next = temp
return True
- 不带头结点的单链表
def Insert(i, elem):
global head
assert i >= 0
if i == 0:
elem.next = head
head = elem
cur = head
while i > 1:
i -= 1
cur = cur.next
if not cur:
return False
temp = cur.next
cur.next = elem
elem.next = temp
return True
5.删除指定位置元素
- 带头结点
def ListDelete(head, i):
assert i >= 0
cur = head
while i != 0:
i -= 1
cur = cur.next
if not cur.next:
return False
cur.next = cur.next.next
return True
6.创建单链表
- 尾插法
# 带头结点
def BuildLink_Tail(l):
head = ListNode()
cur = head
for elem in l:
cur.next = ListNode(elem)
cur = cur.next
return head
# 处理
head = BuildLink_Tail([1, 2, 3, 4])
while head.next:
head = head.next
print(head.val)
# 不带头结点
def BuildLink_Tail(l):
if not l:
return None
head = ListNode(l[0])
cur = head
for elem in l[1:]:
cur.next = ListNode(elem)
cur = cur.next
return head
# 处理
head = BuildLink_Tail([1, 2, 3, 4])
while head:
print(head.val)
head = head.next
- 头插法
# 带头结点
def BuildLink_Head(l):
head = ListNode()
for elem in l:
temp = head.next
head.next = ListNode(elem, temp)
return head
# 不带头结点
def BuildLink_Head(l):
head = None
for elem in l:
head = ListNode(elem, head)
return head
双链表
class DLinkNode:
def __init__(self, val=0, next=None, prior):
self.val = val
self.next = next
self.prior = prior
用来解决单链表无法逆向索引的问题
循环链表
包括循环单链表和循环双链表
题目解析
移除链表元素
1.题目描述
2.解题思路及代码
直接使用带头结点的单链表进行操作,可以节省很多边界条件。
public ListNode removeElements(ListNode head, int val) {
ListNode head1 = new ListNode();
head1.next = head;
ListNode prev = head1;
while(prev.next != null) {
if (prev.next.val == val) prev.next = prev.next.next;
else prev = prev.next;
}
return head1.next;
}
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeElements(self, head: ListNode, val: int) -> ListNode:
head1 = ListNode(next=head)
cur = head1
while cur.next:
if cur.next.val == val:
cur.next = cur.next.next
else:
cur = cur.next
return head1.next
旋转链表
1.题目描述
2.解题思路及代码
首先是k的操作,如果k大于链表的长度,那么只需要移动k%length次即可,然后需要将首尾相连,然后确定head和末尾的值即可。
public ListNode rotateRight(ListNode head, int k) {
int len = 0;
if (head == null) return null;
ListNode cur = head;
while(cur.next != null) {
cur = cur.next;
len ++ ;
}
k = k % (len + 1);
cur.next = head;
cur = head;
for (int i = 0; i < len - k; i ++ ) {
cur = cur.next;
}
head = cur.next;
cur.next = null;
return head;
}
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
if not head:
return None
len = 0
cur = head
while cur.next:
cur = cur.next
len += 1
cur.next = head
k = k % (len + 1)
cur = head
for i in range(len - k):
cur = cur.next
head = cur.next
cur.next = None
return head
合并两个有序链表
1.题目描述
2.题目思路及代码
使用两个指针指向两个链表,然后把链表中小的元素放到新的链表中,为了避免边界问题,这里使用了带头结点的链表,因此最后需要返回head.next
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode head = new ListNode();
ListNode cur1 = list1;
ListNode cur2 = list2;
ListNode cur = head;
while(cur1 != null && cur2 != null) {
if (cur1.val > cur2.val) {
cur.next = cur2;
cur2 = cur2.next;
} else {
cur.next = cur1;
cur1 = cur1.next;
}
cur = cur.next;
}
cur.next = cur1 == null ? cur2 : cur1;
return head.next;
}
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
cur1 = list1
cur2 = list2
head = ListNode()
cur = head
while cur1 and cur2:
if cur1.val > cur2.val:
cur.next = cur2
cur2 = cur2.next
else:
cur.next = cur1
cur1 = cur1.next
cur = cur.next
cur.next = cur1 if cur1 is not None else cur2
return head.next
相交链表
1.题目描述
2.解题思路及代码
使用双指针分别指向headA和headB,然后分别移动到下一节点,如果指向headA的为空,则指向headB,同理如果指向headB的指针为空,则指向headA,直到两个指针值相等,返回最后的值即可。
具体证明详见链接中的题解。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) return null;
ListNode curA = headA, curB = headB;
while (curA != curB) {
if (curA == null) {
curA = headB;
} else {
curA = curA.next;
}
if (curB == null) {
curB = headA;
} else {
curB = curB.next;
}
}
return curA;
}
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
curA = headA
curB = headB
while curA != curB:
curA = headB if curA is None else curA.next
curB = headA if curB is None else curB.next
return curA
删除排序链表中的重复元素 II
1.题目描述
2.解题思路及代码
为了保证能够删除重复的所有元素,因此如果链表的下一个节点和下下个节点值相同,就要让链表的下一个节点指向第三个节点(如果第三个节点的值仍然和链表下一节点值相等,结点指向继续往下走,因此这里需要保存下一个节点的值),这里依然使用带有头结点的链表,从而避免边界问题。
public ListNode deleteDuplicates(ListNode head) {
if (head == null) return null;
ListNode head1 = new ListNode();
head1.next = head;
ListNode cur = head1;
while (cur.next != null && cur.next.next != null) {
if (cur.next.val == cur.next.next.val) {
int x = cur.next.val;
while (cur.next != null && cur.next.val == x)
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return head1.next;
}
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
if not head:
return None
head1 = ListNode(next=head)
cur = head1
while cur.next and cur.next.next:
if cur.next.val == cur.next.next.val:
x = cur.next.val
while cur.next and cur.next.val == x:
cur.next = cur.next.next
else:
cur = cur.next
return head1.next