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; //链表节点个数 -
模板类要具有类的操作
-
构造函数
用于简单的初始化数据,这样就不必再写一个初始化函数了
//构造函数 数据初始化 My_List() { pFront = pEnd = nullptr; cursize = 0; } -
析构函数
用于在最后释放链表,删除节点,而且自动调用
~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,则需要更新头节点,原理同头插法
- 如果插入的是任意合理的地方,则需要到达对应位置节点的前一个节点,则让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; }
本文来自博客园,作者:hugeYlh,转载请注明原文链接:https://www.cnblogs.com/helloylh/p/17209753.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 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)