基于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);*/
}