左神基础班- 可能有环可能无环的链表 -判断是否相交

博客给出有环与无环链表不相交的代码组合,使用 return nullptr;表示该情况,还提及有完整带测试的代码。

 

//判断是否有环
LinkNode* loop(LinkNode* head){
	LinkNode* f = head->next;
	LinkNode* s = head->next;
	//注意这边的 &&
	while(f->next != nullptr && f->next->next != nullptr){
		s = s->next;
		f = f->next->next;
		if(s == f){
			f = head->next;
			break;
		}
	}
	//代表无环
	if(f->next==nullptr || f->next->next == nullptr){
		return nullptr;
	}
	//若有环
	while(s != f){
		s = s->next;
		f = f->next;
	}
	return s;
}

 

 

//2无环单链表是否相交
LinkNode* noloop(LinkNode* head1, LinkNode* head2){
	int num1 = 0;
	int num2 = 0;
	LinkNode* go1 = head1;
	LinkNode* go2 = head2;
	while(go1->next != nullptr){
		go1 = go1->next;
		num1++;
	}
	while(go2->next != nullptr){
		go2 = go2->next;
		num2++;
	}
	if(go1 != go2){
		return nullptr;
	}
	num1 = num1-num2;
	go1 = num1 > 0? head1:head2;
	go2 = go1 == head1? head2 : head1;
	if(num1<0){
		num1 = -num1;
	}
	while(num1 > 0){
		go1 = go1->next;
		num1--;	
	}
	while(go1 != go2){
		go1 = go1->next;
		go2 = go2->next;
	}
	return go1;
}

 

 

 

 

 

//两个有环链表 是否相交
LinkNode* hasloop(LinkNode* head1, LinkNode* head2){
	//在环外的链上相交,则其入环节点一定相同
	if(loop(head1) == loop(head2)){
		LinkNode* enloop = loop(head1);
		LinkNode* go1 = head1;
		LinkNode* go2 = head2;
		int num1 = 0;
		int num2 = 0;
		while(go1 ->next != enloop){
			num1++;
			go1 = go1->next;
		}
		while(go2->next != enloop){
			num2++;
			go2 = go2->next;
		}
		num1 = num1 - num2;
		go1 = num1 > 0? head1 : head2;
		go2 = go1 == head1 ? head2 : head1;
		if(num1<0)
			num1 = -num1;
		while(num1 > 0){
			go1 = go1->next;
			num1--;
		}
		while(go1 != go2){
			go1 = go1->next;
			go2 = go2->next;
		}
		return go1;
	}else{
		//另外两种结构: 66 或 三毛头没有中间一根毛
		//从一个入环节点开始沿着环遍历,如果重新回到原始位置没碰到另外一个入环节点,则为66结构
		LinkNode* enloop1 = loop(head1);
		LinkNode* enloop1_go = enloop1;
		LinkNode* enloop2 = loop(head2);
		while(enloop1_go->next != enloop1){
			enloop1_go = enloop1_go->next;
			if(enloop1_go == enloop2){
				return enloop1;
			}
		}
		//66结构
		return nullptr;
	}
}

 

最终组合起来使用: return nullptr; 表示 一个有环一个无环的链表比不相交

LinkNode* judge(LinkNode* head1, LinkNode* head2){
    if(head1 == nullptr || head2 == nullptr){
        return nullptr;
    }
	// 两个无环单链表是否相交
	if(loop(head1) == nullptr && loop(head2) == nullptr){
		return noloop(head1, head2);
	}else if(loop(head1) != nullptr && loop(head2)!= nullptr){
		return hasloop(head1, head2);
	}
	return nullptr;
}

 

 

完整的 ,带测试的代码:

