⊰第三篇⊱ 链表
為什么需要鏈表
順序表的構(gòu)建需要預(yù)先知道數(shù)據(jù)大小來(lái)申請(qǐng)連續(xù)的存儲(chǔ)空間,而在進(jìn)行擴(kuò)充時(shí)又需要進(jìn)行數(shù)據(jù)的搬遷,所以使用起來(lái)并不是很靈活。
鏈表結(jié)構(gòu)可以充分利用計(jì)算機(jī)內(nèi)存空間,實(shí)現(xiàn)靈活的內(nèi)存動(dòng)態(tài)管理。
鏈表的定義
鏈表(Linked list)是一種常見(jiàn)的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),是一種線性表,但是不像順序表一樣連續(xù)存儲(chǔ)數(shù)據(jù),而是在每一個(gè)節(jié)點(diǎn)(數(shù)據(jù)存儲(chǔ)單元)里存放下一個(gè)節(jié)點(diǎn)的位置信息(即地址)。
單向鏈表
單向鏈表也叫單鏈表,是鏈表中最簡(jiǎn)單的一種形式,它的每個(gè)節(jié)點(diǎn)包含兩個(gè)域,一個(gè)信息域(元素域)和一個(gè)鏈接域。這個(gè)鏈接指向鏈表中的下一個(gè)節(jié)點(diǎn),而最后一個(gè)節(jié)點(diǎn)的鏈接域則指向一個(gè)空值。
- 表元素域elem用來(lái)存放具體的數(shù)據(jù)。
- 鏈接域next用來(lái)存放下一個(gè)節(jié)點(diǎn)的位置(python中的標(biāo)識(shí))
- 變量p指向鏈表的頭節(jié)點(diǎn)(首節(jié)點(diǎn))的位置,從p出發(fā)能找到表中的任意節(jié)點(diǎn)。
節(jié)點(diǎn)實(shí)現(xiàn)
class SingleNode(object):"""單鏈表的結(jié)點(diǎn)"""def __init__(self,item):# _item存放數(shù)據(jù)元素self.item = item# _next是下一個(gè)節(jié)點(diǎn)的標(biāo)識(shí)self.next = None單鏈表的操作
- is_empty() 鏈表是否為空
- length() 鏈表長(zhǎng)度
- travel() 遍歷整個(gè)鏈表
- add(item) 鏈表頭部添加元素
- append(item) 鏈表尾部添加元素
- insert(pos, item) 指定位置添加元素
- remove(item) 刪除節(jié)點(diǎn)
- search(item) 查找節(jié)點(diǎn)是否存在
單鏈表的實(shí)現(xiàn)
class SingleLinkList(object):"""單鏈表"""def __init__(self):self._head = Nonedef is_empty(self):"""判斷鏈表是否為空"""return self._head == Nonedef length(self):"""鏈表長(zhǎng)度"""# cur初始時(shí)指向頭節(jié)點(diǎn)cur = self._headcount = 0# 尾節(jié)點(diǎn)指向None,當(dāng)未到達(dá)尾部時(shí)while cur != None:count += 1# 將cur后移一個(gè)節(jié)點(diǎn)cur = cur.nextreturn countdef travel(self):"""遍歷鏈表"""cur = self._headwhile cur != None:print cur.item,cur = cur.nextprint ""頭部添加元素
def add(self, item):"""頭部添加元素"""# 先創(chuàng)建一個(gè)保存item值的節(jié)點(diǎn)node = SingleNode(item)# 將新節(jié)點(diǎn)的鏈接域next指向頭節(jié)點(diǎn),即_head指向的位置node.next = self._head# 將鏈表的頭_head指向新節(jié)點(diǎn)self._head = node
尾部添加元素
def append(self, item):"""尾部添加元素"""node = SingleNode(item)# 先判斷鏈表是否為空,若是空鏈表,則將_head指向新節(jié)點(diǎn)if self.is_empty():self._head = node# 若不為空,則找到尾部,將尾節(jié)點(diǎn)的next指向新節(jié)點(diǎn)else:cur = self._headwhile cur.next != None:cur = cur.nextcur.next = node指定位置添加元素
def insert(self, pos, item):"""指定位置添加元素"""# 若指定位置pos為第一個(gè)元素之前,則執(zhí)行頭部插入if pos <= 0:self.add(item)# 若指定位置超過(guò)鏈表尾部,則執(zhí)行尾部插入elif pos > (self.length()-1):self.append(item)# 找到指定位置else:node = SingleNode(item)count = 0# pre用來(lái)指向指定位置pos的前一個(gè)位置pos-1,初始從頭節(jié)點(diǎn)開(kāi)始移動(dòng)到指定位置pre = self._headwhile count < (pos-1):count += 1pre = pre.next# 先將新節(jié)點(diǎn)node的next指向插入位置的節(jié)點(diǎn)node.next = pre.next# 將插入位置的前一個(gè)節(jié)點(diǎn)的next指向新節(jié)點(diǎn)pre.next = node刪除節(jié)點(diǎn)
def remove(self,item):"""刪除節(jié)點(diǎn)"""cur = self._headpre = Nonewhile cur != None:# 找到了指定元素if cur.item == item:# 如果第一個(gè)就是刪除的節(jié)點(diǎn)if not pre:# 將頭指針指向頭節(jié)點(diǎn)的后一個(gè)節(jié)點(diǎn)self._head = cur.nextelse:# 將刪除位置前一個(gè)節(jié)點(diǎn)的next指向刪除位置的后一個(gè)節(jié)點(diǎn)pre.next = cur.nextbreakelse:# 繼續(xù)按鏈表后移節(jié)點(diǎn)pre = curcur = cur.next查找節(jié)點(diǎn)是否存在
def search(self,item):"""鏈表查找節(jié)點(diǎn)是否存在,并返回True或者False"""cur = self._headwhile cur != None:if cur.item == item:return Truecur = cur.nextreturn False測(cè)試
if __name__ == "__main__":ll = SingleLinkList()ll.add(1)ll.add(2)ll.append(3)ll.insert(2, 4)print "length:",ll.length()ll.travel()print ll.search(3)print ll.search(5)ll.remove(1)print "length:",ll.length()ll.travel()鏈表與順序表的對(duì)比
鏈表失去了順序表隨機(jī)讀取的優(yōu)點(diǎn),同時(shí)鏈表由于增加了結(jié)點(diǎn)的指針域,空間開(kāi)銷(xiāo)比較大,但對(duì)存儲(chǔ)空間的使用要相對(duì)靈活。
鏈表與順序表的各種操作復(fù)雜度如下所示:
注意雖然表面看起來(lái)復(fù)雜度都是 O(n),但是鏈表和順序表在插入和刪除時(shí)進(jìn)行的是完全不同的操作。鏈表的主要耗時(shí)操作是遍歷查找,刪除和插入操作本身的復(fù)雜度是O(1)。順序表查找很快,主要耗時(shí)的操作是拷貝覆蓋。因?yàn)槌四繕?biāo)元素在尾部的特殊情況,順序表進(jìn)行插入和刪除時(shí)需要對(duì)操作點(diǎn)之后的所有元素進(jìn)行前后移位操作,只能通過(guò)拷貝和覆蓋的方法進(jìn)行。
單向循環(huán)鏈表
單鏈表的一個(gè)變形是單向循環(huán)鏈表,鏈表中最后一個(gè)節(jié)點(diǎn)的next域不再為None,而是指向鏈表的頭節(jié)點(diǎn)。
操作
- is_empty() 判斷鏈表是否為空
- length() 返回鏈表的長(zhǎng)度
- travel() 遍歷
- add(item) 在頭部添加一個(gè)節(jié)點(diǎn)
- append(item) 在尾部添加一個(gè)節(jié)點(diǎn)
- insert(pos, item) 在指定位置pos添加節(jié)點(diǎn)
- remove(item) 刪除一個(gè)節(jié)點(diǎn)
- search(item) 查找節(jié)點(diǎn)是否存在
實(shí)現(xiàn)
class Node(object):"""節(jié)點(diǎn)"""def __init__(self, item):self.item = itemself.next = Noneclass SinCycLinkedlist(object):"""單向循環(huán)鏈表"""def __init__(self):self._head = Nonedef is_empty(self):"""判斷鏈表是否為空"""return self._head == Nonedef length(self):"""返回鏈表的長(zhǎng)度"""# 如果鏈表為空,返回長(zhǎng)度0if self.is_empty():return 0count = 1cur = self._headwhile cur.next != self._head:count += 1cur = cur.nextreturn countdef travel(self):"""遍歷鏈表"""if self.is_empty():returncur = self._headprint cur.item,while cur.next != self._head:cur = cur.nextprint cur.item,print ""def add(self, item):"""頭部添加節(jié)點(diǎn)"""node = Node(item)if self.is_empty():self._head = nodenode.next = self._headelse:#添加的節(jié)點(diǎn)指向_headnode.next = self._head# 移到鏈表尾部,將尾部節(jié)點(diǎn)的next指向nodecur = self._headwhile cur.next != self._head:cur = cur.nextcur.next = node#_head指向添加node的self._head = nodedef append(self, item):"""尾部添加節(jié)點(diǎn)"""node = Node(item)if self.is_empty():self._head = nodenode.next = self._headelse:# 移到鏈表尾部cur = self._headwhile cur.next != self._head:cur = cur.next# 將尾節(jié)點(diǎn)指向nodecur.next = node# 將node指向頭節(jié)點(diǎn)_headnode.next = self._headdef insert(self, pos, item):"""在指定位置添加節(jié)點(diǎn)"""if pos <= 0:self.add(item)elif pos > (self.length()-1):self.append(item)else:node = Node(item)cur = self._headcount = 0# 移動(dòng)到指定位置的前一個(gè)位置while count < (pos-1):count += 1cur = cur.nextnode.next = cur.nextcur.next = nodedef remove(self, item):"""刪除一個(gè)節(jié)點(diǎn)"""# 若鏈表為空,則直接返回if self.is_empty():return# 將cur指向頭節(jié)點(diǎn)cur = self._headpre = None# 若頭節(jié)點(diǎn)的元素就是要查找的元素itemif cur.item == item:# 如果鏈表不止一個(gè)節(jié)點(diǎn)if cur.next != self._head:# 先找到尾節(jié)點(diǎn),將尾節(jié)點(diǎn)的next指向第二個(gè)節(jié)點(diǎn)while cur.next != self._head:cur = cur.next# cur指向了尾節(jié)點(diǎn)cur.next = self._head.nextself._head = self._head.nextelse:# 鏈表只有一個(gè)節(jié)點(diǎn)self._head = Noneelse:pre = self._head# 第一個(gè)節(jié)點(diǎn)不是要?jiǎng)h除的while cur.next != self._head:# 找到了要?jiǎng)h除的元素if cur.item == item:# 刪除pre.next = cur.nextreturnelse:pre = curcur = cur.next# cur 指向尾節(jié)點(diǎn)if cur.item == item:# 尾部刪除pre.next = cur.nextdef search(self, item):"""查找節(jié)點(diǎn)是否存在"""if self.is_empty():return Falsecur = self._headif cur.item == item:return Truewhile cur.next != self._head:cur = cur.nextif cur.item == item:return Truereturn Falseif __name__ == "__main__":ll = SinCycLinkedlist()ll.add(1)ll.add(2)ll.append(3)ll.insert(2, 4)ll.insert(4, 5)ll.insert(0, 6)print "length:",ll.length()ll.travel()print ll.search(3)print ll.search(7)ll.remove(1)print "length:",ll.length()ll.travel()雙向鏈表
一種更復(fù)雜的鏈表是“雙向鏈表”或“雙面鏈表”。每個(gè)節(jié)點(diǎn)有兩個(gè)鏈接:一個(gè)指向前一個(gè)節(jié)點(diǎn),當(dāng)此節(jié)點(diǎn)為第一個(gè)節(jié)點(diǎn)時(shí),指向空值;而另一個(gè)指向下一個(gè)節(jié)點(diǎn),當(dāng)此節(jié)點(diǎn)為最后一個(gè)節(jié)點(diǎn)時(shí),指向空值。
操作
- is_empty() 鏈表是否為空
- length() 鏈表長(zhǎng)度
- travel() 遍歷鏈表
- add(item) 鏈表頭部添加
- append(item) 鏈表尾部添加
- insert(pos, item) 指定位置添加
- remove(item) 刪除節(jié)點(diǎn)
- search(item) 查找節(jié)點(diǎn)是否存在
實(shí)現(xiàn)
class Node(object):"""雙向鏈表節(jié)點(diǎn)"""def __init__(self, item):self.item = itemself.next = Noneself.prev = Noneclass DLinkList(object):"""雙向鏈表"""def __init__(self):self._head = Nonedef is_empty(self):"""判斷鏈表是否為空"""return self._head == Nonedef length(self):"""返回鏈表的長(zhǎng)度"""cur = self._headcount = 0while cur != None:count += 1cur = cur.nextreturn countdef travel(self):"""遍歷鏈表"""cur = self._headwhile cur != None:print cur.item,cur = cur.nextprint ""def add(self, item):"""頭部插入元素"""node = Node(item)if self.is_empty():# 如果是空鏈表,將_head指向nodeself._head = nodeelse:# 將node的next指向_head的頭節(jié)點(diǎn)node.next = self._head# 將_head的頭節(jié)點(diǎn)的prev指向nodeself._head.prev = node# 將_head 指向nodeself._head = nodedef append(self, item):"""尾部插入元素"""node = Node(item)if self.is_empty():# 如果是空鏈表,將_head指向nodeself._head = nodeelse:# 移動(dòng)到鏈表尾部cur = self._headwhile cur.next != None:cur = cur.next# 將尾節(jié)點(diǎn)cur的next指向nodecur.next = node# 將node的prev指向curnode.prev = curdef search(self, item):"""查找元素是否存在"""cur = self._headwhile cur != None:if cur.item == item:return Truecur = cur.nextreturn False指定位置插入節(jié)點(diǎn)
def insert(self, pos, item):"""在指定位置添加節(jié)點(diǎn)"""if pos <= 0:self.add(item)elif pos > (self.length()-1):self.append(item)else:node = Node(item)cur = self._headcount = 0# 移動(dòng)到指定位置的前一個(gè)位置while count < (pos-1):count += 1cur = cur.next# 將node的prev指向curnode.prev = cur# 將node的next指向cur的下一個(gè)節(jié)點(diǎn)node.next = cur.next# 將cur的下一個(gè)節(jié)點(diǎn)的prev指向nodecur.next.prev = node# 將cur的next指向nodecur.next = node刪除元素
def remove(self, item):"""刪除元素"""if self.is_empty():returnelse:cur = self._headif cur.item == item:# 如果首節(jié)點(diǎn)的元素即是要?jiǎng)h除的元素if cur.next == None:# 如果鏈表只有這一個(gè)節(jié)點(diǎn)self._head = Noneelse:# 將第二個(gè)節(jié)點(diǎn)的prev設(shè)置為Nonecur.next.prev = None# 將_head指向第二個(gè)節(jié)點(diǎn)self._head = cur.nextreturnwhile cur != None:if cur.item == item:# 將cur的前一個(gè)節(jié)點(diǎn)的next指向cur的后一個(gè)節(jié)點(diǎn)cur.prev.next = cur.next# 將cur的后一個(gè)節(jié)點(diǎn)的prev指向cur的前一個(gè)節(jié)點(diǎn)cur.next.prev = cur.prevbreakcur = cur.next測(cè)試
if __name__ == "__main__":ll = DLinkList()ll.add(1)ll.add(2)ll.append(3)ll.insert(2, 4)ll.insert(4, 5)ll.insert(0, 6)print "length:",ll.length()ll.travel()print ll.search(3)print ll.search(4)ll.remove(1)print "length:",ll.length()ll.travel()轉(zhuǎn)載于:https://www.cnblogs.com/yzls/articles/9551783.html
總結(jié)
- 上一篇: IBM的SOA方法论之一——五个切入点和
- 下一篇: 总结一些通用的处理方法