Python-用面向对象实现LinkedList链表

1、简介

1.1、链表分类

单向链表实现append、iternodes方法
双向链表实现append、pop(尾部弹出)、insert、remove(使用索引移除)、iternodes方法
为链表提供__getitem__、__iter____setitem__等方法

1.2、链表实现方法

实现LinkedList链表
链表有单向链表、双向链表

 

对于链表来说
每一个结点是一个独立的对象,结点对象有内容,还知道下一跳是什么。
链表则是一个容器,它内部装着一个个结点对象。
所以,建议设计2个类,一个是结点Node类,一个是链表LinkedList类。
如同一个箱子是容器,里面放的小球就是一个个节点。
如同一串珠子,节点对象是一个个珠子,每一颗珠子关联其前后的珠子,所有珠子形成串珠的概念,相
当于容器。一串珠子可以从固定一头提起,这是单向链表;如果这串珠子可以从两头中的任意一头提
起,这就是双向链表。

2、单向链表

# 解决ListNode注解延后评估,3.10之前使用注解延后评估功能必须有下一句
from __future__ import annotations


class ListNode:
    """结点保存内容和下一跳"""

    def __init__(self, item, next: ListNode = None):  # 注解延后评估
        self.item = item
        self.next = next

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


class LinkedList:
    """容器,有头尾"""

    def __init__(self):
        self.head = None
        self.tail = None  # 单向链表为什么需要保存这个尾巴?

    def append(self, item):
        node = ListNode(item)
        if self.head is None:  # 0个元素
            self.head = node
        else:  # 多于1个元素
            self.tail.next = node
        self.tail = node  # 设置新tail
        return self  # return self的好处?

    def iternodes(self):
        current: ListNode = self.head
        while current:
            yield current
            current = current.next


ll = LinkedList()
ll.append(1).append(2).append(3)
ll.append('abc').append('def')
print(ll.head)
print(ll.tail)
print('-' * 30)
for i, item in enumerate(ll.iternodes()):
    print(i, item)

3、双向链表

双向链表实现append、pop、insert、remove、iternodes方法
实现单向链表没有实现的pop、remove、insert方法,补上。
双向链表的iternodes要实现两头迭代
# 解决ListNode注解延后评估,3.10之前使用注解延后评估功能必须有下一句
from __future__ import annotations


class ListNode:
    """结点保存内容和下一跳"""

    def __init__(self, item, prev: ListNode = None, next: ListNode = None):  # 注解延后评估
        self.item = item
        self.prev = prev  # 增加上一跳
        self.next = next

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


class LinkedList:
    """容器,有头尾"""

    def __init__(self):
        self.head = None
        self.tail = None  # 单向链表为什么需要保存这个尾巴?

    def append(self, item):
        node = ListNode(item)
        if self.head is None:  # 0个元素
            self.head = node
            self.tail = node
        else:  # 多于1个元素
            self.tail.next = node
            node.prev = self.tail
        self.tail = node  # 设置新tail
        return self  # return self的好处?

    def pop(self):
        """尾部弹出"""
        if self.tail is None:
            raise Exception('Empty')
        node: ListNode = self.tail
        item = node.item
        prev = node.prev
        if prev is None:  # only one node
            self.head = None
            self.tail = None
        else:
            prev.next = None
            self.tail = prev
        return item

    def insert(self, index, item):
        """指定索引插入"""
        if index < 0:
            raise IndexError('Not negative index:{}'.format(index))
        current = None
        for i, node in enumerate(self.iternodes()):
            if index == i:
                current = node
                break
        else:
            self.append(item)  # 尾部追加
            return
        node = ListNode(item)
        prev = current.prev  # 当前结点的前一个
        next = current.next  # 当前结点的后一个
        # prev is None、current is self.head、i==0意思相同
        if index == 0:  # 开头插入
            self.head = node
        else:  # 中间插入
            node.prev = prev
            prev.next = node
        node.next = current
        current.prev = node

    def remove(self, index):
        """指定index删除"""
        if self.tail is None:
            raise Exception('Empty')
        if index < 0:
            raise IndexError('Not negative index:{}'.format(index))
        current = None
        for i, node in enumerate(self.iternodes()):
            if index == i:
                current = node
                break
        else:  # Not Found
            raise IndexError('Index out of range:{}'.format(index))
        prev = current.prev
        next = current.next
        # 4种情况
        if prev is None and next is None:  # only one node
            self.head = None
            self.tail = None
        elif prev is None:  # 多于一个结点,移除头部
            self.head = next
            next.prev = None
        elif next is None:  # 多于一个结点,移除尾部
            self.tail = prev
            prev.next = None
        else:  # 在中间,头尾不变
            prev.next = next
            next.prev = prev
        del current

    def iternodes(self):
        current: ListNode = self.head
        while current:
            yield current
            current = current.next


