双向循环链表

双向循环链表类似于双链表,但是在实现上有不同:

双向循环链表没有头尾哨兵节点,因此在插入/删除链表时必须考虑特殊情况:往空表中插入第一个元素和删除表中最后一个元素,另外还需要注意的是,如果插入/删除的是表中的第一个元素,将会改变起始指针begin的位置,造成起始指针的左移或者右移,这也是一种特殊情况。

另外,由于循环链表没有尽头,所以遍历链表时必须已知链表长度,这就要求循环链表类必须要有一个成员变量currentLength记录链表长度,这一点在单链表/双链表中并不是必须的。

最后,在获取第i个节点的地址的move函数中,可以稍作改进,当i小于或等于链表长度的一半是按顺序遍历,当i大于长的的一半是逆序遍历,这样move函数的平均查找时间从n/2降低为n/4,n为链表长度。

#include <iostream>
using namespace std;

// 线性表:顺序表和链表共同的抽象类
template<typename elemType>
class list{
public:
    virtual void clear() = 0;                            // 删除线性表中的所有数据元素
    virtual int length() const = 0;                      // 求线性表的长度
    virtual void insert(int i, const elemType & x) = 0;  // 在第i个位置插入一个元素
    virtual void remove(int i) = 0;                      // 删除第i个位置的元素
    virtual int search(const elemType & x) const = 0;    // 搜索某个元素x在线性表中是否出现
    virtual elemType visit(int i) const = 0;             // 返回线性表中第i个数据元素的值
    virtual void traverse(bool reverse) const = 0;       // 按序访问线性表的每一数据元素
    virtual ~list(){};
};


// 循环双链表
template<typename elemType>
class dcLinkList:public list<elemType>{
public:
    struct node{
        elemType data;
        node *prev, *next;

        node(const elemType & x, node* p = NULL, node* n = NULL)
            {data = x; prev = p; next = n;}
        node():prev(NULL), next(NULL){}
        ~node(){}
    };

    node* begin;
    int currentLength;

    node* move(int i) const;

    class NoSuchNodeError{};

public:
    dcLinkList():begin(NULL), currentLength(0){}
    ~dcLinkList(){clear();}

    void clear();
    int length() const{return currentLength;}
    void insert(int i, const elemType & x);
    void remove(int i);
    int search(const elemType & x) const;
    elemType visit(int i) const;
    void traverse(bool reverse = false) const;
};


template<typename elemType>
void dcLinkList<elemType>::clear(){
    node* p = begin;
    node* q;

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


template<typename elemType>
typename dcLinkList<elemType>::node* dcLinkList<elemType>::move(int i) const{
    node* p = begin;

    if(2 * i > currentLength)
        for(int j = 0; j < currentLength - i; ++j)
            p = p->prev;
    else
        for(int j = 0; j < i; ++j)
            p = p->next;
    return p;
}


template<typename elemType>
void dcLinkList<elemType>::remove(int i){
    if(i < 0 || i >= currentLength) throw NoSuchNodeError();

    if(currentLength == 1){
        delete begin;
        begin = NULL;
    }
    else{
        node* p = move(i);

        if(i == 0) begin = begin->next;
        p->next->prev = p->prev;
        p->prev->next = p->next;
        delete p;
    }
    --currentLength;
}


template<typename elemType>
void dcLinkList<elemType>::insert(int i, const elemType & x){
    if(i < 0 || i > currentLength) throw NoSuchNodeError();

    if(currentLength == 0){
        node* p = new node(x);

        p->next = p;
        p->prev = p;
        begin = p;
    }
    else{
        node* pos = move(i);
        node* p = new node(x, pos->prev, pos);

        p->prev->next = p;
        p->next->prev = p;
        if(i == 0) begin = p;
    }
    ++currentLength;
}


template<typename elemType>
void dcLinkList<elemType>::traverse(bool reverse) const{
    if(reverse){
        node* p = begin->prev;
        for(int i = 0; i < currentLength; ++i){
            cout << p->data << " ";
            p = p->prev;
        }
    }
    else{
        node* p = begin;
        for(int i = 0; i < currentLength; ++i){
            cout << p->data << " ";
            p = p->next;
        }
    }
    cout << endl;
}


template<typename elemType>
elemType dcLinkList<elemType>::visit(int i) const{
    if(i < 0 || i >= currentLength) throw NoSuchNodeError();

    return move(i)->data;
}


template<typename elemType>
int dcLinkList<elemType>::search(const elemType & x) const{
    node* p = begin;
    int i = 0;

    for(; i < currentLength && p->data != x; ++i) p = p->next;
    if(i == currentLength) return -1; else return i;
}
原文地址:https://www.cnblogs.com/LC32/p/13452671.html