c++封装模板单链表

基于C++ 模板类的模板链表(单链表)

首先定义节点类型

  • 具有一个data数据 next指针 以及一个像类一样的构造函数,用于方便的创建节点类型
template <class _Ty>
struct Node
{
_Ty data;
Node<_Ty>* next;
Node<_Ty>(const _Ty& data) :data(data)
{
next = nullptr;
}
};

创建链表类

  • 为方便操作创建两个指针,分别指向链表首元节点末尾节点

  • 并且记录链表节点的数量 方便操作

    private:
    Node<_T>* pFront; //指向头节点的指针
    Node<_T>* pEnd; //指向尾节点的指针
    int cursize; //链表节点个数
  • 模板类要具有类的操作

    1. 构造函数

      用于简单的初始化数据,这样就不必再写一个初始化函数了

      //构造函数 数据初始化
      My_List()
      {
      pFront = pEnd = nullptr;
      cursize = 0;
      }
    2. 析构函数

      用于在最后释放链表,删除节点,而且自动调用

      ~My_List();
      template<class _T>
      inline My_List<_T>::~My_List()
      {
      /*
      析构函数 释放链表
      */
      Node<_T>* pTemp = nullptr;
      while (pFront)
      {
      pTemp = pFront->next;
      delete pFront;
      pFront = pTemp;
      }
      }
  • 链表的基本操作

    • 创建节点

      ​ 创建节点,注意此处可以直接调用struct定义的构造函数来创建新的节点

      template<class _T>
      inline Node<_T>* My_List<_T>::Create_Node(const _T& New_data)
      {
      //创建节点
      Node<_T>* pNew = new Node<_T>(New_data);
      if (pNew == nullptr)
      {
      //节点创建失败
      return nullptr;
      }
      pNew->next = nullptr;
      return pNew;
      }
    • 链表的尾插法

      ​ pEnd的next指向pNew,pNew更新为pEnd
      在这里插入图片描述

      template<class _T>
      inline void My_List<_T>::push_back(const _T& Insert_data)
      {
      //调用创建节点的函数
      Node<_T>* pNew =Create_Node(Insert_data);
      if (pNew == nullptr)
      {
      cout << "节点开辟失败!\n";
      return;
      }
      if (isempty())
      {
      //如果为空,直接插入
      pFront = pEnd = pNew;
      }
      else
      {
      //如果不为空,尾指针的next指向新节点,
      //更新尾指针位置
      pEnd->next = pNew;
      pEnd = pNew;
      }
      cursize++;
      return;
      }
    • 链表的头插法

      ​ 新节点的next指针指向pFront,pNew更新为pFront
      在这里插入图片描述

      //链表头插
      template<class _T>
      inline void My_List<_T>::push_head(const _T& Insert_data)
      {
      Node<_T>* pNew = Create_Node(Insert_data);
      if (pNew == nullptr)
      {
      cout << "节点开辟失败!\n";
      return;
      }
      if (isempty())
      {
      pFront = pEnd = pNew;
      }
      else
      {
      pNew->next = pFront;
      pFront = pNew;
      }
      cursize++;
      return;
      }
    • 在任意位置插入链表

      ​ 在链表不为空的情况下,如果输入的pos位置不合理,则自动插入到较合理的地方

      1. 如果插入的地方是1,则需要更新头节点,原理同头插法
      2. 如果插入的是任意合理的地方,则需要到达对应位置节点的前一个节点,则让pNew的next指向pTemp的next,pTemp的next指向pNew,实现节点的连接
        在这里插入图片描述
      //往pos位置插入节点
      template<class _T>
      inline void My_List<_T>::Insert_Node(const _T& Insert_data,int pos)
      {
      if (isempty())
      {
      cout << "链表为空!\n" << endl;
      return;
      }
      if (pos <= 0)
      {
      cout << "插入位置无效,执行头插操作\n";
      push_head(Insert_data);
      }
      else if (pos > cursize)
      {
      cout << "插入位置无效,执行尾插操作\n";
      push_back(Insert_data);
      }
      else
      {
      Node<_T>* pNew=Create_Node(Insert_data);
      Node<_T>* pTemp = pFront;
      //插入第一个位置
      if (pos == 1)
      {
      pNew->next = pFront;
      pFront = pNew;
      }
      else
      {
      //找到待插入的前一个位置
      for (int i = 0; i < pos - 2; i++)
      {
      pTemp = pTemp->next;
      }
      pNew->next = pTemp->next;
      pTemp->next = pNew;
      }
      cursize++;
      }
      return;
      }
    • 链表节点的查找

      ​ 查找链表节点,常用作删除节点的前置操作,传入要查找的节点的数据,依次遍历链表,当某个节点的data等于FindData时,返回这个pFind指针,没有找到则返回nullptr

      template<class _T>
      inline Node<_T>* My_List<_T>::Find_Node(const _T& Find_data)
      {
      Node<_T>* pFind = pFront;
      while (pFind)
      {
      if (pFind->data == Find_data)
      {
      return pFind;
      }
      pFind = pFind->next;
      }
      return nullptr;
      }
    • 链表节点的删除

      ​ 利用查找函数查找节点,定义临时pTemp,让其到达待删除节点的前一个节点,pTemp的next指向pDel的next ,从而实现跳过pDel ,接着delete pDel 即可做到删除节点

    在这里插入图片描述

    template<class _T>
    inline void My_List<_T>::Delete_Node(const _T& Delete_data)
    {
    if (isempty())
    {
    cout << "链表为空\n";
    return;
    }
    Node<_T>* pDel = Find_Node(Delete_data);
    if (pDel == nullptr)
    {
    cout << "未查找到要删除的节点!\n";
    }
    else
    {
    Node<_T>* pTemp = pFront;
    while (pTemp->next!=pDel)
    {
    pTemp = pTemp->next;
    }
    pTemp->next = pDel->next;
    delete pDel;
    cursize--;
    }
    return;
    }
    • 遍历整个链表

      ​ 遍历没啥好说的

      template<class _T>
      inline void My_List<_T>::Travel_Node() const
      {
      Node<_T>* pTemp = pFront;
      while (pTemp)
      {
      cout << pTemp->data << " ";
      pTemp = pTemp->next;
      }
      cout << '\n';
      }
    • 其他操作 (万金油)

      ​ 链表的操作基本已经结束,以下为访问链表的其他操作

      //显示链表的节点个数
      int size()const;
      //判断链表是否为空
      bool isempty()const;
      //返回链表的头节点的值
      _T front()const;
      //返回链表的尾节点的值
      _T back()const;
      template<class _T>
      inline int My_List<_T>::size() const
      {
      return cursize;
      }
      template<class _T>
      inline bool My_List<_T>::isempty() const
      {
      return cursize == 0;
      }
      template<class _T>
      inline _T My_List<_T>::front() const
      {
      return pFront->data;
      }
      template<class _T>
      inline _T My_List<_T>::back() const
      {
      return pEnd->data;
      }

