• python中的数据结构-链表


    一.什么是链表

    链表是由一系列节点构成,每个节点由一个值域和指针域构成,值域中存储着用户数据,指针域中存储这指向下一个节点的指针.根据结构的不同,链表可以分为单向链表、单向循环链表、双向链表、双向循环链表等。单向链表的结构如下图所示:

     

    head 节点永远指向第一个节点, tail节点永远指向最后一个节点,节点中最后一个指针指向的是None 值,链表本质上就是由指针链接起来的一系列值.

    二.为什么使用链表

    我们经常拿链表和数组作比较,实际上数组是一组固定长度的序列,链表可以动态地分配元素,下面我们了解一下使用链表的优缺点

      优点:

      链表节省内存.它只针对待存储数据分配所需内存,在创建数组时,必须预先设置数组的大小,然后再添加数据,这可能会浪费内存。

      缺点

      查找或访问特定节点的时间是O(n). 在链接列表中查找值时,必须从头开始,并一次检查一每个元素以找到要查找的值。 如果链接列表的长度为n,则最多花费O(n)。

      而很多语言中在数组中查找特定的元素则需花费O(1)时间

    三.python 实现链表

          1)节点

      python 用类来实现链表的数据结构,节点(Node)是链表中存储数据的地方,除了数据之外节点中还有指向下一个节点的指针。节点是实现链表的基本模块,下边用python代码来实现一个节点类

     class Node:
         def _init_(self,val):
           self.val=val
           self.next_node = None       #the pointer initially points to pointer
    
         def get_val(self):   
           return self.val            #returns the stored data
    
         def get_next(self):
           return self.next_node       #returns the next node (the node to which the object node points)
    
         def set_val(self, new_val):
            self.val = new_val       # reset the vaue to a new value
    def set_next(self, new_next): self.next_node = new_next # reset the pointer to a new node

            此节点类只有一个构建函数,接收一个数据参数,其中next表示指针域的指针,接下来我们用如下方式去初始化一个链表:

    node1 = Node(4)
    node2 = Node(21)
    node3 = Node(90)
    node1.next = node2  #4->21
    node2.next = node3  #21->90
    # the entire linked list now looks like: 4->21->90

       借助上边的节点类我们可以很方便的构造出链表

      2)链表

      单向链表的实现包含了如下几个方法:

      append(): 向链表中增加一个元素

           insert(): 向链表中插入一个新节点

      size(): 返回链表的长度

      search(): 在链表中查找数据项是否存在

      delete(): 删除链表中的数据项

            empty(): 判断链表是否为空

            iterate(): 遍历链表

            链表的头结点:

      首先构建链表的头结点也就是链表中的第一个节点,当链表在初始化时不包含任何节点,所以它的头节点设置为空  

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

      实例化代码如下

    linklist = LinkedList()

                  append()

                  append方法表示增加元素到链表,这和insert方法不同,前者使新增加的元素成为链表中第一个节点,而后者是根据索引值来判断插入到链表的哪个位置。代码如下:

      def append(self, val):
         new_node = Node(val)
         if self.head is None:
          self.head = new_node
          self.tail = new_node
         else:
          self.tail.set_next(new_node)
          self.tail = new_node

            insert()

            该方法获得一个数据,对于给定数据初始化一个节点,并将该节点添加到链表中去。最简单的实现方法是把它插入到链表头处,并让新节点指向原来的头结点,该方法二时间复杂度为O(1):

    def insert(self, val):
        new_node = Node(val)
        new_node.set_next(self.head)
        self.head = new_node

      如果要在特定位置插入节点要提前找到这个位置,在链表中只能采用遍历的方法,时间复杂度为O(n). 同时我们还要考虑额外的三种情况:

      1)空链表时

      2)插入位置超出链表节点的长度时 

      3)插入位置是链表的最后一个节点时,需要移动tail

        def insert(self, index, val):
              current_node = self.head
              current_node_index = 9
              if current_node is None:
                raise Exception('This is an empty linked list')
              while current_node_index < index-1:
                current_node = current_node.next
                if current_node is None:
                  raise Exception('exceed the length of the list')
                current_node_index += 1
                node = Node(val)
                node.next = current_node.next
                current_node.next = node
                if node.next is None:
                  self.tail = node
      

        size()

                   返回链表长度的方法非常简单,统计链表中的节点数目直到找不到更多的节点为止返回遍历的节点的数目。该方法从表头开始,直到最后一个节点的next指针指向None时链表遍历完成。同时用计数器记录下已经遍历的节点的数目

     def size(self):
         current_node = self.head
         count = 0
         if current_node is None:
            return 'This is an empty linked list'
         while current_node:
            count += 1
            current_node = current_node.get_next()
          return count

                 search()

                search()与size() 方法很相似,但是除了要遍历整个链表,search()还要检查他遍历的每一个节点是否包含要查找的数据,并返回含有该数据的节点。如果该方法遍历整个链表没有找到包含该数据的节点,它将会抛出一个异常并通知用户该数据不在链表中   

     def search(self, val):
         current_node = self.head
         found = false
         while current_node and found is false:
           if current_node.get_val == val:
             found = True
           else:
             current_node = current_node.get_next()
         if current_node is None:
           raise ValueError('Data not in list')

                 delete()

                 delete()与search()方法非常相似,它采用与serch()相同的方法遍历整个链表,但除了要记录下当前节点之外, delete()还要记住当前节点的上一个节点,当deleta()方法遍历到要删除的节点时,它会将待删除节点的上一个节点的指针指向待删除节点的下一个节点,此时链表中将没有节点指向待删除节点。该方法的时间复杂度为O(n),因为在最坏情况下该方法要访问链表中的所有节点。同时我们还需要考虑如下几种情况:

        1) 空链表,直接抛出异常

                2) 删除第一个节点时,移动head到删除节点的next指针指向的对象

                3) 链表只有一个节点时,把head与tail都指向None即可

                4) 删除最后一个节点时,需要移动tail到上一个节点

                5) 遍历链表时要判断给定的索引是否大于链表的长度,如果大于则抛出异常信息 

       def delete(self, val):
         curent_node = self.head
         previous = None
         found = False
         while current_node and found is False:
           if current_node.get_val() == val:
             found = True
           else:
             previous = current_node
             current_node = current_node.get_next()
         if current_node is None:
           raise ValueError('Data not in list') 
         if self.head is self.tail:          # when there is only one node in the list
           self.head = None 
           self.tail = None
         if current_node is None:            #when delete the tail node  
           self.tail = current_node
         if previous is None:               #when delete the first node
           self.head = current_node.get_next()
         else :
           previous.set_next(current.get_next())
     

                 empty()

            判断链表是否为空就看他的头指针是否为空

       def empty(self):
            return return self.head is None

        iterate()
                 
    遍历链表从头结点开始,直到节点的指针指向None为止

        def iterate(self):
          if not self.head:       # if the linked list is empty
            return
          current_node = self.head
          yield current_node.val
          while current_node.next
            current_node = current_node.next
            yield current_node.val

      完整代码如下

      1 class Node:
      2   def __init__(self,val):
      3     self.val=val
      4     self.next = None #the pointer initially points to pointer
      5   def get_val(self):
      6     return self.val
      7   def get_next(self):
      8     return self.next
      9   def set_val(self, new_val):
     10       self.val = new_val
     11   def set_next(self, new_next):
     12       self.next = new_next
     13 
     14 class LinkedList:
     15   def __init__(self):
     16     self.head = None
     17     self.tail = None
     18 
     19   def insert(self, index, val):
     20         current_node = self.head
     21         current_node_index = 0
     22         if current_node is None:
     23           raise Exception('This is an empty linked list')
     24         while current_node_index < index-1:
     25           current_node = current_node.next
     26           if current_node is None:
     27             raise Exception('exceed the length of the list')
     28           current_node_index += 1
     29         node = Node(val)
     30         node.next = current_node.next
     31         current_node.next = node
     32         if node.next is None:
     33           self.tail = node
     34   def size(self):
     35     current_node = self.head
     36     count = 0
     37     if current_node is None:
     38       return 'This is an empty linked list'
     39     while current_node:
     40       count += 1
     41       current_node = current_node.get_next()
     42     return count
     43 
     44   def search(self, val):
     45     current_node = self.head
     46     found = False
     47     while current_node and found is False:
     48       if current_node.get_val() == val:
     49         found = True
     50       else:
     51         current_node = current_node.get_next()
     52     if current_node is None:
     53       raise ValueError('Data not in list')
     54     return found
     55 
     56   def delete(self, val):
     57     current_node = self.head
     58     previous = None
     59     found = False
     60     while current_node and found is False:
     61       if current_node.get_val() == val:
     62         found = True
     63       else:
     64         previous = current_node
     65         current_node = current_node.get_next()
     66 
     67     if current_node is None:
     68       raise ValueError('Data not in list')
     69 
     70     if self.head is self.tail:
     71       self.head = None
     72       self.tail = None
     73 
     74     if current_node is None:
     75       self.tail = current_node
     76 
     77     if previous is None:
     78       self.head = current_node.get_next()
     79     else :
     80       previous.set_next(current.get_next())
     81 
     82   def iterate(self):
     83     if not self.head:
     84       return
     85     current_node = self.head
     86     yield current_node.val
     87     while current_node.next:
     88       current_node = current_node.next
     89       yield current_node.val
     90 
     91   def append(self, val):
     92     new_node = Node(val)
     93     if self.head is None:
     94      self.head = new_node
     95      self.tail = new_node
     96     else:
     97      self.tail.set_next(new_node)
     98      self.tail = new_node
     99   def empty(self):
    100     return self.head is None
    101 
    102 if __name__ == '__main__':
    103   linklist = LinkedList()
    104   for i in range(50):
    105     linklist.append(i)
    106   print(linklist.empty())
    107   linklist.insert(20,20)
    108   linklist.delete(0)
    109   for node in linklist.iterate():
    110     print('node is {0}'.format(node))
    111   print(linklist.size())
    112   print(linklist.search(13))
                                                                     

    参考链接:

    http://zhaochj.github.io/2016/05/12/2016-05-12-%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84-%E9%93%BE%E8%A1%A8/

    https://www.codefellows.org/blog/implementing-a-singly-linked-list-in-python/

      

  • 相关阅读:
    没有技术驱动型公司 | 每个人都得加班 | 关注软技能
    各种15min(启动、横盘、破位)样例
    最新win10教育版激活密匙 win10各版本永久激活序列号
    大数定律具体是个什么概念?
    统计与概率——马同学高等数学
    三星MagicInfo Express软件制作介绍
    !!网上找的【英语单词词根记忆顺口溜】
    一个故事轻松记忆常见252个英语字根
    分享一个开源的音频分析软件
    C#连接XAMPP中的mysql 数据库(windows)
  • 原文地址:https://www.cnblogs.com/laozhanghahaha/p/8642333.html
Copyright © 2020-2023  润新知