先给出几个要用的函数。
1.Begin():
Node* Begin(pNode pHead)
{
return pHead;
}
2.End():
Node* End(pNode pHead)
{
pNode pCur = pHead;
if(!pCur)
{
return NULL;
}
while(pCur->_pNext)
{
pCur = pCur->_pNext;
}
return pCur;
}
3.Length():
size_t Length(pNode pHead)
{
if(!pHead)
return 0;
size_t count = 0;
while(pHead->_pNext)
{
count++;
pHead = pHead->_pNext;
}
return count;
}
4.Print():
void print(pNode pHead)
{
Node* pCur = pHead;
while(pCur)
{
cout<<pCur->_or<<" ";
pCur = pCur->_pNext;
}
cout<<endl;
}
5.删除无头单链表
(1)先将要删除结点(pCur)的下一个节点(pNext)值赋过去。
(2)将pCur的下一个节点连接到pNext的下一个节点,pCur->next = pNext->next。
(3)删除pNext即可。
先将pCur的值覆盖,再删除pCur的下一个节点。实际上释放的并不是pCur的空间。
void DeleteNotTaileNode(pNode pCur)
{
pNode pNext = pCur->_pNext;
pCur->_or = pNext->_or;
pCur->_pNext = pNext->_pNext;
free(pNext);
pNext = NULL;
}
1.判断链表是否带环。
(1)定义两个指针fast和slow,fast每次走两个,slow每次走一个;
如果带环,fast总会与slow相遇, 返回相遇点。
如果不带环,那fast总会为空。
pNode IsCircle(pNode pHead)
{
pNode fast = pHead;
pNode slow = pHead;
//如果不带环,那么fast一定会走到空。
while(fast && fast->_pNext)
{
fast = fast->_pNext->_pNext;
slow = slow->_pNext;
if(fast == slow)
return fast;
}
return NULL;
}
2.如果链表带环,求出环的长度。
如果链表带环,从相遇点走一圈,就能计算出len。
size_t GetCircleLen(pNode pMeetNode)
{
pNode pNode = pMeetNode;
size_t count = 1;
while(pNode->_pNext != pMeetNode)
{
count++;
pNode = pNode->_pNext;
}
return count;
}
3.如果带环,求出环的入口点。
pNode EnterCircleNode(pNode pHead, pNode pMeetNode)
{
if(!pMeetNode)
return NULL;
pNode pFirst = pHead;
pNode pSecond = pMeetNode;
while(pFirst != pSecond)
{
pFirst = pFirst->_pNext;
pSecond = pSecond->_pNext;
}
return pFirst;
}
4.判断两个不带环的链表是否相交。
bool IsIntersect(pNode pHead1, pNode pHead2)
{
//两个链表相交,则最后一个节点一定相等。
//所以只需判断最后一个节点是否相等即可。
if(!pHead1 || !pHead2)
return false;
pNode pEndNode1 = End(pHead1);
pNode pEndNode2 = End(pHead2);
if(pEndNode1 == pEndNode2)
return true;
return false;
}
5.如果不带环的链表相交,则求出交点。
(1)计算链条链表的长度。
(2)让较长的链表先向下移动,直到两条链表长度相等。
(3)让两条链表同时向下移动,直到链表为空,判断链表是否相等。
若相等则返回该节点;
若不相等则返回NULL。
pNode IntersectNode(pNode pHead1, pNode pHead2)
{
if(!IsIntersect(pHead1, pHead2))
return NULL;
size_t len1 = Length(pHead1);
size_t len2 = Length(pHead2);
pNode pCur1 = pHead1;
pNode pCur2 = pHead2;
int gas = len1 - len2;
while(gas > 0)
{
//表明pHead1比pHead2长。
pCur1 = pCur1->_pNext;
gas--;
}
while(gas < 0)
{
//表明pHead2比pHead1长。
pCur2 = pCur2->_pNext;
gas++;
}
while(pCur1 && pCur2)
{
if(pCur1 == pCur2)
return pCur1;
pCur1 = pCur1->_pNext;
pCur2 = pCur2->_pNext;
}
return NULL;
}
6.判断两个链表是否相交(可能带环)。
(1)判断两个链表是否带环,若不带环则调用上面函数进行处理;
若带环则进行下面步骤。
(2)获取到两个链表的相遇点 。
(3)让其中一个相遇点在环中移动,判断和另一个相遇点是否相等。若相等则两个带环链表相交,若不相等则不相交。
bool IsIntersectWithCircle(pNode pHead1, pNode pHead2)
{
//两个链表相交,则最后一个节点一定相等。
if(!pHead1 || !pHead2)
return false;
pNode pMeet1 = IsCircle(pHead1);
pNode pMeet2 = IsCircle(pHead2);
if(!pMeet1 && !pMeet2)
return IsIntersect(pHead1, pHead2);
while(pMeet1)
{
if(pMeet1 == pMeet2)
return true;
pMeet1 = pMeet1->_pNext;
}
return false;
}
7.判断两个链表的交点(可能带环)
pNode IntersectNodeWithCircle(pNode pHead1, pNode pHead2)
{
//如果两个链表没有相交,则返回NULL;
if(!IsIntersectWithCircle(pHead1, pHead2))
return NULL;
pNode pMeet1 = IsCircle(pHead1);
pNode pMeet2 = IsCircle(pHead2);
if(!pMeet1 && !pMeet2)
return IntersectNode(pHead1, pHead2);
//如果相交了,先判断入口点是否相同
pNode EnterNode1 = EnterCircleNode(pHead1, pMeet1);
pNode EnterNode2 = EnterCircleNode(pHead2, pMeet2);
//入口点相同,为环外相交,存在一个交点
//入口点不同,为环内相交,整个环都是交点
if(EnterNode1 == EnterNode2)
{
//环内相交,将入口点与pHead2的头结点连起来,
//重新形成一个带环链表,交点就是环的入口点.
EnterNode1->_pNext = pHead2;
pNode NewMeet = IsCircle(pHead1);
pNode NewEnterNode = EnterCircleNode(pHead1, NewMeet);
return NewEnterNode;
}
return NULL;
}
测试:
void FunTest()
{
int arr1[]={1,18,6,72,9,43,27,0};
int arr2[]={0,4,7};
int i = 0;
Node* pHead1;
Init(&pHead1);
//Node* pHead2;
//Init(&pHead2);
for(;i<sizeof(arr1)/sizeof(arr1[0]); i++)
{
Insert(&pHead1, arr1[i]);
}
print(pHead1);
//DeleteNotTaileNode(Select(pHead1, 9));
//print(pHead1);
/*测试两个带环链表是否相交
End(pHead1)->_pNext = Select(pHead1, 9);
for(i=0;i<sizeof(arr2)/sizeof(arr2[0]); i++)
{
Insert(&pHead2, arr2[i]);
}
End(pHead2)->_pNext = Select(pHead1, 6);
pNode Node = IntersectNodeWithCircle(pHead1, pHead2);
*/
/*测试链表是否带环,和环的入口点
End(pHead)->_pNext = Select(pHead, 9);
pNode pMeetNode = IsCircle(pHead);
int len = GetCircleLen(pMeetNode);
pNode pEnter = EnterCircleNode(pHead, pMeetNode);
*/
/*创建新链表
Node* pHead2;
Init(&pHead2);
for(i=0;i<sizeof(arr2)/sizeof(arr2[0]); i++)
{
Insert(&pHead2, arr2[i]);
}
*/
}