1. 程式人生 > >單鏈表的實現(給定某結點,刪除它;給定某結點,在他前面插入一個結點等)

單鏈表的實現(給定某結點,刪除它;給定某結點,在他前面插入一個結點等)

基於C++語言實現單鏈表(利用模板)

首先,我們要搞清楚單鏈表的特徵,在什麼情況下適合用該資料結構。
1.連結串列在記憶體上的存放是不連續的,所以不能依賴下標來定址
單鏈表的結構分佈圖
由於它的記憶體結構分佈,決定了它適用於插入刪除較多的情況(時間複雜度O(1))

現在我們來研究關於單鏈表的相關問題:具體程式碼在結尾
1.判斷一個單鏈表是否有環
利用快慢指標(slow,fast),起始都指向頭,slow一次走一個結點,fast一次走兩個結點,當slow==fast時,跳出迴圈,if(fast==NULL||fast->next==NULL)則說明無環,返回NULL,否則返回fast->next(此為進入環的第一個結點)。在此也可返回bool值,但為了程式碼的複用,返回了fast->next或者NULL。具體操作需要根據實際要求。程式碼在最後。
2.只給定單鏈表中某個結點p(並非最後一個結點,即p->next!=NULL)指標,刪除該結點。


要刪除一個結點,必須知道他的前驅結點。所以在此,將該節點的後一個結點的資料域賦值給該結點,然後刪除該節點的後一個結點即可(缺陷,不能刪除最後一個結點)
3.只給定單鏈表中某個結點p(非空結點),在p前面插入一個結點
建立一個新結點,連線到該結點之後,將該結點的資料域賦值給新結點的資料域,再將要插入的資料域賦值給該結點
4.給定兩個單鏈表(head1, head2),檢測兩個連結串列是否有交點,如果有返回第一個交點。
只需要將兩個連結串列相連判斷是否有環,則可解決,呼叫功能1即可
5.單鏈表的逆置
①利用頭插進行逆置
②利用前後指標進行逆置
6.已知遞增有序的單鏈表 A,B 和C 分別儲存了一個集合,設計演算法實現 A:=A∪(B∩C)並使求解結構 A 仍保持遞增。要求演算法的時間複雜度為 O(|A|+|B|+|C|)。其中,|A|為集合A 的元素個數。

都為有序單鏈表,則進行遍歷的時候不需要進行重複遍歷。

#include <iostream>
using namespace std;

template <typename T>
class Link;

