求两个单链表的第一个交点(人搜)

/*************************************************************
 * file:find_common_node_of_two_lists.c
 * brief:找个两个单链表的第一个交点
 * yejing@2015.1.20    1.0      creat
 *************************************************************/
 #include <stdio.h>
 #include <stdlib.h>
 
 typedef struct __node_t{
	struct __node_t* next;
	int              value;
 }node_t
 
 //获取从头开始的两个不同速指针第一次交汇的节点,没有返回NULL
 node_t* get_cross_node(node_t* phead){
	if(!phead)
		return NULL;
	node_t *one_step, *two_step;
	one_step = two_step = phead;
	while(two_step && one_step->next){
		one_step = one_step->next;
		two_step = two_step->next->next;
		if(one_step == two_step)
			return one_step;
	}
	
	return NULL;
 }
 
 //通过判断尾节点是否相等判断两个链表是否交叉,如果交叉返回长度差并标示那个比较长
 int check_no_circle_lists_crossed(node_t* phead_1, node_t* phead_2, int* diff_len, int* bigger_one, node_t* mark){
	if(!phead_1 || !phead_2 || is_crossed)
		return;
	node_t *tmp1, *tmp2;
	int count1 = 1, count2 = 1;
	tmp1 = phead1;
	tmp2 = phead2;
	while(tmp1->next != mark){
		++count1; tmp1 = tmp1->next;
	}
	while(tmp2->next != mark){
		++count2; tmp2 = tmp2->next;
	}
	
	if(tmp2 == tmp1){
		if(count2 <= count1){
			*diff_len = count1 - count2;
			*bigger_one = 1;
		}
		else{
			*diff_len = count2 - count1;
			*bigger_one = 2;
		}
		return 1;
	}
	
	return 0;
	
 }
 
 /*
 返回NULL表示没有交点的情况
 */
 node_t* process(node_t* phead_1, node_t* phead_2){
	if(!phead_1 || !phead_2)
		return NULL;
		
	int diff_len = 0, bigger_one = 0;
	node_t *meet_node1, *meet_node2;
	node_t *tmp1, tmp2;
	meet_node1 = get_cross_node(phead_1);
	meet_node2 = get_cross_node(phead_2);
		
	//因为是单链表,所以不可能出现一个有环一个无环还相交的情况
	if((meet_node1 && !meet_node2)||(!meet_node1 && meet_node2))
	   return NULL;
	//两个都无环
	else if(!meet_node1 && !meet_node2){
		//两个无环单链表如果相交,最后一个节点一定相等。
		//另外一个办法是将一个头接到另外一个尾上看是不是有环,判断方法与上面类似
		if(check_no_circle_lists_crossed(phead_1, phead_2, &diff_len, &bigger_one, NULL)){
			//消除两个链表的长度差
			tmp1 = phead_1; tmp2 = phead_2;
			if(1 == bigger_one)
				while(diff_len-- > 0 && tmp1->next)
					tmp1 = tmp1->next;
			else
				while(diff_len-- > 0 && tmp2->next)
					tmp2 = tmp2->next;
			
			while(tmp1 && tmp2){
					if(tmp1 == phead2)
						return phead1;
					tmp1 = tmp1->next;
					tmp2 = tmp2->next;
				}
		}
		else
			return NULL;
	}
	//两个链表都有环,如果交叉,则环必定是公共环,入口也必定是一个
	else{
		/*先求入环口,而需要先明确的是:
		1,重合的时候two_step的路程一定是one_step的两倍。
		2,一旦one_step进入环内,无论如何two_step一定能在一圈之内追上它。
		假设从起始点到入环口路程为x,截止相遇时在环内走过y,一圈为m,two在圈中走了n次
		则2(x+y) = x + y + m.n,即 x + y = m.n,即x+y一定是圈的整数倍。
		所以从x开始再走y的路程,就是入口,同时也是起点到入口的距离。
		如果同时走,当二者相等时就是入口
		*/
		node_t* circle_enter1 = phead_1;
		node_t* circle_enter2 = phead_2;
		while(meet_node1 && circle_enter1)
		{
			if(meet_node1 == circle_enter1)
				break;
			meet_node1 = meet_node1->next;
			circle_enter1 = circle_enter1->next;
		}
		while(meet_node2 && circle_enter2)
		{
			if(meet_node2 == circle_enter2)
				break;
			meet_node2 = meet_node2->next;
			circle_enter2 = circle_enter2->next;
		}
		
		if(circle_enter2 == circle_enter1){
			//两种情况,1,环入口是第一个的公共点,2,在入环之前就已经重合了
			//这里可以先用上满没有环的判断办法计算交点
			if(check_no_circle_lists_crossed(phead_1, phead_2, &diff_len, &bigger_one, circle_enter2)){
				//消除两个链表的长度差
				tmp1 = phead_1; tmp2 = phead_2;
				if(1 == bigger_one)
					while(diff_len-- > 0 && tmp1->next)
						tmp1 = tmp1->next;
				else
					while(diff_len-- > 0 && tmp2->next)
						tmp2 = tmp2->next;
				
				while(tmp1 && tmp2){
						if(tmp1 == phead2)
							return phead1;
						tmp1 = tmp1->next;
						tmp2 = tmp2->next;
				}
			}
			else//在环入口之前没有交点,返回环入口点
				return circle_enter1;
			
		}
		else
			return NULL;//两个环不相交
		
	}
	return NULL;
 }
 
 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
