请参照书P233-235.
这道题让我联想起几道关于单向链表的经典题目:
- 如果判断一个单项链表是否存在环?
- 已知一个单向链表存在环,如果找出该环的入口点?
- 已知两个链表相交,如何找出相交的第一个节点?
- 如果对一个单向链表进行反转?
- 已知一个单向链表,不知道该链表的头指针,已知一个节点的指针,如何将该节点从链表中删除?
题1:设置两个指针(p1, p2),初始值都指向头,p1每次前进一步,p2每次前进二步,如果链表存在环,则p2先进入环, p1后进入环,两个指针在环中走动,必定相遇。
题2:根据题1的结果,假定链表长为L,环长为c,链表头到入口点距离为x,入口点到相遇点的距离为y,z为相遇点回到入口点的距离。
L=x+y+z
假定p1,p2指针相遇时,p2指针在环中走了n圈,则有
x+y=nc
所以,x=nc-y=(n-1)c+(L-x)-y=(n-1)c+z
由公式得出:将p1指向表头,p2指向相遇点,p1,p2同时一步一步前进,当p1前进x步时,p1刚好在入口点,p2在前进了n-1个环后,也回到入口点,这时两个指针指向同一个节点,该节点就是入口点。
题3:题跟题2一样,可以将一个链表的尾节点指向另外一个,这样就问题2一样的解法了。当然,完成时,记得把指针重新置空。
另外一个办法,就是分别计算出两个链表的长度,分别为maxL,minL,分别设置指针p1,p2指向两个链表,p1指针指向长链表,p1先前进maxL-minL的距离,然后两个指针同时前进,当p1和p2指向同一个节点时,该节点即为相交的第一个节点,如果没有找到,就表示这两个链表不相交
题4:
解法一:可以设置三个指针,pre,cur,next,pre
node *pre=NULL;
node *next=NULL;
node *cur=head;
while(!cur)
{
next=cur->next;
cur->next=pre;
pre=cur;
cur=next;
}
解法二:使用递归
node *newRoot;
node *reverseNode(node *cur)
{
if(!cur || !cur.next)
{
newRoot=root;
return cur;
}
node *tmp= reverseNode(cur->next);
tmp->next=cur;
return cur;
}
题5:因为不知道链表的头指针,因此当前节点(B)如果被删除,链表将断裂,因此可以用一个指针指向当前节点(B)的下一个节点(C),然后将下一个节点复制到当前节点,这样当前节点数据就为下一个节点的数据了,而且指向了下下个节点,然后删除C节点。
附上《编程之美》该题的三页: