一、题目简述
给定单链表的头结点 head ,找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
例如:
返回值为5的节点。
返回值为2的节点
二、题目分析
链表不像数组一样,在开始时并不知道链表节点的个数。若要计算出链表节点个数,只能将链表遍历一遍;计算出链表size大小后,又要遍历链表到size/2的位置,这样一来太过于麻烦。
采用快慢指针的方法便可以很方便的找到中间节点。慢指针slow走一步,快指针fast走两步。当fast走完整个链表时,slow只走了fast的路程的一半,即为链表的中间节点位置。
当然还有许多要注意的问题,在循环遍历链表时,链表节点个数是奇数还是偶数对于循环的停止条件要求有所不同。
例如:
当节点个数为奇数时
slow已将走到中间节点位置,但fast还不为NULL,还要继续向后走,便会造成NULL指针的访问。所以此时while的条件应该为while(fast->next)
当节点个数为偶数时
slow节点走到中间位置,fast为空,此时while循环条件为while(fast)
三、代码分析
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
}
基于两种情况,while的判断条件应该为while(fast&&fast->next)
fast先判断,如果fast为NULL,说明节点为奇数个,fast为假,逻辑与右边便不再判断。fast->next为NULL,说明节点数为奇数。
在逻辑与运算中,因为左右表达式都为true,整个表达式才为true;若左边表达式为false,那么整个表达式已经为fasle,右边表达式也不会被计算判断,所以fast必须要在逻辑与左边,避免空指针的解引用。
最后返回slow所在节点即可。
四、完整代码
struct ListNode* middleNode(struct ListNode* head) {
struct ListNode* slow=head;//慢指针
struct ListNode* fast=head;//快指针
while(fast&&fast->next)//注意条件的判断,避免NULL的引用
{
slow=slow->next;//slow走一步
fast=fast->next->next;//fast走两步
}
return slow;
}