由于类模板不支持分离编译,我们可以将模板类成员函数的声明和定义放在一个.hpp的文件中

模板实现单链表_第1张图片

SList.hpp

#pragma once

#include
using namespace std;
#include

template

struct LinkNode      //节点类(建议写法)
{
	LinkNode(const T x);
	T _data;    //节点的数据
	LinkNode* _next;    //指向该节点的下一个节点
};
template
class SList
{
public:
	SList();         //构造函数
	SList(const SList& s);        //拷贝构造
	SList &operator=(SList s);    //赋值运算符的重载
	~SList();

   //单链表的具体操作
	void Reverse();   //翻转
	void Swap(SList& s);
	void PrintSList();   //打印链表
	void PushBack(const T& x);    //在尾部插入一个节点
	void Clear();         //链表置空
	void PopBack();       //删除尾节点
	void PushFront(T x);  //头插
	void PopFront();    //删除首节点
	void Insert(LinkNode* pos, T x);//固定位置插入一个节点
	void Erase(LinkNode* pos);        //删除某一节点
	LinkNode* Find(T x);       //查找节点并返回这个节点的地址
	int Amount();   //计算链表节点的数目
	void Remove(T x);     //查找某节点并删除
	void RemoveAll(T x);      //删除链表中所有的x

private:
	LinkNode* _head;     //指向头节点
	LinkNode* _tail;        //指向尾节点
};


template
LinkNode::LinkNode(const T x)
:_data(x)
, _next(NULL)
{}

template
SList::SList()         //构造函数
: _head(NULL)
, _tail(NULL)
{}

template
SList::SList(const SList& s)          //拷贝构造
: _head(NULL)
, _tail(NULL)
{
	if (s._head == NULL)
	{
		return;
	}
	LinkNode* tmp = s._head;
	do{
		PushBack(tmp->_data);
		tmp = tmp->_next;
	} while (tmp != s._head);

}

template
SList&  SList::operator=(SList s)     //赋值运算符的重载再优化(推荐写法)
{
	if (this != &s)
	{
		swap(_head, s._head);
		swap(_tail, s._tail);
	}
	return *this;
}

template
SList::~SList()    //析构
{
	Clear();
}

template
void SList::Reverse()   //链表逆置(利用头插新节点的方法)
{
	if (_head == NULL || _head->_next == _tail)
	{
		return;
	}
	int ret = Amount();
	_tail = new LinkNode(_head->_data);
	LinkNode* begin = NULL;
	LinkNode* tmp = _tail;
	while (--ret)
	{
		LinkNode* del = _head;
		_head = _head->_next;
		delete del;    //这里不要忘记做清理工作,否则内存泄漏
		begin = new LinkNode(_head->_data);
		begin->_next = tmp;
		_tail->_next = begin;
		tmp = begin;
	}
	_head = begin;
}

template
void SList::PrintSList()//打印链表
{
	//头结点为空时,无需打印链表
	if (_head == NULL)
	{
		cout << "This SList is Empty !" << endl;
		return;
	}
	else
	{
		LinkNode* tmp = _head;
		do{
			cout << tmp->_data << "-->";
			tmp = tmp->_next;
		} while (tmp != _head);
		cout << endl;
	}
}

template
void SList::PushBack(const T& x)    //在尾部插入一个节点
{
	//如果链表为空,插入节点后只有一个节点,此时_head=_tail
	if (_head == NULL)
	{
		_head = new LinkNode(x);
		_tail = _head;
		_tail->_next = _head;
	}
	else
	{
		_tail->_next = new LinkNode(x);
		_tail = _tail->_next;
		_tail->_next = _head;
	}
}

template
void SList::Clear()         //链表置空
{
	LinkNode* begin = _head;
	while (begin != _tail)
	{
		_head = _head->_next;
		delete begin;
		begin = _head;
	}
	_head = NULL;
	_tail = NULL;
}

template
void SList::PopBack()    //尾删
{
	if (_head == NULL)
	{
		cout << "This SList is empty !" << endl;
	}
	else if (_head == _tail)
	{
		delete _head;
		_head = NULL;
		_tail = NULL;
	}
	else
	{
		LinkNode* cur = _head;
		while (cur->_next != _tail)
		{
			cur = cur->_next;
		}
		delete _tail;
		_tail = cur;
		_tail->_next = _head;
	}
}
template
void SList::PushFront(T x)  //头插
{
	if (_head == NULL)
	{
		PushBack(x);
	}
	else
	{
		LinkNode* tmp = _head;
		_head = new LinkNode(x);
		_head->_next = tmp;
		_tail->_next = _head;
	}
}
template
void SList::PopFront()    //删除首节点
{
	if (_head == NULL)
	{
		cout << "This SList is empty !" << endl;
		return;
	}
	LinkNode* tmp = _head;
	_head = _head->_next;
	_tail->_next = _head;
	delete tmp;
}

//固定位置插入一个节点(这个函数需和Find函数搭配使用)
//先用Find函数找到新节点需要插入的位置
//(将Find函数的返回值传给Insert函数的参数pos),再在pos节点后面插入新节点x
template
void SList::Insert(LinkNode* pos, T x)
{
	assert(pos);
	if (pos == _tail)
	{
		PushBack(x);
	}
	else
	{
		LinkNode* tmp = new LinkNode(x);
		tmp->_next = pos->_next;
		pos->_next = tmp;
	}
}

//删除某一节点,同样,要先找到该节点并传参给Erase函数
template
void SList::Erase(LinkNode* pos)
{
	assert(pos);
	if (pos == _tail)
	{
		PopBack();
	}
	if (pos == _head)
	{
		PopFront();
	}
	else
	{
		LinkNode* prev = _head;
		while (prev->_next != pos)
		{
			prev = prev->_next;
		}
		prev->_next = pos->_next;
		delete pos;
	}
}

template
LinkNode* SList::Find(T x)       //查找节点并返回这个节点的地址
{
	if (_head == NULL)
	{
		cout << "This SList is empty !" << endl;
		return NULL;
	}
	else
	{
		LinkNode* tmp = _head;
		do{
			if (tmp->_data == x)
			{
				return tmp;
			}
			tmp = tmp->_next;
		} while (tmp != _head);
		return NULL;
	}
}
template
int SList::Amount()   //计算链表节点的数目
{
	if (_head == NULL)
	{
		return 0;
	}
	else
	{
		int count = 0;
		LinkNode* cur = _head;
		while (cur != _tail)
		{
			count++;
			cur = cur->_next;
		}
		return ++count;
	}
}
template
void SList::Remove(T x)      //查找某节点并删除
{
	if (_head == NULL)
	{
		cout << "This SList is empty !" << endl;
	}
	else
	{
		LinkNode* tmp = Find(x);
		if (tmp != NULL)
		{
			Erase(tmp);
		}
	}
}
template
void SList::RemoveAll(T x)       //删除链表中所有的x
{
	if (_head == NULL)
	{
		cout << "This SList is empty !" << endl;
		return;
	}
	//如果链表不为空,设置left和right前后指针,从头至尾遍历一遍,delete节点的data为x的节点

	LinkNode* left = _tail;
	LinkNode* right = _head;
	int count = Amount();
	while (count--)
	{
		//当要删掉的节点是头节点时,需要注意头节点要指向它的下一个节点
		//当要删掉的节点是尾节点时,需要注意尾节点要指向它的上一个节点
		//当left和right指向同一块要删掉的节点时,将链表置空

		if (right->_data == x)
		{
			if (_head == right)
			{
				_head = _head->_next;
			}
			if (_tail == right)
			{
				_tail = left;
			}
			if (right == left)
			{
				_head = NULL;
				_tail = NULL;
				return;
			}
			LinkNode* tmp = right;
			right = right->_next;
			delete tmp;
			left->_next = right;
		}
		else
		{
			left = right;
			right = right->_next;
		}
	}
}

Test.cpp

// 用例测试
#include"Slist.hpp"

void Test()
{
	SList list1;
	list1.PushBack(1);
	list1.PushBack(2);
	list1.PushBack(3);
	list1.PushBack(4);
	list1.PushBack(5);
	cout << "SList 1: ";
	list1.PrintSList();

    SList list2 = list1;
	cout << "SList 2: ";
	list2.PrintSList();

	SList list3 (list1);
	cout << "SList 3: ";
	list3.PrintSList();

	SList list4;
	list4 = list1;
	cout << "SList 4: ";
	list4.PrintSList();

	cout << endl;
	list1.RemoveAll(2);
	cout << "SList 1: ";
	list1.PrintSList();

    list2.Reverse();
	cout << "SList 2: ";
	list2.PrintSList();

	list3.PopBack();
	cout << "SList 3: ";
	list3.PrintSList();

	list4.Clear();
	cout << "SList 4: ";
	list4.PrintSList();

	cout << endl;
	list1.Erase(list1.Find(4));
	cout << "SList 1: ";
	list1.PrintSList();

	list1.PopFront();
	cout << "SList 1: ";
	list1.PrintSList();
	list1.PushFront(0);
	cout << "SList 1: ";
	list1.PrintSList();

	list1.Insert(list1.Find(3), 0);
	cout << "SList 1: ";
	list1.PrintSList();

	list1.RemoveAll(0);
	cout << "SList 1: ";
	list1.PrintSList();

}


int main()
{
	Test();
	system("pause");
}

模板实现单链表_第2张图片