ll = LinkedList()
ll.append(1).append(2).append(3)
ll.append('abc').append('def')
print(ll.head)
print(ll.tail)
print('-' * 30)
for i, item in enumerate(ll.iternodes()):
    print(i, item)
ll.insert(0, 'start')
ll.insert(20, 'end')
print('~' * 30)
for i, item in enumerate(ll.iternodes()):
    print(i, item)
ll.remove(5)
ll.remove(4)
ll.remove(0)
ll.pop()
print('=' * 30)
for i, item in enumerate(ll.iternodes()):
    print(i, item)

4、容器化

# 解决ListNode注解延后评估,3.10之前使用注解延后评估功能必须有下一句
from __future__ import annotations


class ListNode:
    """结点保存内容和下一跳"""

    def __init__(self, item, prev: ListNode = None, next: ListNode = None):  # 注解延后评估
        self.item = item
        self.prev = prev  # 增加上一跳
        self.next = next

    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:  # 0个元素
            self.head = node
            self.tail = node
        else:  # 多于1个元素
            self.tail.next = node
            node.prev = self.tail
        self.tail = node  # 设置新tail
        self._size += 1
        return self  # return self的好处?

    def pop(self):
        """尾部弹出"""
        if self.tail is None:
            raise Exception('Empty')
        node: ListNode = self.tail
        item = node.item
        prev = node.prev
        if prev is None:  # only one node
            self.head = None
            self.tail = None
        else:
            prev.next = None
            self.tail = prev
        self._size -= 1
        return item

    def insert(self, index, item):
        """指定索引插入"""
        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  # 当前结点的后一个
        # prev is None、current is self.head、i==0意思相同
        if index == 0:  # 开头插入
            self.head = node
        else:  # 中间插入
            node.prev = prev
            prev.next = node
        node.next = current
        current.prev = node
        self._size += 1

    def remove(self, index):
        """指定index删除"""
        if self.tail is None:
            raise Exception('Empty')
        current = self[index]
        prev = current.prev
        next = current.next
        # 4种情况
        if prev is None and next is None:  # only one node
            self.head = None
            self.tail = None
        elif prev is None:  # 多于一个结点,移除头部
            self.head = next
            next.prev = None
        elif next is None:  # 多于一个结点,移除尾部
            self.tail = prev
            prev.next = None
        else:  # 在中间,头尾不变
            prev.next = next
            next.prev = prev
        del current
        self._size -= 1

    def iternodes(self, reverse=False):
        current: ListNode = 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

    # def __iter__(self):
    #     #yield from self.iternodes()
    #     return self.iternodes()
    __iter__ = iternodes

    def __reversed__(self):
        # reversed内建函数优先使用__reversed__
        # 如果不提供则使用序列协议,__len__和__getitem__方法
        return self.iternodes(True)

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

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


ll = LinkedList()
ll.append(1).append(2).append(3)
ll.append('abc').append('def')
print(ll.head)
print(ll.tail)
print('-' * 30)
for i, item in enumerate(ll):
    print(i, item)
ll.insert(0, 'start')
ll.insert(20, 'end')
print('~' * 30)
for item in ll:
    print(item)
ll.remove(5)
ll.remove(4)
ll.remove(0)
ll.pop()
print('=' * 30)
for item in ll:
    print(item)
ll[0] = 100
ll[-1] = 300
print('+' * 30)
print(*reversed(ll), sep='\n')

 

posted @ 2023-07-26 11:55  小粉优化大师  阅读(85)  评论(0)    收藏  举报