DTLib - CircleList、DualLinkList、DualCircleList

目录

1、循环链表的实现 

2、编程实验 

3、循环链表的应用 

4、双向链表的实现 

5、编程实验 

6、双向循环链表的实现

7、编程实验 


1、循环链表的实现 

概念上 

                -任意数据元素都有—个前驱和—个后继

                -所有的数据元素的关系构成—个逻辑上的环 

实现上 

                -循环链表是一种特殊的单链表 

                -尾结点的指针域保存了首结点的地址

                 -特殊处理首元素的插入操作和删除操作 

循环链表的逻辑构成 

  

循环链表的继承层次结构

   

循环链表的实现思路

                -通过模板定义CircleList类,继承自LinkList类 

                -定义内部函数last_to_first() , 用于将单链表首尾相连 

                -特殊处理:首元素的插入操作和删除操作 

                -重新实现:清空操作和遍历操作 

循环链表的实现要点

                -插入位置为0时: 

                       ★ 头结点和尾结点均指向新结点 

                       ★ 新结点成为首结点插入链表 

                -删除位置为0时

                       ★ 头结点和尾结点指向位置为1的结点 

                       ★ 安全销毁首结点

2、编程实验 

循环链表的实现     CircleList.h

#ifndef CIRCLELIST_H
#define CIRCLELIST_H

#include "LinkList.h"

namespace DTLib
{

template <typename T>
class CircleList : public  LinkList<T>
{
protected:
    typedef typename LinkList<T>::Node Node;

    Node* last() const
    {
        return this->position(this->m_length - 1)->next;
    }

    void last_to_first() const//O(n)
    {
        last()->next = this->m_header.next;
    }

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

public:
    bool insert(int i, const T& e)
    {
        bool ret = true;

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

        ret = this->LinkList<T>::insert(i, e);

        if( ret && i == 0)
        {
            last_to_first();
        }

        return ret;
    }

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

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

        i = mod(i);

        if(i == 0)
        {
            Node* toDel = this->m_header.next;

            if(toDel != 0)
            {
                this->m_header.next = toDel->next;
                this->m_length--;

                if(this->m_length > 0)
                {
                    last_to_first();

                    if(toDel == this->m_current)
                    {
                        this->m_current = toDel->next;
                    }
                }
                else
                {
                    this->m_header.next = 0;
                    this->m_current = 0;
                }

                this->destroy(toDel);
            }
            else
            {
                ret = false;
            }
        }
        else
        {
            this->LinkList<T>::remove(i);
        }

        return ret;
    }

    bool set(int i, const T& e)
    {
        return this->LinkList<T>::set(mod(i), e);
    }

    T get(int i) const
    {
        return this->LinkList<T>::get(mod(i));
    }

    bool get(int i, T& e) const
    {
        return this->LinkList<T>::get(mod(i), e);
    }



    //不安全的做法:直接调用父类find函数,数据元素是对象时,重载的"=="可能抛异常,
    //函数直接返回,无法调用last_to_first(),循环链表状态直接被改变
    /*int find(const T& e) const
    {
        int ret = -1;

        last()->next = 0;

        ret = this->LinkList<T>::find(e);

        last_to_first();

        return ret;
    }*/

    int find(const T& e) const
    {
        int ret = -1;

        Node* slider = this->m_header.next;

        for(int i = 0; i < this->m_length; i++)
        {
            if(slider->value == e) //即便抛异常也不会改变循环链表的状态
            {
                ret = i;
                break;
            }

            slider = slider->next;
        }

        return ret;
    }

    /*void clear()
    {
        if(this->m_length > 0)
        {
            last()->next = 0;
            this->LinkList<T>::clear();
        }
    }*/

    void clear()
    {
        while(this->m_length > 1)
        {
            remove(1);//不remove(0)的原因是效率问题
        }

        if(this->m_length == 1)
        {
            Node* toDel = this->m_header.next;

            this->m_header.next = 0;
            this->m_current = 0;
            this->m_length = 0;

            this->destroy(toDel);
        }
    }

    bool move(int i, int step)
    {
        return this->LinkList<T>::move(mod(i), step);
    }

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

