链表中常见的使用方法逻辑整理

8 篇文章 0 订阅
8 篇文章 0 订阅

链表常见的使用方法逻辑整理


1. 链表特点

链表特点

  • 由节点组成:链表是由一个个节点组成的数据结构,每个节点包含数据和指向下一个节点的引用(指针/链接)。
  • 动态插入和删除:相对于数组,链表可以更轻松地进行节点的插入和删除操作,因为只需要调整节点的指针,而无需移动大量元素。
  • 内存利用灵活:链表的节点在内存中不必连续存储,这使得链表可以更灵活地利用内存,但也可能导致对内存的随机访问效率较低。
  • 随机访问效率低:链表的节点不能直接通过索引进行访问,需要从头节点开始逐个遍历,因此随机访问效率较低。
  • 多种类型:链表有单向链表、双向链表和循环链表等不同类型,每种类型都有不同的特点和适用场景。

链表是一种由节点组成的线性数据结构,每个节点包含一个数据元素和一个指向下一个节点的指针。跟数据对比有差异

  • 数组能够通过固定下标查找对应的数据,查找性能优越,但是每次插入/删除数据都需要将对应节点后续的数据整体挪移,因此数组的更新成本较大
  • 链表更新节点时只需要重新插入一个新节点,并调整上下节点的指针,无需移动后续的所有节点,因此更新成本较小,但是当需要获取当个节点数据时,由于没有固定下标,因此必须从头开始查找,因此查询性能较差

两者类型的数据结构,分别在读写时表现有差异,因此需要根据不同的应用场景(读写的频率差异)进行合理使用

2. 链表创建

链表中的每一个元素都是一个节点,每个节点通常包含两部分:数据和下一个节点的引用。

class Node:
    def __init__(self, data):
        self.data = data  # 节点存储的数据
        self.next = None  # 默认下一个节点为空
        
class LinkedList:
    def __init__(self):
        self.head = None  # 初始链表为空

3. 链表遍历通用方法

3.1 在链表的开头添加元素

def add_first(self, data):
    new_node = Node(data)   # 创建新的节点
    new_node.next = self.head  # 将新节点指向当前的头节点
    self.head = new_node    # 更新头节点为新节点

LinkedList.add_first = add_first

3.2 在链表的结尾添加元素

def add_last(self, data):
    new_node = Node(data)
    if self.head is None:  # 若链表为空,则直接将新节点设置为头节点
        self.head = new_node
        return
    last_node = self.head  # 遍历到链表的尾部
    while last_node.next:
        last_node = last_node.next
    last_node.next = new_node  # 在链表尾部添加新节点

LinkedList.add_last = add_last

3.3 删除链表的第一个元素

def remove_first(self):
    if self.head:
        self.head = self.head.next  # 更新头节点为下一个节点

LinkedList.remove_first = remove_first

3.4 删除链表的最后一个元素

def remove_last(self):
    if self.head is None:  # 若链表为空,直接返回
        return
    if self.head.next is None:  # 若链表只有一个元素,将头节点设置为空
        self.head = None
        return
    second_to_last = self.head  # 找到倒数第二个节点
    while second_to_last.next.next:
        second_to_last = second_to_last.next
    second_to_last.next = None  # 将倒数第二个节点的next设置为空,从而删除最后一个节点

LinkedList.remove_last = remove_last

3.5 遍历链表

def print_list(self):
    current_node = self.head  # 从头节点开始遍历
    while current_node:
        print(current_node.data, end=" -> ")
        current_node = current_node.next  # 移动到下一个节点
    print("None")

LinkedList.print_list = print_list

3.6 查找链表中的元素

def search(self, target):
    current_node = self.head  # 从头节点开始遍历
    while current_node:
        if current_node.data == target:  # 若找到目标数据,返回True
            return True
        current_node = current_node.next  # 移动到下一个节点
    return False  # 遍历完链表后,未找到目标数据,返回False

LinkedList.search = search

3.7 反转链表

def reverse(self):
    prev = None  # 上一个节点
    current = self.head  # 当前节点
    while current:
        next_node = current.next  # 记录下一个节点
        current.next = prev  # 将当前节点指向上一个节点
        prev = current  # 更新上一个节点为当前节点
        current = next_node  # 移动到下一个节点
    self.head = prev  # 更新头节点

LinkedList.reverse = reverse

4. 常见面试题

一些总结

4.1 相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交:

在这里插入图片描述

题目数据 保证 整个链式结构中不存在环。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        if headA is None or headB is None:
            return

        pA, pB = headA, headB

        while pA != pB:
            pA = headB if pA is None else pA.next
            pB = headA if pB is None else pB.next

        return pA

4.2 反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:
在这里插入图片描述

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:

在这里插入图片描述

输入:head = [1,2]
输出:[2,1]
示例 3:

输入:head = []
输出:[]

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        pre, cur = None, head
        while cur:
            next = cur.next
            cur.next = pre
            pre = cur
            cur = next
        return pre 

4.3 环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

在这里插入图片描述

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

在这里插入图片描述

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

在这里插入图片描述

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

# Definition for singly-linked list.
class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution(object):
    def hasCycle(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """

        slow, fast = head, head
        while fast is not None and fast.next is not None and slow != None:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                return True
        return False

4.4 环形链表 II

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

在这里插入图片描述

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

在这里插入图片描述

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

在这里插入图片描述

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        slow, fast = head, head
        while True:
            if not (fast and fast.next): return
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                break

        first= head
        while first != slow:
            first, slow = first.next, slow.next
        
        return first

4.5 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例 1:

在这里插入图片描述

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def mergeTwoLists(self, list1, list2):
        """
        :type list1: Optional[ListNode]
        :type list2: Optional[ListNode]
        :rtype: Optional[ListNode]
        """
        if not list1: return list2
        if not list2: return list1

        if list1.val <= list2.val:
            list1.next = self.mergeTwoLists(list1.next, list2)
            return list1
        
        list2.next = self.mergeTwoLists(list1, list2.next)
        return list2        

4.6 两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:
在这里插入图片描述

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.

示例 2:

输入:l1 = [0], l2 = [0]
输出:[0]

示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        cur = dummy = ListNode()
        carry = 0
        while l1 or l2 or carry:
            # 做加合运算
            carry += (l1.val if l1 else 0) + (l2.val if l2 else 0)
            # 如果超过10,需要做进位调整
            cur.next = ListNode(carry%10)
            #  取余数
            carry //= 10
            # 在一个节点
            cur = cur.next
            if l1: l1 = l1.next
            if l2: l2 = l2.next
        return dummy.next

4.7 删除链表的倒数第 N 个结点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

在这里插入图片描述

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:

输入:head = [1], n = 1
输出:[]
示例 3:

输入:head = [1,2], n = 1
输出:[1]

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        slow = dummy_head = ListNode(next=head)
        fast = head
        while fast and n:
            fast = fast.next
            n -=1

        while fast:
            fast = fast.next
            slow = slow.next
        
        slow.next = slow.next.next
        return dummy_head.next
        

4.8 两两交换链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

在这里插入图片描述

输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:

输入:head = []
输出:[]
示例 3:

输入:head = [1]
输出:[1]

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        p = ListNode(-1)
        a,b,p.next,tmp = p,p,head,p
        while b.next and b.next.next:
            a,b = a.next,b.next.next
            tmp.next,a.next,b.next = b,b.next,a
            tmp,b = a,a
        return p.next

5. 参考文档

暂无,相关面试题请参考leetcode以及相关说明

  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值