链表知识点
在开始前,我们先回顾一下链表的一些知识点。
一、链表是什么
1.定义:链表(Linked list)是一种常见的基础数据结构,是一种线性表,在每一个节点(数据存储单元)里存放下一个节点的位置信息
2.优点:顺序表的构建需要预知数据大小来申请连续存储空间,扩充时需要进行数据迁移,使用不灵活,链表充分利用计算机内存空间,实现灵活内存动态管理
二、单向列表
1.定义:单向链表(单链表)是链表中最简单一种形式,它的每个节点包含两个域——信息域(元素域)和链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。
head 保存首地址,elem 存储数据,next 指向下一结点地址。
2.相关方法:
方法 | 说明 |
s_empty() | 链表是否为空 |
length() | 链表长度 |
travel() | 遍历整个链表 |
add(item) | 链表头部添加元素 |
append(item) | 链表尾部添加元素 |
insert(pos,item) | 在指定位置添加元素 |
remove(item) | 删除节点 |
search(item) | 查找结点是否存在 |
3. 代码实现
#定义节点
class Node(object):
def __init__(self,elem):
self.elem=elem
self.next=None
#构造单向链表
class SingleLinkedList:
#判断链表是否为空:_head指向None,则为空
def is_empty(self):
'''
if self._head==None:
print("True")
else:
print("False")
'''
return self._head==None
#单向链表初始化
def __init__(self,node=None):
#判断node是否为空
if node!=None:
headNode=Node(node)
self._head=headNode
else:
self._head=node
#计算链表长度
def length(self):
count=0
curNode=self._head
while curNode!=None:
count+=1
curNode=curNode.next
return count
#遍历链表
def travel(self):
curNode=self._head
while curNode!=None:
print(curNode.elem,end='\t')
curNode=curNode.next
print(" ")
#在头部添加元素
def add(self,item):
#将传入的值构造成节点
node=Node(item)
#将新节点的链接域next指向头节点
node.next=self._head
#将链表的头_head指向新节点
self._head=node
#在尾部添加元素
def append(self,item):
#将传入的值构造成节点
node=Node(item)
if self.is_empty(): #单链表为空
self._head=node
else: #单链表不为空
curNode=self._head
while curNode.next!=None:
curNode=curNode.next
#修改节点,最后一个节点的next指向node
curNode.next=node
#在指定位置添加元素
def insert(self,pos,item):
#如果pos<=0,默认插入到头部
if pos<=0:
self.add(item)
#如果pos>链表长度,直接在尾部追加
elif pos>(self.length()-1):
self.append(item)
else:
#构造节点
node=Node(item)
count=0
preNode=self._head
while count<(pos-1): #查找前一个节点
count+=1
preNode=preNode.next
#修改指向
#将前一个节点的next指向插入节点
node.next=preNode.next
#将插入位置的前一个节点next指向新节点
preNode.next=node
#查找节点是否存在
def search(self,item):
curNode=self._head
while curNode!=None:
if curNode.elem==item:
return True
curNode=curNode.next
return False
#删除节点
def remove(self,item):
curNode=self._head
preNode=None
while curNode!=None:
if curNode.elem==item:
#判断是否是头节点
if preNode==None:#是头节点
self._head=curNode.next
else:
#删除
preNode.next=curNode.next
break
else:
preNode=curNode
curNode=curNode.next
if __name__=="__main__":
#初始化元素值为10单向链表
singleLinkedList=SingleLinkedList(30)
print("是否为空链表:",singleLinkedList.is_empty())
print("链表长度为:",singleLinkedList.length())
print("----遍历链表----")
singleLinkedList.travel()
print("-----查找-----",singleLinkedList.search(30))
print("-----头部插入-----")
singleLinkedList.add(1)
singleLinkedList.add(2)
singleLinkedList.add(3)
singleLinkedList.travel()
print("-----尾部追加-----")
singleLinkedList.append(10)
singleLinkedList.append(20)
singleLinkedList.travel()
print("-----链表长度-----",singleLinkedList.length())
print("-----指定位置插入-----")
singleLinkedList.insert(-1,100)
singleLinkedList.travel()
print("-----删除节点-----")
singleLinkedList.remove(100)
singleLinkedList.travel()
三、双向链表
1. 双向链表是一种更复杂的链表。每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值,而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。
2. 代码实现
class Node:
def __init__(self,elem):
self.elem=elem
self.next=None #下一个节点
self.prev=None #前一个节点
class DoubleLinkedList:
# 双向链表初始化
def __init__(self, node=None):
# 判断node是否为空
if node != None:
headNode=Node(node)
self._head=headNode
else:
self._head=node
def is_empty(self):
'''
if self._head==None:
print("True")
else:
print("False")
'''
return self._head==None
#计算链表长度
def length(self):
count=0
curNode=self._head
while curNode!=None:
count+=1
curNode=curNode.next
return count
#遍历链表
def travel(self):
curNode=self._head
while curNode!=None:
print(curNode.elem,end='\t')
curNode=curNode.next
print(" ")
#在头部添加元素
def add(self,item):
#判断是否空链表
node = Node(item)
if self.is_empty():
self._head=node
else:
#将传入的值构造成节点
node=Node(item)
#将新节点的链接域next指向头节点
node.next=self._head
#将_head的头节点的prev指向node
self._head.prev=node
#将链表的头_head指向新节点
self._head=node
#在尾部追加元素
def append(self,item):
#将传入的值构造成节点
node=Node(item)
if self.is_empty(): #双向链表为空
self._head=node
else: #双向链表不为空
curNode=self._head
while curNode.next!=None:
curNode=curNode.next
#修改节点,最后一个节点的next指向node
curNode.next=node
#将node节点的前驱指向当前节点
node.prev=curNode
#在指定位置添加元素
def insert(self,pos,item):
#如果pos<=0,默认插入到头部
if pos<=0:
self.add(item)
#如果pos>链表长度,直接在尾部追加
elif pos>(self.length()-1):
self.append(item)
else:
#构造节点
node=Node(item)
count=0
curNode=self._head
while count<(pos-1): #查找前一个节点
count+=1
curNode=curNode.next
#修改指向
#node节点前驱指向当前节点
node.prev=curNode
#node节点的next指向当前节点的下一个节点
node.next=curNode.next
#当前节点的下一个节点的前驱指向node节点
curNode.next.prev=node
#当前节点的下一个节点指向node节点
curNode.next=node
#查找节点是否存在
def search(self,item):
curNode=self._head
while curNode!=None:
if curNode.elem==item:
return True
curNode=curNode.next
return False
#删除节点
def remove(self,item):
curNode=self._head
while curNode!=None:
if curNode.elem==item:
#判断是否是头节点
if curNode==self._head:#是头节点
self._head=curNode.next
#判断当前节点是否只有一个节点
if curNode.next:
curNode.next.prev==None
else:
#删除
curNode.prev.next=curNode.next
#判断当前节点是否是最后一个节点,若是,不需要移动下一个
if curNode.next:
curNode.next.prev=curNode.prev
break
else:
curNode=curNode.next
if __name__=="__main__":
doubleLinkedList=DoubleLinkedList()
print("-----头部添加-----")
doubleLinkedList.add(11)
doubleLinkedList.add(22)
doubleLinkedList.add(33)
doubleLinkedList.travel()
print("-----尾部追加-----")
doubleLinkedList.append(44)
doubleLinkedList.travel()
print("指定位置插入")
doubleLinkedList.insert(3,100)
doubleLinkedList.travel()
print("-----删除元素-----")
doubleLinkedList.remove(33)
doubleLinkedList.travel()
第一题
203. Remove Linked List Elements
Given the
head
of a linked list and an integerval
, remove all the nodes of the linked list that hasNode.val == val
, and return the new head.
思路:链表有空链表和非空链表两种。对于非空链表,第一个节点的操作和后面的有所不同。而在头节点前面加一个虚拟节点(dummy),这样可以让头节点变得和后面的节点一样。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
dummy = ListNode(next = head)
cur = dummy
while cur.next!=None:
if cur.next.val == val:
cur.next = cur.next.next
else:
cur = cur.next
return dummy.next
第二题
Design your implementation of the linked list. You can choose to use a singly or doubly linked list.
A node in a singly linked list should have two attributes:val
andnext
.val
is the value of the current node, andnext
is a pointer/reference to the next node.
If you want to use the doubly linked list, you will need one more attributeprev
to indicate the previous node in the linked list. Assume all nodes in the linked list are 0-indexed.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class MyLinkedList:
def __init__(self):
self.dummy_head = ListNode()
self.size = 0
def get(self, index: int) -> int:
if index < 0 or index >= self.size:
return -1
current = self.dummy_head.next
for i in range(index):
current = current.next
return current.val
def addAtHead(self, val: int) -> None:
self.dummy_head.next = ListNode(val, self.dummy_head.next)
self.size += 1
def addAtTail(self, val: int) -> None:
current = self.dummy_head
while current.next:
current = current.next
current.next = ListNode(val)
self.size += 1
def addAtIndex(self, index: int, val: int) -> None:
if index < 0 or index > self.size:
return
current = self.dummy_head
for i in range(index):
current = current.next
current.next = ListNode(val, current.next)
self.size += 1
def deleteAtIndex(self, index: int) -> None:
if index < 0 or index >= self.size:
return
current = self.dummy_head
for i in range(index):
current = current.next
current.next = current.next.next
self.size -= 1
# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)
第三题
Given the
head
of a singly linked list, reverse the list, and return the reversed list.
只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表
双指针法可以做出来
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
cur = head
pre = None
while cur:
temp = cur.next
cur.next = pre
pre = cur
cur = temp
return pre