第29课 循环链表的实现

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第29课 循环链表的实现相关的知识,希望对你有一定的参考价值。

1. 什么是循环链表

技术分享 

(1)概念上

  ①任意数据元素都一个前驱一个后继

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

(2)实现上

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

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

2. 循环链表的实现思路

(1)通过模板定义CircleList类,继承自LinkList类

技术分享 

(2)定义内部函数makeCircle()用于将单链表首尾相连

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

  ①插入位置为0时头结点和尾结点均指向新结点新结点成为首结点

  ②删除位置为0时头结点和尾结点指向位置为1的结点安全销毁首结点

(4)重新实现:清空操作和遍历操作

【编程实验】循环链表的实现

//Iterator.h

#ifndef _ITERATOR_H_
#define _ITERATOR_H_

//#include "Exception.h"

namespace DTLib {

//迭代器类型
struct InputIterator_tag{};
struct OutputIterator_tag{};
struct ForwardIterator_tag : public InputIterator_tag{};
struct BidirectionalIterator_tag : public ForwardIterator_tag{};
struct RandomAccessIterator_tag : public BidirectionalIterator_tag{};

//类型萃取
template <class Iterator>
struct IteratorTraits
{
    typedef typename Iterator::iterator_category iterator_category;
    typedef typename Iterator::value_type   value_type;
    typedef typename Iterator::difference_type  difference_type;
    typedef typename Iterator::pointer   pointer;
    typedef typename Iterator::reference reference;
};

//对指针类型的特化
template < class T>
struct IteratorTraits<T*>
{
    typedef RandomAccessIterator_tag iterator_category; //指针类型是可以随机访问的
    typedef T          value_type;
    typedef ptrdiff_t  difference_type;
    typedef T*         pointer;
    typedef T&         reference;
};

//对常量指针类型的特化
template < class T>
struct IteratorTraits<const T*>
{
    typedef RandomAccessIterator_tag iterator_category; //指针类型是可以随机访问的
    typedef T          value_type;
    typedef ptrdiff_t  difference_type;
    typedef const T*         pointer;
    typedef const T&         reference;
};

//双向迭代器(数组类型)
template<class T, class Ref, class Ptr>
struct ArrayIterator
{
    typedef ArrayIterator<T, T&, T*>   iterator;
    typedef ArrayIterator<T, const T&, const T*> const_iterator;
    typedef ArrayIterator<T, Ref, Ptr>   self;

    typedef RandomAccessIterator_tag  iterator_category; //迭代器类型
    typedef T   value_type; //值类型
    typedef Ptr pointer;    //指针类型
    typedef Ref  reference; //引用类型
    typedef ptrdiff_t difference_type;

    T*  space;   //地址空间的起始位置
    T*  cursor;  //当前节点指针
    int length;

    ArrayIterator(T* x, int len = 0) : space(x),cursor(x),length(len){}
    ArrayIterator(const iterator& x) : space(x.space), cursor(x.cursor),length(x.length){}

    //重载==和!=操作符
    bool operator ==(const self& x) const
    {
        return cursor == x.cursor;
    }

    bool operator !=(const self& x) const
    {
        return cursor != x.cursor;
    }

    //重载*和->操作符
    reference operator*() const
    {
        return (*cursor);
    }

    pointer operator->() const
    {
        return &(operator*());
    }

    //前置++
    self& operator++()
    {
        if(cursor != NULL){
            ++cursor;
            if(cursor >= (space + length)){
                cursor = NULL;
            }
        }

        return *this;
    }

    //后置++
    self operator++(int)
    {
        self tmp = *this;
        ++(*this);

        return tmp;
    }

    //前置--
    self& operator--()
    {
        --cursor;
        return *this;
    }

    //后置--
    self operator--(int)
    {
        self tmp = *this;
        --(*this);

        return tmp;
    }

    self& operator+(int n)
    {
        if(cursor != NULL){
            cursor += n;
            if(cursor <= (space + length)){
                cursor = NULL;
            }
        }
        return *this;
    }

    self& operator+=(int n)
    {
        *this = *this + n;
        return *this ;
    }

    self& operator-(int n)
    {
        if(cursor != NULL){
            cursor -= n;
            if(cursor < (space)){
                cursor = NULL;
            }
        }
        return *this;
    }

    self& operator-=(int n)
    {
        *this = *this - n;
        return *this ;
    }

    //省略了operator+和operator-操作符的重载
};

//前向迭代器(链表型)
template<class T, class Ref, class Ptr, class Node>
struct ForwardIterator
{
    typedef ForwardIterator<T, T&, T*, Node>   iterator;
    typedef ForwardIterator<T, const T&, const T*, Node> const_iterator;
    typedef ForwardIterator<T, Ref, Ptr, Node>   self;

