Python链表小练习---删除链表的倒数第K个节点和旋转链表

1、删除链表的倒数第K个节点
题目描述:
给定一个链表: 1->2->3->4->5, 和 k = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

解题思路:

  1. 使用两个指针p,q,刚开始两个指针指向链表的头部
  2. 让q指针向后移动k个节点,p和q节点之间的举例保持为k
  3. p和q同时向后移动,直到q.next = None,此时p节点为删除节点的前一个节点
  4. 删除倒数第k个节点,p.next = p.next.next

实现代码如下:

from SingleLink import SingleLink

def delKthToTail(link, k):
    """
    删除链表的倒数第K个元素
        1. 判断用户输入的合法性?link k
        2. 如果输入数据合法
            1). p,q两个指针指向头部
            2). 让q指针向后移动k个位置,两者保持距离为k
            3). p,q同时向后移动,直到q.next为None
            4). 删除倒数第K个元素,p.next = p.next.next
    :param link:
    :param k:
    :return:
    """
    #1. 判断用户输入的合法性?link k
    if not link:
        return
    if not link._head:
        return
    if k <= 0:
        return
    # 2.1)让p指针和q指针指向头部
    p = link._head
    q = link._head

    #  2). 让q指针向后移动k个位置,两者保持距离为k
    for i in range(k):
        q = q.next
    #  3). p,q同时向后移动,直到q.next为None
    while q.next != None:
        p = p.next
        q = q.next

    #  4). 删除倒数第K个元素,p.next = p.next.next
    p.next = p.next.next

    return link

if __name__ == '__main__':
    link = SingleLink()
    for i in range(5):
        link.append(i + 1)

    link1 = delKthToTail(link, 3)
    link1.travel()

SingleLink代码如下:

class Node(object):
    """单链表节点的封装"""
    def __init__(self, element):
        self.element = element
        self.next = None

class SingleLink(object):
    """单链表的封装"""
    def __init__(self):
        # 默认为空
        self._head = None

    def is_empty(self):
        """是否为空"""
        return self._head == None

    def __len__(self):
        """
        求链表长度
            1. 判断是否为空,为空直接返回0
            2. 不为空时依次遍历,长度加1之后将下一个节点赋值给当前
        """
        if self.is_empty():
            return 0
        else:
            cur = self._head
            length = 0
            while cur != None:
                length += 1
                cur = cur.next
            return length

    def travel(self):
        """遍历链表"""
        if self.is_empty():
            print('空链表')
        else:
            cur = self._head
            while cur.next != None:
                print(cur.element, end=',')
                cur = cur.next
            print(cur.element)

    def append(self, item):
        """
        尾部添加元素
            1. 先判断链表是否为空,若为空,将_head指向新节点
            2. 若不为空,找到尾部,将尾节点next指向新节点
        :param item:
        :return:
        """
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            if cur.next == None:
                cur.next = node


    def add(self, item):
        """
        头部添加元素:
            1. 创建一个保存item值的节点
            2. 将新节点的next指向头结点,即_head指向的位置
            3. 将链表的头_head指向新节点
        :param item:
        :return:
        """
        node = Node(item)
        node.next = self._head
        self._head = node

    def insert(self, index, item):
        """
        指定位置添加元素
            1. 指定位置为头部之前,则头部添加元素
            2. 指定位置为尾部之后,则尾部添加元素
            3. 中间位置:需要找出指定位置的前一个元素,得到其尾部,插入的节点的尾部指向前面得到的尾部,
                        前一个元素新的尾部指向插入的头部
        :param index:
        :param item:
        :return:
        """

        if index <= 0:
            self.add(item)
        elif index >= len(self):
            self.append(item)
        else:
            node = Node(item)
            count = 0  # 当前节点的位置
            cur = self._head
            # 寻找插入节点的前一个节点
            while count < index - 1:
                count += 1
                cur = cur.next
            # 插入节点的前一个节点的尾部成为了插入节点的尾部指向
            # 然后将插入节点的前一个节点的尾部指向更新为新插入节点的头部
            node.next = cur.next
            cur.next = node

    def remove(self, item):
        """
        删除指定元素的节点
            1. 删除头部节点
            2. 删除其他位置的节点
        :param item:
        :return:
        """
        """
            既然要删除当前节点,首先想的就是遍历链表找到对应节点并且删除,
            这里直接省去了遍历的操作,直接给出了对应的节点。 
            既然想删除当前节点那么将给定的节点的val和next全部转换成当前节点的下一个节点所对应的值,
            那么当前节点在本链表中就相当于替换成了下一个节点。
            """
        cur = self._head
        pre = None
        while cur != None:
            if cur.element == item:
                if not pre:
                    self._head = cur.next
                else:
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next



    def search(self, item):
        """
        判断查找的元素在节点中是否存在,返回Bool类型
        :param item:
        :return:
        """
        cur = self._head
        while cur.next != None:
            if cur.element == item:
                return True
            cur = cur.next
        if cur.element == item:
            return True

        return False

2、旋转链表
题目描述:给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

示例 1:
输入: 1->2->3->4->5, k = 2
输出: 4->5->1->2->3

示例 2:
输入: 0->1->2, k = 4
输出: 2->0->1

解题思路:

  1. 访问到链表最后,尾部节点的next指向头部节点,将链表转换为单向寻哈un链表,最后在需要断开的位置再断开变成单向链表
  2. 对k进行处理,k = k%链表长度,因为存在k > 链表长度和k < 小于链表长度两种情况
  3. 寻找断开位置的前一个节点,length - k - 1,更新头部节点–>link._head = prev.next
  4. 断开链表,尾部.next=None
from SingleLink import SingleLink


def rorateRight(link, k):
    # 1). 判断合法性?link是否存在,是否为空
    if not link:
        return
    if not link._head:
        return
    # 2). 如果合法
    # 1. 访问链表到最后,将链表转换为单向循环链表,尾部节点的next指向头部
    length = 1
    cur = link._head
    while cur.next != None:
        length += 1
        cur = cur.next
    # 首尾相连
    cur.next = link._head

    # 2. 寻找断开位置的前一个结点,len-k%len-1,更新链表头结点
    k = k % length
    prev = link._head
    for i in range(length - k - 1):
        prev = prev.next
    # 更新链表头结点
    link._head = prev.next
    # 3.断开链表循环的部分,尾部指向为None
    prev.next = None

    return link


if __name__ == '__main__':
    link = SingleLink()
    for i in range(5):
        link.append(i)
    link.travel()
    link1 = rorateRight(link, 2)
    link1.travel()

SingleLink代码和上面删除链表的倒数第K个节点是一样的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值