zoukankan      html  css  js  c++  java
  • C语言强化(七)链表相交问题_5 找到两个有环链表的相交结点

    有环链表是否相交我们也可以判断了,剩下的就是获得有环链表相交结点


    题目

    给出俩个单向链表的头指针,比如 h1,h2,判断这俩个链表是否相交



    解题步骤

    1. 判断两个【无环】链表是否相交
    2. 找到两个【无环】链表的相交结点
    3. 判断链表是否带环
    4. 判断两个【有环】链表是否相交
    5. 找到两个【有环】链表的相交结点

    思路:
    显然,有环链表的相交点其实就是环的入口
    如图


    所以 问题转为求环的入口

    直接上理论,具体解释不难,纯粹是一道小学数学追赶问题

    若在头结点和快慢指针相遇结点分别设一指针,同步(单步)前进,则最后一定相遇在环入口结点

    关于快慢指针的介绍,请参考链表相交问题第三节


    创建函数:获得有环链表入口

    /*
    获得有环链表入口
    	若在头结点和相遇结点分别设一指针,同步(单步)前进,
    	则最后一定相遇在环入口结点
    */
    ListNode * getCircleListEnter(ListNode * head){
    	if(head==NULL)
    		return NULL;
    	ListNode * node = ifCircle(head);
    	if(node==NULL)
    		return NULL;
    	while(node!=NULL&&head!=NULL){
    		if(node==head)
    			return node;
    		node=node->nextNode;
    		head=head->nextNode;
    	}
    	return NULL;
    }
    

    源代码

    #include <stdio.h>
    #include<stdlib.h>
    #include <iostream>
    
    
    using namespace std;
    
    /**
    5.找到两个【有环】链表的相交结点
    思路
    	即找两个入口点
    	若在头结点和相遇结点分别设一指针,同步(单步)前进,
    	则最后一定相遇在环入口结点
    */
    
    /**
    链表结构体
    */
    struct ListNode{
    	int data;
    	ListNode * nextNode;
    	ListNode(ListNode * node,int value){
    		nextNode=node;
    		data=value;
    	}
    };
    
    ListNode * L1;
    ListNode * L2;
    
    /**
    判断链表是否有环
    node  链表头指针
    
    方法:用两个指针,一个指针步长为1,一个指针步长为2,若最后相遇,则链表有环
    有环 返回两指针相遇位置
    无环 返回NULL
    */
    ListNode * ifCircle(ListNode * node){
    	if(NULL==node)
    		return false;
    	ListNode * fast = node;
    	ListNode * slow = node;
    	while(NULL!=fast&&NULL!=fast->nextNode){
    		fast=fast->nextNode->nextNode;//步长为2
    		slow=slow->nextNode;//步长为1
    		if(fast==slow){
    			cout<<"链表有环"<<endl;
    			return fast;
    		}
    	}
    	cout<<"链表无环"<<endl;
    	return NULL;
    }
    
    /*判断结点是不是在链表上
    head  链表头
    node  结点
    */
    bool ifNodeOnList(ListNode * head,ListNode * node){
    
    	if(node==NULL)
    		return 0;
    	//为防止有环链表无限遍历,首先进行有无环判断
    	ListNode * circleNode = ifCircle(head);
    	int count = 0;//经过重复结点的次数
    	while(head!=NULL&&count<2){
    		if(head==node)
    			return 1;
    		if(head==circleNode)
    			count++;
    		head=head->nextNode;
    	}
    	return 0;
    }
    
    //判断有环链表是否相交
    bool ifCircleListCross(ListNode * L1,ListNode * L2){
    	ListNode * node = ifCircle(L1);
    	if(node!=NULL)
    		return ifNodeOnList(L2,node);
    	return 0;
    }
    
    /*
    获得有环链表入口
    	若在头结点和相遇结点分别设一指针,同步(单步)前进,
    	则最后一定相遇在环入口结点
    */
    ListNode * getCircleListEnter(ListNode * head){
    	if(head==NULL)
    		return NULL;
    	ListNode * node = ifCircle(head);
    	if(node==NULL)
    		return NULL;
    	while(node!=NULL&&head!=NULL){
    		if(node==head)
    			return node;
    		node=node->nextNode;
    		head=head->nextNode;
    	}
    	return NULL;
    }
    
    //创建有环链表
    ListNode * createCircleList(){
    	ListNode * node = new ListNode(NULL,0);
    	ListNode * enter = node;
    	node = new ListNode(node,1);
    	node = new ListNode(node,2);
    	enter->nextNode=node;
    	node = new ListNode(node,3);
    	node = new ListNode(node,4);
    	return node;
    }
    
    //创建有环链表相交
    void createCircleListCross(){
    	L1 = new ListNode(NULL,0);
    	ListNode * enter2 = L1;//L2的入口
    	L1 = new ListNode(L1,1);
    	L1 = new ListNode(L1,2);
    	enter2->nextNode=L1;//L1的入口
    	L1 = new ListNode(L1,3);
    	L1 = new ListNode(L1,4);
    
    	L2 = new ListNode(enter2,0);
    	L2 = new ListNode(L2,1);
    	L2 = new ListNode(L2,2);
    }
    
    
    //创建有环链表不相交
    void createCircleListNotCross(){
    	L1=createCircleList();
    	L2=createCircleList();
    }
    
    void main()
    {
    	createCircleListCross();
    	ListNode * node = getCircleListEnter(L1);
    	cout<<"有环链表L1的入口(相交点1)"<<node->data<<endl;
    	node = getCircleListEnter(L2);
    	cout<<"有环链表L2的入口(相交点2)"<<node->data<<endl;
    	system("pause");
    }

    至此,这道古老的链表相交问题终于讲完了,总结下思路

    判断链表是否带环(第三节

    不带环,用不带环的方法,判断是否相交、求相交点(第一节第二节

    带环,用带环的方法,判断是否相交、求相交点(第三节第四节


  • 相关阅读:
    Java实现 LeetCode 27 移除元素
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 24 两两交换链表中的节点
    Java实现 LeetCode 24 两两交换链表中的节点
    Java实现 LeetCode 24 两两交换链表中的节点
  • 原文地址:https://www.cnblogs.com/javdroider/p/5184291.html
Copyright © 2011-2022 走看看