    typedef ForwardIterator_tag  iterator_category; //迭代器类型
    typedef T   value_type; //值类型
    typedef Ptr pointer;    //指针类型
    typedef Ref  reference; //引用类型
    typedef ptrdiff_t difference_type;
    typedef Node*  node_type; //节点指针类型

    node_type  cursor;  //迭代器当前所指节点

    ForwardIterator(node_type x) : cursor(x){}
    ForwardIterator(const iterator& x) : cursor(x.cursor){}

    //重载==和!=操作符
    bool operator ==(const self& x) const
    {
        return cursor == x.cursor;
    }

    bool operator !=(const self& x) const
    {
        return cursor != x.cursor;
    }

    //重载*和->操作符
    reference operator*() const
    {
        return (*cursor).value;
    }

    pointer operator->() const
    {
        return &(operator*());
    }

    //前置++
    self& operator++()
    {
        cursor = (node_type)(cursor->next);
        return *this;
    }

    //后置++
    self operator++(int)
    {
        self tmp = *this;
        ++(*this);

        return tmp;
    }

    self& operator+(int n)
    {
        for(int i=0; i<n; i++)
            if(cursor != NULL)
                cursor = (node_type)(cursor->next);
        return *this;
    }

    self& operator+=(int n)
    {
        *this = *this + n;
        return *this ;
    }

};

//双向迭代器(链表型)
template<class T, class Ref, class Ptr, class Node>
struct ListIterator
{
    typedef ListIterator<T, T&, T*, Node>   iterator;
    typedef ListIterator<T, const T&, const T*, Node> const_iterator;
    typedef ListIterator<T, Ref, Ptr, Node>   self;

    typedef BidirectionalIterator_tag  iterator_category; //迭代器类型
    typedef T   value_type; //值类型
    typedef Ptr pointer;    //指针类型
    typedef Ref  reference; //引用类型
    typedef ptrdiff_t difference_type;
    typedef Node*  node_type; //节点指针类型

    node_type  cursor;  //迭代器当前所指节点

    ListIterator(node_type x) : cursor(x){}
    ListIterator(const iterator& x) : cursor(x.cursor){}

    //重载==和!=操作符
    bool operator ==(const self& x) const
    {
        return cursor == x.cursor;
    }

    bool operator !=(const self& x) const
    {
        return cursor != x.cursor;
    }

    //重载*和->操作符
    reference operator*() const
    {
        return (*cursor).value;
    }

    pointer operator->() const
    {
        return &(operator*());
    }

    //前置++
    self& operator++()
    {
        cursor = (node_type)(cursor->next);
        return *this;
    }

    //后置++
    self operator++(int)
    {
        self tmp = *this;
        ++(*this);

        return tmp;
    }

    //前置--
    self& operator--()
    {
        cursor = (node_type)(cursor->prev);
        return *this;
    }

    //后置--
    self operator--(int)
    {
        self tmp = *this;
        --(*this);

        return tmp;
    }

    self& operator+(int n)
    {
        for(int i=0; i<n; i++)
            if(cursor != NULL)
                cursor = (node_type)(cursor->next);
        return *this;
    }

    self& operator+=(int n)
    {
        *this = *this + n;
        return *this ;
    }

    self& operator-(int n)
    {
        for(int i=0; i<n; i++)
            if(cursor != NULL)
                cursor = (node_type)(cursor->prev);
        return *this;
    }

    self& operator-=(int n)
    {
        *this = *this - n;
        return *this ;
    }
};

}

#endif // _ITERATOR_H_

//LinkList.h

#ifndef _LINKLIST_H_
#define _LINKLIST_H_

#include "list.h"
#include "Exception.h"
#include "Iterator.h"

namespace DTLib
{

template <typename T>
class LinkList : public List<T>
{
protected:
    //结点类型(内部类)
    struct Node : public Object
    {
        T value;    //数据域
        Node* next; //指针域s
    };

    //由于m_header在定义时会调用T的构造函数。如果T的设计者在构造函数中抛
    //出异常,当LinkList<T> list时会产生异常。这时调用者可能会怀疑是
    //LinkList设计出了问题,而不会认为是T的问题,因为他根本就没有手工定义
    //T的对象(如:T t),为了防止这种现象的出现,可“借尸还魂”,防止在定义
    //m_header时调用T的构造函数。
    //mutable Node m_header;  //头结点

    //“借尸还魂”:定义一个与Node内存模型完全一样的结构体

