下一篇:Python实现单向链表(下):整合式实现增删改查操作
链表简介
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
链表和数组区别:链表不需要一系列连续的内存
链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分: 一个是存储数据元素的数据域 (在下面代码中用data存储);另一个是存储下一个结点地址的指针域 (在下面代码中用next存储)
链表优点
链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。
链表克服了数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
链表缺点 失去了数组随机读取的优点链表由于增加了结点的指针域,空间开销比较大。
单向链表
结点的指向是单向的,从前一个结点指向后一个结点
碎碎念:是节点还是结点?
转自:《【数据结构】节点和结点,到底怎么区分?》 一篇文章彻底把区别说清楚了,感激涕零 节点呢,被认为是一个实体,有处理能力,比如,网络上的一台计算机;而结点则只是一个交叉点,像“结绳记事”,打个结,做个标记,仅此而已,还有就是,要记住:一般算法中点的都是结点。
大体思路
需要写两个类: Node类:用于创建结点,并将结点以(人类)能看懂的字符串形式输出,而不是显示内存地址LinkedList类:用于将各结点连成链表,并实现对链表进行操作的一些方法
代码
创建Node类: class Node:def __init__(self, data, next=None):self.data = data # 数据,当前结点的元素self.next = None # 指针,指向下一个结点def __repr__(self): # 把结点表示为一个字符串return "NodeValue({})".format(self.data)
调用测试: n = Node(1)print(n) # 因为写了__repr__方法,所以输出的是Node(1),而不是内存地址
创建LinkedList类:
准备工作:初始化方法 & 打印字符串方法 想要达到的输出效果类似于: NodeValue(1) --> NodeValue(3) --> NodeValue(4) --> END class LinkedList:def __init__(self):self.head = None # 初始化头结点## 打印链表def __repr__(self):cursor = self.headstring_repr = ""while cursor:string_repr += f"{cursor} --> "cursor = cursor.nextreturn string_repr + "END"
「查」:方法
1. is_empty() 判断链表是否为空 def is_empty(self):return self.head == None
2. length() 返回链表长度 def length(self):if self.head is None:return 0cursor = self.headcount = 0while cursor:count += 1cursor = cursor.nextreturn count
3. exist(data) 判断结点是否存在 def exist(self, data):""":return: True or False:rtype: Boolean"""cursor = self.headwhile cursor:if cursor.data == data:return Trueelse:cursor = cursor.nextreturn False
4. travel() 遍历整个链表 def travel(self):if self.head is None:return Nonecursor = self.headwhile cursor:print(cursor)cursor = cursor.next
5. getitem(index) 根据索引,得到链表中该位置的值 def getitem(self, index):current = self.headif current is None:raise IndexError("This is an empty linked list.")for i in range(1, index):# 目标超过链表范围if current.next is None:raiseIndexError("Index out of range")current = current.nextreturn current
6. search(data) 返回该结点出现的左数第一个的位置,不存在返回-1 def search(self, data):if self.exist(data) == False:return -1else:cursor = self.headcount = 0while cursor:count += 1if cursor.data == data:return countelse:cursor = cursor.next
「增」:方法
7. insert_head(data) 在链表头部添加元素 def insert_head(self, data):new_node = Node(data)# 创建一个新结点if self.head: # 如果已存在头部结点# 让新创建的结点的next指向原本的头结点# 也就是说,新结点成为了原本的头结点的上一个结点new_node.next = self.headself.head = new_node # 重置头结点
8. append(data) 在链表尾部添加元素 def append(self, data):if self.head is None:# 如果链表目前为空,则在头结点添加该元素self.insert_head(data)else:cursor = self.headwhile cursor.next: # 遍历链表cursor = cursor.next# 创建一个新结点添加到链表尾部cursor.next = Node(data)
9. insert(pos, data) 在链表中的指定位置添加元素 def insert(self, pos, data):""":param pos: 要插入结点的位置,从0开始。pos > 0,代表是从左开始数的位置pos = 0,代表在头部添加pos < 0,代表是从右开始数的位置,倒数从-1开始也就是说 链表长度 + 倒数下标 = 正数下标:type pos: int:param data: 要插入的结点值:type data: int"""if pos > 0:if self.head is None:# 如果链表目前为空,则在头结点添加该元素self.insert_head(data)else:new_node = Node(data)# 创建一个新结点# 通过循环,得到新结点的上一个结点pre = self.headcount = 0while count < (pos-1):count += 1pre = pre.next# 让新结点指向原本该位置的结点new_node.next = pre.next# 让上一个结点指向新结点pre.next = new_nodeelif pos == 0:self.insert_head(data)elif pos < 0:if self.head is None:# 如果链表目前为空,则在头结点添加该元素self.insert_head(data)else:new_node = Node(data)# 通过循环,得到新结点正数顺序的上一个结点leftpos = self.length() + pospre = self.headcount = 0while count < (leftpos - 1):count += 1pre = pre.next# 让新结点指向原本该位置的结点new_node.next = pre.next# 让上一个结点指向新结点pre.next = new_node
「删」:方法
10. delete_head() 删除头结点 def delete_head(self):temp = self.headif self.head:self.head = temp.nexttemp.next = None
11. delete_tail() 删除尾结点 cursor = self.headif self.head:if self.head.next is None:self.head = Noneelse:while cursor.next.next:cursor = cursor.nextcursor.next, cursor = None, cursor.nextelif self.head == None:return "This is an empty linked list."
12. remove(data) 删除结点,若存在值相等的结点,仅删除左起第一个 def remove(self, data):""":return: 返回删除结点后的链表;若传入的数据在链表中不存在,则返回原链表"""if self.exist(data) == False:return selfelse:pre = self.headcursor = pre.nextcount = 0while cursor:if cursor.data == data:# 删除,也就是让该结点的上一结点直接连到该结点的下一结点pre.next = cursor.nextcursor.next = Nonereturn selfelse:pre = pre.nextcursor = cursor.next
13. removeall(data) 删除结点,若存在值相等的结点,删除所有 def removeall(self, data):""":return: 返回删除结点后的链表;若传入的数据在链表中不存在,则返回原链表"""while self.exist(data):self.remove(data)return self
「改」:方法
14. setitem(index, data) 根据索引,为链表中该位置的值重新赋值 def setitem(self, index, data):current = self.headif current is None:raise IndexError("This is an empty linked list.")for i in range(1, index):# 目标超过链表范围if current.next is None:raiseIndexError("Index out of range")current = current.nextcurrent.data = data
其他方法
15. linklist(object) 传入对象,一次性将序列中的所有元素构建成一个链表 def linklist(self, object):self.head = Node(object[0])temp = self.headfor i in object[1:]:node = Node(i)# 将上一个结点指向下一个结点temp.next = nodetemp = temp.next
下一篇:Python实现单向链表(下):整合式实现增删改查操作 Info Author: Shanshan Yan Wechat: shanshan700224 Copyright: All rights reserved