#include <stdio.h> #include <stdlib.h> //定义链表结构体 struct Node { int data; struct Node *next; }; //创建链表函数 struct Node *createList(int n) { struct Node *head, *p, *q; int i, num; head = (struct Node *)malloc(sizeof(struct Node)); head->next = NULL; q = head; for (i = 0; i < n; i++) { printf("请输入第%d个节点的值:", i + 1); scanf("%d", &num); p = (struct Node *)malloc(sizeof(struct Node)); p->data = num; p->next = NULL; q->next = p; q = p; } return head; } //输出链表函数 void printList(struct Node *head) { struct Node *p; p = head->next; while (p != NULL) { printf("%d ", p->data); p = p->next; } printf("\n"); } //逆置链表函数 void reverseList(struct Node *head) { struct Node *p, *q, *r; p = head->next; q = NULL; while (p != NULL) { r = p->next; p->next = q; q = p; p = r; } head->next = q; } //找中间节点函数 struct Node *findMiddleNode(struct Node *head) { struct Node *p, *q; p = head->next; q = head->next; while (q != NULL && q->next != NULL) { p = p->next; q = q->next->next; } return p; } //找倒数第k个节点函数 struct Node *findKthNode(struct Node *head, int k) { struct Node *p, *q; p = head->next; q = head->next; while (k > 0 && q != NULL) { q = q->next; k--; } if (k > 0) return NULL; while (q != NULL) { p = p->next; q = q->next; } return p; } //删除倒数第k个节点函数 void deleteKthNode(struct Node *head, int k) { struct Node *p, *q; p = head; q = head->next; while (k > 0 && q != NULL) { p = q; q = q->next; k--; } if (k > 0) return; p->next = q->next; free(q); } //判断链表是否有环函数 int hasCycle(struct Node *head) { struct Node *p, *q; p = head; q = head; while (q != NULL && q->next != NULL) { p = p->next; q = q->next->next; if (p == q) return 1; } return 0; } //找出环的交点函数 struct Node *findCycleNode(struct Node *head) { struct Node *p, *q; int flag = 0; p = head; q = head; while (q != NULL && q->next != NULL) { p = p->next; q = q->next->next; if (p == q) { flag = 1; break; } } if (flag == 0) return NULL; p = head; while (p != q) { p = p->next; q = q->next; } return p; } //判断两个单链表是否相交函数 int isIntersect(struct Node *head1, struct Node *head2) { struct Node *p, *q; p = head1; q = head2; while (p->next != NULL) { p = p->next; } while (q->next != NULL) { q = q->next; } if (p == q) return 1; else return 0; } int main() { struct Node *head1, *head2, *p; int n, k; printf("请输入链表1的节点个数:"); scanf("%d", &n); head1 = createList(n); printf("链表1为:"); printList(head1); reverseList(head1); printf("逆置后的链表1为:"); printList(head1); p = findMiddleNode(head1); printf("链表1的中间节点为:%d\n", p->data); printf("请输入链表1的倒数第k个节点:"); scanf("%d", &k); p = findKthNode(head1, k); printf("链表1的倒数第%d个节点为:%d\n", k, p->data); deleteKthNode(head1, k); printf("删除倒数第%d个节点后的链表1为:", k); printList(head1); if (hasCycle(head1)) { p = findCycleNode(head1); printf("链表1有环,环的交点为:%d\n", p->data); } else { printf("链表1没有环\n"); } printf("请输入链表2的节点个数:"); scanf("%d", &n); head2 = createList(n); printf("链表2为:"); printList(head2); if (isIntersect(head1, head2)) { printf("链表1和链表2相交\n"); p = findCycleNode(head1); printf("链表1和链表2的交点为:%d\n", p->data); } else { printf("链表1和链表2不相交\n"); } return 0; }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值