    mutable struct : public Object{
        char reserved[sizeof(T)];
        Node* next;
    } m_header;
    int m_length;   //链表长度

    //获取指定下标的元素
    Node* position(int index) const   //O(n)
    {
        Node* ret = (Node*)&m_header; //由于const对象不能修改成员变量的值
                               //对m_header取地址就可能会修改m_header
                               //的值,可将m_header声明为mutable

        for(int pos=0; pos<index; ++pos){
            ret = ret->next;
        }

        return ret; //注意要查找的元素地址保存在该节点的next指针域中
    }

    //封装节点创建和销毁函数,以便子类可以重载这个函数。
    virtual Node* createNode()
    {
        return new Node();
    }

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

public:
    LinkList()
    {
        m_header.next = NULL;
        m_length = 0;

    }

    bool insert(const T &elem) //O(n)
    {
        return insert(m_length, elem);
    }

    bool insert(int index, const T& elem)  //O(n)
    {
        bool ret = ((0 <= index) && (index <= m_length));

        if (ret){
            Node* node = createNode();//new Node();

            if(node != NULL){
                Node* current = position(index);

                node->value = elem;
                node->next = current->next;
                current->next = node;

                ++m_length;
            }else{
                THROW_EXCEPTION(NotEnoughMemoryException, "Not enougth memory to insert new element ...");
            }
        }

        return ret;
    }

    bool remove(int index)  //O(n)
    {
        bool ret = ((0 <= index) && (index < m_length));

        if(ret){
            Node* current = position(index); //要删除的元素地址保存在curr->next中

            Node* toDel = current->next;

            current->next = toDel->next;

            --m_length;

            destroyNode(toDel); //delete toDel;如果Node析构中抛异常时会出现异常不安全行为
                                //必须保证其之后的--m_length移动该句之前,以保证异常安全。

            //--m_length;
        }

        return ret;
    }

    virtual bool set(int index, const T& elem) //O(n)
    {
        bool ret = (0 <= index) && (index < m_length);

        if(ret){
            Node* current = position(index);

            (current->next)->value = elem;
        }

        return ret;
    }

    virtual T get(int index) const  //O(n)
    {
        T ret;
        if(get(index, ret)){
            return ret;
        }else{
            THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid paramter index to get element ...");
        }
    }

    bool get(int index, T& elem) const  //O(n)
    {
        bool ret = (0 <= index) && (index < m_length);

        if(ret){
            Node* current = position(index);

            elem = (current->next)->value;
        }

        return ret;
    }

    //反转链表
    void reverse()   //O(n)
    {
        Node* curr = m_header.next; //从第1个节点开始
        Node* prev = NULL;//当前节点的上一个节点

        while(curr != NULL){
            Node* nxt = curr->next; //保存当前节点的下一个节点

            curr->next = prev; //开始反转:指向先前一个节点

            prev = curr;       //prev前进
            curr = nxt;        //curr前进
        }

        m_header.next = prev;
    }

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

        while(node){
            if(node->value == elem){
                ret = i;
                break;
            }

            node = node->next;
            ++i;
        }

        return ret;
    }

    int length() const  //O(1)
    {
        return m_length;
    }

    void clear()  //O(n)
    {
        while(m_header.next){
            Node* toDel = m_header.next;

            m_header.next = toDel->next;
            --m_length;

            destroyNode(toDel); //delete toDel;Node析构中如果抛异常,会出现异常不安全。
        }
    }

    ~LinkList()
    {
        clear();
    }

public:
    typedef ForwardIterator<T, T&, T*, Node>   iterator;
    typedef ForwardIterator<T, const T&, const T*, Node> const_iterator;

    iterator begin()
    {
        //调用Iterator(Link_type)构造函数
        return (Node*)(m_header.next);
    }

    virtual iterator end()
    {
        return  NULL;
    }

    const_iterator begin() const
    {
        //调用Iterator(Link_type)构造函数
        return (Node*)(m_header.next);
    }

    virtual const iterator end() const
    {
        return  NULL;
    }

    virtual iterator erase(iterator position)
    {
        iterator ret = position.cursor->next;

        Node* toDel = position.cursor;
        if(toDel != NULL){
            Node* prev = (Node*)&this->m_header;
            for(int i=0; i<this->m_length; i++){
                if (prev->next == position.cursor){
                    prev->next = position.cursor->next;
                    --m_length;

                    if(m_length == 0)
                        m_header.next = NULL;

                    destroyNode(toDel);
                    break;
                }
                prev = prev->next;
            }
        }

        return ret;
    }

};

}

#endif // _LINKLIST_H_

