python資料結構之連結串列
1.功能實現
連結串列(Linked list)是一種常見的基礎資料結構,是一種線性表,但是並不會按線性的順序儲存資料,而是在每一個節點裡存到下一個節點的指標(Pointer)。由於不必須按順序儲存,連結串列在插入的時候可以達到O(1)的複雜度,比另一種線性表順序錶快得多,但是查詢一個節點或者訪問特定編號的節點則需要O(n)的時間,而順序表相應的時間複雜度分別是O(logn)和O(1)。
特點:使用連結串列結構可以克服陣列連結串列需要預先知道資料大小的缺點,連結串列結構可以充分利用計算機記憶體空間,實現靈活的記憶體動態管理。但是連結串列失去了陣列隨機讀取的優點,同時連結串列由於增加了結點的指標域,空間開銷比較大。
基本操作:包括建立連結串列(初始化)、獲取長度、插入、查詢、刪除、遍歷,以及略複雜的連結串列逆序和結點交換。下面將這些操作一一實現並作出解釋。
class ListNode(object): def __init__(self,data,p = None): self.data = data self.next = p class Linklist(object): def __init__(self): self.head = None def set(self): # 初始建立 print('input:') data = input() if data != "": self.head = ListNode(int(data)) p = self.head else: print('over!') return while 1: data = input() if data != "": p.next = ListNode(int(data)) p = p.next else: print('over!') break @property def show(self): # 遍歷連結串列 print('連結串列元素如下:') p = self.head if p == None: print('Empty!') return while p: print(p.data,end=',') p = p.next print('over!') return @property def isempty(self): # 判斷是否空 p = self.head if p == None: return True else: return False @property def length(self): # 獲取長度 p = self.head l = 0 while p: l += 1 p = p.next return l def insert(self,data,pos): # 資料插入 if self.isempty and pos != 1: raise Exception('wrong position!') p = self.head if pos == 1: self.head = ListNode(data) self.head.next = p n = 2 while n < pos and p.next != None: p = p.next n += 1 if n == pos: tmp = p.next p.next = ListNode(data) p = p.next p.next = tmp elif n < pos: raise Exception('wrong position!') def delete(self,pos): # 刪除操作 p = self.head # 假設位置資訊有效 if pos == 1: return self.head.next for i in range(pos - 2): p = p.next p.next = p.next.next
2.倒數第k結點及連結串列合併
1)題目如下:輸入一個連結串列,輸出該連結串列中倒數第k個結點。
class ListNode(object): def __init__(self, x): self.val=x self.next=None class Solution(object): def __init__(self, head, k): n=0 p=head while p!=None: n+=1 p=p.next if n<k: return None p=head m=1 while m<n-k+1: m+=1 p=p.next return p
2)題目如下:輸入兩個單調遞增的連結串列,輸出兩個連結串列合成後的連結串列,當然我們需要合成後的連結串列滿足單調不減規則。
class ListNode:
def __init__(self, x):
self.x=x
self.next=None
class Solution:
def merge(self, pHead1, pHead2):
if pHead1 is None:
return pHead2
if pHead2 is None:
return pHead1
if pHead1.val<=pHead2.val:
pHead1.next=merge(pHead1.nextm pHead2)
else:
pHead2.next=merge(pHead1, pHead2.next)
3.連結串列右移/連結串列分割/連結串列逆序
1). 61. Rotate List (將連結串列右移K個位置)
Given a list, rotate the list to the right by k places, where k is non-negative.
Example:
Given 1->2->3->4->5->NULL and k = 2,
return 4->5->1->2->3->NULL.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def rotateRight(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
if head == None:
return None
length = 1
p = head
while p.next:
p = p.next
length += 1
if k == length:
return head
elif k > length:
k = k%length
cn = 1
q = head
while cn < (length-k):
q = q.next
cn += 1
p.next = head
newhead = q.next
q.next = None
return newhead
2. 86. Partition List(連結串列分割)
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.You should preserve the original relative order of the nodes in each of the two partitions.
For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def partition(self, head, x):
"""
:type head: ListNode
:type x: int
:rtype: ListNode
"""
if head == None:
return head
p1 = ListNode(-1)
p2 = ListNode(-1)
h1, h2 = p1, p2
while head:
if head.val <x:
p1.next = head
p1 = p1.next
else:
p2.next = head
p2 = p2.next
head = head.next
p2.next = None
p1.next = h2.next
return h1.next
3). 92. Reverse Linked List II(連結串列逆序)
class Solution:
def reverseBetween(self, head, m, n):
"""
:type head: ListNode
:type m: int
:type n: int
:rtype: ListNode
"""
if head == None:
return head
elif m == n:
return head
new = ListNode(-1)
new.next = head
head = new
p = head
pre = head
for i in range(m):
pre = p
p = p.next
q = p
for i in range(n-m):
q = q.next
# reverse
pre_p = q.next
cur = p
for i in range(n-m+1):
h = cur
tmp = cur.next
cur.next = pre_p
pre_p = cur
cur = tmp
pre.next = q
return head.next
4.移除重複項及帶隨機指標的連結串列複製
1)82. Remove Duplicates from Sorted List II (從有序列表中移除重複項)
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
For example,
Given 1->2->3->3->4->4->5, return 1->2->5.
Given 1->1->1->2->3, return 2->3.
1)82. Remove Duplicates from Sorted List II (從有序列表中移除重複項)
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
For example,
Given 1->2->3->3->4->4->5, return 1->2->5.
Given 1->1->1->2->3, return 2->3.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplicates(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head == None or head.next == None:
return head
fhead = ListNode(0)
fhead.next = head
pre = fhead
cur = head
while cur:
while cur.next and cur.val==cur.next.val:
cur = cur.next
if pre.next == cur: # 如果只此一個值,不刪除,pre後移
pre = cur
else:
pre.next = cur.next # 如果不只一個,刪除這些結點,pre暫不後移
cur = cur.next
return fhead.next
2)138. Copy List with Random Pointer(複製含有隨機指標的連結串列)
# Definition for singly-linked list with a random pointer.
# class RandomListNode(object):
# def __init__(self, x):
# self.label = x
# self.next = None
# self.random = None
class Solution(object):
def copyRandomList(self, head):
"""
:type head: RandomListNode
:rtype: RandomListNode
"""
if head == None:
return None
p = head
while p:
tmp = p.next
p.next = RandomListNode(p.label)
p.next.next = tmp
p = tmp
p = head
while p:
if p.random:
p.next.random = p.random.next
p = p.next.next
newhead = RandomListNode(0)
p = head
q = newhead
while p:
tmp = p.next.next
q.next = p.next
q = q.next
p.next = tmp
p = tmp
return newhead.next
5.帶環連結串列及交叉連結串列(雙指標法)
1)160.Intersection of Two Linked Lists 兩連結串列交叉
Write a program to find the node at which the intersection of two singly linked lists begins.For example, the following two linked lists:
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3
begin to intersect at node c1.
Notes:
If the two linked lists have no intersection at all, return null.
The linked lists must retain their original structure after the function returns.
You may assume there are no cycles anywhere in the entire linked structure.
Your code should preferably run in O(n) time and use only O(1) memory.
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
p1, p2 = headA, headB
while p1 is not p2:
p1 = headB if not p1 else p1.next
p2 = headA if not p2 else p2.next
return p1
2)142. Linked List Cycle II 帶環的連結串列
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Note: Do not modify the linked list.
Follow up:Can you solve it without using extra space?
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head == None:
return None
pslow = head
pfast = head
k = 0
while pfast.next and pfast.next.next:
pslow = pslow.next
pfast = pfast.next.next
k += 1
if pslow == pfast:
break
if pfast.next==None or pfast.next.next==None:
return None
# 確定有環,開始尋找
p1 = head
p2 = pslow
while p1!=p2:
p1 = p1.next
p2 = p2.next
return p1