1. 程式人生 > >Python資料結構-連結串列

Python資料結構-連結串列

1)概念:連結串列是一種物理儲存單元上非連續、非順序的儲存結構資料元素的邏輯順序是通過連結串列中的指標連結次序實現的。連結串列由一系列結點(連結串列中每一個元素稱為結點)組成,結點可以在執行時動態生成。每個結點包括兩個部分:一個是儲存資料元素的資料域,另一個是儲存下一個結點地址的指標域。 相比於線性表順序結構,操作複雜。由於不必須按順序儲存,連結串列在插入的時候可以達到O(1)的複雜度,比另一種線性表順序錶快得多,但是查詢一個節點或者訪問特定編號的節點則需要O(n)的時間,而線性表和順序表相應的時間複雜度分別是O(logn)和O(1)。

使用連結串列結構可以克服陣列連結串列需要預先知道資料大小的缺點,連結串列結構可以充分利用計算機記憶體空間,實現靈活的記憶體動態管理。但是連結串列失去了

陣列隨機讀取的優點,同時連結串列由於增加了結點的指標域,空間開銷比較大。連結串列最明顯的好處就是,常規陣列排列關聯專案的方式可能不同於這些資料專案在記憶體磁碟上順序,資料的存取往往要在不同的排列順序中轉換。連結串列允許插入和移除表上任意位置上的節點,但是不允許隨機存取。連結串列有很多種不同的型別:單向連結串列雙向連結串列以及迴圈連結串列。連結串列可以在多種程式語言中實現。像Lisp和Scheme這樣的語言的內建資料型別中就包含了連結串列的存取和操作。程式語言或面嚮物件語言,如C,C++和Java依靠易變工具來生成連結串列。

2)單向連結串列實現

class SingleNode:
    """
節點類"""
   
def __init__(self,value,next=None):
        self.value = value
        self.next = next

    def __repr__(self):
        return '{}==>{}'.format(self.value,self.next.value if self.next else None)

class LinkedList:
    def __init__(self):
        self.head = None
        self.tail = None

    def append(self,value):
        """
尾部追加"""
       
node = SingleNode(value)        #頭尾是誰
                                        #當前尾部
                                        #當前的尾部的下一個指向新的node。
         #當前尾部
        tail = self.tail       #第一個元素加進來,問self.tail尾部是誰。
        if tail is None:
            self.head = node
        else:
            tail.next = node
        self.tail = node

        return self

    def iternodes(self):
        current = self.head
        while current:
            yield current
            current = current.next


ll = LinkedList()
ll.append('abd').append(1).append(3).append('def')


for i in ll.iternodes():
    print(i)

思路:(1)首先要定義兩個類。節點類和容器類

(2)考慮到節點元素和節點元素的下一跳是誰。

(3)元素的容器內要考慮到頭部和尾部。

(4)定義append方法,尾部追加元素,當前節點等於第一個節點類追加元素。

(5)考慮到如果容器內沒有元素,那麼當前的頭部和尾部都為None,追加一個元素後,頭部不變,尾部就是當前的node。

(6)如果不為空,頭部不變,尾部為下一跳,最後當前的尾部為例項的尾部。

(7)定義迭代方法。利用生成器,每次取元素的當前節點,從頭開始,yield當前元素,下一跳元素,當前節點等下一跳的元素。

3)#雙向列表
class SingleNode:
    """節點類"""
   
def __init__(self,value,next=None,prev=None):
        self.value = value
        self.next = next
        self.prev = prev

    def __repr__(self):
        return '{}<=={}==>{}'.format(
            self.prev.value if self.prev else None,
            self.value,
            self.next.value if self.next else None)

class LinkedList:
    """容器類"""
   
def __init__(self):
        self.head = None
        self.tail = None

    def append(self,value):
        """尾部追加"""
       
node = SingleNode(value)        #頭尾是誰
                                        #當前尾部
                                        #當前的尾部的下一個指向新的node。
         #當前尾部
        tail = self.tail       #第一個元素加進來,問self.tail尾部是誰。
        if tail is None:     #新增第一個元素
            self.head = node
        else:
            tail.next = node
            node.prev = tail    #新增新元素進來,此時尾部還未指向新節點node,當前尾部還是上一個node的尾部。
                                # 所以新節點的上一跳為當前的尾部。
        self.tail = node

        return self

    def pop(self):
        """尾部彈出"""
       
