模板实现单链表

由于类模板不支持分离编译,我们可以将模板类成员函数的声明和定义放在一个.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;
		}
	}
}

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

wKiom1b-DGWwSeNJAAAHqYpbNgM164.png



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章