您的位置:首页 > 职场人生

程序员编程艺术--->6、关于链表的追赶问题

2014-02-22 21:22 357 查看
本章主要涉及链表的相关检测问题,诸如:


链表的倒数第k个结点
检测链表是否带环
两链表是否相交

而此类问题,如果用直观的想法去做的话,无疑时间复杂度不太可观,因此可以继续寻求更加的解决方案。下面就这些问题展开来谈。

1、求链表的倒数第k个结点

解析:(1)两次遍历链表,第一次求出链表的长度,第二次找出n-k个结点,便是倒数第k个结点。

(2)既然要尔链表的倒数第k 个结点,那么是不是可以用两个指向该链表的指针,让它们保持k的距离遍历链表呢?当然可以,那么在前的指针到达末尾的时候,后面的指针便是指向倒数第k个结点。这样的话,只需要遍历一次链表

追赶之一。

代码如下:

Node * GetKNode(int k)
{
Node *first = NULL, *second = NULL;
first = second = head;
int count = 0;
while(count<k-1)
{
first = first->next;
count++;
}
while(first->next!=NULL)
{
first = first->next;
second = second->next;
}
return second;

}


2、检测单链表是否带环

解析:其实这个问题也是一个两指针遍历链表时的追赶问题。p1,p2同时遍历链表,并且p2的速度是p1的两倍,如果链表不带环的话,p1肯定是追赶不上p2的,那如果二者能相遇,则必须存在环呀。

Node *IsCircled(Node *head)
{
Node *fast = head, *slow = head;
while(fast!=NULL && slow!= NULL)
{
if(fast == slow)
return fast;
fast = fast->next->next;
slow = slow->next;
}
return NULL;
}


3、检测两单链表是否相交

解析:1,假设链表无环的情况,如何判断相交呢?

(1)最直观的方法,分别遍历两链表上的结点,看其是否在另外一条链表中。那么最坏的情况下时间复杂度为O(length1 * length2).

(2)将第二个链表接在第一个链表后面,如果得到的链表有环,则说明一定相交

(3)如果两个链表相交,则在它们的第一个交点到尾节点都是公共的。那么只需要判断它们的最后一个结点是否相同就可以啦。这样时间复杂度降到了O(length1 + length2)。

2、如果链表有环的情况

(1)一条有环,一条无环,则不可能相交

(2)两条都有环,则判断带环链表的连接点(即,上面提到的快慢两指针第一次相遇的那个结点)是否也在另外一条链表上。

因此,判断链表是否相交:

判断链表是否带环,若都不带环,则判断它们的尾结点是否相同;若都带环,则判断其中一条带环链表的连接点是否也在另一条上。

Node *IsCircled(Node *head)
{
Node *fast = head, *slow = head;
while(fast!=NULL && slow!= NULL)
{
if(fast == slow)
return fast;
fast = fast->next->next;
slow = slow->next;
}
return NULL;
}

bool CheckCrossing(Node *head1, Node *head2)
{
Node *p1 = head1, *p2 = head2;
Node *CrossingNode1 = IsCircled(head1);
Node *CrossingNode2 = IsCircled(head2);
if(!CrossingNode1 && !CrossingNode2)//无环
{
while(p1->next)
p1 = p1->next;
while(p2->next)
p2 = p2->next;
if(p1 == p2)
return true;
else
return false;
}
else if(CrossingNode2 && CrossingNode1)//都有环
{
while(head2)
{
if(CrossingNode1 == head2)
return true;
head2 = head2->next;
}
}
else
return false;
}


4、求两链表相交的第一个交点

解析:记录两个链表的长度length1 , length2, 会发现二者之差为m, 那么让指向长链表的指针先行m 步,然后指向短链表的指针再和它一起同时往前走,并进行比较,发现第一个相同的结点便是它们的交点。

思考题:

题目描述:

在一条左右水平放置的直线轨道上任选两个点,放置两个机器人,请用如下指令系统为机器人设计控制程序,使这两个机器人能够在直线轨道上相遇。(注意两个机器人用你写的同一个程序来控制)

指令系统:只包含4条指令,向左、向右、条件判定、无条件跳转。其中向左(右)指令每次能控制机器人向左(右)移动一步;条件判定指令能对机器人所在的位置进行条件测试,测试结果是如果对方机器人曾经到过这里就返回true,否则返回false;无条件跳转,类似汇编里面的跳转,可以跳转到任何地方。

解析:这也同样是链表的追赶问题。机器人A和B,B在A的前面,如果A和B一直保持相同的速度往前走,那么它们永远也不会相遇的。但是如果A一但到达B曾经走过的点,那么马上提速至原来的两倍,那么肯定可以在{AB}/move_right个单位内追上B.


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: