模板實現單鏈表

由於類模板不支持分離編譯,我們可以將模板類成員函數的聲明和定義放在一個.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



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