鱼C论坛

 找回密码
 立即注册
查看: 1472|回复: 0

[技术交流] Python实现双链数据结构(实现迭代协议,支持切片)

[复制链接]
发表于 2020-3-12 04:33:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 Stubborn 于 2020-3-12 04:38 编辑

链表--双向链表


关于双链表,还有大佬有什么更好的建议吗???求提点


双向链表

又称为**双链表**,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱,因此,在双向链表中,节点由三部分组成:节点数据,指向下一个节点的指针(`next`指针),指向前一个节点的指针(`prev`指针)。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表

双向链表图例


prev.png


双链表特点

  • - 创建双链表时无需指定链表的长度。
  • - 比起单链表,双链表需要多一个指针用于指向前驱节点,所以需要存储空间比单链表多一点。
  • - 双链表的插入和删除需要同时维护 next 和 prev 两个指针。
  • - 双链表中的元素访问需要通过顺序访问,即要通过遍历的方式来寻找元素。


Python代码实现,实现迭代协议,支持切片
# -*- coding: utf-8 -*-
# !/usr/bin/python3
"""
@ Version : ??
@ Author : Alex
@ Software : Pycharm
@ Time : 2020/3/9 下午3:18
"""

import sys

_no_value = object()


class EmptyException(Exception): ...


class Iterator:

    def __init__(self, node):
        self.node = node

    def __iter__(self):
        return self

    def __next__(self):
        try:
            cls = self.node
            self.node = self.node.next
        except AttributeError:
            raise StopIteration()
        return cls


class DoubleLinkedList:
    """
    双链表,只有头部的pre,和尾部的next指针为None
    """

    class _Node:
        """value表示值,key表示内存地址"""

        def __init__(self, value):
            self.value = value
            self.key = id(self)
            self.pre = None
            self.next = None

        def __str__(self):
            return f'<--key:{self.key}\tvalue:{self.value}-->'

        def __repr__(self):
            return f'<--key:{self.key}\tvalue:{self.value}-->'

    def __init__(self, capacity=0xffff):
        self._head = None
        self._length = 0  # 链表中已有的节点个数,或者说长度
        self.capacity = capacity  # 链表的最多可容纳的节点个数
        self.head = self._head

    def __iter__(self):
        return Iterator(self._head)

    def __len__(self):
        return self._length

    def __contains__(self, value):
        cur = self._head
        while cur is not None:
            if cur.val == value:
                return True
            cur = cur.next
        return False

    def __getitem__(self, index):
        if isinstance(index, slice):
            return self._slice(index)

        if (not self.is_empty) or (index > self._length) or (index + self._length < 0):
            raise IndexError('DoubleLinkedList index out of range')
        if index < 0:
            index += self._length + 1
        return self._getitem(index)

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

    def __delitem__(self, index):
        """
        删除一个节点:
            per_node <---> node <-->  next_node
                per_node的next指向next_node
                next_node的pre指向per_node
                node 的pre和next修改为None,或者del
        """
        node = self[index]
        try:
            node.pre.next, node.next.pre = node.next, node.pre
            node.pre = node.next = None
            self._length -= 1
        except AttributeError:
            raise IndexError('DoubleLinkedList index out of range')

    @property
    def is_empty(self):
        return bool(self._head)

    @property
    def length(self):
        return self._length

    def _slice(self, s):
        cls = type(self)()
        start, stop, step = s.start or 0, s.stop or sys.maxsize, s.step or 1
        [cls.append(self[i].value) for i in list(range(start, stop, step))]
        return cls

    def _getitem(self, index):
        idx = 1
        node = self._head
        while node.next:
            if idx == index: break
            node = node.next
            idx += 1
        return node

    def _add(self, node):
        """头部添加"""
        node.next = self._head
        self._head = node
        if node.next is not None: node.next.pre = node

    def _append(self, node):
        """尾部添加"""
        head = self._head
        while head.next:
            head = head.next
        head.next = node
        node.pre = head

    def _insert(self, node, index):
        """
        :param node:    需要插入的节点
        :param index:   插入的索引位置

        _per_node <---> node <-->_node
        修改_per_node的next指针,指向node
        修改_node的pre指针,指向node
        在分别修改node的next和pre指针指向前后node节点
        """
        _node = self[index]
        _per_node = _node.pre
        if _per_node is None: self._add(node)

        _per_node.next = node
        node.pre = _node.pre
        node.next = _node
        _node.pre = node

    def append(self, value, index=None, head=False):
        """
            添加一个节点, 默认从尾部添加
        :param value: 节点值
        :param index: int型  如果有值,认为是插入一个节点
        :param head:  bool型 如果是True,认为是从头部插入
        注意如果index和head同为True , 默认为头部插入节点
        """
        if self._length == self.capacity:
            raise EmptyException("链表超出最大长度")
        node_cls = self._Node(value)
        if self._head is None or head:
            self._add(node_cls)
        elif index is not None:
            self._insert(node_cls, index)
        else:
            self._append(node_cls)

        self._length += 1

    def delete(self, key):
        del self[key]

    def get(self, index, val_type=_no_value):
        """
        val_type: 如果有设置默认值,发生报错将返回默认值
        """
        if val_type is not _no_value:
            try:
                return self[index]
            except Exception as e:
                return val_type
        return self[index]


if __name__ == '__main__':
    t = DoubleLinkedList()
    t.append(2)
    t.append(3)
    t.append(4)
    print(len(t[1:5:2]))
    for i in t: print(i)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-23 17:30

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表