#empty
        if self.tail is None:
            raise Exception('empty')
        #just one
        # if self.head.next is None:
        # if self.tail.prev is None:
        #node = self.tail
        oldtail = self.tail  #等價於上面
        if self.head is self.tail:  #just one current
            self.head = None
            self.tail = None
        else:
            # node.prev = None
            # node.prev.next = None
            # self.tail = node.prev    #更新尾部
            prev = oldtail.prev
            prev.next = None
            self.tail = prev    #等價於上面的
        oldtail.prev = None
        return oldtail

    def insert(self,index,value):
        if index < 0:
            raise IndexError('Wrong index{}'.format(index))

        current = None
        for i,node in enumerate(self.iternodes()):
            if index == i:
                current = node
                break
        else:
            #超過當前迭代。index>length -1
            self.append(value)  #空連結串列直接尾部追加,然後返回了
            return
        #找到內部的插入點,非空的
        #至少node一定有,不能是node
        prev = current.prev
        #next = current.next

        node = SingleNode(value)
        if index == 0:
            node.next = current
            current.prev = node

            self.head = node
        else:
            prev.next = node
            node.next = current
            current.prev = node
            node.prev = prev

    def remove(self,index):

    #很多元素
    #兩個元素
    #1個元素
    #0個元素
        if index < 0:
            raise IndexError('Wrong index{}'.format(index))

        if self.tail is None:     #0個元素
            raise Exception('empty')

        if self.head is self.tail:  #一個元素
            node = self.head
            self.head = None
            self.tail = None
            del node
            return 0

        current = None
        for i, node in enumerate(self.iternodes()):
            if index == i:
                current = node
                break
        # else:
        #     raise IndexError('out of boundary')
        else:
            # 超過當前迭代。index>length -1
            self.pop()  # 空連結串列直接尾部追加,然後返回了
            return
        prev = current.prev
        next = current.next

        if index == 0:
            next.prev = None
            self.head = next
        #tail 處理
        elif next is None:  #移除尾部
            prev.next = None
            self.tail = prev
        else:#mid處理
            prev.next = next
            next.prev = prev
        del current
        return index

    # def iternodes(self):
    #     current = self.head
    #     while current:
    #         yield current
    #         current = current.next

    def iternodes(self,reverse = False):
        current = self.tail if reverse else self.head
        while current:
            yield current
            current = current.prev if reverse else current.next

ll = LinkedList()
ll.append('abd').append(1).append(3).append('def')

for i in ll.iternodes():
    print(i)
print('+++++++')
print(ll.pop())
print(ll.pop())
ll.insert(1000,'acd')
ll.insert(3,3)
print('-----------------')
for i in ll.iternodes(True):
    print(i)
ll.remove(1000)

for i in ll.iternodes():
    print(i)

思路:(1)在單向連結串列的基礎上改進雙向連結串列。因為是雙向的所喲增加上一跳。

(2)定義pop方法,尾部彈出,考慮到連結串列裡面只有一個元素,為空和不為空的三種情況。一、如果為空的話,直接丟擲異常。二、一個元素的話,頭部和尾部全部為空。三、定義舊的尾部為原來的尾部,上一跳為原來尾部的上一跳,上一跳的下一跳變為None,新的尾部為原來node的上一跳,舊的尾部的上一跳為空,返回舊尾部。

(3)Insert方法(需要索引index和值),一、首先不支援副索引,如果輸入的索引為負數的,直接丟擲異常。二、索引超屆的的直接尾部追加。三、利用for迴圈來迭代連結串列,索引對應迭代序號,如果索引為0的情況下,對應的元素上一跳為新元素,當前元素的下一跳為對應的元素node。如果在中間插入的話,需要有四種改變,前面元素的下一跳為當前要插入的元素,後面的元素上一跳為當前這個元素。當前元素前元素的前一跳還是前一跳,前面元素的下一跳是當前元素。

else:

 prev.next = node

node.next = current

current.prev = node

node.prev = prev

(4)remove要考慮四種情況:有很多元素,有兩個元素,有一個元素,有0個元素。一、支援副索引。二、0個元素的話,直接丟擲異常屬性。三、一個元素的話,頭部尾部全部為空。

4)改變成為容器;
class SingleNode:
    def __init__(self,value,next = None,prev = None):
        self.value = value
        self.next = next
        self.prev = prev

    def __repr__(self):
        return "{}<=={}==>{}".format(
            self.prev.value if self.prev else None,
            self.value,
            self.next.value if self.next else None)

class LinkList:
    def __init__(self):
        self.head = None
        self.tail = None
        self.items = []

    def append(self,value):
        node = SingleNode(value)
        tail = self.tail
        if tail is None:
            # self.tail = node
            self.head = node
        else:
            tail.next = node
            node.prev = tail

        self.tail = node
        self.items.append(node)
        return self

    def pop(self):
        if self.tail is None:      #empty
            raise Exception('empty')
        oldtail = self.tail
        if self.head is self.tail:
            self.tail = None
            self.head = None
        else:
            prev = oldtail.prev
            prev.next = None
            self.tail = prev
        oldtail.prev = None
        self.items.pop()

        return oldtail

    def insert(self,index,value,):
        if index < 0:
            raise IndexError('wrong index{}'.format(index))

        current = None
        for i,conde in enumerate(self.iternodes()):
            if index == i:
                current = conde
                break
        else:   ###超過當前迭代。
            self.append(value)
            # self.items.append(value)
            return

        #找到內部插入點
        prev = current.prev
        next = current.next

        node = SingleNode(value)

        if index == 0:   #在頭部插入
            node.next = current
            current.prev = node

            self.head = node

        else:
            current.prev = node
            node.next = current
            prev.next = node
            node.prev = prev
        self.items.insert(index,node)

    def remove(self,index):

        if index < 0 :
            raise IndexError('Wrong index{}'.format(index))

        if self.tail is None:    #0個元素
            raise Exception('empty')

        if self.head is self.tail:#一個元素
            node  = self.head
            self.head = None
            self.tail = None
            del node
            self.items.pop()
            return 0

        current  = None
        for i,node in enumerate(self.iternodes()):
            if index == i:
                current = node
                break
        else:
            self.pop()
            self.items.pop()
            return
        prev = current.prev
        next = current.next


        if index == 0:
            next.prev = None
            self.head = next
        else:  #中間的處理
            prev.next = next
            next.prev = prev
        del current
        self.items.pop(index)
        return index



    # def iternodes(self):
    #     current = self.head
    #     while current:
    #         yield current
    #         current = current.next
    #

    def iternodes(self,revese=False):
        current = self.head
        while current:
            yield current
            current =self.tail if revese else current.next
 
 

