單鏈表的實現(給定某結點,刪除它;給定某結點,在他前面插入一個結點等)
阿新 • • 發佈:2019-02-09
基於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);*/
}