新手上路,勿噴。C++連結串列的建立,遍歷,刪除,插入等等
//list.h
#pragma once template<typename T>class slistNode { public: slistNode() { next = nullptr; cout << "呼叫了slistnode的建構函式" << endl; } ~slistNode() {delete next;cout << "呼叫了slistnode的解構函式" << endl;}; T data; slistNode* next; };
template<typename T> class myslist { private: unsigned int listlength; slistNode<T>* headnode; public: myslist();//初始化 ~myslist();//用於刪除lastnode,headnode。他們動態分配了記憶體 unsigned int length();//連結串列元素的個數 bool add(int n);//在連結串列的頭部插入節點 void traversal();//遍歷整個連結串列並列印 bool isEmpty();//判斷連結串列是否為空 slistNode<T>* find(T x);//查詢第一個值為x的節點,返回節點的地址,找不到返回NULL void Delete(T x);//刪除第一個值為x的節點 bool insert(T x,int n);//在第n個節點後插入值為x的節點 bool insertlast(T x);//在連結串列的尾部插入節點 }; template<typename T> myslist<T>::~myslist() { delete headnode; cout << "呼叫的myslist的解構函式" << endl; }
template<typename T> myslist<T>::myslist() { cout << "呼叫的myslist的建構函式" << endl; headnode = new slistNode<T>();//這裡呼叫預設建構函式,所以head->next=nullptr;如果有形參,則呼叫對應的建構函式。 headnode->data = 0; listlength = 0; }
template<typename T> unsigned int myslist<T>::length() { return listlength; }
template<typename T> bool myslist<T>::add(int n) { int i = 0; for (i; i < n; i++) { cout << "請輸入你想插入的第" <<n-i << "個數據"; T data1; cin >> data1; cout << endl; //下面這個動態指標分配了地址的,這樣每次後生成的位置都會指向在它之前生成的那個節點的指標域。 slistNode<T>* node = new slistNode<T>(); if (node == nullptr) { cout << "動態記憶體分配失敗" << endl; return 0; } //每次頭節點指向的位置都是上一次迴圈生成的節點的地址,這使得每個節點都是在頭節點後面插入的。 node->next = headnode->next; node->data = data1; headnode->next=node; } listlength = listlength + n; return 1; }
template<typename T>
void myslist<T>::traversal() { if (headnode->next == nullptr) cout << "該連結串列的長度為0" << endl; else { slistNode<T>* node = headnode; while (node->next != nullptr) { cout << "連結串列中的資料為" << ": "<<node->next->data<<endl; node = node->next; } cout << "\n輸出完畢" << endl; }
}
template<typename T> bool myslist<T>::isEmpty() { if (headnode->next == nullptr) { cout << "連結串列已經空了" << endl; return true; } else { cout << "連結串列非空" << endl; return false; } }
template<typename T> void myslist<T>::Delete(T x) { slistNode<T>* node= headnode; while (node->next != nullptr) { if (node->next->data == x) { slistNode<T>* node1 = node->next; node1 = node->next; node->next = node1->next; listlength = listlength - 1; } else node = node->next; } cout << "該連結串列沒有該值" << endl; }
template<typename T> bool myslist<T>::insert(T x,int n) { slistNode<T>* node = new slistNode<T>(); if (node == nullptr) { cout << "動態記憶體分配失敗" << endl; return 0; } node->next = headnode->next;//注意:這裡將node=headnode是錯誤的,後者是將指標headnode賦給node,這會導致node與headnode指向同一個記憶體, //使得原先分配給node的記憶體洩漏,同時,導致travel時,由於headnode地址和Node一樣,從而headnode->next==headnode if (n < 0) { cout << "你輸入的位置不合理" << endl; return 0; } else if (n == 0) { node->data = x; headnode->next = node; return 1; } else if (n > listlength) { cout << "你輸入的位置超過連結串列的長度" << endl; return 0; } else if (0 < n&&n < listlength) { if (node->next == nullptr) { cout << "你輸入的位置不合理" << endl; return 0; } else { slistNode<T>* node1 = headnode; int i = 0; while (i < n) { node1 = node1->next;//不要給指向新節點的指標重新賦值,這回改變指標的地址,從而建立新節點的意圖會失敗。使用中間指標 i++; } node->next = node1->next; node1->next = node; node->data = x; return 1; } } }
template<typename T> bool myslist<T>::insertlast(T x) { slistNode<T>* node = new slistNode<T>(); if (node == nullptr) { cout << "動態記憶體分配失敗" << endl; return 0; } if (headnode->next == nullptr) { headnode->next = node; node->data = x; } else { slistNode<T>* node1 = headnode; while (node1->next != nullptr) { node1 = node1->next; } node1->next = node; node->data = x; listlength = listlength + 1; } }
template<typename T> slistNode<T>* myslist<T>::find(T x) { slistNode<T>* node =headnode; if (node->next == nullptr) { cout << "該連結串列沒有值:" << x<<endl; } else { int i = 0; while (node->next != nullptr) { i = i + 1; if (node->next->data == x) { cout << "連結串列中該值是第:" << i << "個位置" << endl; cout << "它的地址為:" << node << endl; return node; } else node = node->next; } cout << "該連結串列沒有值:" << x << endl; } }
//1,使用new動態分配記憶體的指標物件,不手動釋放記憶體時,是不會呼叫解構函式的,但如果該類的物件是包含在另一個物件裡面,則當另一個物件生命結束時, //則會先呼叫該類的物件解構函式,再呼叫另一個物件的解構函式。 //2,將一個物件指標賦值為空,還是分配了記憶體的 //3,在物件釋放之前,不要將其對應的指標賦值新指標。這會使得記憶體洩漏
//main.cpp
#include"List2.h" #include<iostream> using namespace std; int main() { { myslist<int> list; list.isEmpty(); cout << "連結串列的長度為:" << list.length() << endl; int n; cout << "請輸入連結串列首部插入資料的個數:"; cin >> n; cout << endl; list.add(n); list.traversal(); list.isEmpty(); cout << "連結串列的長度為:" << list.length() << endl; cout << "請輸入你想要在連結串列中尋找的值:"; int n1; cin >> n1; cout << endl; slistNode<int>* b=list.find(n1); list.Delete(n1); cout << "在刪除值:" << n1 << "後,連結串列的中的值為:"; list.traversal(); int m, n2; cout << "請輸入你想插入連結串列中值的大小:"; cin >> m; cout << endl; cout << "請輸入你想插入連結串列中值的位置"; cin >> n2; cout << endl; list.insert(m,n2-1); cout << "在插入新值"<<m<<"後,連結串列中的值為"; list.traversal(); int x; cout << "請輸入你想在連結串列尾部插入值的大小:"; cin >> x; cout << endl; list.insertlast(x); list.traversal();
} system("pause"); return 0; }
菜鳥一隻