思路:改變容器化就是利用技巧和原來的保持一致就行了。

(1)容器裡面設定一個屬性self.items = []初始化一個列表。

(2)Append方法裡面和原來的方法一致,self.items.append(node)

(3)Pop方法裡面和原方法一樣,也是尾部增加一個self.items.pop()尾部彈出一個元素。

(4)insert方法裡面,超出索引的話,直接尾部增加元素,採用self.items.append(value).找到尾部插入點:self.items.insert(index,node)

(5)remove方法,如果是一個元素的話,也是採用尾部彈出的方法,self.items.pop().多個元素的話直接就是self.items.pop(index)

1)使用getitem查詢元素

class SingleNode:
    def __init__(self,value,next = None,prev = None):
        self.value = value
        self.next = next
        self.prev = prev

    def __repr__(self):
        return "{}<=={}==>{}".format(
            self.prev.value if self.prev else None,
            self.value,
            self.next.value if self.next else None)

class LinkList:
    def __init__(self):
        self.head = None
        self.tail = None
        self.items = []

    def append(self,value):
        node = SingleNode(value)
        tail = self.tail
        if tail is None:
            # self.tail = node
            self.head = node
        else:
            tail.next = node
            node.prev = tail

        self.tail = node
        self.items.append(node)
        return self

    def pop(self):
        if self.tail is None:      #empty
            raise Exception('empty')
        oldtail = self.tail
        if self.head is self.tail:
            self.tail = None
            self.head = None
        else:
            prev = oldtail.prev
            prev.next = None
            self.tail = prev
        oldtail.prev = None
        self.items.pop()

        return oldtail

    def insert(self,index,value,):
        if index < 0:
            raise IndexError('wrong index{}'.format(index))

        current = None
        for i,conde in enumerate(self.iternodes()):
            if index == i:
                current = conde
                break
        else:   ###超過當前迭代。
            self.append(value)
            # self.items.append(value)
            return

        #找到內部插入點
        prev = current.prev
        next = current.next

        node = SingleNode(value)

        if index == 0:   #在頭部插入
            node.next = current
            current.prev = node

            self.head = node

        else:
            current.prev = node
            node.next = current
            prev.next = node
            node.prev = prev
        self.items.insert(index,node)

    def remove(self,index):

        if index < 0 :
            raise IndexError('Wrong index{}'.format(index))

        if self.tail is None:    #0個元素
            raise Exception('empty')

        if self.head is self.tail:#一個元素
            node  = self.head
            self.head = None
            self.tail = None
            del node
            self.items.pop()
            return 0

        current  = None
        for i,node in enumerate(self.iternodes()):
            if index == i:
                current = node
                break
        else:
            self.pop()
            self.items.pop()
            return
        prev = current.prev
        next = current.next


        if index == 0:
            next.prev = None
            self.head = next
        else:  #中間的處理
            prev.next = next
            next.prev = prev
        del current
        self.items.pop(index)
        return index



    # def iternodes(self):
    #     current = self.head
    #     while current:
    #         yield current
    #         current = current.next
    #

    def iternodes(self,revese=False):
        current = self.head
        while current:
            yield current
            current =self.tail if revese else current.next

    # def __len__(self):
    #     return len()
    #
    # def __setitem__(self, key, value):
    #     self.items[key] = value
    #
    # def __getitem__(self, index):
    #     return self.items[index]
    def getitem(self,index):
        if index < 0:
            raise Exception('wrong index{}'.format(index))

        current = None
        for i,node in enumerate(self.iternodes()):
            if i == index:
                return self.items[index]
        else:
            return self.items[-1]


ll = LinkList()
ll.append(2).append(3).append(4).append(5)
for i in ll.iternodes():
    print(i)
print('-------------')
ll.pop()
ll.pop()
for i in ll.iternodes():
    print(i)

ll.insert(5,5)
ll.insert(100,100)
for i in ll.iternodes():
    print(i)
print('++++++++++')
ll.remove(1)
for i in ll.iternodes():
    print(i)