python 链表 【测试题】

5 篇文章 0 订阅
5 篇文章 0 订阅

注意:

  • 这里的head是只存储地址。
实例讲解
prev = None  # 前指针节点
curr = head  # 当前指针节点
# 每次循环,都将当前节点指向它前面的节点,然后当前节点和前节点后移
while curr:
    nextTemp = curr.next  # 临时节点,暂存当前节点的下一节点,用于后移
    curr.next = prev  # 将当前节点指向它前面的节点
    prev = curr  # 前指针后移
    curr = nextTemp  # 当前指针后移
return prev 
  • 第四行的nextTemp = curr.next :(.next在等号右边)表示下一个节点的地址
  • 第五行的curr.next (.next在等号左边)表示curr所指节点的地址

1 .链表基本功能

class ListNode:
"""
创建单个节点
"""
def __init__(self, x):
    self.val = x
    self.next = None


class MyLinkedList(object):
    """
    单链表
    """

def __init__(self):
    """
    头指针默认地址为空
    长度为0
    """
    self.head = None
    self.length = 0


def is_empty(self):
    """判断链表是否为空"""
    return self.head == None

def get(self, index):
    """
    依据索引值获取指定节点值(下表从0开始)
    :type index: int
    :rtype: int
    """
    if index < 0 or index >= self.length:
        """
        索引值小于0或者索引值大于等于长度,返回-1
        """
        return -1
    p = self.head
    for i in range(self.length):
        if i == index:
            return p.val
        else:
            p = p.next

def addAtHead(self, val):
    """头部添加元素"""
    # 先创建一个保存val值的节点
    node = ListNode(val)
    # 将新节点的链接域next指向头节点,即self.head指向的位置
    node.next = self.head
    # 将链表的头self.head指向新节点
    self.head = node
    self.length += 1

def addAtTail(self, val):
    """尾部添加元素"""
    node = ListNode(val)
    # 先判断链表是否为空,若是空链表,则将self.head指向新节点
    if self.is_empty():
        self.head = node
    # 若不为空,则找到尾部,将尾节点的next指向新节点
    else:
        cur = self.head
        while cur.next:
            """找到最后一个节点"""
            cur = cur.next
        cur.next = node
    self.length += 1

def addAtIndex(self, index, val):
    """
    在指定为值添加索引,下标从0开始
    思想:新建一个计数变量count
    :type index: int
    :type val: int
    :rtype: None
    """
    head = self.head
    if index <= 0:
        self.addAtHead(val)
    elif index == self.length:
        """
        索引值等于链表长度,讲节点加到链表的尾部
        """
        self.addAtTail(val)

    elif index < self.length and index > 0:
        prev = head
        count = 0
        while count < index - 1:
            count += 1
            prev = prev.next
        node = ListNode(val)
        node.next = prev.next
        prev.next = node
    self.length += 1


def deleteNode(self, val):
    """
    删除指定节点node ,从头遍历
    :param node:
    :return: 返回新链表q
    """
    head = self.head
    q = head
    """
    p,q 用来 迭代
    
    """
    p = q.next
    if q.val == val:    
        """如果头结点就是要删除的结"""
        self.length -= 1
        self.head = p
        """
        要改变self.head,因为遍历的时候是从self.head开始的
        """
        print('self.length:', self.length)
        return p
    while p:
        if p.val == val:
            q.next = p.next
            self.length -= 1
            print('lenth', self.length)
            return q
        else:
            q = p
            p = p.next

def deleteAtIndex(self, index):
    """
    在指定位置删除
    :type index: int
    :rtype: None
    """
    prev = self.head
    if index == 0:
        self.head = self.head.next
    elif index > 0 and index < self.length:
        # count从1开始
        count = 1
        while count < index:
            prev = prev.index
        prev.next = prev.next.next
    self.length -= 1


def travel(self):
    """遍历链表"""
    cur = self.head
    while cur:
        print('val:', cur.val)
        cur = cur.next
    print("")

