python实现双向链表基本结构及其基本方法

双向链表是在单向链表的基础上更为复杂的数据结构,其中一个节点除了含有自身信息外,还应该含有下连接一下个节点和上一个节点的信息。

双向链表适用于需要双向查找节点值的场景中,在数据量难以估计并且数据增删操作频繁的场景中,双向链表有一定优势;链表在内存中呈现的状态是离散的地址块,不需要像列表一样预先分配内存空间,在内存的充分利用上更胜一筹,不过增加了一些额外开销。

双向链表结构如图:

2019-04-06-22_24_24.png

定义基本的节点类和链表类:

class Node:
    """节点类"""
    def __init__(self, item):
        self.item = item
        self.next = None
        self.prev = None


class DLinkList:
    """
    双向列表类
    """

    def __init__(self):
        self.head = None


时间双向链表类的基本属性:是否为空,链表长度、链表遍历;判断链表是否为空只需要看头部head是否指向空,链表遍历只需要从头部到最后一个节点的下一个节点指向为空的情况,同时链表长度也是根据最后一个节点的下一个节点是否指向空来判断,基本实现如下:

class Node:
    """节点类"""
    def __init__(self, item):
        self.item = item
        self.next = None
        self.prev = None


class DLinkList:
    """
    双向列表类
    """

    def __init__(self):
        self._head = None

    @property
    def is_empty(self):
        return None == self._head

    @property
    def length(self):
        if self.is_empty:
            return 0
        n = 1
        cur = self._head
        while None != cur.next:
            cur = cur.next
            n += 1
        return n

    @property
    def ergodic(self):
        if self.is_empty:
            raise ValueError('ERROR NULL')
        cur = self._head
        print(cur.item)
        while None != cur.next:
            cur = cur.next
            print(cur.item)
        return True


接下来实现添加节点相关的操作,在头部添加、任意位置添加、尾部添加,注意在任意插入节点的时候,需要对节点进行遍历并计数,注意计数起始是1,而不是0,对应的节点是从第二个节点开始。

class Node:
    """节点类"""
    def __init__(self, item):
        self.item = item
        self.next = None
        self.prev = None


class DLinkList:
    """
    双向列表类
    """

    def __init__(self):
        self._head = None

    @property
    def is_empty(self):
        """
        是否为空
        :return:
        """

        return None == self._head

    @property
    def length(self):
        """
        链表长度
        :return:
        """

        if self.is_empty:
            return 0
        n = 1
        cur = self._head
        while None != cur.next:
            cur = cur.next
            n += 1
        return n

    @property
    def ergodic(self):
        """
        遍历链表
        :return:
        """

        if self.is_empty:
            raise ValueError('ERROR NULL')
        cur = self._head
        print(cur.item)
        while None != cur.next:
            cur = cur.next
            print(cur.item)
        return True

    def add(self, item):
        """
        在头部添加节点
        :param item:
        :return:
        """

        node = Node(item)
        if self.is_empty:
            self._head = node
        else:
            node.next = self._head
            self._head.prev = node
            self._head = node

    def append(self, item):
        """
        在尾部添加节点
        :return:
        """

        if self.is_empty:
            self.add(item)
        else:
            node = Node(item)
            cur = self._head
            while None != cur.next:
                cur = cur.next
            cur.next = node
            node.prev = cur

    def insert(self, index, item):
        """
        在任意位置插入节点
        :param index:
        :param item:
        :return:
        """

        if index == 0:
            self.add(item)
        elif index+1 >= self.length:
            self.append(item)
        else:
            n = 1
            node = Node(item)
            cur = self._head
            while Node != cur.next:
                pre = cur
                cur = cur.next
                if n == index:
                    break
            pre.next = node
            node.prev = pre
            node.next = cur
            cur.prev = node


在实现较为复杂的删除节点操作和判断节点是否存在的方法。

class Node:
    """节点类"""
    def __init__(self, item):
        self.item = item
        self.next = None
        self.prev = None


