数据结构和算法-链表
鏈表分類
- 單向鏈表
- 雙向鏈表
優(yōu)勢:- 刪除某個節(jié)點更加高效, 可以快速找到前驅(qū)節(jié)點
- 可以方便的在某個節(jié)點前插入元素
循環(huán)鏈表
當要處理的數(shù)據(jù)具有環(huán)形結(jié)構(gòu)的時候, 適合循環(huán)鏈表. 如約瑟夫環(huán)問題雙向循環(huán)鏈表
數(shù)組的缺點是大小固定, 一旦聲明長度就要占用連續(xù)的內(nèi)存空間, 當空間不夠用時更換更大的空間, 此時就需要將原數(shù)組的所有數(shù)據(jù)遷移過去, 比較費時. 鏈表則可以動態(tài)擴容.
數(shù)組在查詢上可以更快, 鏈表在插入和刪除上更快, 為了結(jié)合數(shù)組和鏈表的優(yōu)點, 有同時使用的情況, 比如一個網(wǎng)站的用戶注冊, 可以以A-Z為數(shù)組, 在每個字母后面加入鏈表, 這樣可以在添加新用戶的時候能快速找到要添加的鏈表并進行插入, 同時在查詢用戶的時候也能縮短查詢時間
常見邊界條件
- 鏈表為空
- 只有一個節(jié)點
- 只有兩個節(jié)點
- 指針在頭結(jié)點和尾節(jié)點的處理
常見問題
- 單鏈表反轉(zhuǎn)
- 檢測鏈表中是否有環(huán)
- 兩個有序鏈表合并
- 刪除鏈表倒數(shù)第n個節(jié)點
- 求鏈表的中間節(jié)點
單向鏈表
""" 單鏈表 """class Node(object):def __init__(self, data, next_=None):self.data = dataself.next_ = next_class SingleLinkedList(object):def __init__(self):self.head = Nonedef is_empty(self):return self.head == Nonedef size(self):current = self.headnum = 0while current != None:current = current.next_num += 1return numdef prepend(self, value):"""在頭部添加節(jié)點:param value::return:"""self.head = Node(value, self.head)def append(self, value):"""在尾部追加節(jié)點:param value::return:"""node = Node(value)if self.is_empty():self.head = nodeelse:current = self.headwhile current.next_ != None:current = current.next_current.next_ = nodedef insert(self, position, value):"""指定位置插入節(jié)點, 從1開始計數(shù):param position::param value::return:"""if position <= 1:self.prepend(value)elif position > self.size():self.append(value)else:node = Node(value)tmp_pos = 1pre_node = Nonecurrent = self.headwhile tmp_pos < position:pre_node = currentcurrent = current.next_tmp_pos += 1node.next_ = currentpre_node.next_ = nodedef delete(self, value):if self.is_empty():raise Exception("empty")pre_node = Nonecurrent = self.headwhile current != None:if current.data == value:# 判斷刪除的元素是不是第一個if not pre_node:self.head = current.next_else:pre_node.next_ = current.next_breakelse:pre_node = currentcurrent = current.next_def pop_first(self):if self.is_empty():raise Exception("empty")data = self.head.dataself.head = self.head.next_return datadef pop_last(self):if self.is_empty():raise Exception("empty")pre_node = Nonecurrent = self.headwhile current.next_ != None:pre_node = currentcurrent = current.next_data = current.dataif pre_node == None:self.head = Noneelse:pre_node.next = Nonereturn datadef find(self, value):status = Falsecurrent = self.headwhile current != None and not status:if current.data == value:status = Trueelse:current = current.next_return status單鏈表反轉(zhuǎn)
# coding:utf-8""" 單鏈表反轉(zhuǎn) """class Node(object):def __init__(self, data, next_=None):self.data = dataself.next_ = next_def reverse(linked_list):head = linked_listpre = Nonewhile head != None:current = headhead = current.next_current.next_ = prepre = currentreturn predef output(linked_list):current = linked_listres = []while current != None:res.append(current.data)current = current.next_print(res)if __name__ == '__main__':link = Node(1, Node(2, Node(3, Node(4, Node(5, Node(6, Node(7, Node(8, Node(9)))))))))output(link)root = reverse(link)output(root)""" [1, 2, 3, 4, 5, 6, 7, 8, 9] [9, 8, 7, 6, 5, 4, 3, 2, 1] """鏈表成對調(diào)換
# coding:utf-8""" 鏈表成對調(diào)換1 -> 2 -> 3 -> 4 調(diào)換后為 2 -> 1 -> 4 -> 3 """class Node(object):def __init__(self, data, next_=None):self.data = dataself.next_ = next_def swap(head):if head != None and head.next_ != None:after = head.next_head.next_ = swap(after.next_)after.next_ = headreturn afterreturn headdef output(linked_list):current = linked_listres = []while current != None:res.append(current.data)current = current.next_print(res)if __name__ == '__main__':link = Node(1, Node(2, Node(3, Node(4))))output(link)print('----')link1 = swap(link)output(link1)""" [1, 2, 3, 4] ---- [2, 1, 4, 3] """判斷是否交叉鏈表
- 求出兩個鏈表的長度之差sub_size
- 讓較長鏈表快速走sub_size步
- 最后依次比較兩條鏈表對應(yīng)的值是否相等, 相等處則是交點
時間復(fù)雜度O(m+n)
判斷鏈表是否有環(huán)
定義兩個游標first和later, first步長是1, later步長是2. 同時向前走, 如果有環(huán)一定會遇到. 復(fù)雜度O(n)
# -*- coding:utf-8 -*-""" 判斷鏈表是否有環(huán) """class Node(object):def __init__(self, data, next_=None):self.data = dataself.next_ = next_def check(head):current1 = current2 = headwhile True:current1 = current1.next_ # 指向第一個節(jié)點current2 = current2.next_.next_ # 指向第二個節(jié)點if (not current1) or (not current2):breakif current1.data == current2.data:return Truereturn Falseif __name__ == '__main__':node1 = Node(6)node2 = Node(2)node3 = Node(3)node4 = Node(4)node5 = Node(5)node6 = Node(6)node1.next_ = node2node2.next_ = node3node3.next_ = node4node4.next_ = node5node5.next_ = node6node6.next_ = node3 # 環(huán)交點assert check(node1) == True查找單鏈表倒數(shù)第k個元素
定義兩個指針first, later都初始化指向頭節(jié)點, 然后first先走k步, 再同時走, 當first到尾節(jié)點的時候, 讀出later節(jié)點的值. 復(fù)雜度是O(n)
# -*- coding:utf-8 -*-""" 找到鏈表的倒數(shù)第K個元素定義兩個游標, 第二個游標先走k-1步, 之后再同時走, 此時第一個游標停留位置就是倒數(shù)第K個元素 """class Node(object):def __init__(self, data, next_=None):self.data = dataself.next_ = next_def find_reverse_k(head, k):c1 = headcurrent = headfor _ in range(k - 1):current = current.next_c2 = currentwhile c2.next_ != None:c2 = c2.next_c1 = c1.next_return c1.dataif __name__ == '__main__':link = Node(1, Node(2, Node(3, Node(4, Node(5, Node(6, Node(7, Node(8, Node(9)))))))))assert find_reverse_k(link, 3) == 7assert find_reverse_k(link, 1) == 9assert find_reverse_k(link, 2) == 8合并兩個有序鏈表
# coding:utf-8""" 合并兩個有序單鏈表輸入:1->2->4, 1->3->4 輸出:1->1->2->3->4->4 """class Node(object):def __init__(self, data, next_=None):self.data = dataself.next_ = next_def merge2linkedlist(l1, l2):"""合并兩個有序鏈表:param l1::param l2::return:"""if l1 == None and l2 == None:raise Exception("None!!!")if l1 == None:return l2if l2 == None:return l1# 使用head為輔助節(jié)點head = Node(0)current = headwhile l1 and l2:if l1.data <= l2.data:current.next_ = l1l1 = l1.next_elif l1.data > l2.data:current.next_ = l2l2 = l2.next_current = current.next_if l1:current.next_ = l1if l2:current.next_ = l2return head.next_if __name__ == "__main__":l1 = Node(1, Node(2, Node(4)))l2 = Node(1, Node(3, Node(4)))tmp = merge2linkedlist(l1, l2)res = []while tmp:res.append(tmp.data)tmp = tmp.next_print(res)""" [1, 1, 2, 3, 4, 4] """合并K個有序單鏈表
- 方法一
把K個鏈表2個為一組進行合并, 不斷分組, 最后合并為一個有序鏈表 - 方法二
遍歷所有鏈表將所有元素放在一個數(shù)組中, 然后對數(shù)組進行排序, 最后生成一個有序鏈表.
時間復(fù)雜度:
如果所有鏈表共有n個元素, 遍歷需要O(n), 對數(shù)組排序需要O(nlogn), 最后連接O(n). 所以總的復(fù)雜度是O(n + nlogn + n), 也就是O(nlogn)
注意
我們說空間復(fù)雜度的時候, 是指除了原本的數(shù)據(jù)存儲空間外, 算法還需要的額外的存儲空間, 即不管原來所占空間是多少
資料
- <>
- <>
- <>
轉(zhuǎn)載于:https://www.cnblogs.com/zlone/p/10993902.html
總結(jié)
以上是生活随笔為你收集整理的数据结构和算法-链表的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python说文解字_杂谈06
- 下一篇: Yet Another Multiple