双向循环链表DualCircleList的实现(利用Linux内核链表)

目标

  使用Linux内核链表实现双向循环链表DualCircleList。

设计思路

  数据结点之间在逻辑上构成双向循环链表,头结点仅用于结点的定位。
这里写图片描述

实现思路

(1)通过模板定义 DualCirclelist 类,继承自 DualLinkList类;
(2)在 DualCircleList 内部使用 Linux 内核链表进行实现;
(3)使用 struct list_head 定义 DualCirclelist 的头结点;
(4)特殊处理:循环遍历时忽略头结点。

实现要点

(1)通过list_head进行目标结点的定位(position(i));
(2)通过list_entry将list_head指针转换为目标结点指针;
(3)通过list_for_each实现int find(const T& e)函数;
(4)遍历函数中的next()和pre()需要考虑跳过头结点。

代码实现

#ifndef _DUALCIRCLELIST_
#define _DUALCIRCLELIST_

#include "LinuxList.h"
#include "DualLinkList.h"

namespace DTLib
{
    template <typename T>
    class DualCircleList : public DualLinkList<T>
    {
    protected:
        struct Node : public Object 
        {
            list_head head;
            T value;
        };

        list_head m_header;
        list_head* m_current;

        list_head* position(int i) const
        {
            list_head* ret = const_cast<list_head*>(&m_header); // position函数为const

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

            return ret;

        }

        int mod(int i) const
        {
            return (this->m_length == 0) ? 0 : (i % this->m_length);
        }

    public:
        DualCircleList()
        {
            this->m_length = 0;
            this->m_step = 1;

            m_current = NULL;

            INIT_LIST_HEAD(&m_header);
        }

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

        bool insert(int i, const T& e)
        {
            bool ret = true;
            Node* node = new Node();

            i = i % (this->m_length + 1);

            if (node != NULL)
            {
                node->value = e;

                list_add_tail(&node->head, position(i)->next);

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

            return ret;
        }


        bool remove(int i)
        {
            bool ret = true;

            i = mod(i);

            ret = ((0 <= i) && (i < this->m_length));

            if (ret)
            {
                list_head* toDel = position(i)->next;

                if (m_current == toDel)
                {
                    m_current = m_current->next;
                }

                list_del(toDel);

                this->m_length--;

                // delete toDel; // 因为toDel实际上指向的是节点中的head成员,要将它转换为真正的节点!
                // delete的时候是list_head,但是new出来的是Node
                // list_entry不仅调整了指针的位置也调整的指针所指的大小(list_entry不仅仅是调整位置,因为
                // delete的时候不仅需要内存位置也需要知道内存的大小)

                delete list_entry(toDel, Node, head);
            }

            return ret;

        }

        bool set(int i, const T& e)
        {
            bool ret = true;

            i = mod(i);

            ret = ((0 <= i) && (i < this->m_length));

            if (ret)
            {
                // position(i)->next->value = e;错
                // 应该将position(i)->next这个指针转换成指向实际节点的指针
                list_entry(position(i)->next, Node, head);
            }

            return ret;
        }

        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 = true;

            i = mod(i);

            ret = ((0 <= i) && (i < this->m_length));

            if (ret)
            {
                // e = position(i)->next->value;错,原因同bool set(int i, const T& e)
                e = list_entry(position(i)->next, Node, head)->value;
            }
            return ret;
        }

        int find(const T& e) const
        {
            int ret = -1;
            int i = 0;
            list_head* slider = NULL;

            list_for_each(slider, &m_header)
            {
                if (list_entry(slider, Node, head)->value == e)
                {
                    ret = i;
                    break;
                }

                i++;
            }

            return ret;
        }

        int length() const
        {
            return this->m_length;
        }

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

        bool move(int i, int step = 1)
        {
            bool ret = (step > 0);

            i = mod(i);

            ret = ret && ((0 <= i) && (i < this->m_length));

            if (ret)
            {
                m_current = position(i)->next;

                this->m_step = step;
            }

            return ret;

        }

        bool end()
        {
            return (m_current == NULL) || (this->m_length == 0);
        }

        T current() 
        {
            if (!end()) 
            {
                return list_entry(m_current, Node, head)->value;
            }
            else
            {
                THROW_EXCEPTION(InvalidOperationException, "No value at current position...");
            }
        }

        bool next() // 要跳过头结点
        {
            int i = 0;

            while ((i < this->m_step) && !end()) 
            {
                if (m_current != &m_header) //  如果当前在头结点就跳过
                {
                    m_current = m_current->next;
                    i++;
                }
                else
                {
                    m_current = m_current->next;
                }
            }

            if (m_current == &m_header) //  移动过后如果当前在头结点
            {
                m_current = m_current->next;
            }

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

        bool pre()
        {
            int i = 0;

            while ((i < this->m_step) && !end())
            {
                if (m_current != &m_header) //  如果当前在头结点就跳过
                {
                    m_current = m_current->prev;
                    i++;
                }
                else
                {
                    m_current = m_current->prev;
                }
            }

            if (m_current == &m_header) //  移动过后如果当前在头结点
            {
                m_current = m_current->prev;
            }


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


        ~DualCircleList()
        {
            clear();
        }

    };
}


#endif

测试代码

#include <iostream>
#include "DualCircleList.h"
using namespace std;
using namespace DTLib;

int main(void)
{
    DualCircleList<int> dl;

    for (int i = 0; i < 5; i++)
    {
        //dl.insert(0, i);
        //dl.insert(0, 5);

        dl.insert(i);
        dl.insert(5);
    }

    cout << "begin delete..." << endl;


    dl.move(dl.length() - 1); // 移动游标
    while (dl.find(5) != -1)
    {
        if (dl.current() == 5)
        {
            cout << dl.current() << endl;
            dl.remove(dl.find(dl.current()));
        }
        else
        {
            dl.pre();
        }
    }

    cout << "end delete" << endl;

    int i = 0;

    for (dl.move(dl.length() - 1); (i < dl.length()) && !dl.end(); dl.pre(), i++)
    {
        cout << dl.current() << endl;
    }

    return 0;
}

测试输出

begin delete...
5
5
5
5
5
end delete
4
3
2
1
0
请按任意键继续. . .

至此,线性表相关的类已全部实现:
            这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值