程序1——判断链表是否有环,环的入口点,求环长

理论:

(来自网络,但原创已经无法追溯,一转载链接如下:http://blog.csdn.net/wuzhekai1985/article/details/6725263)


       若存在环,如何找到环的入口点(即上图中的结点E)?
       解答:如图中所示,设链起点到环入口点间的距离为x,环入口点到fast与low重合点的距离为y,又设在fast与low重合时fast已绕环n周(n>0),且此时low移动总长度为s,则fast移动总长度为2s,环的长度为r。则
        s + nr = 2s,n>0      ①
        s = x + y                 ②
       由①式得  s = nr                 
       代入②式得
       nr = x + y
       x = nr - y                ③
       现让一指针p从链表起点处开始遍历,指针q从encounter处开始遍历,且p和q移动步长均为1。则当p移动x步即到达环的入口点,由③式可知,此时q也已移动x步即nr - y步。由于q是从encounter处开始移动,故q移动nr步是移回到了encounter处,再退y步则是到了环的入口点。也即,当p1移动x步第一次到达环的入口点时,p2也恰好到达了该入口点。


无代码无真相

恳请各位指正批评。

#include "list.h"

plist encounter(plist head)
{
	plist fast, slow;
	if(head == NULL)
	{
		printf("list error\n");
		return 0;
	}
	fast = slow = head;
	while(fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;
		if(fast == slow)
		{
			return fast;
		}
	}

	return NULL;
}

plist get_encounter_node(plist head)
{
	plist p, q;
	p = head;
	q = encounter(head);
	if(q != NULL)
	{
		while(p != q)
		{
			p = p->next;
			q = q->next;
		}
	}
	return q;
}

int main()
{
	int i;
	plist head;
	plist p, q;
	plist new;
	plist enc;
	
	head = init_list();
	
	for(i = 0; i < 4; i++)
	{
		tail_insert(head, i);
	}
		
	p = head;
	while(p->next != NULL)
	{
		p = p->next;
	}
	//
	//create ring node
	new = (plist)malloc(sizeof(list));
	if(new == NULL)
	{
		printf("malloc error in %s line %d\n", __FUNCTION__, __LINE__);
	}
	new->data = 111;
	new->next = p->next;
	p->next = new;
	
	p = new;
	for(i = 0; i < 4; i++)
	{
		q = (plist)malloc(sizeof(list));
		if(new == NULL)
		{
			printf("malloc error in %s line %d\n", __FUNCTION__, __LINE__);
		}
		q->data = 2*i+1;
		q->next = p->next;
		p->next = q;
		p = q;
	}
	q->next = new;
	/
	enc = get_encounter_node(head);
	if(enc != NULL)
	{
		printf("Entry node is %d\n", enc->data);
	}
	else
	{
		printf("No ring\n");
	}

	free_ring_list(head, enc);

	return 0;
}

#ifndef _LIST_H_
#define _LIST_H_
#include <stdio.h>
#include <stdlib.h>

struct list
{
	int data;
	struct list *next;
};

typedef struct list list;
typedef struct list *plist;


plist init_list()
{
	plist head;
	head = (plist)malloc(sizeof(list));
	if(head == NULL)
	{
		printf("malloc error in init_list\n");
		return NULL;
	}
	head->data = 0;
	head->next = NULL;
	return head;
}

int head_insert(plist head, int d)
{
	plist p;
	if(head == NULL)
	{
		printf("list error in insert\n");
		return -1;
	}
	p = (plist)malloc(sizeof(list));
	if(p == NULL)
	{
		printf("malloc error in insert\n");
		return -1;
	}
	
	p->data = d;
	p->next = head->next;
	head->next = p;

	return 0;
}

int tail_insert(plist head, int d)
{
	plist p, q;
	if(head == NULL)
	{
		printf("list error in insert\n");
		return -1;
	}

	p = head;
	while(p->next != NULL)
	{
		p = p->next;
	}

	q = (plist)malloc(sizeof(list));
	if(q == NULL)
	{
		printf("malloc error in insert\n");
		return -1;
	}
	
	q->data = d;
	q->next = p->next;
	p->next = q;

	return 0;
}

void print_list(plist head)
{
	plist p = head->next;
	while(p)
	{
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

void free_list(plist head)
{
	plist p, q;
	p = head;
	while(p)
	{
		q = p->next;
		free(p);
		p = q;
	}
}

void free_ring_list(plist head, plist enc)
{
	plist p, q;
	p = head;
	int flag = 0;
	while(p)
	{
		if(p == enc)
		{
			if(flag == 0)
			{
				flag = 1;
			}
			else
			{
				return;
			}
		}
		q = p->next;
		free(p);
		p = q;
	}
}

#endif


update:

求环长

理论:

      从快慢指针的相遇点开始,指针每次走一步,如果再次到达相遇点就是一圈,这样就记录了环长。

无代码无真相:

int get_ring_len(plist head)
{
    int count = 0;
    plist p, enc;
    enc = encounter(head);
    p = enc->next;
    while(p != enc)
    {
        p = p->next;
        count++;
    }
    count++;
    return count;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值