class DLinkList:
    """
    双向列表类
    """

    def __init__(self):
        self._head = None

    @property
    def is_empty(self):
        """
        是否为空
        :return:
        """

        return None == self._head

    @property
    def length(self):
        """
        链表长度
        :return:
        """

        if self.is_empty:
            return 0
        n = 1
        cur = self._head
        while None != cur.next:
            cur = cur.next
            n += 1
        return n

    @property
    def ergodic(self):
        """
        遍历链表
        :return:
        """

        if self.is_empty:
            raise ValueError('ERROR NULL')
        cur = self._head
        print(cur.item)
        while None != cur.next:
            cur = cur.next
            print(cur.item)
        return True

    def add(self, item):
        """
        在头部添加节点
        :param item:
        :return:
        """

        node = Node(item)
        if self.is_empty:
            self._head = node
        else:
            node.next = self._head
            self._head.prev = node
            self._head = node

    def append(self, item):
        """
        在尾部添加节点
        :return:
        """

        if self.is_empty:
            self.add(item)
        else:
            node = Node(item)
            cur = self._head
            while None != cur.next:
                cur = cur.next
            cur.next = node
            node.prev = cur

    def insert(self, index, item):
        """
        在任意位置插入节点
        :param index:
        :param item:
        :return:
        """

        if index == 0:
            self.add(item)
        elif index+1 >= self.length:
            self.append(item)
        else:
            n = 1
            node = Node(item)
            cur = self._head
            while Node != cur:
                pre = cur
                cur = cur.next
                if n == index:
                    break
            pre.next = node
            node.prev = pre
            node.next = cur
            cur.prev = node

    def search(self, item):
        """
        查找节点是否存在
        :param item:
        :return:
        """

        if self.is_empty:
            raise ValueError("ERROR NULL")
        cur = self._head
        while None != cur:
            if cur.item == item:
                return True
            cur = cur.next
        return False

    def deltel(self, item):
        """删除节点元素"""
        if self.is_empty:
            raise ValueError('ERROR NULL')
        else:
            cur = self._head
            while None != cur:
                if cur.item == item:
                    if not cur.prev:  # 第一个节点
                        if None != cur.next:  # 不止一个节点
                            self._head = cur.next
                            cur.next.prev = None
                        else:  # 只有一个节点
                            self._head = None
                    else:  # 不是第一个节点
                        if cur.next == None:  # 最后一个节点
                            cur.prev.next = None
                        else:  # 中间节点
                            cur.prev.next = cur.next
                            cur.next.prev = cur.prev
                cur = cur.next


注意在删除节点的时候要考虑几种特殊情况:删除节点为第一个节点,并且链表只有一个节点;删除节点为第一个节点并且链表长度大于1;删除节点是中间节点;删除节点是最后一个节点;

2019-04-06-22_24_24.png


来源:https://yq.aliyun.com/articles/696984


智能推荐

【数据结构与算法】之队列的基本介绍及其数组、链表实现---第五篇

