当前位置:   article > 正文

Python:链表构造与链表元素增删 【算法村E1链表笔记(青铜)】_python链表构造

python链表构造

前言

在几乎绝大多数的算法课中,链表都是放在第一节课的:链表非常基础而重要,对于后续理解、运用其他数据结构,或者学习算法来说,它都是很好的敲门砖。本篇文章,讲解如何在python中构造一个单链表,以及单链表的增加与删除操作。

(本文参考图片部分来自“Hello 算法”,这是一本Github上的开源书,也是非常优秀的学习材料,本文的行文风格和部分知识点也是来源于此;另外部分图片来自“编程导航算法村”,本文大部分知识点和思想过程来源于此)


目录

Python中如何构造一个链表

遍历链表(用于获取长度、查找目标值)

Python中增加链表元素

在链表首部增加元素

在链表中间增加元素

在链表尾部增加元素

总结

Python中删除链表元素

在链表首部删除元素

在链表中间删除元素

在链表尾部删除元素

总结

完整代码


Python中如何构造一个链表

(一个链表的结构如图所示)

链表(LinkedList)由节点(Node)顺序连接组成,每个节点包含一个值(Value)和指向下一个节点的指针(Pointer)或者叫引用(Reference)。

链表存在头节点(head),而且通常情况下,“头节点head”和“链表head”都是可以被接受的称呼。

链表的尾节点指向的是“空”,在Python中记为None。

链表定义方式:

  1. class ListNode:
  2. """链表节点类"""
  3. def __init__(self,val:int):
  4. self.val = val #节点值
  5. self.next = None # 指向下一节点的指针(引用)
  6. def get_data(self):
  7. return self.val
  8. def set_data(self,val):
  9. self.val = val
  10. def get_next(self):
  11. return self.next
  12. def set_next(self,next):
  13. self.next = next

在这样最正式的定义方式下,我们定义了链表节点类,并且使用四个set、get函数,来定义或获取每个节点的值以及节点之间的指向关系。

然而,在力扣(LeetCode)上的算法题中,还经常以另一种方式来创建链表:

  1. class ListNode:
  2. def __init__(self,val=0,next=None):
  3. self.val = val
  4. self.next = next
  5. # 创建实例
  6. listnoode = ListNode(1)

这种定义方式下能直接使用listnode.val和listnode.next进行操作,虽然违背了面向对象的设计要求,但无疑更加精简和方便。

在定义完链表之后,我们进行初始化链表操作。

例如,问我们初始化链表1 -> 3 -> 2 -> 5 -> 4。

  1. # 初始化各个节点
  2. n0 = ListNode(1)
  3. n1 = ListNode(3)
  4. n2 = ListNode(2)
  5. n3 = ListNode(5)
  6. n4 = ListNode(4)
  7. # 构建引用指向
  8. n0.next = n1
  9. n1.next = n2
  10. n2.next = n3
  11. n3.next = n4

以上,我们成功实现了对链表的定义(创建)初始化这两个操作。


遍历链表(用于获取长度、查找目标值)

核心代码就是"head = head.next",可以理解成一个指针在不断向后移动。

第一种,遍历获取链表长度(就是节点的总个数)

  1. def length(self):
  2. """链表长度"""
  3. # cur初始时指向头节点
  4. cur = self._head
  5. count = 0
  6. # 尾节点指向None,当未到达尾部时
  7. while cur != None:
  8. count += 1
  9. # 将cur后移一个节点
  10. cur = cur.next
  11. return count

