双向链表实现(面向对象、魔术方法练习)

用面向对象实现LinkedList链表
双向链表实现append、pop(尾部弹出)、insert、remove(使用索引移除)、iternodes方法
为链表提供__getitem__、__iter__、__setitem__等方法

from __future__ import annotations


class ListNode:
    def __init__(self, item, next: ListNode = None, prev: ListNode = None):
        self.item = item
        self.next = next
        self.prev = prev

    def __repr__(self):
        return "{}<=={}==>{}".format(
            self.prev.item if self.prev else None,
            self.item,
            self.next.item if self.next else None)

    __str__ = __repr__


class LinkedList:
    def __init__(self):
        self.head = None
        self.tail = None
        self._size = 0

    def append(self, item):
        node = ListNode(item)
        if self.head is None:  # 空链表
            self.head = node
        else:
            node.prev = self.tail
            self.tail.next = node
        self.tail = node
        self._size += 1
        return self

    def pop(self):  # 尾部弹出
        if self.tail is None:  # 没有元素
            raise Exception('Empty LinkedList')
        node: ListNode = self.tail
        item = node.item
        prev = node.prev
        if self.head == self.tail:  # 只有一个元素
            self.head = None
            self.tail = None
        else:
            self.tail = prev
            prev.next = None
        self._size -= 1
        return item

    def insert(self, index, item):
        # if index < 0:
        #     raise IndexError('not support negative index')
        # current = None
        # for i, node in enumerate(self.iter_nodes()):  # 遍历查找插入点
        #     if i == index:
        #         current = node
        #         break
        # else:
        #     self.append(item)
        #     return
        if index >= len(self):  # 大于长度尾部追加
            self.append(item)
            return
        if index < -len(self):  # 相当于在头部插入
            index = 0
        current = self[index]
        node = ListNode(item)
        prev = current.prev
        # next = current.next
        if index == 0:  # 开头插入,插入到index前面,先把插入点之前的关系修复,再统一修复插入点后面的关系
            self.head = node
        else:
            node.prev = prev
            prev.next = node
        node.next = current
        current.prev = node
        self._size += 1

    def remove(self, index):
        if self.tail is None:
            raise Exception('Empty')

        # if index < 0:
        #     raise IndexError('not support negative index')

        # current = None
        # for i, node in enumerate(self.iter_nodes()):  # 遍历查找插入点
        #     if i == index:
        #         current = node
        #         break
        # else:
        #     raise IndexError('out of range')
        current = self[index]
        prev = current.prev
        next = current.next
        if prev is None and next is None:  # 只有一个元素
            self.head = None
            self.tail = None
        elif prev is None:  # 多个元素,删除元素为第一个元素
            self.head = next
            next.prev = None
        elif next is None:  # 多个元素,删除元素为最后一个
            prev.next = None
            self.tail = prev
        else:  # 多个元素,删除中间元素
            prev.next = next
            next.prev = prev

        del current
        self._size -= 1

    def iter_nodes(self, reverse=False):
        current = self.head if not reverse else self.tail

        while current:
            yield current
            current = current.next if not reverse else current.prev

    size = property(lambda self: self._size)

    # 容器化
    def __len__(self):
        return self._size

    __iter__ = iter_nodes

    def __reversed__(self):
        return self.iter_nodes(True)

    def __getitem__(self, index):
        # if index >= 0:
        #     for i, node in enumerate(self.iter_nodes(False), 0):
        #         if index == i:
        #             return node # return node.item
        # if index < 0:
        #     for i, node in enumerate(self.iter_nodes(True), 1):
        #         if index == -i:
        #             return node
        if index >= len(self) or index < -len(self):  # 正负超界
            raise IndexError('out of index')
        start = 0 if index >= 0 else 1
        reverse = False if index >= 0 else True
        for i, node in enumerate(self.iter_nodes(reverse), start):
            if abs(index) == i:
                return node

    def __setitem__(self, index, value):
        self[index].item = value

链表中的节点和链表(看作容器)为两个类:

  • 节点(node):有prev、next、item三个属性。
  • 链表(LinkedList):有head(头节点)、tail(尾节点)和大小三个属性

测试结果:

ll = LinkedList()
ll.append(1).append(2).append('x')
ll[2] = 3
for i in ll.iter_nodes():
    print(i)
print('-' * 30)
print(*reversed(ll), sep='\n')
print('*' * 30)
print(ll[0])
ll.pop()
ll.insert(1, '4')
for i in ll.iter_nodes():
    print(i)
print('+' * 30)
ll.remove(1)
for i in ll.iter_nodes():
    print(i)

posted @ 2021-12-15 11:13  Atlas-777  阅读(36)  评论(0)    收藏  举报