模板实现单链表

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

SList.hpp

#pragma once

#include<iostream>
using namespace std;
#include<assert.h>

template<class T>

struct LinkNode      //节点类(建议写法)
{
	LinkNode(const T x);
	T _data;    //节点的数据
	LinkNode<T>* _next;    //指向该节点的下一个节点
};
template<class T>
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<T>* pos, T x);//固定位置插入一个节点
	void Erase(LinkNode<T>* pos);        //删除某一节点
	LinkNode<T>* Find(T x);       //查找节点并返回这个节点的地址
	int Amount();   //计算链表节点的数目
	void Remove(T x);     //查找某节点并删除
	void RemoveAll(T x);      //删除链表中所有的x

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

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

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

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

}

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

template<class T>
SList<T>::~SList()    //析构
{
	Clear();
}

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

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

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

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

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

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

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

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

	LinkNode<T>* left = _tail;
	LinkNode<T>* 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<T>* tmp = right;
			right = right->_next;
			delete tmp;
			left->_next = right;
		}
		else
		{
			left = right;
			right = right->_next;
		}
	}
}

Test.cpp

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

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

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

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

	SList<int> 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");
}

时间: 2024-10-13 18:01:03

模板实现单链表的相关文章

[C++] 利用模板的模板参数实现单链表

模板的模板顾名思义就是一个模板函数的参数是另一个模板函数的模板. 模板函数有兴趣的读者请看我上一篇博客模板函数,实现顺序表, 请看模板的模板简要举例 上边两张图片就是模板的模板类型了,模板的模板也可以使用缺省参数(这一点与函数相似) 好了上面介绍过了,现在直接上代码吧,我个人觉得一个函数怎么用,还是直接看实例更容易让人懂, 下面是单链表的节点类, 用的是模板函数 #pragma once #include<iostream> using namespace std; #include<s

C++ 单链表模板类实现

单链表的C语言描述 基本运算的算法--置空表.求表的长度.取结点.定位运算.插入运算.删除运算.建立不带头结点的单链表(头插入法建表).建立带头结点的单链表(尾插入法建表),输出带头结点的单链表 #include<cstdio>#include<iostream>using namespace std;template <class T>class Linklist{private: struct node { T date; node * next; node():n

单链表的结点类模板

C++语言程序设计进阶 (2015年秋) 郑莉教授 http://www.xuetangx.com/courses?org=-1&cid=117&page_type=0&page=2 单链表 //单链表的结点类模板 template <class T> class Node{ private: Node<T> *next;//后继结点的指针 public: T data; Node(const T& item,Node<T>*next =

C++数据结构 单链表(模板类)

利用模板类实现单链表及其功能 需要实现的操作: [1] push_back       [2] push_front [3] show_list       [0] quit_system [4] pop_back        [5] pop_front [6] insert_val      [7] delete_val [8] find            [9]length [10] clear          [11]destroy [12] reserv         [13]

单链表sLinkList类,模板类

sLinkList模板类,单链表代码 1 /* 2 该文件按习惯可以分成.h文件和实现的.cpp文件 3 */ 4 template <class elemType> 5 class sLinkList 6 { 7 private: 8 struct node{ //定义单链表中的结点结构 9 elemType data; 10 node *next; 11 12 node(const elemType &x, node *n = NULL) 13 { 14 data = x; nex

用模板实现顺序表与单链表

//顺序表 #include<iostream> using namespace std; template<typename T> class SeqList { public: SeqList(); ~SeqList(); SeqList(const SeqList& s); SeqList& operator=(const SeqList &s); void _CheakCapacity(); void PushBack(const T& x)

单链表的c++实现,使用模板

节点的构造 #include<iostream> using namespace std; template<class _Ty> class list; template<class _Ty> class list_node { friend class list<_Ty>; public: list_node():next(NULL) {} list_node(const _Ty item, list_node<_Ty>* tail=NULL

单链表类模板

单链表类模板节点头 ListNode.h 1 #include "stdafx.h" 2 #include<iostream> 3 using namespace std ; 4 template<typename Type> class SingleList; 5 template <typename Type> 6 class ListNode{ 7 private: 8 friend class SingleList<Type>;

单链表(模板类)

#include<iostream>#include<assert.h>using namespace std; template <class T>struct Node{ Node(const T& x) :_data(x) , _pNext(NULL) { } Node<T> *_pNext; T _data;};template <class T>class SList{public: SList() :_pHead(NULL)