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個節點是一樣的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章