模板实现单链表

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

wKioL1b-DTfhVzcnAAAKFtUh58k269.png

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


wKiom1b-DGWwSeNJAAAHqYpbNgM164.png



本文出自 “言安阳” 博客,谢绝转载!

面向对象程序设计课程作业 1. 请创建一个数据类型为T的链表类模板List,实现以下成员函数: 1) 默认构造函数List(),将该链表初始化为一个空链表(10分) 2) 拷贝构造函数List(const List& list),根据一个给定的链表构造当前链表(10分) 3) 析构函数~List(),释放链表中的所有节点(10分) 4) Push_back(T e)函数,往链表最末尾插入一个元素为e的节点(10分) 5) operator<<()友元函数,将链表的所有元素按顺序输出(10分) 6) operator=()函数,实现两个链表的赋值操作(10分) 7) operator+()函数,实现两个链表的连接,A=B+C(10分) 2. 请编main函数,测试该类模板的正确性: 1) 用List模板定义一个List类型的模板类对象int_listB,从键盘读入m个整数,调用Push_back函数将这m个整数依次插入到该链表中;(4分) 2) 用List模板定义一个List类型的模板类对象int_listC,从键盘读入n个整数,调用Push_back函数将这n个整数依次插入到该链表中;(4分) 3) 用List模板定义一个List类型的模板类对象int_listA,调用List的成员函数实现A = B + C;(4分) 4) 用cout直接输出int_listA的所有元素(3分) 5) 用List模板定义List类型的模板类对象double_listA, double_listB, double_listC,重复上述操作。(15分) 3. 输入输出样例: 1) 输入样例 4 12 23 34 45 3 56 67 78 3 1.2 2.3 3.4 4 4.5 5.6 6.7 7.8 2) 输出样例 12 23 34 45 56 67 78 1.2 2.3 3.4 4.5 5.6 6.7 7.8
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值