def midNode(self):
    """
    快慢指针,寻找中间节点
    fast走两步,slow走一步
    :return:返回mid的值
    """
    head = self.head
    if head is None or head.next is None:
        """没有节点,或者只有一个节点
        """
        return head.val
    fast = head
    slow = head
    while fast.next and fast.next.next:
        """
        当为奇数个点的时候,fast.next会为空,跳出while循环
        当为偶数个点的时候,fast.next.next会为空,跳出while循环
        """
        fast = fast.next.next
        slow = slow.next
    if fast.next:
        print('有偶数个点')
    else:
        print('有奇数个点')
    return slow.val


def reverseList(self, head):
    """
    反转一个单向链表
    :param head:头部指针
    :param prev:反转后的头结点
    :return: 返回反转后的链表
    """
    prev = None  # 前指针节点
    curr = head  # 当前指针节点
    # 每次循环,都将当前节点指向它前面的节点,然后当前节点和前节点后移
    while curr:
        nextTemp = curr.next  # 临时节点,暂存当前节点的下一节点,用于后移
        curr.next = prev  # 将当前节点指向它前面的节点
        prev = curr  # 前指针后移
        curr = nextTemp  # 当前指针后移
    return prev

# 递归思路:在return处调用自己(尾递归)
    # if not head:
    #     return prev
    #
    # curr, head.next = head.next, prev  # 新旧链表的两个方向同时前进
    # return self.reverseList(curr, head)

def isPalindrome(self):
    """
    判断回文链表的思想:
    1.找到中间节点slow
    2.把后半部分,逆序
    3.把前半部分和后半部分比较

    :type head: ListNode
    :rtype: bool
    """
    head = self.head
    fast = head
    slow = head
    while fast and fast.next:
        """
        当fast.next为None说明,fast已经在最后一个节点。也表明有奇数个点
        当fast.next.next为空None,fast在倒数第二个节点。也表明有偶数个点
        """
        fast = fast.next.next
        slow = slow.next

    prev = None  # 前指针节点
    curr = slow  # 当前指针节点
    # 每次循环,都将当前节点指向它前面的节点,然后当前节点和前节点后移
    while curr:
        nextTemp = curr.next  # 临时节点,暂存当前节点的下一节点,用于后移
        curr.next = prev  # 将当前节点指向它前面的节点
        prev = curr  # 前指针后移
        curr = nextTemp  # 当前指针后移
    while head and prev:
        if head.val != prev.val:
            return False
        head = head.next
        prev = prev.next
    return True

def getIntersectionNode(self, headA, headB):
    """
    相交链表,找到两个单链表相交的起始节点

    例如:
    listA = [4,1,8,4,5], listB = [5,0,1,8,4,5]
    相交节点的值为8

    :type head1, head1: ListNode
    :rtype: ListNode
    """

    """
    定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差)
    两个指针等于移动了相同的距离, 有交点就返回, 无交点就是各走了两条指针的长度
    """
    p = headA
    q = headB
    # 在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头, 而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null == null
    while p != q:
        p = p.next if p else headB  # 如果p成立,p = p.next,若不成立,p = headB
        q = q.next if q else headA
    return p

L = MyLinkedList()
print('----插入节点:-----')
L.addAtTail(1)
L.addAtTail(2)
L.addAtTail(3)
L.addAtTail(2)
L.addAtTail(1)
L.travel()
print('----寻找中间节点----')
A = L.midNode()
print(A)
print('----依据索引值获取节点的值-----')
b = L.get(2)
print(b)
print('----依据索引进行添加值(下标从0开始)----')
L.addAtIndex(2, 6)
L.travel()
print('长度:', L.length)
print('----删除节点(包括可以删除头部,尾部)----')
L.deleteNode(3)

print('----根据索引值删除指定节点(下标从0开始)----')
L.deleteAtIndex(0)
L.travel()

print('----判断是不是回文链表----')
L.travel()
print(L.isPalindrome())
# print(D)

2. 根据值删除链表中的节点

信息

请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。

现有一个链表 – head = [4,5,1,9]

示例 1:

输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:

输入: head = [4,5,1,9], node = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.

说明:

链表至少包含两个节点。
链表中所有节点的值都是唯一的。
给定的节点为非末尾节点并且一定是链表中的一个有效节点。
不要从你的函数中返回任何结果。

答案:

class ListNode:
	  def __init__(self, x):
	  self.val = x
	  self.next = None