测试模板链表

​ 模板链表适用于其他任意类型 包括int string double 甚至是我们定义的类 ,只要其定义了合适的重载运算符,如<<

在这里插入图片描述

#ifndef MY_LISTL_H_
#define MY_LIST_H_
#include <iostream>
using namespace std;
template <class _Ty>
struct Node
{
_Ty data;
Node<_Ty>* next;
Node<_Ty>(const _Ty& data) :data(data)
{
next = nullptr;
}
};
template <class _T>
class My_List
{
private:
Node<_T>* pFront;
Node<_T>* pEnd;
int cursize; //链表节点个数
public:
My_List()
{
pFront = pEnd = nullptr;
cursize = 0;
}
~My_List();
//创建节点
Node<_T>* Create_Node(const _T& New_data);
//链表尾插法
void push_back(const _T& Insert_data);
//链表头插法
void push_head(const _T& Insert_data);
//插入节点
void Insert_Node(const _T& Insert_data,int pos);
//链表节点的查找
Node<_T>* Find_Node(const _T& Find_data);
//链表的删除节点
void Delete_Node(const _T& Delete_data);
//遍历链表
void Travel_Node()const;
//显示链表的节点个数
int size()const;
//判断链表是否为空
bool isempty()const;
//返回链表的头节点的值
_T front()const;
//返回链表的尾节点的值
_T back()const;
};
#endif
template<class _T>
inline My_List<_T>::~My_List()
{
/*
析构函数 释放链表
*/
Node<_T>* pTemp = nullptr;
while (pFront)
{
pTemp = pFront->next;
delete pFront;
pFront = pTemp;
}
}
template<class _T>
inline Node<_T>* My_List<_T>::Create_Node(const _T& New_data)
{
Node<_T>* pNew = new Node<_T>(New_data);
if (pNew == nullptr)
{
//节点创建失败
return nullptr;
}
pNew->next = nullptr;
return pNew;
}
//链表尾插
template<class _T>
inline void My_List<_T>::push_back(const _T& Insert_data)
{
Node<_T>* pNew = Create_Node(Insert_data);
if (pNew == nullptr)
{
cout << "节点开辟失败!\n";
return;
}
if (isempty())
{
pFront = pEnd = pNew;
}
else
{
pEnd->next = pNew;
pEnd = pNew;
}
cursize++;
return;
}
//链表头插
template<class _T>
inline void My_List<_T>::push_head(const _T& Insert_data)
{
Node<_T>* pNew = Create_Node(Insert_data);
if (pNew == nullptr)
{
cout << "节点开辟失败!\n";
return;
}
if (isempty())
{
pFront = pEnd = pNew;
}
else
{
pNew->next = pFront;
pFront = pNew;
}
cursize++;
return;
}
//往pos位置插入节点
template<class _T>
inline void My_List<_T>::Insert_Node(const _T& Insert_data,int pos)
{
if (isempty())
{
cout << "链表为空!\n" << endl;
return;
}
if (pos <= 0)
{
cout << "插入位置无效,执行头插操作\n";
push_head(Insert_data);
}
else if (pos > cursize)
{
cout << "插入位置无效,执行尾插操作\n";
push_back(Insert_data);
}
else
{
Node<_T>* pNew = Create_Node(Insert_data);
Node<_T>* pTemp = pFront;
//插入第一个位置
if (pos == 1)
{
pNew->next = pFront;
pFront = pNew;
}
else
{
//找到待插入的前一个位置
for (int i = 0; i < pos - 2; i++)
{
pTemp = pTemp->next;
}
pNew->next = pTemp->next;
pTemp->next = pNew;
}
cursize++;
}
return;
}
template<class _T>
inline Node<_T>* My_List<_T>::Find_Node(const _T& Find_data)
{
Node<_T>* pFind = pFront;
while (pFind)
{
if (pFind->data == Find_data)
{
return pFind;
}
pFind = pFind->next;
}
return nullptr;
}
template<class _T>
inline void My_List<_T>::Delete_Node(const _T& Delete_data)
{
if (isempty())
{
cout << "链表为空\n";
return;
}
Node<_T>* pDel = Find_Node(Delete_data);
if (pDel == nullptr)
{
cout << "未查找到要删除的节点!\n";
}
else
{
Node<_T>* pTemp = pFront;
while (pTemp->next!=pDel)
{
pTemp = pTemp->next;
}
pTemp->next = pDel->next;
delete pDel;
cursize--;
}
return;
}
template<class _T>
inline void My_List<_T>::Travel_Node() const
{
Node<_T>* pTemp = pFront;
while (pTemp)
{
cout << pTemp->data << " ";
pTemp = pTemp->next;
}
cout << '\n';
}
template<class _T>
inline int My_List<_T>::size() const
{
return cursize;
}
template<class _T>
inline bool My_List<_T>::isempty() const
{
return cursize == 0;
}
template<class _T>
inline _T My_List<_T>::front() const
{
return pFront->data;
}
template<class _T>
inline _T My_List<_T>::back() const
{
return pEnd->data;
}
#include "My_List.h"
int main()
{
#if 1
My_List<int> a;
for (int i = 0; i < 5; i++)
{
a.push_back(i);
}
for (int i = 5; i < 10; i++)
{
a.push_head(i);
}
a.Travel_Node();
a.Delete_Node(99);
a.Travel_Node();
a.Insert_Node(99, 1);
cout << a.front() << endl;
a.Travel_Node();
return 0;
}
posted @   hugeYlh  阅读(36)  评论(0编辑  收藏  举报  
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示