数组跟链表
数组跟链表是都是一维的数据结构,因此经常一起对比学习,
- 数组(arry)是顺序存储结构 按顺序存储到一个连续固定空间的内存上;所以扩容时空间大小需要手动改动。不便于修改。
- 链表(linked list)是用指针连接元素的链式存储结构,不要求连续。查找不方便。
- 数组查询访问速度快为O(1),插入删除效率慢为O(n)。
- 链表则相反,链表查询慢O(n),插入删除为O(1)。
存储形式
储存[1,2,3,4,5] 这些值,在数组跟链表表现分别为下图。
代码表现
数组
a=[1,2,3,4,5] #此为python list,比array更多用法。
链表
class ListNode:
def __init__(self,val,next=None):
self.val=val
self.next=next
a=ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))
代码应用
数组
list的相关接口可以查询官方库
链表
在python中不存在指针,所以用引用来表示指针,下面代码实现了根据序号获取元素、新增元素以及删除元素,下图为双链表实现的函数为:
-
get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
-
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
-
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
-
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
-
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
class MyLinkedList: # 初始化链表
def __init__(self):
self.head = None # 头节点
self.tail=None #尾节点
self.size=0
def get(self,index:int)->int:
if index<0 or index>=self.size:
return -1
cur=self.head
for i in range(index):
cur=cur.next
return cur.val
def addAtHead(self,val:int)->None:
node=ListNode(val)
if self.head==None:
self.head=node
self.tail=node
else:
node.next=self.head
self.head=node
self.size+=1
def addAtTail(self,val:int)->None:
node=ListNode(val)
if self.tail==None:
self.tail=node
self.head=node
else:
self.tail.next=node
self.tail=node
self.size+=1
def addAtIndex(self,index:int,val:int)->None:
if index<0 or index>self.size:
return None
if index==0:
self.addAtHead(val)
self.size+=1
else:
cur=self.head
for i in range(index-1):
cur=cur.next
node=ListNode(val)
node.next=cur.next
cur.next=node
self.size+=1
def deleteAtIndex(self,index:int)->None:
if index<0 or index>=self.size:
return None
if index == 0:
self.head =self.head.next
self.size-=1
else:
cur = self.head
for i in range(index - 1):
cur = cur.next
cur.next = cur.next.next
self.size -= 1
def __str__(self):
cur=self.head
res=[]
while cur:
res.append(str(cur.val))
cur=cur.next
return '->'.join(res)
链表基础题目
1. 反转链表
将一个链表进行反转 leetcode 206
from typing import Optional
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]:
if not head:
return None
cur= head
pre=None
while cur:
cur.next,cur,pre=pre,cur.next,cur #理解此处即可
return pre
2. 判断链表是否有环
链表可以指向链表任意位置,判断链表是否有环 Leetcode 141
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
if not head:
return False
slow =head
fast= head.next
while fast and fast.next:
if fast == slow :
return True
slow ,fast= slow.next,fast.next.next
return False
3. 两数相加
将两个链表像加法一样求和,需要模拟进位 leetcode 2
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
if not l1:
return l2
if not l2:
return l1
head= ListNode(0)
cur =head
carry=0
while l1 or l2 :
if l1:
carry +=l1.val
l1=l1.next
if l2:
carry +=l2.val
l2=l2.next
cur.next=ListNode(carry%10)
cur=cur.next
carry= carry //10
if carry:
cur.next=ListNode(carry) # 进位
return head.next