本章主要内容如下:
* 带头结点的链表反转
* 不带头结点的链表反转
* 链表有环
1、 带头结点的链表反转
思路:遍历每个节点,将其插入到头结点跟第一个节点之间,使其成为新的第一节点,其他的相应后移,即可实现。复杂度O(n)
#include<stdio.h>
#include<stdlib.h>
struct ListNode
{
int data;
struct ListNode *next;
};
void Reverse(ListNode *pHead)
{
ListNode *pCurrent = pHead->next;
ListNode *pNext = NULL;
pHead->next = NULL;
while(pCurrent)
{
pNext = pCurrent->next;
pCurrent->next = pHead->next;
pHead->next = pCurrent;
pCurrent = pNext;
}
}
int main()
{
ListNode *pList = (ListNode*)malloc(sizeof(ListNode));
ListNode *pCurrent = pList;
pCurrent->data = 0xffffffff;
for(int i=0; i<10; i++)
{
ListNode *q =(ListNode*)malloc(sizeof(ListNode));
q->data = i;
pCurrent->next = q;
pCurrent = q;
printf("%d, ", pCurrent->data);
}
printf("\n");
pCurrent->next = NULL;
Reverse(pList);
pCurrent = pList->next;
while(pCurrent)
{
printf("%d, ", pCurrent->data);
ListNode *p = pCurrent;
pCurrent = pCurrent->next;
free(p);
}
free(pList);
return 0;
}
2、 不带头结点的链表反转
#include<stdio.h>
#include<stdlib.h>
struct ListNode
{
int data;
struct ListNode *next;
};
void Reverse(ListNode *&pHead)
{
ListNode *pCurrent = pHead;
ListNode *pPrev = NULL;
ListNode *pNext = NULL;
while (pCurrent)
{
pNext = pCurrent->next;
pCurrent->next = pPrev;
pPrev = pCurrent;
pCurrent = pNext;
}
pHead = pPrev;
}
int main()
{
ListNode *pList = (ListNode*)malloc(sizeof(ListNode));
ListNode *pCurrent = pList;
pCurrent->data = 0;
for(int i=1; i<10; i++)
{
ListNode *q =(ListNode*)malloc(sizeof(ListNode));
q->data = i;
pCurrent->next = q;
pCurrent = q;
}
pCurrent->next = NULL;
Reverse(pList);
pCurrent = pList;
while(pCurrent)
{
printf("%d, ", pCurrent->data);
ListNode *p = pCurrent;
pCurrent = pCurrent->next;
free(p);
}
return 0;
}
3、 链表有环
3.1如何判断有环?
方法:快慢指针,采用2个指针不同步数(步数小的每次1步,步数大的每次2步),步数大的如果能够与步数小的相遇则必然存在环。
bool hasCircle(ListNode *pHead)
{
ListNode *slow = pHead;
ListNode *fast = pHead;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
break;
}
return !(fast==NULL || fast->next==NULL);
}
3.2 如何查找环的的入口节点
假设,当二者此一次相遇时,其走过的路程关系是2*(a+b)=a+(b+c)*n+b, 其中n为快指针在环内转的圈数,则a=(b+c)*n-b.
这样,一个指针从头开始,另一个指针从相遇点开始,步长为1进行移动,二者的相遇点即是环的入口点
ListNode *findCircleIn(ListNode *pHead)
{
ListNode *slow = pHead;
ListNode *fast = pHead;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
break;
}
if (fast == NULL || fast->next == NULL)
return NULL;
slow = pHead;
while (slow != fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
3.3 计算环的长度
找到环的入口节点后,从入口节点遍历,再次回到入口节点,即可计算出环的长度
int findCircleIn(ListNode *pHead)
{
ListNode *slow = pHead;
ListNode *fast = pHead;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
break;
}
if (fast == NULL || fast->next == NULL)
return 0;
slow = pHead;
while (slow != fast)
{
slow = slow->next;
fast = fast->next;
}
ListNode *p = slow->next;
int length = 1;
while (p != slow)
{
length++;
p = p->next;
}
return length;
}
4、两个单链表是否相交
http://blog.163.com/bbluesnow@126/blog/static/27784545201251051156817/