(顺便一提,cur,pre,pos,target,count,temp,fast/slow(或fa/sl、f/s),res/ans,等都是常见变量名(因为大家都很偷懒(bushi,大意分别为:现在指针、前一指针、目标数、位置、计数、临时变量、快指针/慢指针、结果/答案,前两个在本文中就分别表示:现在的节点、前一个节点)

第二种,遍历链表,查找目标值:

  1. def find(head: ListNode, target: int) -> int:
  2. """在链表中查找值为 target 的首个节点"""
  3. index = 0
  4. while head:
  5. if head.val == target:
  6. return index
  7. head = head.next
  8. index += 1
  9. return -1

Python中增加链表元素

当我们需要在链表的 第N个元素后面 插入一个新的节点,我们该如何做呢?

在链表首部增加元素

当我们需要在表头直接插入一个元素的时候,我们可以直接创建一个新节点(newNode),让新节点指向原有的头节点head即可。

为了方便后续操作,我们一般还将“修改后”的头节点head变为我们插入的这个新节点newNode。

在链表中间增加元素

 在中间增加元素较为复杂,因为我们需要先遍历找到正确的位置,随后进行修改。

而修改的过程同样有坑。

如下图,如果我们直接让(15)指向新节点(new),会导致原有的链表直接断开,因为新节点(new)的后面是一个None,而不是原来存在的(7)->(40)。

而且,由于此时原本的链表head已经被你修改过,Python会自动“帮你”回收掉“不需要”的原先后半截链表,甚至无法再改回最初的链表了。

因此,我们应该先创建一个指向关系,将新节点new和后续的(7)连接,再将(15)指向(new),如此我们总算让回收机制正确地帮助了我们(

image.png

在链表尾部增加元素

与首部相似,我们只需要让尾节点(40)指向新节点(new)即可(因为在定义的时候,我们让任何新节点new的nex都t默认为None)

image.png

总结

代码如下:

  1. # 头部添加
  2. def add(self, item):
  3. """头部添加元素"""
  4. node = Node(item)
  5. node.next = self._head
  6. self._head = node
  7. # 尾部添加
  8. def append(self, item):
  9. """尾部添加元素"""
  10. node = Node(item)
  11. if self.is_empty():
  12. self._head = node
  13. else:
  14. cur = self._head
  15. while cur.next != None:
  16. cur = cur.next
  17. cur.next = node
  18. # 指定位置添加(头、尾、中间)
  19. def insert(self, pos, item):
  20. """指定位置添加元素"""
  21. if pos < 0:
  22. self.add(item)
  23. elif pos >= self.length():
  24. self.append(item)
  25. else:
  26. node = Node(item)
  27. pre = self._head
  28. count = 0
  29. while count < (pos-1):
  30. count += 1
  31. pre = pre.next
  32. node.next = pre.next
  33. node = pre.next

Python中删除链表元素

当我们知道怎样增加链表元素,那么删除也是类似的。

在链表首部删除元素

与增加相反:当插入元素时,我们让新节点newNode.next=head,创造了一个指向关系;当删除时,我们舍去一层指向关系,让head.next等于head,即让(15)变成这个链表新的头节点。

image.png

在链表中间删除元素

在中间删除也是同样的较为复杂,因为我们仍然需要先遍历、再操作。

为了同样避免链条断开的风险。我们在删除操作中需要先遍历到要删除元素之前,这个先前节点的指针指向next的next,即直接跳过要被删除的元素。

核心代码:cur.next=cur.next.next

image.png

在链表尾部删除元素

同样需要遍历,不过这次的遍历是遍历到最后一个元素之前,即倒数第二个元素,让倒数第二个元素的next变为None即可。

image.png

总结

代码如下:

  1. def remove(self, item):
  2. """删除节点"""
  3. cur = self._head
  4. pre = None
  5. while cur != None:
  6. if cur.item == item:
  7. if pre is None:
  8. self._head = cur
  9. else:
  10. pre.next = cur.n
  11. else:
  12. pre = cur
  13. cur = cur.next

完整代码

  1. class Node(object):
  2. """单链表节点"""
  3. def __init__(self, item):
  4. # _item存放数据元素
  5. self.item = item
  6. # _next是下一个节点的标识
  7. self.next = None
  8. def is_empty(self):
  9. """判断链表是否为空"""
  10. return self._head == None
  11. def length(self):
  12. """链表长度"""
  13. cur = self._head
  14. count = 0
  15. while cur != None:
  16. count += 1
  17. cur = cur.next
  18. return count
  19. # 头部添加
  20. def add(self, item):
  21. """头部添加元素"""
  22. node = Node(item)
  23. node.next = self._head
  24. self._head = node
  25. # 尾部添加
  26. def append(self, item):
  27. """尾部添加元素"""
  28. node = Node(item)
  29. if self.is_empty():
  30. self._head = node
  31. else:
  32. cur = self._head
  33. while cur.next != None:
  34. cur = cur.next
  35. cur.next = node
  36. # 指定位置添加
  37. def insert(self, pos, item):
  38. """指定位置添加元素"""
  39. if pos < 0:
  40. self.add(item)
  41. elif pos >= self.length():
  42. self.append(item)
  43. else:
  44. node = Node(item)
  45. pre = self._head
  46. count = 0
  47. while count < (pos-1):
  48. count += 1
  49. pre = pre.next
  50. node.next = pre.next
  51. node = pre.next
  52. # 删除结点
  53. def remove(self, item):
  54. """删除节点"""
  55. cur = self._head
  56. pre = None
  57. while cur != None:
  58. if cur.item == item:
  59. if pre is None:
  60. self._head = cur.next
  61. else:
  62. pre.next = cur.next
  63. else:
  64. pre = cur
  65. cur = cur.next

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

闽ICP备14008679号