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
posted @ 2020-02-27 15:02  HaroldC  阅读(189)  评论(0编辑  收藏  举报