Serie de estructura de datos de Python: lista vinculada de una sola vía de Python, admite índice negativo, índice de división, para acceso iterativo, búsqueda de posición de circuito cerrado, adecuado para la práctica de LintCode

# -*- coding:utf8 -*-
# [email protected]
# Python 单向链表,支持负数索引、切片索引,支持迭代访问,支持闭环检测
# https://blog.csdn.net/liuqixuan1994/article/details/103789486

from collections import Iterable
from warnings import warn


class ListNode(object):
    """链表结点"""

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

    def __repr__(self):
        return str(self.val)


class LinkedList(object):
    """Python单向链表"""

    def __init__(self, data=None):
        if data is None:
            self.head = None
            self.__length = 0  # 长度为私有属性,外部不可修改,仅能通过len()运算符读取
        elif isinstance(data, ListNode):
            self.head = data
            self.__length = 1
        elif isinstance(data, Iterable):
            self.head = None
            self.__length = 0
            for v in data:
                self.append(v)
        else:
            self.head = ListNode(data)
            self.__length = 1

    def isEmpty(self):
        return (self.__length == 0)

    def append(self, valOrNode):
        """在当前链表的末尾追加元素。"""
        elem = None
        if isinstance(valOrNode, ListNode):
            if valOrNode.next is not None:
                warn("valOrNode.next is not None, new ListNode will be cloned. "
                     "If you want to append all follow-up nodes, please use 'extend'.")
                elem = ListNode(valOrNode.val)
            else:
                elem = valOrNode
        else:
            elem = ListNode(valOrNode)
        elem.next = None  # 截断可能存在的后续

        if self.head is None:
            self.head = elem
        else:
            node = self.head
            while node.next:
                node = node.next
            node.next = elem
        self.__length += 1

    def extend(self, data):
        """将data附加到当前链表之后。
        data可以是:1.(有后继的)结点;2.另一个链表;3.可迭代对象。
        """
        # 将data整理成以in_head为起点的链表
        in_len, in_head = 0, None
        if isinstance(data, ListNode):
            in_crt = in_head = data
            while in_crt is not None:
                in_crt = in_crt.next
                in_len += 1
        elif isinstance(data, LinkedList):
            in_crt = in_head = data.head
            in_len = len(data)
        elif isinstance(data, Iterable):
            in_crt = in_head = ListNode(0)  # 为方便构建添加临时头结点
            for val in data:
                in_crt.next = ListNode(val)
                in_crt = in_crt.next
                in_len += 1
            in_head = in_head.next  # 删除临时头结点
        # 将in_head挂载到当前链表的末尾,注意此函数不做闭环检查
        if self.head is None:
            self.head = in_head
        else:
            this_last, _ = self.__findnode(self.__length - 1)
            this_last.next = in_head
        self.__length += in_len
        return self

    def __checkidx(self, index):
        """索引校正。"""
        if self.isEmpty():
            raise IndexError("this LinkedList is empty.")
        if index < 0:  # 转换负数索引
            index += self.__length
        if index < 0 or index >= self.__length:
            raise IndexError('index out of range.')
        return index

    def __findnode(self, index):
        crt, nxt = self.head, self.head.next
        for _ in range(index):
            crt, nxt = nxt, nxt.next
        return crt, nxt

    def __findprev(self, index):
        prev, crt = None, self.head
        for _ in range(index):
            prev, crt = crt, crt.next
        return prev, crt

    def pop(self, index=0):
        """弹出指定位置的元素,默认以队列的方式弹出第0个元素。"""
        index = self.__checkidx(index)
        if index == 0:
            ans = self.head.val
            self.head = self.head.next
        else:
            prev, crt = self.__findprev(index)
            ans = crt.val
            prev.next = crt.next
        self.__length -= 1
        return ans

    def delete(self, index):
        index = self.__checkidx(index)

        if index == 0:
            self.head = self.head.next
        else:
            prev, crt = self.__findprev(index)
            prev.next = crt.next
        self.__length -= 1

    def insert(self, before_index, valOrNode):
        """在指定位置之前插入元素。
        before_index最大可以等于当前链表length,此时相当于在最后追加元素。"""
        if before_index == self.__length:
            self.append(valOrNode)
            return

        before_index = self.__checkidx(before_index)

        if isinstance(valOrNode, ListNode):
            if valOrNode.next is not None:
                warn("valOrNode.next is not None, new ListNode will be cloned.")
                elem = ListNode(valOrNode.val)
            else:
                elem = valOrNode
        else:
            elem = ListNode(valOrNode)

        if before_index == 0:
            elem.next = self.head
            self.head = elem
        else:
            prev, crt = self.__findprev(before_index)
            elem.next = crt
            prev.next = elem
        self.__length += 1

    def update(self, index, val):
        """更新指定位置处元素的值。"""
        index = self.__checkidx(index)

        crt, _ = self.__findnode(index)
        crt.val = val

    def getItem(self, index):
        index = self.__checkidx(index)

        crt, _ = self.__findnode(index)
        return crt

    def getIndex(self, val):
        """获取第一个值为val的元素的位置。"""
        if self.isEmpty():
            raise IndexError("this linked list is empty.")

        i = 0
        crt = self.head
        while i < self.__length:
            if crt.val == val:
                return i
            crt = crt.next
            i += 1
        return -1

    def clear(self):
        self.head = None
        self.__length = 0

    def clone(self):
        """深度克隆当前链表。修改当前链表不会影响克隆链表。"""
        new = LinkedList(0)
        this_crt = self.head
        new_crt = new.head
        while this_crt:
            new_crt.next = ListNode(this_crt.val)
            new_crt, this_crt = new_crt.next, this_crt.next
        new.head = new.head.next
        new.length = self.__length
        return new

    def checkclosedcycle(self, dismiss=False):
        """检查当前链表是否存在闭环,获取闭环的位置及长度。
        无闭环返回 (False, 0),否则返回 (闭环位置, 闭环长度)。
        若 dissmiss=True,则解除闭环。
        注意:解除闭环可能导致链表长度发生变化!"""
        slow = fast = self.head
        exist = False
        ciclen = 0
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            ciclen += 1
            if slow is fast and fast is not None:
                exist = True
                break
        if exist:  # 获取闭环位置
            seeker, end = self.head, slow
            idx = 0
            while seeker is not slow:
                seeker = seeker.next
                end = slow
                slow = slow.next
                idx += 1
            if dismiss:
                end.next = None
                self.__length = idx + ciclen
            return (idx, ciclen)
        else:
            return (False, 0)

    def __repr__(self):
        if self.isEmpty():
            return "{}"
        node = self.head
        ans = "{"
        for _ in range(self.__length):    # 采用长度判断而非node is not None,防止死循环
            ans += str(node.val) + ','
            node = node.next
        ans = ans[:-1] + "}"
        return ans

    def __getitem__(self, ind):
        if isinstance(ind, int):
            return self.getItem(ind)
        elif isinstance(ind, slice):    # 切片检索
            ans = []
            idxs = list(range(self.__length)[ind])
            if ind.step < 0:
                idxs.reverse()
            i, crt = 0, self.head
            while i < self.__length and idxs:
                if i == idxs[0]:
                    ans.append(crt)
                    idxs = idxs[1:]
                i, crt = i + 1, crt.next
            if ind.step < 0:
                ans.reverse()
            return ans

    def __setitem__(self, ind, val):
        self.update(ind, val)

    def __len__(self):
        return self.__length

    def __iter__(self):
        return LinkedListIterator(self)

    def __add__(self, operand):
        ans = self.clone()
        ans.extend(operand)
        return ans


class LinkedListIterator:
    """迭代器,主要用作for循环访问LinkedList。"""

    def __init__(self, llist):
        self.crt = llist.head
        self.__length = len(llist)

    def __iter__(self):
        return self

    def __next__(self):
        if self.crt is not None:
            prev = self.crt
            self.crt = self.crt.next
            return prev
        else:
            raise StopIteration

Guess you like

Origin blog.csdn.net/liuqixuan1994/article/details/103789486