判断单链是否循环,并且找出第一个循环节点

本文介绍了一种高效的方法来判断单链表是否循环,并找出首个循环节点。通过双指针技术和哈希集合的应用,实现了简洁易懂的解决方案。

介绍

    判断单链是否循环,并且找出第一个循环节点。

思路

    【判断单链是否循环】:如果单链是循环的,那么循环部分就是封闭的。这好比一个田径运动场,当两个人跑步时,开始虽然有一定的间距,但他们迟早会相遇的。

顺其自然的我们从中抽取一个数学模型,一个是步长Steps(对应两人刚开始跑步时的间距);一个是判断单链循环的条件nodeX==nodeY(两人“相遇”)。

    【找出第一个循环节点】:我想过好多其它方法,实现起来都比较难,后来出去骑行了两个小时,回来后就想到借助Hash存储,Hash元素包含判断,结果实现起来既容易,又好懂。

    比如:下图就是一个循环单链,第一个循环节点为3。


package shuai.study.link.circle;

import java.util.HashSet;
import java.util.Set;

class Node {
	String data = null;
	Node nextNode = null;

	public Node(String data, Node nextNode) {
		this.data = data;
		this.nextNode = nextNode;
	}
}

/////////////////////////////////////////////////////////////////////////////////////////

class SingleCircleLink {
	Node firstNode = null;

	Node nodeX = null;
	Node nodeY = null;

	public SingleCircleLink(Node firstNode) {
		this.firstNode = firstNode;

		this.nodeX = firstNode;
		this.nodeY = firstNode;
	}

	public boolean isSingleCircleLink() {
		/*
		 * This while block judge whether this link is circle or not.
		 */
		while (nodeY != null && (nodeY = nodeY.nextNode) != null && nodeX != nodeY) {
			nodeX = nodeX.nextNode;
			nodeY = nodeY.nextNode;
		}

		/*
		 * if Node.next is null, then it illustrates this link isn't circle link.
		 */
		return nodeY != null;
	}

	public void printFirstCircleNode(boolean isSingleCircleLinkFlag) {
		if (isSingleCircleLinkFlag) {
			System.out.println("This is single circle link");

			Set<Node> hashSet = new HashSet<Node>();
			Node nodeZ = firstNode;

			/*
			 * This while block will find the first circle node.
			 */
			while (true) {
				hashSet.add(nodeZ);
				nodeZ = nodeZ.nextNode;

				if (hashSet.contains(nodeZ)) {
					break;
				}
			}

			System.out.println("The first circle node is " + nodeZ.data);
		} else {
			System.out.println("This is not single circle link");
		}
	}
}

/////////////////////////////////////////////////////////////////////////////////////////

/**
 * @author shengshu
 * 
 */
public class SingleCircleLinkApp {
	public static void main(String[] args) {
		Node node6 = new Node("6", null);
		Node node5 = new Node("5", node6);
		Node node4 = new Node("4", node5);
		Node node3 = new Node("3", node4);
		Node node2 = new Node("2", node3);
		Node node1 = new Node("1", node2);

		node6.nextNode = node3;

		SingleCircleLink singleCircleLink = new SingleCircleLink(node1);
		singleCircleLink.printFirstCircleNode(singleCircleLink.isSingleCircleLink());
	}
}





                
<think>好的,用户想找用C语言实现单链循环队列的示例。之前我给了Python的例子,现在需要转换成C语言,并且结合用户提供的引用内容。首先,我需要回顾用户提供的引用资料,看看有没有相关的代码或结构可以参考。 引用[1]展示了C语言中链表的结构体定义和初始化,包括节点结构体Node和初始化函数initlink()。这可以作为基础,但用户需要的是循环队列,可能需要调整结构。引用[3]提到链队列需要头尾指针,并且通常有头结点,这可能在循环队列中是否需要呢?用户给的Python实现里没有头结点,但C语言的链队列可能有。需要确定循环队列的结构是否包含头结点。 引用[4]中的销毁队列函数展示了如何释放所有节点,这在C语言中很重要,避免内存泄漏。用户的需求是循环队列,所以初始化时需要创建固定数量的节点并连接成环,类似之前的Python示例,但用C语言实现。 现在需要将之前的Python代码转换为C语言。循环队列的关键点是预分配固定大小的节点,头尾指针移动,以及判断空和满的条件。在C中,结构体需要定义队列结构,包含头指针、尾指针、容量和当前大小等信息。同时,每个节点需要包含数据和next指针。 初始化时,要创建k个节点,并将它们首尾相连成环。入队和出队操作需要移动头尾指针,并处理数据判断空和满的条件可能基于size变量,或者通过指针的位置,比如tail->next == head来表示满,但如果有固定容量,用size可能更简单。 用户提供的引用[3]提到链队列通常有头结点,但循环队列是否需要呢?在Python示例中没有头结点,直接使用head和tail指向实际节点。可能在这种情况下,不需要头结点,直接让head指向第一个有效节点,tail指向最后一个节点的下一个位置(即环结构)。 需要注意内存管理,C语言中需要手动分配和释放内存。初始化时malloc节点,销毁时要free所有节点。入队时若已满则返回错误,出队时返回数据并移动头指针。 需要确保代码示例正确,包括结构体定义、初始化函数、入队出队函数,以及空满判断。同时,引用用户提供的资料中的相关部分,比如结构体定义参考引用[1],队列结构参考引用[3],销毁函数参考引用[4]等。 可能存在错误点:循环队列的初始化是否正确形成环,头尾指针的移动是否正确,空满判断是否准确。需要仔细检查指针操作,避免内存泄漏或访问错误。 最后,给出相关问题,帮助用户进一步理解实现细节和应用场景。</think>### C语言单链循环队列实现详解 #### 核心数据结构定义 ```c #include <stdio.h> #include <stdlib.h> // 链表节点结构体(参考引用[1]) typedef struct Node { int data; struct Node* next; } Node; // 循环队列容器结构体(参考引用[3]) typedef struct { Node* head; // 队首指针 Node* tail; // 队尾指针 int capacity; // 队列容量 int size; // 当前元素数量 } CircularQueue; ``` #### 初始化函数 ```c // 创建固定长度的环形链表(核心逻辑参考引用[3]) CircularQueue* createQueue(int k
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值