数据结构 单链表相关习题2 (*包含求带环链表环的入口)

1.判断链表是否带环,带环返回1,不带换返回0

//判断链表是否带环,带环返回1,不带换返回0
int HasCycle(LinkNode* head)
{
	if(head == NULL)
	{
		//空链表
		return -1;
	}
	if(head->next == NULL)
	{
		return 0;
	}
	LinkNode* low = head;
	LinkNode* fast = head;
	while(fast != NULL && fast->next != NULL)
	{
		//快指针一次向后两步,慢指针一次向后移动一步,如果两支针相遇说明链表带环
		low = low->next;
		fast = fast->next->next;
		if(low == fast)
		{
			//表示快慢指针相遇,链表带环,返回1
			return 1;
		}
	}
	return 0;
}
//测试函数
void TestHasCycle()
{
	TITLE;
	LinkNode* head;
	LinkListInit(&head);
	LinkListPushBack(&head,'a');
	LinkListPushBack(&head,'b');
	LinkListPushBack(&head,'c');
	LinkListPushBack(&head,'d');
	LinkListPrint(head,"尾插4个元素,链表不带环");
	int ret = HasCycle(head);
	printf("expect is 0,actual is %d\n",ret);
	LinkListPushBack(&head,'e');
	LinkNode* D = LinkListFind(head,'d');
	LinkNode* E = LinkListFind(head,'e');
	LinkListPrint(head,"尾插一元素e并让e的next指向d,形成一个带环单链表");
	E->next = D;
	ret = HasCycle(head);
	printf("expect is 1,actual is %d\n",ret);
}

运行结果:


2.如果链表带环, 求出环的长度 

解题思路:我们通过快慢指针相遇来判定出链表是否带环。如果得知带环,我们把两指针相遇位置记录下来,并再次遍历环,直达在此遇到相遇点。此时我们就可以得到环的长度。

//如果链表带环, 求出环的长度 
size_t GetCycleLen(LinkNode* head)
{
    if(head == NULL)
    {   
        return 0;
    }   
    if(head->next == NULL)
    {   
        return 0;
    }   
    LinkNode* low = head;
    LinkNode* fast = head;
    while(fast != NULL && fast->next != NULL)
    {   
        //快指针一次向后两步,慢指针一次向后移动一步,如果两支针相遇说明链表带环
        low = low->next;
        fast = fast->next->next;
        if(low == fast)
        {   
            //表示快慢指针相遇,链表带环,此时跳出循环
            //low指针指向的即为相遇点
            break;
        }   
    }   
    LinkNode* cur = low->next;
    int i = 1;
    //遍历环一遍遇到相遇点结束,可得环的长度
    while(cur != low)
    {   
        i++;
        cur = cur->next;
    }   
    return i;
}
//测试函数
void TestGetCycleLen()
{
    TITLE;
    LinkNode* head;
    LinkListInit(&head);
    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'d');
    LinkListPushBack(&head,'e');
    LinkNode* D = LinkListFind(head,'d');
    LinkNode* E = LinkListFind(head,'e');
    LinkListPrint(head,"尾插5个元素,并让e的next指向d,形成一个带环单链表");
    E->next = D;
    int ret = GetCycleLen(head);
    printf("expect is 2,actual is %d\n",ret);
}

运行结果:

3.如果链表带环, 求出环的入口 

解析:


//如果链表带环求出环的入口 
LinkNode* GetCycleEntry(LinkNode* head)
{
    if(head == NULL)
    {
        //空链表
        return NULL;
    }
    if(head->next == NULL)
    {
        return 0;
    }
    LinkNode* low = head;
    LinkNode* fast = head;
    LinkNode* cur = head;
    LinkNode* meet = NULL;
    while(fast != NULL && fast->next != NULL)
    {
        //快指针一次向后两步,慢指针一次向后移动一步,如果两支针相遇说明链表带环
        low = low->next;
        fast = fast->next->next;
        if(low == fast)
        {
            //表示快慢指针相遇,链表带环,记录相遇点.并跳出循环
            meet = low;
            break;
        }
    }
    //当cur与相遇点的指针再次相遇时,即为环的入口点
    while(cur != meet)
    {
        meet = meet->next;
        cur = cur->next;
    }
    return meet;
}

测试函数:

void TestGetCycleEntry()
{
    TITLE;
    LinkNode* head;
    LinkListInit(&head);
    LinkListPushBack(&head,'a');
    LinkListPushBack(&head,'b');
    LinkListPushBack(&head,'c');
    LinkListPushBack(&head,'d');
    LinkListPushBack(&head,'e');
    LinkNode* D = LinkListFind(head,'d');
    LinkNode* E = LinkListFind(head,'e');
    LinkListPrint(head,"尾插5个元素,并让e的next指向d,形成一个带环单链表");
    E->next = D;
    LinkNode* ret = GetCycleEntry(head);
    printf("expect is d,actual is %c\n",ret->data);
}

运行结果:


猜你喜欢

转载自blog.csdn.net/ihaha233/article/details/80346371