    ~CircleList()
    {
        clear();
    }

};

}

#endif // CIRCLELIST_H

3、循环链表的应用 

约瑟夫环问题 

                    已知n个人(以编号0, 1 , 2 , 3 ,…,n-1分别表示)围坐在—张圆桌周围。

                    从编号为k的人开始报数,数到m的那个人出列;他的下—个人又从1开始报数,

                    数到m的那个人又出列;依此规律重复下去,直到圆桌周围的入全部出列。 

小故事

                    在罗马人占领乔塔帕特后,39个犹太人与 Josephus及他的朋友躲到一个洞中,39个犹大人 

                    决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始 

                    报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。 

                    然而Josephus和他的朋友并不想遵从。那么,一开始要站在什么地方才能避免被处决? 

约瑟夫问题     main.cpp

#include <iostream>
#include "CircleList.h"

using namespace std;
using namespace DTLib;

void josephus(int n, int s, int m)
{
    CircleList<int> cl;

    for(int i = 1; i <= n; i++)
    {
        cl.insert(i);//1 ~ 41
    }

    cl.move(s-1, m-1);  //游标指向0处,步长2

    while( cl.length() > 0 )
    {
        cl.next();

        cout << cl.current() << "  ";  //当前要自杀的

        cl.remove(cl.find(cl.current()));
    }
}

int main()
{
    josephus(41, 1, 3);  //41个人,从1号开始数,数到第三个人开始自杀

    return 0;
}

4、双向链表的实现 

单链表的另—个缺陷 

   -单向性:只能从头结点开始高效访问链表中的数据元素 

   -缺陷:如果需要逆向访问单链表中的数据元素将极其低效

int main()
{
    LinkList<int> l;

    for(int i=0; i<5; i++) //O(n)
    {
        l.insert(0, i);
    }

    for(int i=l.length()-1; i>=0; i--) //O(n^2)
    {
        cout << l.get(i) << endl;
    }

    return 0;
}

新的线性表 

                   在“单链表”的结点中增加指针pre, 用于指向当前结点的前驱结点。

 

       -  双向链表是为了弥补单链表的缺陷而重新设计的 

       -  在概念上,双向链表不是单链表,没有继承关系 

       -  双向链表中的游标能够直接访问当前结点的前驱和后继

       -  双向链表是线性表概念的最终实现(更贴近理论上的线性表)

双向链表的继承层次结构

 

5、编程实验 

双向链表的实现     DualLinkList.h          

#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
    {
        T value;
        Node* next;
        Node* pre;
    };

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

    int m_length;

    Node* m_current;
    int m_step;

    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 = 0;
        m_header.pre = 0;
        m_length = 0;
        m_current = 0;
        m_step = 1;
    }

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

        if( ret )
        {
            Node* node = create();
            
            if( node )
            {
                Node* current = position(i);
                Node* next = current->next;
                
                node->value = e;
                
                node->next = next;
                current->next = node;
                
                //第0个结点的的pre指针为NULL
                if(current != reinterpret_cast<Node*>(&m_header))
                {
                    node->pre = current;
                }
                else
                {
                    node->pre = 0;
                }

                //不是尾部插入结点
                if(next != 0)
                {
                    next->pre = node;
                }

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

        return ret;
    }

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

    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;

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

            current->next = next;

            if(next != 0)
            {
                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;
    }

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

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

        return ret;
    }

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

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

    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 == 0);
    }

    virtual T current()
    {
        if( !end() )
        {
            return m_current->value;
        }
    }

    virtual bool next()
    {
        int i = 0;

        while(i < m_step && !end())
        {
            m_current = m_current->next;
            i++;
        }

        return i == m_step;
    }

    virtual bool pre()
    {
        int i = 0;

        while(i < m_step && !end())
        {
            m_current = m_current->pre;
            i++;
        }

        return i == m_step;
    }

    ~DualLinkList()
    {
        clear();
    }
};
}

#endif // DUALLINKLIST_H

main.cpp

#include <iostream>
#include "DualLinkList.h"

using namespace std;
using namespace DTLib;

