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