基于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;
}