第一课链表基础知识
链表概念:线性表数据结构,用来存储相同类型的数据,可以用不连续的存储空间。
每个信息需要占用多个存储单元,构成一个节点,每个节点不仅需要存储信息还要存储该元素后继逻辑元素节点的位置指针,
优点:增删方便
缺点:查找不方便,比起数组,占用空间较大
分类:单向、双向Doublely Linked List:双向指针,直至前驱后驱
循环链表Circular Linked List 首位相接,可从一个位置访问全部节点
基础操作:定义节点链表、新建线性链表、求链表长度、增删查改操作
1.定义节点链表:
节点ListNode:定义节点,值,指针
#链节点类
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
链表LinkedList:
#链表类
Class LinkedList
def _init_ (self):
self.head= None
新建线性链表:
2.建立一个线性链表:
根据线性表的数据元素动态生成链节点,并依次将其连接到链表中。
- 从所给线性表的第 1 个数据元素开始依次获取表中的数据元素。
- 每获取一个数据元素,就为该数据元素生成一个新节点,将新节点插入到链表的尾部。
- 插入完毕之后返回第 1 个链节点的地址
# 根据 data 初始化一个新链表 def create(self, data): self.head = ListNode(0) cur = self.head for i in range(len(data)): node = ListNode(data[i]) cur.next = node cur = cur.next
求链表长度:
3.求线性链表长度:
使用指针变量 𝑐𝑢𝑟 顺着链表 𝑛𝑒𝑥𝑡 指针进行移动,并使用计数器 𝑐𝑜𝑢𝑛𝑡 记录元素个数。
- 让指针变量 𝑐𝑢𝑟 指向链表的第 1 个链节点。
- 顺着链节点的 𝑛𝑒𝑥𝑡 指针遍历链表,指针变量 𝑐𝑢𝑟 每指向一个链节点,计数器就做一次计数。
- 等 𝑐𝑢𝑟 指向为空时结束遍历,此时计数器的数值就是链表的长度,将其返回即可。
# 获取线性链表长度 def length(self): count = 0 cur = self.head while cur: count += 1 cur = cur.next return count
4.增删查改操作
4.1查找链表元素
在链表中查找值为 𝑣𝑎𝑙 的元素:从头节点 ℎ𝑒𝑎𝑑 开始,沿着链表节点逐一进行查找。如果查找成功,返回被查找节点的地址;否则返回 𝑁𝑜𝑛𝑒。
- 让指针变量 𝑐𝑢𝑟 指向链表的第 1 个链节点。
- 顺着链节点的 𝑛𝑒𝑥𝑡 指针遍历链表,如果遇到 𝑐𝑢𝑟.𝑣𝑎𝑙==𝑣𝑎𝑙,则返回当前指针变量 𝑐𝑢𝑟。
- 如果 𝑐𝑢𝑟 指向为空时也未找到,则该链表中没有值为 𝑣𝑎𝑙 的元素,则返回 𝑁𝑜𝑛𝑒。
#查找元素
def find(self,var):
cur=self.head
while cur:
if val==cur.vall:
return cur
cur = cur.next
return None
「在链表中查找值为 𝑣𝑎𝑙 的元素」的操作依赖于链表的链节点个数,因此,「在链表中查找值为 𝑣𝑎𝑙 的元素」的时间复杂度为 𝑂(𝑛),$n$ 为链表长度。
4.2插入元素
链表中插入元素操作分为三种:
- 链表头部插入元素:在链表第 1 个链节点之前插入值为 𝑣𝑎𝑙 的链节点。
- 链表尾部插入元素:在链表最后 1 个链节点之后插入值为 𝑣𝑎𝑙 的链节点。
- 链表中间插入元素:在链表第 𝑖 个链节点之前插入值为 𝑣𝑎𝑙 的链节点。
接下来我们分别讲解一下。
4.2.1链表头部插入元素
链表头部插入元素:在链表第 1 个链节点之前插入值为 𝑣𝑎𝑙 的链节点。
- 先创建一个值为 𝑣𝑎𝑙 的链节点 𝑛𝑜𝑑𝑒。
- 然后将 𝑛𝑜𝑑𝑒 的 𝑛𝑒𝑥𝑡 指针指向链表的头节点 ℎ𝑒𝑎𝑑。
- 再将链表的头节点 ℎ𝑒𝑎𝑑 指向 𝑛𝑜𝑑𝑒。
#头部插入
def insert_Front(self , var):
node=ListNode(var)
node.next=self.head
self.head=node
「链表头部插入元素」的操作与链表的长度无关,因此,「链表头部插入元素」的时间复杂度为 𝑂(1)。
4.2.2 链表尾部插入元素
链表尾部插入元素:
「链表尾部插入元素」的操作需要将 𝑐𝑢𝑟 从链表头部移动到尾部,操作次数是 𝑛 次,因此,「链表尾部插入元素」的时间复杂度是 𝑂(𝑛)。
在链表最后 1 个链节点之后插入值为 𝑣𝑎𝑙 的链节点。
- 先创建一个值为 𝑣𝑎𝑙 的链节点 𝑛𝑜𝑑𝑒。
- 使用指针 𝑐𝑢𝑟 指向链表的头节点 ℎ𝑒𝑎𝑑。
- 通过链节点的 𝑛𝑒𝑥𝑡 指针移动 𝑐𝑢𝑟 指针,从而遍历链表,直到 𝑐𝑢𝑟.𝑛𝑒𝑥𝑡 为 𝑁𝑜𝑛𝑒。
- 令 𝑐𝑢𝑟.𝑛𝑒𝑥𝑡 指向将新的链节点 𝑛𝑜𝑑𝑒。
#尾部插入
def insertRear(self,var)
node=ListNode(var)
cur=self.head
while cur.next:
cur=cur.next
cur.next=node
4.2.3 链表中间插入元素
链表中间插入元素:在链表第 𝑖 个链节点之前插入值为 𝑣𝑎𝑙 的链节点。
「链表中间插入元素」的操作需要将 𝑐𝑢𝑟 从链表头部移动到第 𝑖 个链节点之前,操作的平均
时间复杂度是 𝑂(𝑛),因此,「链表中间插入元素」的时间复杂度是 𝑂(𝑛)。
- 使用指针变量 𝑐𝑢𝑟 和一个计数器 𝑐𝑜𝑢𝑛𝑡。令 𝑐𝑢𝑟 指向链表的头节点,$count$ 初始值赋值为 0。
- 沿着链节点的 𝑛𝑒𝑥𝑡 指针遍历链表,指针变量 𝑐𝑢𝑟 每指向一个链节点,计数器就做一次计数。
- 当遍历到第 𝑖𝑛𝑑𝑒𝑥−1 个链节点时停止遍历。
- 创建一个值为 𝑣𝑎𝑙 的链节点 𝑛𝑜𝑑𝑒。
- 将 𝑛𝑜𝑑𝑒.𝑛𝑒𝑥𝑡 指向 𝑐𝑢𝑟.𝑛𝑒𝑥𝑡。
- 然后令 𝑐𝑢𝑟.𝑛𝑒𝑥𝑡 指向 𝑛𝑜𝑑𝑒。
#中间插入链表
def insertInside(self,index,val):
count =0
cur=self.head
while cur and count <index-1:
count+=1
cur=cur.next
if not cur:
return 'Error'
node=ListNode(val)
node.next=cur.next
cur.next=node
4.3删除元素
链表的删除元素操作分为三种情况:
- 链表头部删除元素:删除链表的第 1 个链节点。
- 链表尾部删除元素:删除链表末尾最后 1 个链节点。
- 链表中间删除元素:删除链表第 𝑖 个链节点。接下来我们分别讲解一下。
4.3.1链表头部删除元素
链表头部删除元素:删除链表的第 1 个链节点。
- 直接将 𝑠𝑒𝑙𝑓.ℎ𝑒𝑎𝑑 沿着 𝑛𝑒𝑥𝑡 指针向右移动一步即可。
「链表头部删除元素」 的代码如下:
# 链表头部删除元素 def removeFront(self): if self.head: self.head = self.head.next
「链表头部删除元」只涉及到 1 步移动操作,因此,「链表头部删除元素」的时间复杂度为 𝑂(1)。
#删除头部
def removeFront(self):
if self.head:
self.head=self.head.next
4.3.2链表尾部删除元素
链表尾部删除元素:删除链表末尾最后 1 个链节点。
- 先使用指针变量 𝑐𝑢𝑟 沿着 𝑛𝑒𝑥𝑡 指针移动到倒数第 2 个链节点。
- 然后将此节点的 𝑛𝑒𝑥𝑡 指针指向 𝑁𝑜𝑛𝑒 即可。
「链表尾部删除元素」 的代码如下
#删除尾部
def removeRear(self):
if not self.head or not self.head.next:
return 'Error'
cur = self.head
whhile cur.next.next
cur=cur.next
cur.next=None
「链表尾部删除元素」的操作涉及到移动到链表尾部,操作次数为 𝑛−2 次,因此,「链表尾部删除元素」的时间复杂度为 𝑂(𝑛)。
4.3.3链表中间删除元素
链表中间删除元素:删除链表第 𝑖 个链节点。
- 先使用指针变量 𝑐𝑢𝑟 移动到第 𝑖−1 个位置的链节点。
- 然后将 𝑐𝑢𝑟 的 𝑛𝑒𝑥𝑡 指针,指向要第 𝑖 个元素的下一个节点即可。
#删除中间
def removeInside(self,index):
count=0
cur=self.head
while cur.next and conut<index-1:
count+=1
cur=cur.next
if not cur:
return "Error'
del_node=cur.next
cur.next=del_node.next
4.4 改变元素
将链表中第 𝑖 个元素值改为 𝑣𝑎𝑙:首先要先遍历到第 𝑖 个链节点,然后直接更改第 𝑖 个链节点的元素值。具体做法如下:
- 使用指针变量 𝑐𝑢𝑟 和一个计数器 𝑐𝑜𝑢𝑛𝑡。令 𝑐𝑢𝑟 指向链表的头节点,$count$ 初始值赋值为 0。
- 沿着链节点的 𝑛𝑒𝑥𝑡 指针遍历链表,指针变量 𝑐𝑢𝑟 每指向一个链节点,计数器就做一次计数。
- 当遍历到第 𝑖𝑛𝑑𝑒𝑥 个链节点时停止遍历。
- 直接更改 𝑐𝑢𝑟 的值 𝑣𝑎𝑙。
「将链表中第 𝑖 个元素值改为 𝑣𝑎𝑙」 的代码如下:
#改变元素:第i个改为val
def change(self,index,val):
count =0
cur=self.head
while cur and count<index:
count +=1
cur =cur.next
if not cur:
return :Error'
cur.val=val