zoukankan      html  css  js  c++  java
  • C++泛化单链表

    泛型单链表

    单链表将每个数据分为节点,每个节点存储数据和指向下一个节点的指针。这样数据就不用在内存中使用连续的存储空间,有更大的灵活性。

    这里将单链表分为节点类(Node)和链表类(singleLinkedList),由于链表类需要访问到Node类的数据,因此将Node类的数据声明为public,也可以将链表类声明为节点类的友元类。

    抽向数据类型(ADT) :(linearList.h)

    /*************************************************************************
    > File Name       : linearList.h
    > Author          : Harold
    > Mail            : 2106562095@qq.com
    > Github          : www.github.com/Haroldcc
    > Created Time    : 2020年02月26日  11时02分58秒
    ************************************************************************/
    
    /***** 线性表的抽象定义 *****/
    
    #ifndef LINEARLIST_H
    #define LINEARLIST_H
    
    #include <iostream>
    
    template <typename T>
    class linearList
    {
    public:
        virtual ~linearList() {}
        virtual bool isEmpty() const = 0;                         //是否为空
        virtual int size() const = 0;                             // 元素个数
        virtual T &getElement(int index) const = 0;               // 根据索引获取元素
        virtual void setElement(int index, const T &element) = 0; // 根据索引更改元素值
        virtual int indexOf(const T &element) const = 0;          //指定元素第一次出现的索引
        virtual void removeByIndex(int index) = 0;                //根据索引删除元素并返回
        virtual void removeByElement(const T &element) = 0;       // 删除指定元素
        virtual void add(const T &element) = 0;                   // 在尾部插入元素
        virtual void add(int index, const T &element) = 0;        // 在指定索引处插入元素
        virtual void output(std::ostream &out) const = 0;         // 插入输出流out
    };
    
    #endif
    

    异常类(myException.h)

    /*************************************************************************
    > File Name       : myExceptions.h
    > Author          : Harold
    > Mail            : 2106562095@qq.com
    > Github          : www.github.com/Haroldcc
    > Created Time    : 2020年02月26日  14时32分01秒
    ************************************************************************/
    
    /***** 自定义的异常 *****/
    #ifndef MYEXCEPTIONS_H
    #define MYEXCEPTUONS_H
    
    #include <iostream>
    #include <string>
    
    // 非法参数
    class illegalParameterValue
    {
    private:
        std::string message;
    
    public:
        illegalParameterValue(std::string theMessage = "参数值非法!") : message(theMessage) {}
        void outputMessage() { std::cout << message << std::endl; }
    };
    
    // 非法输入
    class illegalInputData
    {
    private:
        std::string message;
    
    public:
        illegalInputData(std::string theMessage = "非法数据输入!")
        {
            message = theMessage;
        }
    
        void outputMessage() { std::cout << message << std::endl; }
    };
    
    // 非法索引
    class illegalIndex
    {
    private:
        std::string message;
    
    public:
        illegalIndex(std::string theMessage = "非法索引!") : message(theMessage) {}
        void outputMessage() { std::cout << message << std::endl; }
    };
    #endif
    

    单链表头文件(singleLinkedList.h)

    /*************************************************************************
    > File Name       : singleLinkedList.h
    > Author          : Harold
    > Mail            : 2106562095@qq.com
    > Github          : www.github.com/Haroldcc
    > Created Time    : 2020年02月27日  10时12分02秒
    ************************************************************************/
    
    /***** 单链表 *****/
    
    #ifndef SINGLELINKEDLIST_H
    #define SINGLELINKEDLIST_H
    
    #include "linearList.h"   // ADT
    #include "myExceptions.h" // 异常类
    #include <sstream>        // for ostringstream
    
    /*** 链表节点类 ***/
    template <typename T>
    class Node
    {
    public:
        T element;
        Node<T> *next;
    
        Node(){};
        Node(const T &element) { this->element = element; }
        Node(const T &element, Node<T> *next)
        {
            this->element = element;
            this->next = next;
        }
    };
    
    /*** 单链表类 ***/
    template <typename T>
    class singleLinkedList : public linearList<T>
    {
    private:
        void checkIndex(int index) const; // 索引异常检测
    
        Node<T> *firstNode; // 链表头节点指针
        int listSize;       // 链表的元素个数
    
    public:
        /* 构造函数 */
        singleLinkedList(int initialCapacity = 10);
        singleLinkedList(const singleLinkedList<T> &);
        ~singleLinkedList();
    
        /* ADT */
        bool isEmpty() const { return this->listSize == 0; }
        int size() const { return this->listSize; }
        T &getElement(int index) const;
        void setElement(int index, const T &element);
        int indexOf(const T &element) const;
        void removeByIndex(int index);
        void removeByElement(const T &element);
        void add(const T &element);
        void add(int index, const T &element);
        void output(std::ostream &out) const;
    };
    
    // 默认构造
    template <typename T>
    singleLinkedList<T>::singleLinkedList(int initialCapacity)
    {
        if (initialCapacity < 1)
        {
            std::ostringstream s;
            s << "初始化容量 = " << initialCapacity << "必须 > 0";
            throw illegalParameterValue(s.str());
        }
        this->firstNode = nullptr;
        this->listSize = 0;
    }
    
    // 拷贝构造
    template <typename T>
    singleLinkedList<T>::singleLinkedList(const singleLinkedList<T> &list)
    {
        this->listSize = list.listSize;
    
        // list 为空
        if (this->listSize == 0)
        {
            this->firstNode = nullptr;
            return;
        }
    
        // list 不为空
        Node<T> *sourceNode = list.firstNode;               // 要复制链表list的节点
        this->firstNode = new Node<T>(sourceNode->element); // 要复制链表list的首元素
        sourceNode = sourceNode->next;
        Node<T> *targetNode = this->firstNode; // 当前链表 *this 的最后一个节点
        while (sourceNode != nullptr)
        { // 复制剩下的节点
            targetNode->next = new Node<T>(sourceNode->element);
            targetNode = targetNode->next;
            sourceNode = sourceNode->next;
        }
        targetNode->next = nullptr; // 尾部置为空
    }
    
    // 析构函数
    template <typename T>
    singleLinkedList<T>::~singleLinkedList()
    {
        while (this->firstNode != nullptr)
        {
            Node<T> *nextNode = this->firstNode->next;
            delete this->firstNode;
            firstNode = nextNode;
        }
    }
    
    template <typename T>
    void singleLinkedList<T>::checkIndex(int index) const
    {
        if (index < 0 || index >= this->listSize)
        {
            std::ostringstream s;
            s << "index = " << index << "size = " << this->listSize;
            throw illegalIndex(s.str());
        }
    }
    
    // 根据索引获取对应的节点,如未找到,抛异常
    template <typename T>
    T &singleLinkedList<T>::getElement(int index) const
    {
        checkIndex(index);
    
        Node<T> *currentNode = this->firstNode;
        for (int i = 0; i < index; i++)
            currentNode = currentNode->next;
    
        return currentNode->element;
    }
    
    // 根据索引设置元素值
    template <typename T>
    void singleLinkedList<T>::setElement(int index, const T &element)
    {
        checkIndex(index);
    
        Node<T> *currentNode = this->firstNode;
        for (int i = 0; i < index; i++)
            currentNode = currentNode->next;
    
        currentNode->element = element;
    }
    
    // 返回给定元素的索引值,若未找到返回 -1
    template <typename T>
    int singleLinkedList<T>::indexOf(const T &element) const
    {
        Node<T> *currentNode = this->firstNode;
        int index = 0;
        while (currentNode != nullptr && currentNode->element != element)
        {
            currentNode = currentNode->next;
            index++;
        }
    
        if (currentNode == nullptr)
        {
            return -1;
        }
        else
        {
            return index;
        }
    }
    
    // 删除指定索引处的元素值,未找到元素抛异常
    template <typename T>
    void singleLinkedList<T>::removeByIndex(int index)
    {
        checkIndex(index);
    
        Node<T> *deleteNode;
        if (index == 0)
        { // 删除链表中的第一个元素
            deleteNode = this->firstNode;
            this->firstNode = this->firstNode->next;
        }
        else
        {
            Node<T> *p = this->firstNode;
            for (int i = 0; i < index - 1; i++)
                p = p->next;
    
            deleteNode = p->next;
            p->next = p->next->next;
        }
        this->listSize--;
        delete deleteNode;
    }
    
    template <typename T>
    void singleLinkedList<T>::removeByElement(const T &element)
    {
        removeByIndex(indexOf(element));
    }
    
    template <typename T>
    void singleLinkedList<T>::add(const T &element)
    {
        add(this->listSize, element);
    }
    
    // 在指定索引处添加元素
    template <typename T>
    void singleLinkedList<T>::add(int index, const T &element)
    {
        if (index < 0 || index > this->listSize)
        {
            std::ostringstream s;
            s << "index = " << index << "size = " << this->listSize;
            throw illegalIndex(s.str());
        }
    
        if (index == 0)
        { // 头部插入元素
            this->firstNode = new Node<T>(element, this->firstNode);
        }
        else
        {
            Node<T> *p = this->firstNode;
            for (int i = 0; i < index - 1; i++)
            {
                p = p->next;
            }
            p->next = new Node<T>(element, p->next);
        }
        this->listSize++;
    }
    
    template <typename T>
    void singleLinkedList<T>::output(std::ostream &out) const
    {
        for (Node<T> *currentNode = this->firstNode;
             currentNode != nullptr;
             currentNode = currentNode = currentNode->next)
            out << currentNode->element << " ";
    }
    
    // 重载 << 运算符
    template <typename T>
    std::ostream &operator<<(std::ostream &out, const singleLinkedList<T> &list)
    {
        list.output(out);
        return out;
    }
    
    #endif
    

    测试

    #include "linearList.h"
    #include "singleLinkedList.h"
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        // test constructor
       linearList<double> *x = new singleLinkedList<double>;
       singleLinkedList<int> y, z;
    
       // test size
       cout << "Initial size of x, y, and z = "
            << x->size() << ", "
            << y.size() << ", "
            << z.size() << endl;
    
       // test isEmpty
       if (x->isEmpty()) cout << "x is isEmpty" << endl;
       else cout << "x is not isEmpty" << endl;
       if (y.isEmpty()) cout << "y is isEmpty" << endl;
       else cout << "y is not isEmpty" << endl;
    
       // test add
       y.add(0, 2);
       y.add(1, 6);
       y.add(0, 1);
       y.add(2, 4);
       y.add(3, 5);
       y.add(2, 3);
       cout << "Inserted 6 integers, list y should be 1 2 3 4 5 6" << endl;
       cout << "Size of y = " << y.size() << endl;
       if (y.isEmpty()) cout << "y is isEmpty" << endl;
       else cout << "y is not isEmpty" << endl;
       y.output(cout);
       cout << endl << "Testing overloaded <<" << endl;
       cout << y << endl;
    
       // test indexOf
       int index = y.indexOf(4);
       if (index < 0) cout << "4 not found" << endl;
       else cout << "The index of 4 is " << index << endl;
    
       index = y.indexOf(7);
       if (index < 0) cout << "7 not found" << endl;
       else cout << "The index of 7 is " << index << endl;
    
       // test getElement
       cout << "Element with index 0 is " << y.getElement(0) << endl;
       cout << "Element with index 3 is " << y.getElement(3) << endl;
    
       // test removeByIndex
       y.removeByIndex(1);
       cout << "Element 1 erased" << endl;
       cout << "The list is "  << y << endl;
       y.removeByIndex(2);
       cout << "Element 2 erased" << endl;
       cout << "The list is "  << y << endl;
       y.removeByIndex(0);
       cout << "Element 0 erased" << endl;
       cout << "The list is "  << y << endl;
    
       cout << "Size of y = " << y.size() << endl;
       if (y.isEmpty()) cout << "y is isEmpty" << endl;
       else cout << "y is not isEmpty" << endl;
    
       try {y.add(-3, 0);}
       catch (illegalIndex e)
       {
          cout << "Illegal index exception" << endl;
          cout << "Insert index must be between 0 and list size" << endl;
          e.outputMessage();
       }
    
       // test copy constructor
       singleLinkedList<int> w(y);
       y.removeByIndex(0);
       y.removeByIndex(0);
       cout << "w should be old y, new y has first 2 elements removed" << endl;
       cout << "w is " << w << endl;
       cout << "y is " << y << endl;
       
       // a few more inserts, just for fun
       y.add(0,4);
       y.add(0,5);
       y.add(0,6);
       y.add(0,7);
       cout << "y is " << y << endl;
        
        return 0;
    }
    

    输出

    Initial size of x, y, and z = 0, 0, 0
    x is isEmpty
    y is isEmpty
    Inserted 6 integers, list y should be 1 2 3 4 5 6
    Size of y = 6
    y is not isEmpty
    1 2 3 4 5 6
    Testing overloaded <<
    1 2 3 4 5 6
    The index of 4 is 3
    7 not found
    Element with index 0 is 1
    Element with index 3 is 4
    Element 1 erased
    The list is 1 3 4 5 6
    Element 2 erased
    The list is 1 3 5 6
    Element 0 erased
    The list is 3 5 6
    Size of y = 3
    y is not isEmpty
    Illegal index exception
    Insert index must be between 0 and list size
    index = -3size = 3
    w should be old y, new y has first 2 elements removed
    w is 3 5 6
    y is 6
    y is 7 6 5 4 6
    
  • 相关阅读:
    c语言--第零次作业
    Beta 冲刺(3/7)
    Beta 冲刺(2/7)
    福大软工 · 第十次作业
    Beta 冲刺(1/7)
    BETA 版冲刺前准备(团队)
    Alpha 事后诸葛亮(团队)
    Alpha冲刺(10/10)
    Alpha 冲刺 (9/10)
    Alpha 冲刺 (8/10)
  • 原文地址:https://www.cnblogs.com/HaroldC/p/12372218.html
Copyright © 2011-2022 走看看