【C++·数据结构】简单的实现C++链表数据结构,泛型(包含迭代器的实现)

宇宙第一小正太\ (o)/~萌量爆表求带飞=≡Σ((( つo)つ~ dalao们点个关注呗~


大二上网课,老师要求写一个链表数据结构。
小熊虽然很不情愿,但是还是硬着头皮干完啦!!!

本数据链表的核心功能:

void Push_Back(T Value);               //在链表的末尾插入一个元素
    void Pop_Back() { Erase(Length - 1); } //弹出末尾最后一个元素
    void Insert(int Index, T Value);       //在Index之后,添加一个元素
    void Erase(int Index);                 //删除在链表位于Index的元素
    void Clear();                          //清空链表
    int GetLength();                       //获得链表的长度
    T &operator[](int Index);              //或取变量或者设置变量

另外本链表还有一个功能是,实现了一个简单的迭代器:

typedef Node_Iterator iterator; //现在通过tyoedef,iterator就是一种类型

感觉自己又又又水了一次作业QAQ

链表结构设计:

实际上,就算本链表的Size=0,依旧存在两个永远不会被删除的头部标记数据元,和尾部标记数据元。
本链表的结构设计是:PowerBearList是一个链表。在PowerBearList的内部封装了cell数据元,我们通过PowerBearList来操作Cell数据元以此来修改链表的数据。
上文所说的头部标记数据元和尾部标记数据元正是:*cell_Front = new Cell(), *cell_Back = new Cell();位于第21行。
实际上,链表本生真的没有什么难的,很多老师喜欢把简单的问题搞得复杂化,小熊建议您,您只需要知道链表是个数据结构就可以啦,什么约瑟夫环的问题还是什么环的问题,那个属于算法,饭要一口一口吃,咱们先慢慢来。

核心代码完全降解:

定位链表index:

下标从0开始。

在本程序中,您将会看见很多如下这样的代码(在各种函数中它都是高调的出现):

    Cell *ptr = this->cell_Front->Next;
    for (int i = 0; i < Index; i++) {
        ptr = ptr->Next;
    }

其中,第一行的*ptr是一个指针,它进行初始化就在第一行,首先定位到调用函数的对象this,然后再从this的头部标记的Next,找到了真正的第一个在列表中的对象。其中对应的是i=0,然后 ptr = ptr->Next则会自己往下运行查找下一个。

Insert插入cell函数:

哇塞
将这种链表的插入网上已经烂大街了,笔者就不逼逼叨叨了,下面直接贴出关键代码,关键代码并没有绕弯子,读者可以拿出纸和笔花几十秒跟着代码模拟一遍,然后就什么都懂啦。

Cell *leftL, *rightL;
    leftL = ptr;
    rightL = ptr->Next;
    Cell *Middle = new Cell();
    Middle->Value = Value;
    Middle->Pre = leftL;
    Middle->Next = rightL;
    leftL->Next = Middle;
    rightL->Pre = Middle;
    this->Length++;

迭代器的实现:

其实就是在PowerBearList里面又封装了一个Node_Iterator只不过在类里面封装的是private。然后我们又在PowerBearList的public中使用typedef Node_Iterator iterator;来将iterator变为了一种类型为Node_Iterator的类型。
具体实现在代码中已经给出了注释,在这里小熊不再多言。

下面直接贴出这看起来很长实际很简单的代码吧!

代码一览:

// 环境 LLVM Clang++ MacOS
// C++ 标准 C++11
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <vector>
using namespace std;

template <typename T> class PowerBearList {
  private:
    int Length;
    class Cell {
      public:
        T Value;
        Cell *Pre, *Next;
        Cell(T Value) { this->Value = Value; }
        // Cell(T Value) : Value(Value) {}
        // https://stackoverflow.com/questions/19576458/constructor-for-must-explicitly-initialize-the-reference-member
        Cell() : Value() {}
        //下面的则是对一些基本的运算符号进行重载
    } *cell_Front = new Cell(), *cell_Back = new Cell();
    //设置标志物,一个是链表头标记物,一个是链表尾的标记物,新增入的Cell会被夹在中间,这两个标记物是永久存在的
  public:
    PowerBearList();
    PowerBearList(T Value);
    void Push_Back(T Value);               //在链表的末尾插入一个元素
    void Pop_Back() { Erase(Length - 1); } //弹出末尾最后一个元素
    void Insert(int Index, T Value);       //在Index之后,添加一个元素
    void Erase(int Index);                 //删除在链表位于Index的元素
    void Clear();                          //清空链表
    int GetLength();                       //获得链表的长度
    T &operator[](int Index);              //或取变量或者设置变量

  private:
    class Node_Iterator { //迭代器的实现,引用文章如下
                          // https://www.cnblogs.com/wengle520/archive/2020/03/14/12492708.html
      private:
        Cell *ptr; //指向容器中的某个元素

      public:
        Node_Iterator(Cell *p = nullptr) : ptr(p) {}
        //对*进行重载,为了后面的*ite做准备,使用引用是为了方便*ite=1这样的修改
        T &operator*() const { return ptr->Value; }
        //对迭代器的++进行重载
        Node_Iterator &operator++() {
            ptr = ptr->Next;
            return *this;
        }
        Node_Iterator operator++(int) {
            Cell *tmp = ptr;
            // this 是指向Node_Iterator的常量指针,因此*this就是ta的对象,前置++已经被重载过
            ++(*this);
            return Node_Iterator(tmp);
        }
        bool operator==(const Node_Iterator &t) const { return t.ptr == this->ptr; }
        bool operator!=(const Node_Iterator &t) const { return t.ptr != this->ptr; }
    };

  public:
    typedef Node_Iterator iterator; //现在通过tyoedef,iterator就是一种类型
    iterator begin() const { return Node_Iterator(this->cell_Front->Next); }
    iterator end() const { return Node_Iterator(this->cell_Back); }
};
template <typename T> void PowerBearList<T>::Erase(int Index) {
    if (Index < 0 || Index > this->Length - 1 || this->Length == 0) {
        cout << "ERROR:删除元素失败,下标越界,或因为链表数据为空";
        exit(0);
    }
    Cell *ptr = this->cell_Front->Next;
    for (int i = 0; i < Index; i++) {
        ptr = ptr->Next;
    }
    Cell *leftL, *rightL, *middleL;
    leftL = ptr->Pre;
    rightL = ptr->Next;
    middleL = ptr;
    leftL->Next = rightL;
    rightL->Pre = leftL;
    delete[] middleL;
    this->Length--;
}

template <typename T> void PowerBearList<T>::Insert(int Index, T Value) {
    if (this->Length == 0 && Index == 0)
        Push_Back(Value);
    try {
        if (Index < 0 || Index > this->Length - 1) {
            throw "ERROR:访问下标越届,程序停止运行。";
        }
    } catch (const char *msg) {
        std::cout << msg << " "
                  << "实例地址定位:" << this << " "
                  << "使用的方法:void Insert(int Index, T Value);";
        exit(0);
    }
    Cell *ptr = this->cell_Front->Next;
    for (int i = 0; i < Index; i++) {
        ptr = ptr->Next;
    }
    Cell *leftL, *rightL;
    leftL = ptr;
    rightL = ptr->Next;
    Cell *Middle = new Cell();
    Middle->Value = Value;
    Middle->Pre = leftL;
    Middle->Next = rightL;
    leftL->Next = Middle;
    rightL->Pre = Middle;
    this->Length++;
}

template <typename T> PowerBearList<T>::PowerBearList() { this->Length = 0; }
template <typename T> PowerBearList<T>::PowerBearList(T Value) {
    this->Length = 0;
    this->Push_Back(Value);
}

template <typename T> T &PowerBearList<T>::operator[](int Index) {
    Cell *ptr = this->cell_Front->Next;
    try {
        if (Index < 0 || Index > this->Length - 1) {
            throw "ERROR:访问下标越届,程序停止运行。";
        }
        for (int i = 0; i < Index; i++) {
            ptr = ptr->Next;
        }
        return ptr->Value;
    } catch (const char *msg) {
        std::cout << msg << " "
                  << "实例地址定位:" << this << " "
                  << "使用的方法:T &operator[](int Index)";
        exit(0);
    }
}

template <typename T> void PowerBearList<T>::Clear() {
    if (this->Length == 0)
        return;
    Cell *ptr = this->cell_Front;
    //开始释放内存
    for (int i = 0; i < this->Length; i++) {
        ptr = ptr->Next;
        delete[] ptr;
    }
    this->Length = 0;
}

template <typename T> void PowerBearList<T>::Push_Back(T Value) {
    if (this->Length == 0) {
        Cell *a = new Cell();
        a->Value = Value;
        a->Pre = this->cell_Front;
        a->Next = this->cell_Back;
        cell_Front->Next = a;
        cell_Back->Pre = a;
        this->Length++;
    } else {
        Cell *a = new Cell();
        a->Value = Value;
        a->Next = cell_Back;
        a->Pre = cell_Back->Pre;
        cell_Back->Pre->Next = a;
        cell_Back->Pre = a;
        this->Length++;
    }
}

template <typename T> int PowerBearList<T>::GetLength() { return this->Length; }
struct A {
    int a, b;
    A(int A, int B) : a(A), b(B) {}
    A() {} //这里一定要存在一个无参数的构造函数,要不然会有问题。
};

int main() {
#define AllowDebug
#pragma region //宏定义的测试代码
#ifdef AllowDebug
    PowerBearList<int> Seq;
    Seq.Push_Back(1);
    Seq.Push_Back(2);
    Seq.Push_Back(3);
    for (auto ite = Seq.begin(); ite != Seq.end(); ite++) {
        cout << *ite << endl;
    }

    Seq.Pop_Back();

    cout << "----------------" << endl;
    for (auto ite = Seq.begin(); ite != Seq.end(); ite++) {
        cout << *ite << endl;
    }

    Seq.Insert(1, 4);

    cout << "----------------" << endl;
    for (auto ite = Seq.begin(); ite != Seq.end(); ite++) {
        cout << *ite << endl;
    }
#endif
#pragma endregion //折叠一下,要不然不美观。
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值