Python数据结构-链表

Posted Python爱好者666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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)































































































































































































































































































































































































































































































































以上是关于Python数据结构-链表的主要内容,如果未能解决你的问题,请参考以下文章

python代码检测链表中的环并删除环

python代码找到链表的倒数第K个节点并打印

链表(python)

python实现链表反转(转置)

常用python日期日志获取内容循环的代码片段

python 有用的Python代码片段