//拷贝带有随机指针的单链表
#include<iostream>
#include<stack>
#include<unordered_map>
using namespace std;
struct LinkNode{
	int value;
	LinkNode* next;
	LinkNode(int a){
		value = a;
		next = nullptr;
	}
};
LinkNode* loop(LinkNode* head);
LinkNode* noloop(LinkNode* head1, LinkNode* head2);
LinkNode* hasloop(LinkNode* head1, LinkNode* head2);
LinkNode* judge(LinkNode* head1, LinkNode* head2);
int main(){
	LinkNode* head1 = new LinkNode(0);
	LinkNode* a = new LinkNode(1);
	LinkNode* b = new LinkNode(2);
	LinkNode* c = new LinkNode(3);
	LinkNode* d = new LinkNode(4);
	head1->next = a;
	a->next = b;
	b->next = c;
	c->next = d;
	//加环
	d->next = b;

	LinkNode* head2 = new LinkNode(0);
	LinkNode* a2 = new LinkNode(1);
	LinkNode* b2 = new LinkNode(2);
	LinkNode* c2 = new LinkNode(3);
	LinkNode* d2 = new LinkNode(4);
	head2->next = a2;
	a2->next = b2;
	b2->next = c2;
	c2->next = d2;
	d2->next = b2;

	// b2->next = c2;
	//判断一个单链表是否有环
	// if(loop(head2)){
	// 	cout << loop(head)->value <<endl;
	// }else{
	// 	cout << "无环" << endl;
	// }

	// 测试 66 结构
	if(judge(head1, head2) == nullptr){
		cout << "66"<< endl;
	}

	LinkNode* head3 = new LinkNode(0);
	LinkNode* a3 = new LinkNode(1);
	LinkNode* b3 = new LinkNode(2);
	LinkNode* c3 = new LinkNode(3);
	LinkNode* d3 = new LinkNode(4);
	LinkNode* e3 = new LinkNode(5);
	head3->next = a3;
	a3->next = b3;
	b3->next = c3;
	c3->next = d3;
	d3->next = e3;
	e3->next = c3;

	LinkNode* head4 = new LinkNode(0);
	LinkNode* a4 = new LinkNode(1);
	head4->next = a4;
	a4->next = b3;
	//测试环外相遇结构
	if(judge(head3,head4) != nullptr){
		cout << "seconde mode: the node is "<<judge(head3, head4)->value << endl;
	}
	
	LinkNode* head5 = new LinkNode(0);
	LinkNode* a5 = new LinkNode(1);
	head5->next = a5;
	a5->next = d3;
	//环内相交节点
	if(judge(head3,head5) != nullptr){
		cout <<"third mode: the node is"<< judge(head3, head5)->value << endl;	
	}
	

	LinkNode* head6 = new LinkNode(0);
	LinkNode* a6 = new LinkNode(1);
	LinkNode* b6 = new LinkNode(2);
	LinkNode* c6 = new LinkNode(3);
	LinkNode* d6 = new LinkNode(4);
	LinkNode* e6= new LinkNode(5);
	head6->next = a6;
	a6->next = b6;
	b6->next = c6;
	c6->next = d6;
	d6->next = e6;
	LinkNode* head7 = new LinkNode(0);
	LinkNode* a7 = new LinkNode(1);
	LinkNode* b7 = new LinkNode(2);
	head7->next = a7;
	a7->next = b7;
	b7->next = c6;
	//两单链表相交
	if(judge(head6,head7) != nullptr){
		cout <<"two Link have banana, the number : "<< judge(head6, head7)->value;
	}else{
		cout << "two Link no banana" <<endl;
	}
	return 0;
}

