c++單鏈表【建構函式、運算子過載、解構函式、增刪查改等】
阿新 • • 發佈:2018-12-30
c++中的單向連結串列寫法:實現增刪查改、建構函式、運算子過載、解構函式等。
建立標頭檔案SList.h
#pragma once typedef int DataType; //SList要訪問SListNode,可以通過友元函式實現,友元函式在被訪問的類中 class SListNode { friend class SList;//友元函式 public: SListNode(const DataType x) :_data(x) , _next(NULL) {} private: SListNode* _next; DataType _data; }; class SList { public: SList() :_head(NULL) , _tail(NULL) {} //深拷貝 SList(const SList& s) :_head(NULL) , _tail(NULL) { SListNode* cur = s._head; while (cur) { this->PushBack(cur->_data); cur = cur->_next; } } ////深拷貝的傳統寫法 //SList& operator=(const SList& s) //{ // if (this != &s) // { // Clear(); // SListNode* cur = s._head; // while (cur) // { // this->PushBack(cur->_data); // cur = cur->_next; // } // } // return *this; //} //深拷貝的現代寫法 SList& operator=(SList& s) { swap(_head, s._head); swap(_tail, s._tail); return *this; } ~SList() { Clear(); } public: void Clear(); void PushBack(DataType x); void PopBack(); void PushFront(DataType x); void PopFront(); //void Insert(size_t pos,DataType x); void Insert(SListNode* pos, DataType x); void Erase(SListNode* pos); SListNode* Find(DataType x); void PrintSList(); private: SListNode* _head; SListNode* _tail; };
各函式的實現
#include<iostream> using namespace std; #include"SList.h" #include<assert.h> void SList::Clear() { SListNode* cur = _head; while (cur) { SListNode* del = cur; cur = cur->_next; delete del; del = NULL; } } void SList::PrintSList()//列印連結串列 { SListNode* cur = _head; while (cur) { cout << cur->_data << "->"; cur = cur->_next; } cout << "NULL" << endl; } void SList::PushBack(DataType x)//尾插 { if (NULL == _head) { _head = new SListNode(x);//開闢一個值為x的新結點 _tail = _head; } else { //SListNode* cur; //cur->_data = x; //_tail->_next = cur; //_tail = cur; _tail->_next= new SListNode(x); _tail = _tail->_next; } } void SList::PopBack()//尾刪 { if (NULL == _head) { cout << "SList is empty!" << endl; } else if (_head == _tail) { delete _head; _head = _tail = NULL; } else { SListNode* cur = _head;//找到要刪除尾節點的前一個節點cur while (cur->_next->_next) { cur = cur->_next; } delete cur->_next; cur->_next = NULL; _tail = cur; } } void SList::PushFront(DataType x)//頭插 { SListNode* tmp = _head; _head=new SListNode(x); _head->_next = tmp; } void SList::PopFront()//頭刪 { if (NULL == _head) { cout << "SList is empty!" << endl; } else if (NULL == _head->_next) { delete _head; _head = NULL;//delete後要將指標設空,否則產生野指標 } else { SListNode* tmp = _head->_next; delete _head; _head = tmp; } } //void SList::Insert(size_t pos, DataType x) //{ // assert(pos); // SListNode* tmp = _head; // pos -= 1; // while (--pos) // { // tmp = tmp->_next; // } // if (NULL == tmp) // SList::PushBack(x); // else // { // SListNode* next = tmp->_next; // SListNode* cur = new SListNode(x); // tmp->_next = cur; // cur->_next = next; // } //} void SList::Insert(SListNode* pos, DataType x)////指定位置處插入x { assert(pos); SListNode* tmp = _head; while (tmp) { if (NULL == tmp->_next) SList::PushFront(x); else if (pos == tmp->_next) { SListNode* cur = new SListNode(x); cur->_next= tmp->_next; tmp->_next = cur; return;//注意結束迴圈 } tmp = tmp->_next; } } void SList::Erase(SListNode* pos) { assert(pos); SListNode* tmp = _head; while (tmp) { if (NULL == tmp->_next) SList::PopFront(); else if (pos == tmp->_next) { SListNode* cur = tmp->_next->_next; delete tmp->_next; tmp->_next = NULL; tmp->_next = cur; return;//注意結束迴圈 } tmp = tmp->_next; } } SListNode* SList::Find(DataType x) { SListNode* cur = _head; while (cur) { if (x == cur->_data) { return cur; } cur = cur->_next; } return NULL; }
各操作的測試用例
void Test1() {//尾插尾刪 SList S; S.PushBack(1); S.PushBack(2); S.PushBack(3); S.PushBack(4); S.PrintSList(); S.PopBack(); S.PrintSList(); //S.PopBack(); //S.PopBack(); //S.PrintSList(); //S.PopBack(); //S.PopBack(); //S.PopBack(); SList S1(S); S1.PrintSList(); SList S2; S2 = S; S2.PrintSList(); } void Test2() {//頭插頭刪 SList S; S.PushFront(1); S.PushFront(2); S.PushFront(3); S.PushFront(4); S.PrintSList(); S.PopFront(); S.PrintSList(); S.PopFront(); S.PopFront(); S.PopFront(); S.PrintSList(); S.PopFront(); } void Test3() {//指定位置插入某數,查詢某數 SList S; S.PushBack(1); S.PushBack(2); S.PushBack(4); S.PushBack(5); S.PrintSList(); //S.Insert(3, 3); SListNode* p = S.Find(4); S.Insert(p, 3); S.PrintSList(); } void Test4() {//刪除某結點 SList S; S.PushBack(1); S.PushBack(2); S.PushBack(3); S.PushBack(10); S.PushBack(4); S.PushBack(5); S.PrintSList(); SListNode* p = S.Find(10); S.Erase(p); S.PrintSList(); }
友元函式
在實現類之間資料共享時,減少系統開銷,提高效率。如果類A中的函式要訪問類B中的成員(例如:智慧指標類的實現),那麼類A中該函式要是類B的友元函式。具體來說:為了使其他類的成員函式直接訪問該類的私有變數。即:允許外面的類或函式去訪問類的私有變數和保護變數,從而使兩個類共享同一函式。
實際上具體大概有下面兩種情況需要使用友元函式:
(1)運算子過載的某些場合需要使用友元。
(2)兩個類要共享資料的時候。
1.1使用友元函式的優缺點
優點:能夠提高效率,表達簡單、清晰。
缺點:友元函式破環了封裝機制,儘量不使用成員函式,除非不得已的情況下才使用友元函式。
1.2友元函式的引數
因為友元函式沒有this指標,則引數要有三種情況:
(1)要訪問非static成員時,需要物件做引數;
(2)要訪問static成員或全域性變數時,則不需要物件做引數;
(3)如果做引數的物件是全域性物件,則不需要物件做引數;
1.3友元函式的位置
因為友元函式是類外的函式,所以它的宣告可以放在類的私有段或公有段且沒有區別。
1.4友元函式的呼叫
可以直接呼叫友元函式,不需要通過物件或指標
友元函式和類的成員函式的區別
成員函式有this指標,而友元函式沒有this指標。
友元函式是不能被繼承的,就像父親的朋友未必是兒子的朋友。