int main()
{
    DualLinkList<int> d1;

    for(int i = 0; i < 5; i++)
    {
        d1.insert(0, i);
        d1.insert(0, 5);
    }

    for(d1.move(0); !d1.end(); d1.next())
    {
        cout << d1.current() << " ";
    }

    cout << endl;

    for(d1.move(d1.length()-1); !d1.end(); d1.pre())  //逆序访问 O(1)
    {
        cout << d1.current() << " ";
    }

    cout << endl;

    d1.move(d1.length()-1);

    while( !d1.end() )
    {
        if(d1.current() == 5)
        {
            cout << d1.current() << " ";

            d1.remove(d1.find(d1.current()));
        }
        else
        {
            d1.pre();
        }
    }

    cout << endl;

    for(d1.move(d1.length()-1); !d1.end(); d1.pre())
    {
        cout << d1.current() << " ";
    }

    cout << endl;

    return 0;
}

                

6、双向循环链表的实现

        目标

                        使用Linux内核链表实现DTLib中的双向循环链表

 

                        Linux内核链表是带头结点的双向循环链表 

                        DualCircleList使用Linux内核链表进行内部实现 

    

DTLib中双向循环链表的设计思路 

       数据结点之间在逻辑上构成双向循环链表,头结点仅用于结点的定位。 

实现思路

              -通过模板定义DualCircleList类,继承自DualLinkList类 

              -在DualCircleList内部使用Linux内核链表进行实现 

              -使用struct list_head定义DualCircleList的头结点 

              -特殊处理:循环遍历时忽略头结点 

实现要点 

              -通过list_head进行目标结点定位( position(i) ) 

              -通过list_entrylist_head指针转换为目标结点指针 

              -通过list_for_each实现int find(const T& e)函数

              -遍历函数中的 next() pre() 需要考虑跳过头结点

 

7、编程实验 

基于Linux内核链表的双向循环链表     DualCircleList.h

#ifndef DUALCIRCLELIST_H
#define DUALCIRCLELIST_H

#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);

        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 )
        {
            node->value = e;

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

            this->m_length++;
        }
        else
        {
            THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create a 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 = toDel->next;
            }

            list_del(toDel);

            this->m_length--;

            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 )
        {
            list_entry(position(i)->next, Node, head)->value = e;
        }

        return ret;
    }
    T get(int i) const
    {
        T ret;

        if( get(i, ret) )
        {
            return ret;
        }
        else
        {
            THROW_EXCEPTION(IndexOutOfBoundsExpception, "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 = 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(InvalidParameterException, "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 // DUALCIRCLELIST_H

main.cpp

#include <iostream>
#include "DualCircleList.h"

using namespace std;
using namespace DTLib;


int main()
{
    DualCircleList<int> d1;

    for(int i = 0; i < 5; i++)
    {
        d1.insert(0, i);
        d1.insert(0, 5);
    }

    for(int i = 0; i < d1.length(); i++)
    {
        cout << d1.get(i) << " ";
    }
    
    cout << endl;

    d1.move(d1.length() - 1);

    while(d1.find(5) != -1)
    {
        if(d1.current() == 5)
        {
            cout << d1.current() << " ";

            d1.remove(d1.find(d1.current()));
        }
        else
        {
            d1.pre();
        }
    }

    cout << endl;

    for(int i = 0; i < 10; i++)
    {
        cout << d1.get(i) << " ";
    }
    
    cout << endl;

    int i =0;

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

    return 0;
}

                        

 

思考题:下面代码中的pn1和pn2是否相等?为什么? 

#include <iostream>
#include "LinuxList.h"
#include "Object.h"

using namespace DTLib;
using namespace std;

struct Node : public Object
{
    list_head head;
    int value;
};

int main()
{
    Node node;

    list_head* ld = &node.head;

    Node* pn1 = reinterpret_cast<Node*>(ld);
    Node* pn2 = list_entry(ld, Node, head);

    cout << pn1 << endl;
    cout << pn2 << endl;

    cout << ld << endl;
    cout << &node << endl;

    return 0;
}

答:reinterpret_cast有“重新解释”之意,起点在结构体第一个成员
   宏list_entry本质为container_of,就是通过结构变量中一个成员的地址找到这个结构体变量的首地址。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值