双向链表DualLinkList的实现

本文介绍了双向链表的设计思路及其实现细节,旨在解决单链表无法高效逆向访问的问题。通过增加指向当前节点前驱的指针,双向链表能够支持数据元素的前后向访问,提升了数据插入和访问操作的灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单链表的缺陷

在前文中实现了单链表LinkList(点击这里),但是单链表存在一定的缺陷:

  • 只能从头结点开始高效访问链表中的数据元素(单向性);
  • 如果需要逆向访问单链表中的数据元素将极其低效;
  • 数据插如操作和取数据元素操作时间复杂度不一样。
    这里写图片描述

双向链表

因此需要设计一种新的线性表,设计思路:
  在“单链表”的结点中增加一个指针pre,用于指向当前结点的前驱结点。
双向链表的设计
特点:
(1)双向链表是为了弥补单链表的缺陷而重新设计的;
(2)在概念上,双向链表不是单链表,没有继承关系,是兄弟关系;
(3)双向链表中的游标能够直接访问当前结点的前驱和后继;
(3)双向链表是线性表概念的最终实现(更贴近理论上的线性表)。

实现:
双向链表的实现可以直接先复制单链表的实现,然后在上面修改。双向链表是单链表功能上的加强,但是它们并不是父子关系。在其他的设计方案当中是将双向链表当作单链表的子类来设计的。然而,在设计上没有对与错只有合理与不合理,设计并不会影响功能,设计会影响代码后期的维护性和软件产品后期的维护性。

#ifndef _DUALLINKLIST_H_
#define _DUALLINKLIST_H_


#include "List.h"
#include "Exception.h"

namespace DTLib
{
    template < typename T >
    class DualLinkList : public List<T>
    {
    protected:
        struct Node : public Object
        {
        public:
            T value;
            Node* next;
            Node* pre;
        };

        mutable struct : public Object
        {
        public:
            char reserved[sizeof(T)];
            Node* next;
            Node* pre;
        }m_header;

        int m_length;
        int m_step; 
        Node* m_current; 

        Node* position(int i) const
        {
            Node* ret = reinterpret_cast<Node*>(&m_header);

            for (int p = 0; p < i; p++)
            {
                ret = ret->next;
            }

            return ret;
        }

        virtual Node* create()
        {
            return new Node();
        }

        virtual void destroy(Node* pn)
        {
            delete pn;
        }

    public:
        DualLinkList()
        {
            m_header.next = NULL;
            m_header.pre = NULL;
            m_length = 0;
            m_step = 1;
            m_current = NULL;
        }

        bool insert(const T& e)
        {
            return insert(m_length, e);
        }

        bool insert(int i, const T& e)
        {
            bool ret = ((0 <= i) && (i <= m_length));
            if (ret)
            {
                Node* node = create(); // new Node();
                if (node != NULL)
                {

                    Node* current = position(i); 
                    Node* next = current->next;

                    node->value = e;

                    node->next = next; // 第一个结点创建时其node->next为NULL
                    current->next = node;

                    if (current != reinterpret_cast<Node*>(&m_header))
                    {
                        node->pre = current;
                    }
                    else
                    {
                        node->pre = NULL;
                    }

                    if (next != NULL)
                    {
                        next->pre = node;
                    }

                    m_length++;
                }
                else
                {
                    THROW_EXCEPTION(NoEnoughMemoryException, "No memory to insert new element...");
                }


            }

            return ret;

        }


        bool remove(int i)
        {
            bool ret = ((0 <= i) && (i < m_length));

            if (ret)
            {

                Node* current = position(i);
                Node* toDel = current->next;
                Node* next = toDel->next;

                // m_current提前指向要被删除结点的下一个结点,要不然删除该结点之后
                // m_current就是野指针
                if (m_current == toDel)
                {
                    m_current = next;
                }

                current->next = toDel->next;

                if (next != NULL)
                {
                    next->pre = toDel->pre;
                }

                m_length--;

                destroy(toDel); // 保证异常安全

            }

            return ret;

        }

        bool set(int i, const T& e)
        {

            bool ret = ((0 <= i) && (i < m_length));

            if (ret)
            {
                position(i)->next->value = e;
            }

            return ret;
        }

        virtual T get(int i) const
        {
            T ret;

            if (get(i, ret))
            {
                return ret;
            }
            else
            {
                THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element...");
            }

            return ret;
        }

        bool get(int i, T& e) const
        {
            bool ret = ((0 <= i) && (i < m_length));

            if (ret)
            {
                e = position(i)->next->value;
            }
            return ret;
        }

        int find(const T& e) const
        {
            int ret = -1;
            int i = 0;
            Node* node = m_header.next;

            while (node)
            {
                if (node->value == e)
                {
                    ret = i;
                    break;
                }
                else
                {
                    node = node->next;
                    i++;
                }
            }

            return ret;
        }


        int length() const
        {
            return m_length;
        }

        void clear()
        {
            while (m_length > 0)
            {
                remove(0);
            }
        }

        virtual bool move(int i, int step = 1)
        {
            bool ret = (0 <= i) && (i < m_length) && (step > 0);

            if (ret)
            {
                m_current = position(i)->next; // 定位到目标位置的节点
                m_step = step;
            }

            return ret;
        }

        virtual bool end()
        {
            return (m_current == NULL); //  判断游标的值是否为空,空表示遍历结束
        }

        virtual T current() // 返回当前游标所指向的数据元素的值
        {
            if (!end()) // 游标不为空
            {
                return m_current->value;
            }
            else
            {
                THROW_EXCEPTION(InvalidOperationException, "No value at current position...");
            }
        }

        virtual bool next() // 用于移动游标
        {
            int i = 0;

            while ((i < m_step) && !end()) //  每一次移动要移动m_step次
            {
                m_current = m_current->next;
                i++;
            }

            return (i == m_step); //表示当前移动成功
        }

        virtual bool pre()
        {
            int i = 0;

            while ((i < m_step) && !end()) //  每一次移动要移动m_step次
            {
                m_current = m_current->pre;
                i++;
            }

            return (i == m_step); //表示当前移动成功
        }

        ~DualLinkList()
        {
            clear();
        }


    };


}

#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值