template <typename T>
class Node
{
private:
       T _data;
       Node  *_next;
public:
       Node(T val = T()):_data(val),_next(NULL) { }
       friend class Link<
T>; }; //帶頭節點的單鏈表的實現。 template <typename T> class Link { public: Link() { _head = new Node<T>(); } /*~Link() { Node<T>* pcr = _head->_next; while(pcr != NULL) { Node<T> *next = pcr->_next; _head->_next = next; delete pcr; pcr = next; } }*/ void insertHead(T val); void insertTail(T val); void deleteNode(T val); Node<T>* Search(T val); //查詢val對應的節點,有則返回節點的地址,沒有則返回NULL; Node<T>* IsExitsLoop(); //檢測是否有環。 void inverse(); void show(); //列印連結串列的所有節點 void show1(Node<T>* p) //只打印p指向的節點的資料 { if(p != NULL) { cout<<p->_data<<endl; } } void deleteNode(Node<T> *p);//只給定單鏈表中某個結點p(並非最後一個結點,即p->next!=NULL)指標,刪除該結點。 void insertNode(Node<T> *p,T val);//只給定單鏈表中某個結點p(非空結點),在p前面插入一個結點 Node<T>* intersection (Link<T> list2);//給定兩個單鏈表(head1, head2),檢測兩個連結串列是否有交點,如果有返回第一個交點。 void merge(Link<T> list1,Link<T> list2); //已知遞增有序的單鏈表 A,B 和C 分別儲存了一個集合,設計演算法實現 A:=A∪(B∩C) , //並使求解結構 A 仍保持遞增。要求演算法的時間複雜度為 O(|A|+|B|+|C|)。其中,|A|為集合A 的元素個數。 private: Node<T>* _head; }; template <typename T> void Link<T>::show() { Node<T>* pcr = _head->_next; while(pcr != NULL) { cout<<pcr->_data<<" "; pcr = pcr->_next; } cout<<endl; } //template <typename T> //void Link<T>::show1(Node *p) //{ // if(p != NULL) // { // cout<<p->_data<<endl; // } //} template <typename T> void Link<T>::insertHead(T val) { Node *pcr = new Node(val); pcr->_next = _head->_next; _head->_next = pcr; } template <typename T> void Link<T>::insertTail(T val) { Node<T> *pcr = new Node<T>(val); Node<T> *p = _head; while(p->_next != NULL) { p = p->_next; } p->_next = pcr; } template <typename T> void Link<T>::deleteNode( T val) { Node *pcr = _head; while(pcr->_next != NULL) { if(pcr->_next->_data == val) { Node *p = pcr->_next; pcr->_next = p->_next; delete p; return; } pcr = pcr->_next; } } #if 0 template <typename T> void Link<T>::inverse() //單鏈表的逆置-->最簡單的方法,利用頭插法,進行逆置。 { if(_head->_next==NULL || _head->_next->_next==NULL) { return ; } Node *pcr = _head->_next;; _head->_next = NULL; while(pcr!=NULL) { insertHead(pcr->_data); pcr = pcr->_next; } } #endif template <typename T> void Link<T>::inverse() //利用前後指標,來逆置(稍微麻煩) { if(_head->_next==NULL || _head->_next->_next==NULL) { return ; } Node *after = _head->_next; Node *front = _head; front->_next = NULL; while(after != NULL) { front = after; after = after->_next; front->_next = _head->_next; _head->_next = front; } } template <typename T> Node<T>* Link<T>::Search(T val) { Node<T>* p = _head->_next; while(p != NULL) { if(p->_data == val) { return p; } p = p->_next; } return NULL; } //------------------------------單鏈表的相關經典問題--------------------------------------- //給定單鏈表,檢測是否有環。 template <typename T> Node<T>* Link<T>::IsExitsLoop() //利用快慢指標進行解析。 { Node<T> *fast = _head; Node<T> *slow = _head; while(fast != NULL && fast->_next != NULL) { slow = slow->_next; fast = fast->_next->_next; if(slow == fast) { break; } } if(fast==NULL || fast->_next ==NULL) { return NULL; } else { return fast; } } //給定兩個單鏈表(head1, head2),檢測兩個連結串列是否有交點,如果有返回第一個交點。 template <typename T> Node<T>* Link<T>::intersection (Link<T> list2) { Node<T> *p = _head->_next; while(p->_next != NULL) { p=p->_next; } p->_next = list2._head->_next; Node<T> *tmp = IsExitsLoop(); if(tmp != NULL)//有交點 { return tmp->_next; } else { return NULL; } } //只給定單鏈表中某個結點p(並非最後一個結點,即p->next!=NULL)指標,刪除該結點。 template <typename T> void Link<T>::deleteNode(Node<T>* p) { Node<T>* q = p->_next; p->_data = q->_data; p->_next = q->_next; delete q; q= NULL; } //只給定單鏈表中某個結點p(非空結點),在p前面插入一個結點 template <typename T> void Link<T>::insertNode(Node<T>* p,T val) { Node<T>* q = new Node<T>(val); q->_next = p->_next ; p->_next = q; q->_data = p->_data; p->_data = val; } ////已知遞增有序的單鏈表 A,B 和C 分別儲存了一個集合,設計演算法實現 A:=A∪(B∩C) , //並使求解結構 A 仍保持遞增。要求演算法的時間複雜度為 O(|A|+|B|+|C|)。其中,|A|為集合A 的元素個數。 template <typename T> void Link<T>::merge(Link<T> list1,Link<T> list2) { Node<T>* p_list1 = list1._head->_next; Node<T>* p_list2 = list2._head->_next; Node<T>* p_head = _head; while(p_list1 != NULL || p_list2 != NULL ) { if(p_list1->_data > p_list2->_data) { p_list2 = p_list2->_next; } else if(p_list1->_data < p_list2->_data) { p_list1 = p_list1->_next; } else { while(p_head->_next != NULL) { if(p_head->_next->_data > p_list1->_data ) { insertNode(p_head->_next,p_list1->_data); } else if(p_head->_next->_data < p_list1->_data) { p_head = p_head->_next; } else { p_head = p_head->_next; break; } } p_head->_next = new Node<T>(p_list1->_data); p_list2 = p_list2->_next; p_list1 = p_list1->_next; } } } int main() { Link<int> list; /*list.insertHead(1); list.insertHead(2); list.insertHead(3); list.insertHead(4);*/ list.insertTail(1); list.insertTail(3); list.insertTail(5); list.insertTail(7); list.show(); Link<int> list1; list1.insertTail(3); list1.insertTail(4); list1.insertTail(5); list1.insertTail(7); list1.insertTail(8); Link<int> list2; list2.insertTail(2); list2.insertTail(3); list2.insertTail(5); list2.insertTail(6); list2.insertTail(7); list2.insertTail(8); list.merge(list1,list2); list.show(); /*Node<int>* p = list.intersection(list1); if(p != NULL ) { list.show1(p); } list.show();*/ /*list.inverse(); list.show();*/ /*list.deleteNode(4); list.show();*/ //Node<int>* p = list.Search(4); //list.show1(p); //Node<int>* q = list.Search(1); //list.deleteNode(q); //list.insertNode(q,0); //list.show(); //list.show1(q); //p->_next = q; /* Node<int> *s; if(s = list.IsExitsLoop()) { cout<<"該連結串列有環"<<endl; } else { cout<<"該連結串列無環"<<endl; } list.show1(s);*/ }