C++ 模板及智能指针实现链表
C++ 模板及智能指针实现链表
关于链表介绍,网上可以找到很多例子,但大多都是为结构体类,使用new和delete申请和释放内存,稍有不慎容易内存泄露。
在C++11新标准中,智能指针可以很好的解决内存泄漏问题,同时使用模板编程,使得链表不在局限于用于某一种类。
因此尝试使用模板和智能指针,写了一个小小单链表用例,抛砖引玉,希望和大家共同学习进步!
1. 模板和智能指针
参考《C++ Primer》 第五版,第十二章 “动态内存”,第十六章 “模板与泛型编程”;
2. 代码实现
2.1 单链表数据结构类
#include <iostream>
#include <memory> //智能指针头文件
using namespace std;//命名空间
template<typename _Ty>
class Node
{
public:
Node(_Ty vl):pNext(nullptr), m_value(vl)
{
};
~Node() = default;
public:
shared_ptr<Node<_Ty>> pNext;
public:
_Ty m_value;
//private:
//char largeMemory[0x102400000];//用于测试内存使用情况
};
2.2 链表操作函数
2.2.1 插入节点
在指定位置插入指定值的节点
//链表中插入数据,成功返回true,否则返回false
//参数:pHead:链表头指针,value:插入值,pos:插入位置,默认为-1,插到尾部
template<typename _Ty>
bool AddToNode(shared_ptr<Node<_Ty>>& pHead,const _Ty& value,const int& pos = -1)
{
shared_ptr<Node<_Ty>> addValue = make_shared<Node<_Ty>>(value);//新建并初始化对象
shared_ptr<Node<_Ty>> pTemNode = pHead;//指向链表头的临时指针
if (-1 == pos)//插到队尾,一定成功
{
if (nullptr == pTemNode)//如果为空链表
{
pHead = addValue;
}
else
{
while (pTemNode->pNext != nullptr)//找到链表尾
{
pTemNode = pTemNode->pNext;
}
pTemNode->pNext = addValue;//添加到链表尾
}
return true;
}
else if(pos < 0)//错误
{
cout << "Error! The given position is less than 0,but it can equal to -1 to add the node to tail !" << endl;
return false;
}
else//插到指定位置
{
if (0 == pos)//插到链表头
{
addValue->pNext = pHead;
pHead = addValue;
return true;
}
else
{
int temPos = 0;
while (pTemNode->pNext != nullptr && temPos != pos - 1)//寻到指定位置,插到pos前面
{
pTemNode = pTemNode->pNext;
++temPos;
}
if (temPos != pos - 1)//判断给定位置是否大于链表长度
{
cout << "Error! The given position is illegal, it should be no more than " << temPos + 1<< "!" << endl;
return false;
}
addValue->pNext = pTemNode->pNext;
pTemNode->pNext = addValue;
return true;
}
}
}
2.2.2 按给定值删除节点
这里只写了按照指定值删除节点,其它情况(例如删除指定位置)可自己练习
template<typename _Ty>
void DeleteByValue(shared_ptr<Node<_Ty>>& pHead, const _Ty& value)
{
if (nullptr == pHead)//本身为空连边
{
return;
}
//检查链表头是否要删除
while (value == pHead->m_value)
{
pHead = pHead->pNext;
if (nullptr == pHead)/*从头到尾都要删掉的值*/
{
return;
}
}
//删头节点后的节点
shared_ptr<Node<_Ty>> pTem = pHead;
shared_ptr<Node<_Ty>> pTemNext = pHead->pNext;
while (nullptr != pTemNext)
{
if (value == pTemNext->m_value)//如果是要删掉的值,pTem不移动,改pNext值,
{
pTem->pNext = pTemNext->pNext;
}
else
{
pTem = pTemNext;
}
pTemNext = pTemNext->pNext;//pTemNext向前移动
}
return;
}
2.2.3 打印全部节点值
对于int,float,double等类型,可直接使用cout输出
template<typename _Ty>
void printValue(const shared_ptr<Node<_Ty>>& pHead)
{
if (pHead == nullptr)
{
cout << endl << "node len is 0 " << endl;
return;
}
int nLen = 1;
cout << "begin print" << endl;
shared_ptr<Node<_Ty>> tem = pHead;
cout << tem->m_value;
while (tem->pNext != nullptr)
{
++nLen;
tem = tem->pNext;
cout << "->" <<tem->m_value;
}
cout << "->NULL";
cout << endl << "end print, node len is "<< nLen << endl;
}
3 程序程序测试
int main()
{
shared_ptr<Node<int>> nHead = nullptr;//构造int链表
AddToNode(nHead, 2);//在尾部添加2
printValue(nHead);
AddToNode(nHead, 20);
printValue(nHead);
AddToNode(nHead, 2, 0);//在2添加到头节点
printValue(nHead);
AddToNode(nHead, 35, 3);//在位置3添加35(第一的节点序号是0)
printValue(nHead);
DeleteByValue(nHead, 20);//删除值为20的节点
printValue(nHead);
DeleteByValue(nHead, 2);
printValue(nHead);
DeleteByValue(nHead, 35);
printValue(nHead);
system("pause");
return 0;
}
运行结果
begin print
2->NULL
end print, node len is 1
begin print
2->20->NULL
end print, node len is 2
begin print
2->2->20->NULL
end print, node len is 3
begin print
2->2->20->35->NULL
end print, node len is 4
begin print
2->2->35->NULL
end print, node len is 3
begin print
35->NULL
end print, node len is 1
node len is 0
请按任意键继续. . .
4 模板特化
4.1 打印函数
std::string类型等有些类型,无法直接使用cout输出,打印函数需进行模板特化
template<>
void printValue<string>(const shared_ptr<Node<string>>& pHead)//对string类型进行模板特化
{
if (pHead == nullptr)
{
cout << endl << "node len is 0 " << endl;
return;
}
int nLen = 1;
cout << "begin print" << endl;
shared_ptr<Node<string>> tem = pHead;
cout << tem->m_value.c_str();
while (tem->pNext != nullptr)
{
++nLen;
tem = tem->pNext;
cout << "->" << tem->m_value.c_str();
}
cout << "->NULL";
cout << endl << "end print, node len is " << nLen << endl;
}
4.2 测试用例
shared_ptr<Node<string>> nHead = nullptr;
AddToNode(nHead, string("hello"));
printValue(nHead);
AddToNode(nHead, string("world"));
printValue(nHead);
AddToNode(nHead, string("hello"), 0);
printValue(nHead);
DeleteByValue(nHead, string("world"));
printValue(nHead);
DeleteByValue(nHead, string("hello"));
printValue(nHead);
输出结果
begin print
hello->NULL
end print, node len is 1
begin print
hello->world->NULL
end print, node len is 2
begin print
hello->hello->world->NULL
end print, node len is 3
begin print
hello->hello->NULL
end print, node len is 2
node len is 0
请按任意键继续. . .
5 内存增长测试
将类中的巨型数组成员变量放开
写个循环程序,一直跑,内存比较稳定