//判断是否有环
LinkNode* loop(LinkNode* head){
	LinkNode* f = head->next;
	LinkNode* s = head->next;
	//注意这边的 &&
	while(f->next != nullptr && f->next->next != nullptr){
		s = s->next;
		f = f->next->next;
		if(s == f){
			f = head->next;
			break;
		}
	}
	//代表无环
	if(f->next==nullptr || f->next->next == nullptr){
		return nullptr;
	}
	//若有环
	while(s != f){
		s = s->next;
		f = f->next;
	}
	return s;
}
//2无环单链表是否相交
LinkNode* noloop(LinkNode* head1, LinkNode* head2){
	int num1 = 0;
	int num2 = 0;
	LinkNode* go1 = head1;
	LinkNode* go2 = head2;
	while(go1->next != nullptr){
		go1 = go1->next;
		num1++;
	}
	while(go2->next != nullptr){
		go2 = go2->next;
		num2++;
	}
	if(go1 != go2){
		return nullptr;
	}
	num1 = num1-num2;
	go1 = num1 > 0? head1:head2;
	go2 = go1 == head1? head2 : head1;
	if(num1<0){
		num1 = -num1;
	}
	while(num1 > 0){
		go1 = go1->next;
		num1--;	
	}
	while(go1 != go2){
		go1 = go1->next;
		go2 = go2->next;
	}
	return go1;
}
//两个有环链表 是否相交
LinkNode* hasloop(LinkNode* head1, LinkNode* head2){
	//在环外的链上相交,则其入环节点一定相同
	if(loop(head1) == loop(head2)){
		LinkNode* enloop = loop(head1);
		LinkNode* go1 = head1;
		LinkNode* go2 = head2;
		int num1 = 0;
		int num2 = 0;
		while(go1 ->next != enloop){
			num1++;
			go1 = go1->next;
		}
		while(go2->next != enloop){
			num2++;
			go2 = go2->next;
		}
		num1 = num1 - num2;
		go1 = num1 > 0? head1 : head2;
		go2 = go1 == head1 ? head2 : head1;
		if(num1<0)
			num1 = -num1;
		while(num1 > 0){
			go1 = go1->next;
			num1--;
		}
		while(go1 != go2){
			go1 = go1->next;
			go2 = go2->next;
		}
		return go1;
	}else{
		//另外两种结构: 66 或 三毛头没有中间一根毛
		//从一个入环节点开始沿着环遍历,如果重新回到原始位置没碰到另外一个入环节点,则为66结构
		LinkNode* enloop1 = loop(head1);
		LinkNode* enloop1_go = enloop1;
		LinkNode* enloop2 = loop(head2);
		while(enloop1_go->next != enloop1){
			enloop1_go = enloop1_go->next;
			if(enloop1_go == enloop2){
				return enloop1;
			}
		}
		//66结构
		return nullptr;
	}
}

LinkNode* judge(LinkNode* head1, LinkNode* head2){
    if(head1 == nullptr || head2 == nullptr){
        return nullptr;
    }
	// 两个无环单链表是否相交
	if(loop(head1) == nullptr && loop(head2) == nullptr){
		return noloop(head1, head2);
	}else if(loop(head1) != nullptr && loop(head2)!= nullptr){
		return hasloop(head1, head2);
	}
	return nullptr;
}

 

ok,88~~

### 判断链表是否存在的算法 判断链表是否存在,可以使用快慢指针算法(Floyd's Cycle Detection Algorithm)。该算法的核心思想是通过两个指针在链表上移动的速度差异来检测的存在。具体实现如下: #### 算法描述 定义两个指针,一个慢指针(`slow`)和一个快指针(`fast`),初始时都指向链表的头节点。慢指针每次向前移动一步,而快指针每次向前移动两步。如果链表中不存在,则快指针会先到达链表的尾部(即指向空节点),此时可以判断链表。如果链表中存在,那么快指针最终会追上慢指针,二者会相遇[^1]。 #### C语言实现 以下是基于C语言的快慢指针算法实现: ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构 typedef struct ListNode { int val; struct ListNode* next; } ListNode; // 创建新节点 ListNode* createNode(int val) { ListNode* node = (ListNode*)malloc(sizeof(ListNode)); node->val = val; node->next = NULL; return node; } // 判断链表是否 int hasCycle(ListNode* head) { if (head == NULL || head->next == NULL) { return 0; // 链表为空或只有一个节点时,不可能 } ListNode* slow = head; ListNode* fast = head; while (fast != NULL && fast->next != NULL) { slow = slow->next; // 慢指针每次移动一步 fast = fast->next->next; // 快指针每次移动两步 if (slow == fast) { // 如果快慢指针相遇,则存在 return 1; } } return 0; // 快指针到达链表尾部,说明无 } ``` #### 时间与空间复杂度分析 - **时间复杂度**:假设链表长度为 `N`,若链表中不存在,则快指针最多移动 `N` 步;若存在,则快慢指针会在内相遇,循次数为长的整数倍。因此,时间复杂度为 \(O(N)\)[^3]。 - **空间复杂度**:除了两个指针外,未使用额外存储空间,因此空间复杂度为 \(O(1)\)[^3]。 ### 其他方法 除了快慢指针算法,还可以使用哈希集合(Set)的方法来判断链表是否存在。具体思路是遍历链表并将每个节点存入集合中,若发现某个节点已存在于集合中,则说明链表存在[^2]。 #### 哈希集合方法(伪代码) ```c Set set = new Set(); ListNode* current = head; while (current != NULL) { if (set.contains(current)) { return true; // 存在 } set.add(current); current = current->next; } return false; // 无 ``` 此方法的时间复杂度为 \(O(N)\),但需要额外的存储空间,因此空间复杂度为 \(O(N)\)[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值