一、队列的基本概念 1、定义 队列是一种先进先出的线性表。它只允许在表的前端进行删除操作,而在表的后端进行插入操作,具有先进先出、后进后出的特点。进行插入操作的一端成为队尾(tail),进行删除操作的一端称为队头(head)。当队列中没有元素时,则称之为空队列。 在队列中插入一个元素称为入队,从队列中删除一个元素称为出队。因为队列只允许在队尾插入元素,在队头删除元素,所以队列又称为先进先出(FIF...

双向链表的基本操作-C语言

双向链表的实现 本质: 其实就是定义两个指针域, 分别存放直接前驱结点的指针和直接后继结点的指针. 具体实现 定义一个双向链表 创建一个指定大小的双向链表 求链表的长度 双向链表的插入操作 双向链表的删除操作:与插入操作类似, 在此不再赘述 双向链表的遍历 双向链表的销毁 双向链表的倒序遍历 测试 效果图 希望该文章能对大家有所帮助 同时真诚接受大家宝贵评论和建议...

数据结构编程实验----链表的基本操作实现

链表的基本操作的实现,个人感觉链表的实现比顺序表的实现复杂了一点,特别是在操作的实现的过程中对边界的判断有点困难,画图吧,画图就可以很清楚地看出各个节点之间的关系和边界了。 1.链表的定义 2.初始化链表 3.创建链表,使链表含有元素 4.打印输出链表内部的元素 5.求链表的长度 6.查找第i个位置,并返回该位置的值 7.查找链表中值为key的节点,并返回位置 8.插入操作 9.删除操作 10.主...

数据结构单链表的基本操作的实现

数据结构单链表的基本操作的实现 1.1单链表的初始化 1.2 判断链表是否为空 1.3单链表的销毁 清空单链表 求单链表的表长 取值 按照值查找 插入 删除第i个节点 单链表的建立----头插法 单链表的创建----尾插法...

数据结构---双向链表实现队列与循环链表

大话数据结构 一、双向链表(double linked list)如图26.5,是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。双向链表的基本操作与单链表基本一样,除了插入和删除的时候需要更改两个指针变量,需要注意的是修改的顺序很重要,插入如图3-14-5,删除如图3-14-6。 记住口诀:先搞定插入节点的前驱和后继,再搞定后节点的前驱,前节点的后继。 链表的delete操作需要首先找到...

猜你喜欢

单链表的定义、特点、结构及其一些基本操作(精编版)

一、基本运算 1、单链表、双链表的定义: 设计链式存储结构时,每个逻辑节点存储单独存储。 2、单链表的基本结构:  头节点在前,首节点在后。 3、顺序表与链表间存储密度的差异: 顺序表的存储密度为1,而链表的存储密度小于1。 4、 一个是data域部分,一个是指向后继节点的指针域。 5、特点: 6、插入节点: p指针指向a节点。 7、删除节点: 二、基本算法 1、头插法建表 这个算法的时...

原型对象,原型链

函数都有prototype属性,它指向原型对象。 实例对象有__proto__属性,它指向对象原型 每一个原型对象都有constructor输赢,指向构造函数,每一个原型对象又具有__proto__属性,这个指向Object.prototype.在这里插入图片描述...

Node 调用 dubbo 服务的探索及实践

2.Dubbo简介 2.1 什么是dubbo Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。 2.2 流程图 Provider : 暴露服务的服务提供方。 Consumer : 调用远程服务的服务消费方。 Registry : 服务注册与发现的注册中心。 Monito...

mysql总结

mysql基础入门的总结     关于数据库:     数据库是软件开发人员要掌握的基本工具,软件的运行的过程就是操作数据的过程,数据库中的数据无非就是几个操作:增-删-查-改。         Mysql安装完成后,需要配置变量环境,找到配置路径path,然后把mysql安装目录bin文件导入就可以了。 然后运行cm...

adb及monkey常用命令

adb常用命令: 查看手机是否连接:adb devices   连接设备:adb connect 设备ip:端口号  若有连接多个设备需指明设备ip及端口号 安装APP:adb install [-r] 包名  -r表示覆盖安装,首次安装可省略 卸载APP:adb uninstall 包名 列出设备中所有应用包名:adb shell pm list packages ...

问答精选

Correctly formatting GCM notifications?

I'm currently trying out the google cloud messaging service with its sample application "Guestbook." https://developers.google.com/cloud/samples/mbs/ I'm attempting to send notifications tha...

Are there any performance benefits of using Asynchronous functions over Synchronous in Node Js?

Now I came across an article that distinguishes between an Asynchronous function and Synchronous functions. From my understanding of the different examples and explanations, synchronous functions are ...

Python: Costing calculator output

Good day all I'm busy creating a small costing calculator for the signage department. I'm not getting the calculator to output the amount. Brief Description: You enter the height and width and then wh...

Flask-SQLAlchemy - model has no attribute 'foreign_keys'

I have 3 models created with Flask-SQLalchemy: User, Role, UserRole role.py: user.py: user_role.py: If I try (in the console) to get all users via User.query.all() I get AttributeError: 'NoneType' obj...

Seeding many PRNGs, then having to seed them again, what is a good quality approach?

I have many particles that follow an stochastic process in parallel. For each particle, there is a PRNG associated to it. The simulation must go through many repetitions to get average results. For ea...

相关问题

相关文章

热门文章

推荐文章

相关标签

推荐问答