//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 makeCircle() const
    {
        if(this->m_header.next)
            last()->next = this->m_header.next;
    }

    int mod(int value) const
    {
        return (this->m_length == 0) ? 0 : (value % this->m_length);
    }
public:
    bool insert(int index, const T& elem)
    {
        bool ret = true;

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

        ret = LinkList<T>::insert(index, elem);

        //插入0位置时,要特殊处理
        if(ret && (index == 0)){
            makeCircle(); //首尾相连
        }

        return ret;
    }

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

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

        index = mod(index);

        //删除0位置时
        if(index == 0){
            Node* toDel = this->m_header.next;

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

                if(this->m_length > 0){
                    makeCircle();
                }else{
                    this->m_header.next = NULL;
                    this->m_length = 0;
                }

                this->destroyNode(toDel);

            }else{
                ret = false;
            }
        }else{  //删除其他位置(非0位置)的结点
            ret = LinkList<T>::remove(index);
        }

        return ret;
    }

    bool set(int index, const T& elem)
    {
        return LinkList<T>::set(mod(index), elem);
    }

    T get(int index) const
    {
        return LinkList<T>::get(mod(index));
    }

    bool get(int index, const T& elem) const
    {
        return LinkList<T>::get(mod(index), elem);
    }

    int find(const T& elem) const
    {
        int ret = -1;
        Node* slider = this->m_header.next;

        for(int i=0; i<this->m_length; i++){
            if(slider->value == elem){
                ret = i;
                break;
            }

            slider = slider->next;
        }

        return ret;
    }

    void clear()
    {
        while(this->m_length > 1){
            //remove(1)而不remove(0)是因为避开删除首结点
            //而导致效率低下的问题。
            remove(1);
        }

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

            this->destroyNode(toDel);
        }
    }

    ~CircleList()
    {
        clear();
    }
public:
    typedef ForwardIterator<T, T&, T*, Node>   iterator;
    //typedef ForwardIterator<T, const T&, const T*, Node> const_iterator;
    virtual iterator end()
    {
        return this->m_header.next;
    }

    virtual const iterator end() const
    {
        return  this->m_header.next;
    }

    iterator erase(iterator position)
    {
        iterator ret = position.cursor->next;
        Node* toDel = position.cursor;

        if(position == this->begin()){
            if(toDel != NULL){
                this->m_header.next = (this->m_length<=1) ? NULL: toDel->next;
                --this->m_length;
                makeCircle();
                this->destroyNode(toDel);
            }
        }else{
            return LinkList<T>::erase(position);
        }

        return ret;
    }
};

}

#endif // _CIRCLELIST_H_

3. 约瑟夫环问题

(1)小故事

   在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus和他的朋友并不想遵从。那么,一开始要站在什么地方才能避免被处决?

技术分享

(2)约瑟夫环

  己知n个人(以编号0,1,2,3,…,n-1分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。

【编程实验】约瑟夫问题

//main.cpp

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

using namespace std;
using namespace DTLib;

//n个人,从s开始位置,报数到m的人出列。
void josephus(int n, int s, int m)
{
    CircleList<int> cl;

    //给n个人编号
    for(int i=1; i<=n; i++)
    {
        cl.insert(i);
    }

    CircleList<int>::iterator iter = cl.begin();
    iter += (s-1);//移到开始位置

    int i = 0;
    while(cl.length()>0)
    {
        iter += (m-1); //报到m的人出列
        cout <<"(" << ++i << ")" << *iter << "  ";
        if(i % 7 == 0)
            cout << endl;

        iter = cl.erase(iter);
    }
}

int main()
{
    josephus(41,1,3);

    return 0;
}
/*输出结果
(1)3   (2)6   (3)9   (4)12   (5)15   (6)18   (7)21
(8)24  (9)27  (10)30 (11)33  (12)36  (13)39  (14)1
(15)5  (16)10 (17)14 (18)19  (19)23  (20)28  (21)32
(22)37 (23)41 (24)7  (25)13  (26)20  (27)26  (28)34
(29)40 (30)8  (31)17 (32)29  (33)38  (34)11  (35)25
(36)2  (37)22 (38)4  (39)35  (40)16  (41)31
*/

4. 小结

(1)循环链表是一种特殊的单链表

(2)尾结点的指针域保存了首结点的地址

(3)特殊处理首元素的插入操作和删除操作

(4)重新实现清空操作和遍历操作

以上是关于第29课 循环链表的实现的主要内容,如果未能解决你的问题,请参考以下文章

单向循环链表

《链表》之带头双向循环链表

C语言实现双向非循环链表的逆序打印

C语言实现双向非循环链表的清空

C语言实现双向非循环链表的节点插入

静态链表循环链表双向链表(C代码实现)