class Solution:
    def deleteNode(self, node):
        """
        :type node: ListNode
        :rtype: void Do not return anything, modify node in-place instead.
        """
        node.val = node.next.val
        node.next = node.next.next

3.反转一个单链表

信息

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

答案

def reverseList(self,head,prev=None):
    """
    反转一个单向链表
    :param head:头部指针
    :param prev:反转后的头结点
    :return: 返回反转后的链表
    """
    while head:
        curr = head
        head = head.next
        curr.next = prev
        prev = curr
    return prev

    # 递归思路:在return处调用自己(尾递归)
    # if not head:
    #     return prev
    #
    # curr, head.next = head.next, prev  # 新旧链表的两个方向同时前进
    # return self.reverseList(curr, head)

4.合并两个有序链表

信息

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

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

答案

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode):
        if l1 is None and l2 is None:
            return None
		# 新建了一个值为0的头部指针,所以我们在返回的时候要加.next(很巧妙),这样就不包含0这个节点了
        new_list = ListNode(0)
        pre = new_list
        while l1 is not None and l2 is not None:
            if l1.val < l2.val:
                pre.next = l1
                l1 = l1.next
            else:
                pre.next = l2
                l2 = l2.next
            pre = pre.next
        if l1 is not None:
            pre.next = l1
        else:
            pre.next = l2
        return new_list.next

5.删除排序链表中的重复元素

信息

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

示例 1:

输入: 1->1->2
输出: 1->2
示例 2:

输入: 1->1->2->3->3
输出: 1->2->3

答案

 class ListNode:
     def __init__(self, x):
         self.val = x
         self.next = None

class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if head is None:
        return None
    h = ListNode(head.val)
    current = h
    flag = head.val
    while head:
        if flag == head.val:
            head = head.next
        else:
            current.next = ListNode(head.val)
            current = current.next
            flag = head.val
            head = head.next
    return h

6.移除链表元素

信息

删除链表中等于给定值 val 的所有节点。

示例:

输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5

def removeElements(self, head: ListNode, val: int) -> ListNode:
        if head:
            while head.val == val:
                head = head.next
                if head is None:
                    return head
            q = head
            p = q.next
            while p:
                if p.val == val:
                    q.next = p.next
                else:
                    q = q.next
                p = p.next
        return head

7.环形链表

信息

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

示例 1:

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

示例 2:

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

示例 3:

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

进阶

进阶:

你能用 O(1)(即,常量)内存解决此问题吗?

思路

  • 1.快和慢两个指针,如果有环,则一定会相遇。一个指针走一步,一个指针走两步。

答案

 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
        """
        if not head:
            return False
        p1 = head
        p2 = head.next
        while(1):
            if p1 == None or p2 == None or p2.next == None:
                return False
            elif p1 == p2:
                return True
            else:
                p1 = p1.next
                p2 = p2.next.next
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python中数据结构是期末考试中的一个重要部分,涵盖了许多基本概念和高级应用。这里我会简要概述几个常见的数据结构以及它们在Python中的实现: 1. **列表(List)**: Python中最常用的数据结构之一,它可以存储多个不同类型的元素,并支持索引、切片、添加和删除等操作。 2. **元组(Tuple)**: 与列表类似,但一旦创建就不能修改。元组常用于不可变数据或需要定义固定顺序的情况。 3. **集合(Set)**: 集合是一组不重复的元素,支持并集、交集、差集和成员测试等操作。 4. **字典(Dictionary)**: 也称为哈希表,由键值对组成,可以通过键快速查找和修改值。 5. **队列(Queue)**: 如`queue`模块中的`Queue`或`collections`模块的`deque`,用于先进先出(FIFO)的操作。 6. **堆(Heap)**: `heapq`模块提供了堆的实现,常用于优先级队列。 7. **链表(Linked List)**: 可以自定义实现单向或双向链表,支持动态添加和删除元素。 8. **栈(Stack)**: 可以使用列表的append和pop方法实现,或者使用`stacks`模块(如`collections`中的`Stack`)。 相关问题-- 1. 数据结构在Python中的应用有哪些实际场景? 2. 如何在Python中高效地实现队列和堆? 3. 字典的查找和更新操作复杂度是多少? 4. 列表和元组在哪些情况下更适合使用? 5. Python中如何处理重复元素,集合和列表的区别是什么?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值