zoukankan      html  css  js  c++  java
  • 双向循环链表

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

    双向循环链表没有头尾哨兵节点,因此在插入/删除链表时必须考虑特殊情况:往空表中插入第一个元素和删除表中最后一个元素,另外还需要注意的是,如果插入/删除的是表中的第一个元素,将会改变起始指针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;
    }
  • 相关阅读:
    查看程序设计语言排行榜的网站
    转:Android开发实践:用脚本编译Android工程
    ant 自动构建血泪史
    Android ant自动打包 crunch 报错
    android strings.xml 报 is not translated in af,
    HDU 5319
    hdu4405--Aeroplane chess(概率dp第七弹:飞行棋游戏--2012年网络赛)
    Linux 截图
    西工大10级保研机试 柱状图
    Codeforces Round #256 (Div. 2) B. Suffix Structures(模拟)
  • 原文地址:https://www.cnblogs.com/LC32/p/13452671.html
Copyright © 2011-2022 走看看