当前位置:   article > 正文

10.Python修炼之路【14-链表】2018.05.11_python node(item)

python node(item)

关键字:单链表、双链表、循环单链表、循环双链表

一、链表

1.为什么需要链表

        顺序表的构建需要预先知道数据大小来申请连续的存储空间,而在进行扩充时又需要进行数据的搬迁,所以使用起来并不是很灵活。

        链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。

2.链表的定义

        链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)。

        链表的节点的结构如下:

        


二、单向链表

        单向链表也叫单链表,是链表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。


  • 表元素域elem用来存放具体的数据。
  • 链接域next用来存放下一个节点的位置(python中的标识)
  • 变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。

节点实现

  1. class SingleNode(object):
  2. """单链表的结点"""
  3. def __init__(self,item):
  4. # _item存放数据元素
  5. self.item = item
  6. # _next是下一个节点的标识
  7. self.next = None
'
运行

单链表的操作

  • is_empty() 链表是否为空
  • length() 链表长度(列表当中有多少个节点)
  • travel() 遍历整个链表
  • add(item) 链表头部添加元素
  • append(item) 链表尾部添加元素
  • insert(pos, item) 指定位置添加元素
  • remove(item) 删除节点
  • search(item) 查找节点是否存在

单链表的实现

  1. class SingleLinkList(object):
  2. """单链表"""
  3. def __init__(self):
  4. self._head = None
  5. def is_empty(self):
  6. """判断链表是否为空"""
  7. return self._head == None
  8.  """第一种求链表长度的写法"""
  1.     def length(self):
  2. """链表长度"""
  3.  # 判断特殊情况,链表是否为空
        # 若为空,返回长度为0         if self.is_empty():             return 0                
  1.         # cur初始时指向头节点,相当于游标,用来移动遍历节点
  2. cur = self._head
 # 初始化count为0
  1.         count = 0
  2. # 当前节点不为None时
  3. while cur != None:
  4. count += 1
  5. # 将cur后移一个节点
  6. cur = cur.next
  7. return count
        """第二种求链表长度的写法"""      def length(self):         """链表长度"""          # 判断特殊情况,链表是否为空         # 若为空,返回长度为0         if self.is_empty():            return 0         # cur初始时指向头结点,相当于游标,用来移动遍历节点
  1.          cur =sel._head
  2.          # 初始化count为1
         count = 1        # 当前节点的下一个节点不为None时         while cur.next != None:            count += 1            cur = cur.next        return count
  1. def travel(self):
  2. """遍历整个链表"""
  3.         # cur初始时指向头结点,相当于游标,用来移动遍历节点  
  1.         cur = self._head
  2. while cur != None:
  3. print (cur.item,end=" ")# end 表示不换行
  4. cur = cur.next
  5. print ""
'
运行
'
运行

头部添加元素

  1. def add(self, item):
  2. """头部添加元素"""
  3. # 先创建一个保存item值的节点
  4. node = SingleNode(item)
  5. # 将新节点的链接域next指向头节点,即_head指向的位置
  6. node.next = self._head
  7. # 将链表的头_head指向新节点
  8. self._head = node

尾部添加元素

    
  1. def append(self, item):
  2. """尾部添加元素"""
  3. node = SingleNode(item)
  4. # 先判断链表是否为空,若是空链表,则将_head指向新节点
  5. if self.is_empty():另一种写法 if self._head == None:
  6. self._head = node
  7. # 若不为空,则找到尾部,将尾节点的next指向新节点
  8. else:
  9. cur = self._head
  10. while cur.next != None:
  11. cur = cur.next
  12. cur.next = node
指定位置添加元素

    # pos在指定位置插入新节点,item为新插入的节点    def insert(self, pos, item):
  1. """指定位置添加元素"""
  2. # 若指定位置pos为第一个元素之前,则执行头部插入
  3. if pos <= 0:
  4. self.add(item)
  5. # 若指定位置超过链表尾部,则执行尾部插入
  6. elif pos > (self.length()-1):
  7. self.append(item)
  8. # 找到指定位置
  9. else:
  10. node = SingleNode(item)
  11. count = 0
  12. # pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置
  13. pre = self._head
  14. while count < (pos-1):
  15. count += 1
  16. pre = pre.next
  17. # 先将新节点node的next指向插入位置的节点
  18. node.next = pre.next
  19. # 将插入位置的前一个节点的next指向新节点
  20. pre.next = node

删除节点

  1. def remove(self,item):
  2. """删除节点"""
  3.  # cur指向头结点head
  1.         cur = self._head
  2.  # 前驱结点pre初始化为None,不让pre指向任何节点
  1.         pre = None
  2. while cur != None:
  3. # 找到了指定元素
  4. if cur.item == item:
  5. # 先判断此节点是否是头结点
  6. if cur == self._head: # 或者写成if not pre:
  7. # 将头指针指向头节点的后一个节点
  8. self._head = cur.next
  9. else:
  10. # 将删除位置前一个节点的next指向删除位置的后一个节点
  11. pre.next = cur.next # 这段代码也符合要删除的节点是尾节点的情况
  12. break #跳出while循环
  13. else:
  14. # 继续按链表后移节点
  15. pre = cur
  16. cur = cur.next

查找节点是否存在

  1. def search(self,item):
  2. """链表查找节点是否存在,并返回True或者False"""
  3. cur = self._head
  4. while cur != None:#为什么不写cur.next != None,因为这样会丢失最后一个节点,导致其无法参与比较
  5. if cur.item == item:
  6. return True
  7.  else:
  1.                 cur = cur.next
  2. return False

测试

  1. if __name__ == "__main__":
  2. ll = SingleLinkList()
    print(ll.is_empty())    print(ll.length())
  1. ll.add(1)
  2. ll.add(2)
  3. ll.append(3)
  4. ll.insert(2, 4)
  5. print "length:",ll.length()
  6. ll.travel()
  7. print ll.search(3)
  8. print ll.search(5)
  9. ll.remove(1)
  10. print "length:",ll.length()
  11. ll.travel()

链表与顺序表的对比

          链表失去了顺序表随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大,但对存储空间的使用要相对灵活。

          链表与顺序表的各种操作复杂度如下所示:

操作链表顺序表
访问元素O(n)                O(1)
在头部插入/删除O(1)                O(n)
在尾部插入/删除O(n)                O(1)
在中间插入/删除

                    O(n)

(n是要遍历的元素个数)

                O(n)

(n是顺序表要挪多少个位置元素)

         注意虽然表面看起来复杂度都是 O(n),但是链表和顺序表在插入和删除时进行的是完全不同的操作。链表的主要耗时操作是遍历查找,删除和插入操作本身的复杂度是O(1)。

         顺序表查找很快,主要耗时的操作是拷贝覆盖。因为除了目标元素在尾部的特殊情况,顺序表进行插入和删除时需要对操作点之后的所有元素进行前后移位操作,只能通过拷贝和覆盖的方法进行。





声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/858704
推荐阅读
相关标签
  

闽ICP备14008679号