链表
补充:
1、哨兵节点
在某些实现中,可能会在第一个数据记录之前,或者最后一个数据记录之后添加 一个额外的哨兵节点或者哑元节点。 简化和加快一些列表处理的算法 。
2、对比
链表vs.动态数组
都需要动态分配内存块
动态数组: 通过索引访问和分配非常快速,时间复杂度为O(1)
添加元素(插入到数组的末尾)相对比较快,平摊时间复杂度为O(1)
在动态数组里的任意位置添加和删除节点会很慢,时间复杂度为O(n)
当需要对插入和删除做调整时,可能会出现不可预知的表现。 会有一些未使用的空间
链表: 在列表中的任意位置做插入和删除都很快,时间复杂度为O(1)
索引访问(随机访问)慢,时间复杂度为O(n)
一、实现
class Node: def __init__ (self, value = None, next = None): self.value = value self.next = next class LinkedList: def __init__(self): self.head = Node() self.tail = None self.length = 0 def peek(self): if not self.head.next: raise Empty( 'LinkedList is empty' ) return self.head.next def get_first(self): if not self.head.next: raise Empty( 'LinkedList is empty' ) return self.head.next def get_last(self): if not self.head.next: raise Empty( 'LinkedList is empty' ) node = self.head while node.next != None: node = node.next return node def get(self, index): if (index < 0 or index >= self.length): raise Outbound( 'index is out of bound' ); if not self.head.next: raise Empty( 'LinkedList is empty' ) node = self.head.next for i in range(index): node = node.next return node def add_first(self, value): node = Node(value, None) node.next = self.head.next self.head.next = node self.length += 1 def add_last(self, value): new_node = Node(value) node = self.head while node.next != None: node = node.next node.next = new_node self.length += 1 def add(self, index, value): if (index < 0 or index > self.length): raise Outbound( 'index is out of bound' ) if not self.head.next: raise Empty( 'LinkedList is empty' ) new_node = Node(value) node = self.head for i in range(index): node = node.next new_node.next = node.next; node.next = new_node; self.length += 1 def remove_first(self): if not self.head.next: raise Empty( 'LinkedList is empty' ) value = self.head.next self.head.next = self.head.next.next self.length -= 1 return value def remove_last(self): if not self.head.next: raise Empty( 'LinkedList is empty' ) node = self.head.next prev = self.head while node.next != None: prev = node node = node.next prev.next = None return node.value def remove(self, index): if (index < 0 or index >= self.length): raise Outbound( 'index is out of bound' ); if not self.head.next: raise Empty( 'LinkedList is empty' ) node = self.head for i in range(index): node = node.next result = node.next; node.next = node.next.next; self.length += 1 return result; def printlist(self): node = self.head.next count = 0 while node and count<20: print(node.value, end = " ") node = node.next count = count + 1 print('')
二、找到中间节点
方法:快慢指针
def find_middle(lst): assert lst.head is not None and lst.head.next is not None head = lst.head fast = head slow = head while fast is not None and fast.next is not None: fast = fast.next.next slow = slow.next return slow.value
三、判断一个链表是否有环
方法:快慢指针
def has_cycle(lst): return has_cycle_helper(lst.head) def has_cycle_helper(head): if head is None: return False slow = head fast = head while fast is not None and fast.next is not None: fast = fast.next.next slow = slow.next if slow==fast: return True return False
四、寻找循环链表开始节点
方法:快慢指针
def find_beginning(head): if head is None: return None slow = head fast = head while fast is not None and fast.next is not None: fast = fast.next.next slow = slow.next if slow==fast: fast = head break if fast is None or fast.next is None: return None while fast != slow: fast = fast.next slow = slow.next return slow
五、删除链表中的倒数第N个节点
方法:快慢指针
def remove_nth(lst, n): assert n<=lst.length and n > 0 fast = lst.head while n>0: fast = fast.next n = n - 1 slow = lst.head while fast.next is not None: fast = fast.next slow = slow.next result = slow.next slow.next = slow.next.next lst.length = lst.length - 1 return result
六、将一个链表平分为两部分
方法:快慢指针
def split(head): if (head is None): return slow = head fast = head front_last_node = slow while (fast is not None): front_last_node = slow slow = slow.next fast = fast.next.next if fast.next is not None else None front_last_node.next = None front = head back = slow return (front, back)
七、合并两个有序链表
方法:双指针
# O(m + n) def mergeTwoLists1(l1, l2): dummy = cur = Node(0) while l1 and l2: if l1.value < l2.value: cur.next = l1 l1 = l1.next else: cur.next = l2 l2 = l2.next cur = cur.next cur.next = l1 or l2 return dummy.next
递归:
# recursively def mergeTwoLists2(l1, l2): if not l1 or not l2: return l1 or l2 if l1.value < l2.value: l1.next = mergeTwoLists2(l1.next, l2) return l1 else: l2.next = mergeTwoLists2(l1, l2.next) return l2
八、找到两个相交链表的交点
方法:双指针
方法一:
def getIntersectionNode(headA, headB): curA, curB = headA, headB lenA, lenB = 0, 0 while curA is not None: lenA += 1 curA = curA.next while curB is not None: lenB += 1 curB = curB.next curA, curB = headA, headB if lenA > lenB: for i in range(lenA-lenB): curA = curA.next elif lenB > lenA: for i in range(lenB-lenA): curB = curB.next while curB != curA: curB = curB.next curA = curA.next return curA
方法二:
def getIntersectionNode2(headA, headB): if headA and headB: A, B = headA, headB while A!=B: A = A.next if A else headB B = B.next if B else headA return A
九、链表插入排序
def insertionSortList(head): dummy = Node(0) cur = head # pre is the sorted part # when see a new node, start from dummy # cur is the unsorted part while cur is not None: pre = dummy while pre.next is not None and pre.next.value < cur.value: pre = pre.next temp = cur.next cur.next = pre.next pre.next = cur cur = temp return dummy.next
十、链表排序,要求时间O(nlogn),空间O(1)
方法:归并排序
def sortList(head): if head is None or head.next is None: return head mid = getMiddle(head) rHead = mid.next mid.next = None return merge(sortList(head), sortList(rHead)) def merge(lHead, rHead): dummyNode = dummyHead = Node(0) while lHead and rHead: if lHead.value < rHead.value: dummyHead.next = lHead lHead = lHead.next else: dummyHead.next = rHead rHead = rHead.next dummyHead = dummyHead.next if lHead: dummyHead.next = lHead elif rHead: dummyHead.next = rHead return dummyNode.next def getMiddle(head): if head is None: return head slow = head fast = head while fast.next and fast.next.next: slow = slow.next fast = fast.next.next return slow
十一、分区链表partition
def partition(head, x): left_head = Node(None) # head of the list with nodes values < x right_head = Node(None) # head of the list with nodes values >= x left = left_head # attach here nodes with values < x right = right_head # attach here nodes with values >= x # traverse the list and attach current node to left or right nodes while head: if head.value < x: left.next = head left = left.next else: # head.val >= x right.next = head right = right.next head = head.next right.next = None # set tail of the right list to None left.next = right_head.next # attach left list to the right return left_head.next # head of a new partitioned list
十二、反转链表
def reverse(lst): head = lst.head result = None current = head.next nxt = None while current is not None: nxt = current.next current.next = result result = current current = nxt head.next = result
递归:
def reverseRecursion(node): if (node is None or node.next is None): return node p = reverseRecursion(node.next) node.next.next = node node.next = None return p
十三、从位置m到位置n反转链表
def reverseBetween(head, m, n): if m == n: return head dummyNode = Node(0) dummyNode.next = head pre = dummyNode for i in range(m - 1): pre = pre.next # reverse the [m, n] nodes result = None current = pre.next for i in range(n - m + 1): nxt = current.next current.next = result result = current current = nxt pre.next.next = current pre.next = result return dummyNode.next
十四、成对交换节点
def swapPairs(head): dummy = cur = Node(0) dummy.next = head while cur.next and cur.next.next: p1 = cur.next p2 = cur.next.next cur.next = p2 p1.next = p2.next p2.next = p1 cur = cur.next.next return dummy.next
十五、以K为一组交换链表
def reverseKGroup(head, k): if head is None or k < 2: return head next_head = head for i in range(k - 1): next_head = next_head.next if next_head is None: return head ret = next_head current = head while next_head: tail = current prev = None for i in range(k): if next_head: next_head = next_head.next nxt = current.next current.next = prev prev = current current = nxt tail.next = next_head or current return ret
十六、判断是否是回文联表 要求时间O(N),空间O(1)
def isPalindrome(head): rev = None slow = fast = head while fast and fast.next: fast = fast.next.next rev, rev.next, slow = slow, rev, slow.next if fast: slow = slow.next while rev and rev.value == slow.value: slow = slow.next rev = rev.next return not rev
十七、从有序链表中删除重复元素(保留)
def deleteDuplicates(head): if head == None: return head node = head while node.next: if node.value == node.next.value: node.next = node.next.next else: node = node.next return head
十八、从有序链表中删除重复元素(不保留)
def deleteDuplicates2(head): dummy = pre = Node(0) dummy.next = head while head and head.next: if head.value == head.next.value: while head and head.next and head.value == head.next.value: head = head.next head = head.next pre.next = head else: pre = pre.next head = head.next return dummy.next