zoukankan      html  css  js  c++  java
  • 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)
  • 相关阅读:
    新浪微博爬虫项目
    time
    黑客增长
    python2 3 区别
    爬虫高性能相关
    登录_爬取并筛选拉钩网职位信息_自动提交简历
    破解极验验证码
    tesseract-ocr 传统验证码识别
    刻意练习
    计算学员的考试总成绩以及平均成绩
  • 原文地址:https://www.cnblogs.com/wangchunli-blogs/p/9949845.html
Copyright © 2011-2022 走看看