• 数据结构基础(11) --循环链表的设计与实现


    循环链表:最后一个结点的指针域的指针又指回第一个结点的链表;

        循环单链表与单链表的区别在于:表中最有一个节点的指针不再是NULL, 而改为指向头结点(因此要对我们原来的MyList稍作修改), 从而整个链表形成一个环.

        因此, 循环单链表的判空条件不再是头结点的指针是否为空, 而是他是否等于头结点;

        其实如果只是单纯的实现循环链表对单链表的性能提升是不明显的, 反而增加了代码上实现的复杂度, 但是如果与下一篇中的双向链表相结合的话, 在速度上的提升是十分惊人的, 因此这篇博客权当做是一个过渡吧, 为上一篇博客和下一篇博客的结合起着承上启下的作用.

     

        下面是MyList.h的完整代码与解析, 由于代码较多, 希望能够仔细阅读, 但其实下面的大部分代码都与前面类似只是对其中几处稍作修改, 遇到与单链表的不同之处, 我会与++符号作为注释指出:

    #ifndef MYLIST_H_INCLUDED
    #define MYLIST_H_INCLUDED
    
    #include <iostream>
    #include <stdexcept>
    using namespace std;
    
    //循环链表
    //前向声明
    template <typename Type>
    class MyList;
    template <typename Type>
    class ListIterator;
    
    //链表节点
    template <typename Type>
    class Node
    {
        //可以将MyList类作为Node的友元
        //同时也可以将Node类做成MyList的嵌套类, 嵌套在MyList中, 也可以完成该功能
        friend class MyList<Type>;
        friend class ListIterator<Type>;
    
        template <typename T>
        friend ostream &operator<<(ostream &os, const MyList<T> &list);
    private:
        //constructor说明:
        //next = NULL;    //因为这是一个新生成的节点, 因此下一个节点为空
        Node(const Type &dataValue):data(dataValue), next(NULL) {}
    
        Type data;  //数据域:节点数据
        Node *next; //指针域:下一个节点
    };
    
    //链表
    template <typename Type>
    class MyList
    {
        template <typename T>
        friend ostream &operator<<(ostream &os, const MyList<T> &list);
    
        friend class ListIterator<Type>;
    public:
        MyList();
        ~MyList();
    
        //将元素插入表头
        void insertFront(const Type &data);
        //将元素插入到位置index上(index从1开始)
        void insert(const Type &data, int index);
        //删除表中所有值为data的节点
        void remove(const Type &data);
        bool isEmpty() const;
    
    private:
        //指向第一个节点的指针
        Node<Type> *first;
    };
    
    template <typename Type>
    MyList<Type>::MyList()
    {
        //first指向一个空节点
        first = new Node<Type>(0);
    
        // ++ 这是一个关键点
        //first的下一个元素就指向first
        //此时, 代表链表是否已经到达结尾处的判断已经不再是(是否等于NULL)
        //而改为(是否等于first)
        //因为此时first代表链表的最后一个元素
        //同时,first又是第一个元素的前一个元素
        first -> next = first;
    }
    
    template <typename Type>
    MyList<Type>::~MyList()
    {
        Node<Type> *deleteNode = NULL;
        // ++ 保存链表尾元素
        Node<Type> *tmp = first;
    
        // ++ first首先指向第一个真实的元素
        first = first->next;
        //一路到达链表结尾
        while (first != tmp)
        {
            deleteNode = first;
            first = first -> next;
            delete deleteNode;
        }
        // ++ 释放到链表的空节点
        delete tmp;
    }
    
    //这一步与前一版链表相同
    template <typename Type>
    void MyList<Type>::insertFront(const Type &data)
    {
        Node<Type> *newNode = new Node<Type>(data);
        newNode -> next = first -> next;
        first -> next = newNode;
    }
    
    template <typename Type>
    void MyList<Type>::insert(const Type &data, int index)
    {
        //由于我们在表头添加了一个空节点
        //因此如果链表为空, 或者在链表为1的位置添加元素
        //其操作与在其他位置添加元素相同
    
        int count = 1;
        //此时searchNode肯定不为first
        Node<Type> *searchNode = first;
    
        //++ 注意:此处将NULL修改为first
        // 找到要插入的位置
        // 如果所给index过大(超过了链表的长度)
        // 则将该元素插入到链表表尾
        // 原因是 searchNode->next != first 这个条件已经不满足了
        while (count < index && searchNode->next != first)
        {
            ++ count;
            searchNode = searchNode->next;
        }
    
        // 插入链表
        Node<Type> *newNode = new Node<Type>(data);
        newNode->next = searchNode->next;
        searchNode->next = newNode;
    }
    
    template <typename Type>
    void MyList<Type>::remove(const Type &data)
    {
        if (isEmpty())
            return ;
    
        Node<Type> *previous = first;   //保存要删除节点的前一个节点
        for (Node<Type> *searchNode = first->next;
                //searchNode != NULL; // ++ 注意此处不再是判断是否为NULL
                searchNode != first;     // ++ 而是不能等于first, first代表链表的末尾
                searchNode = searchNode->next)
        {
            if (searchNode->data == data)
            {
                previous->next = searchNode->next;
                delete searchNode;
                //重新调整searchNode指针
                //继续遍历链表查看是否还有相等元素
    
                // ++ 注意
                //如果当前searchNode已经到达了最后一个节点
                //也就是searchNode->next已经等于first了, 则下面这条语句不能执行
                if (previous->next == first)
                    break;
    
                searchNode = previous->next;
            }
            previous = searchNode;
        }
    }
    //注意判空条件
    template <typename Type>
    bool MyList<Type>::isEmpty() const
    {
        return first->next == first;
    }
    
    //显示链表中的所有数据(测试用)
    template <typename Type>
    ostream &operator<<(ostream &os, const MyList<Type> &list)
    {
        for (Node<Type> *searchNode = list.first -> next;
                searchNode != list.first;   //++ 注意
                searchNode = searchNode -> next)
        {
            os << searchNode -> data;
            if (searchNode -> next != list.first) // ++ 注意(尚未达到链表的结尾)
                cout << " -> ";
        }
    
        return os;
    }
    
    //ListIterator 除了判空函数的判空条件之外, 没有任何改变
    template <typename Type>
    class ListIterator
    {
    public:
        ListIterator(const MyList<Type> &_list):
            list(_list),
            currentNode((_list.first)->next) {}
    
        //重载 *operator
        const Type &operator*() const throw (std::out_of_range);
        Type &operator*() throw (std::out_of_range);
    
        //重载 ->operator
        const Node<Type> *operator->() const throw (std::out_of_range);
        Node<Type> *operator->() throw (std::out_of_range);
    
        //重载 ++operator
        ListIterator &operator++() throw (std::out_of_range);
        //注意:此处返回的是值,而不是reference
        ListIterator operator++(int) throw (std::out_of_range);
    
        bool isEmpty() const;
    
    private:
        const MyList<Type> &list;
        Node<Type> *currentNode;
    };
    
    template <typename Type>
    bool ListIterator<Type>::isEmpty() const
    {
        // ++ 注意:判空条件改为list.first
        if (currentNode == list.first)
            return true;
        return false;
    }
    template <typename Type>
    const Type &ListIterator<Type>::operator*() const
    throw (std::out_of_range)
    {
        if (isEmpty())
            throw std::out_of_range("iterator is out of range");
        // 返回当前指针指向的内容
        return currentNode->data;
    }
    template <typename Type>
    Type &ListIterator<Type>::operator*()
    throw (std::out_of_range)
    {
        //首先为*this添加const属性,
        //以调用该函数的const版本,
        //然后再使用const_case,
        //将该函数调用所带有的const属性转除
        //operator->()的non-const版本与此类同
        return
            const_cast<Type &>(
                static_cast<const ListIterator<Type> &>(*this).operator*()
            );
    }
    
    template <typename Type>
    const Node<Type> *ListIterator<Type>::operator->() const
    throw (std::out_of_range)
    {
        if (isEmpty())
            throw std::out_of_range("iterator is out of range");
        //直接返回指针
        return currentNode;
    }
    
    template <typename Type>
    Node<Type> *ListIterator<Type>::operator->()
    throw (std::out_of_range)
    {
        // 见上
        return
            const_cast<Node<Type> *> (
                static_cast<const ListIterator<Type> >(*this).operator->()
            );
    }
    
    template <typename Type>
    ListIterator<Type> &ListIterator<Type>::operator++()
    throw (std::out_of_range)
    {
        if (isEmpty())
            throw std::out_of_range("iterator is out of range");
        //指针前移
        currentNode = currentNode->next;
        return *this;
    }
    template <typename Type>
    ListIterator<Type> ListIterator<Type>::operator++(int)
    throw (std::out_of_range)
    {
        ListIterator tmp(*this);
        ++ (*this); //调用前向++版本
    
        return tmp;
    }
    
    #endif // MYLIST_H_INCLUDED

    附-测试代码:

    int main()
    {
        MyList<int> iMyList;
        for (int i = 0; i < 10; ++i)    //1 2 3 4 5 6 7 8 9 10
            iMyList.insert(i+1, i+1);
    
        for (int i = 0; i < 5; ++i)     //40 30 20 10 0 1 2 3 4 5 6 7 8 9 10
            iMyList.insertFront(i*10);
    
        iMyList.insertFront(100);//100 40 30 20 10 0 1 2 3 4 5 6 7 8 9 10
        iMyList.remove(10);      //100 40 30 20 0 1 2 3 4 5 6 7 8 9
        iMyList.remove(8);       //100 40 30 20 0 1 2 3 4 5 6 7 9
    
        cout << "------------ MyList ------------" << endl;
        for (ListIterator<int> iter(iMyList);
                !(iter.isEmpty());
                ++ iter)
            cout << *iter << ' ';
        cout << endl;
        cout << "Test: 
    	" << iMyList << endl;
    
        return 0;
    }

  • 相关阅读:
    LG P4213【模板】杜教筛(Sum)
    JZOJ 3447.摘取作物
    JZOJ 3448.公路维护
    JZOJ 4496. 【GDSOI 2016】第一题 互补约数
    jmeter的参数化之函数助手的使用
    window10平台运行jenkins.war的插件安装失败的解决
    jmeter的断言之响应断言的使用
    在虚拟机里安装完mysql后,开启root远程登录权限
    Word Excel PPT 2016从新手到高手
    Oracle 如何停止正在后台执行的impdp/expdp 任务
  • 原文地址:https://www.cnblogs.com/itrena/p/5926995.html
Copyright © 2020-2023  润新知