求单链表的中间节点

            偶数个节点时返回中间两个节点的前一个

我们可以这样考虑,设想两个人跑步,一个人的速度是另外一个人的两倍,当速度快的人到达了终点,速度慢的人就在赛程的正中间。同样地,我们设置两个游动的指针,慢的指针移动步长为1,快的指针移动的步长为2。一开始都指向链表的头部,当遍历开始时,进行这样的操作:如果快的指针可以向前移动两步并且没有到达链表的尾部的话,快指针就向前移动2个节点,同时慢的指针向前移动1个节点;否则退出,返回慢指针。该算法的实现如下,注意区别链表长度为偶数和奇数的情况:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <iostream.h>
struct ListNode
{
	int data;
	ListNode* next;
};
void InitList(ListNode** head)
{
	*head = (ListNode*)malloc(sizeof(ListNode));
	(*head)->next = NULL;
}
void InsertList(ListNode* head,int d)
{
	assert(head!=NULL);
	ListNode* pNewNode = (ListNode*)malloc(sizeof(ListNode));
	pNewNode->data = d;
	pNewNode->next = head->next;
	head->next = pNewNode;
}
void PrintList(ListNode* head)
{
	if(head == NULL)
	{
		return ;
	}
	ListNode* Next = head->next;
	while(Next!=NULL)
	{
		cout<<Next->data<<endl;
		Next = Next->next;
	}
}
/*
	查找中间结点核心代码
*/
ListNode* FindMidFront(ListNode* head)
{
	if(NULL == head || NULL == head->next)
        return head;
    //ListNode* p1 = head;
    //ListNode* p2 = head;
	/*
	因为我自己实现的链表,头结点没有放数据,所以要从下一个开始。
	如果,头结点有数据,则直接从头结点开始就可以。
	*/
    ListNode* p1 = head->next;
    ListNode* p2 = head->next;
    while(NULL != p2->next && NULL != p2->next->next)
    {
        p1 = p1->next;
        p2 = p2->next->next;
		//cout<<"p1->data="<<p1->data<<endl;仅仅是为了测试
		//cout<<"p2->data="<<p2->data<<endl;
    }
    return p1;
}


int main()
{
	ListNode* pListHead = NULL;
	InitList(&pListHead);
	for(int i=8;i>=0;i--)
	{
		InsertList(pListHead,i);
	}
	ListNode* mid= FindMidFront(pListHead);
	cout<<"链表中的元素为:"<<endl;
	PrintList(pListHead);
	cout<<"中间结间是"<<mid->data<<endl;
	return 0;
}


           偶数个节点时返回中间两个节点的后一个

上面的算法中的循环需要稍微调整一下。前面的算法中,快指针p2每次都移动2步,而本问题中,我们需要改变下策略,变成:只要快指针p2能向前移动一步,那么快指针和慢指针就都同时向前移动一步,再看看快指针是否还能补上一步,如果能补上一步,那么就补上,然后进行下一轮循环,否则就表示到达了链表尾部,返回慢指针即可。实现如下

ListNode* FindMidAfter(ListNode* head)
{
    if(NULL == head || NULL == head->next)
        return head;
    //ListNode* p1 = head;
    //ListNode* p2 = head;
	ListNode* p1 = head->next;
    ListNode* p2 = head->next;
    while(NULL != p2->next)
    {
        p2 = p2->next;
        p1 = p1->next;
        if(NULL == p2->next)
            return p1;
        else
            p2 = p2->next;
    }
    return p1;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值