`
hellobin
  • 浏览: 65437 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

笔试题:如何判断单链表是否存在环

 
阅读更多

给定一个单链表,只给出头指针h:

1、如何判断是否存在环?

2、如何知道环的长度?

3、如何找出环的连接点在哪里?

4、带环链表的长度是多少?

 

解法:

1、对于问题1,使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。

2、对于问题2,记录下问题1的碰撞点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s。

3、问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点。

该定理的证明可参考:http://fayaa.com/tiku/view/7/

4、问题3中已经求出连接点距离头指针的长度,加上问题2中求出的环的长度,二者之和就是带环单链表的长度

 

 

判断是否存在环的程序:

bool IsExitsLoop(slist *head)
{
    slist *slow = head, *fast = head;

    while ( fast && fast->next ) 
    {
        slow = slow->next;
        fast = fast->next->next;
        if ( slow == fast ) break;
    }

    return !(fast == NULL || fast->next == NULL);
}

 

 

寻找环连接点(入口点)的程序:

slist* FindLoopPort(slist *head)
{
    slist *slow = head, *fast = head;

    while ( fast && fast->next ) 
    {
        slow = slow->next;
        fast = fast->next->next;
        if ( slow == fast ) break;
    }

    if (fast == NULL || fast->next == NULL)
        return NULL;

    slow = head;
    while (slow != fast)
    {
         slow = slow->next;
         fast = fast->next;
    }

    return slow;
}

 

完整演示程序:

#include "stdio.h"
#include "stdlib.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int Status;
typedef int ElemType;

typedef struct Node{
	ElemType data;
	struct Node* next;
}Node;

Status initList(Node** L){
	
	*L = (Node*)malloc(sizeof(Node));
	if(!(*L)){
		return ERROR;
	}
	
	(*L)->next = NULL;
	return OK;
}


int listLength(Node* L){
	
	int i = 0;
	Node* p = L->next;
	while(p){
		i++;
		p = p->next;
	}
	return i;
}

// Non-Chain
void createListHead(Node** L, int n){
	
	Node* p;
	int i;
	
	srand(time(0));
	
	*L = (Node*)malloc(sizeof(Node));
	(*L)->next = NULL;
	
	for(i=0; i<n; i++){
		p = (Node*)malloc(sizeof(Node));
		// p->data = rand()%100+1;
		p->data = i+1;
		p->next = (*L)->next;
		(*L)->next = p;
	}
}

// Chain
void createListTail(Node** L, int n){
	
	Node* p, *r;
	int i;
	
	srand(time(0));
	*L = (Node*)malloc(sizeof(Node));
	r = *L;
	
	for(i=0; i<n; i++){
		p = (Node*)malloc(sizeof(Node));
		// p->data = rand()%100+1;
		p->data = i+1;
		r->next = p;
		r = p;
	}
	
	// 把尾节点与第二个节点连接起来
	r->next = (*L)->next->next;
}

// 用两个指针cur1,cur2, cur1每次前进一个pos,cur2每次重头前进直到和cur1指向相同的节点,
// 再比较两者经过的步数是否相等
int hasLoop1(Node* L){
	
	Node* cur1 = L;
	int pos1 = 0;
	
	while(cur1){
		Node* cur2 = L;
		int pos2 = 0;
		while(cur2){
			if(cur2 == cur1){
				if(pos1 == pos2){
					break;
				}
				else{
					printf("Chain is in the %d place\n\n", pos2);
					return 1;
				}
			}
			cur2 = cur2->next;
			pos2++;
		}
		cur1 = cur1->next;
		pos1++;
	}
	
	return 0;
}

// 快慢指针,如果相等则说明有环
int hasLoop2(Node* L){
	
	int step1 = 1;
	int step2 = 2;
	Node* p = L;
	Node* q = L;
	
	while(p!=NULL && q!=NULL && q->next!=NULL){
		p = p->next;
		q = q->next->next;
		
		printf("p:%d, q:%d \n", p->data, q->data);
		
		// 找到相碰点
		if(p == q){
			return 1;
		}
	}
	
	return 0;
}

// 寻找环连接点(入口点)
Node* findLoopEntry(Node* L){
	
	Node* slow = L, *fast=L;
	
	while(fast && slow && fast->next){
		slow = slow->next;
		fast = fast->next->next;
		
		// 找到相碰点
		if(slow == fast){
			printf("Collision point value is %d\n", slow->data);
			break;
		}
	}
	
	if(fast==NULL || fast->next==NULL){
		return NULL;
	}
	
	// 碰撞点p到连接点的距离=头指针到连接点的距离
	slow = L;
	while(slow != fast){
		slow = slow->next;
		fast = fast->next;
	}
	
	return slow;
}



int main(){
	
	Node* L;
	Status i;
	char opp;
	ElemType e;
	int find;
	int tmp;
	
	i = initList(&L);
	printf("After initialization, listLength(L)=%d\n", listLength(L));
	
	printf("\n1.Create Chain Linked list(Tail Insert) \n2.Create Non-Chain Linked List(Head Insert) \n3.Judge if a chain exists \n0.Exit\n\n");
	
	while(opp != '0'){
		scanf("%c", &opp);
		switch(opp){
			case '1':
				createListTail(&L, 10);
				printf("Create Chain LinkedList L(Tail Insert) OK\n");
				printf("\n");
				break;
			
			case '2':
				createListHead(&L, 10);
				printf("Create Non-Chain Linked List(Head Insert) OK\n");
				printf("\n");
				break;
				
			case '3':
				printf("Solution 1: \n\n");
				if(hasLoop1(L)){
					printf("Summary: Chain exists\n\n");
				}
				else{
					printf("Summary: No Chain\n\n");
				}
				
				printf("---------------------------\n\n");
				
				printf("Solution 2: \n\n");
				if(hasLoop2(L)){
					printf("Summary: Chain exists\n\n");
					Node* entry = findLoopEntry(L);
					printf("Entry value is: %d\n", entry->data);
				}
				else{
					printf("Summary: No Chain\n\n");
				}
		}
	}
}

 

分享到:
评论

相关推荐

    C语言链表在笔试常考题.docx

    判断单链表是否有环是指检测链表中是否存在环的操作。例如,链表1-&gt;2-&gt;3-&gt;4-&gt;5-&gt;3是一个有环的链表,因为链表中存在环。 解决方案: ```c bool IsExitsLoop(NodeList head){ NodeList slow=head,fast=head; ...

    nec 技术笔试面试题

    - NEC公司的技术笔试包括选择题、编程题、逻辑推理题等多种题型,这些题型涉及到数据结构、算法、计算机网络、操作系统和编程语言等多方面的知识点。 以上知识点涵盖了文件中提到的大部分内容,并对每个知识点进行...

    2008校园招聘部分500强笔试题

    ### 2008校园招聘部分500强笔试题解析 #### 一、哈希函数冲突问题(选择题) **题目描述**: 在以下哪个使用场景中,所给出的哈希函数会导致较大的冲突? A. 使用手机号码的最后两位数字作为哈希值,用于公共客户...

    北京澳柯网信科技发展有限公司研发笔试题

    题目询问如何检测单链表是否存在环。常用算法是Floyd判环法,也称为“龟兔赛跑”算法。设置快慢两个指针,快指针每次移动两步,慢指针每次移动一步。如果链表存在环,则快慢指针最终会在环内相遇;若不存在环,快...

    算法大全-面试题-数据结构.docx

    假设链表的长度为n,那么可以使用两个指针,一个指针从头节点开始移动,另一个指针从头节点移动两倍的速度,如果两个指针相遇,则链表中存在环。 9. 判断两个单链表是否相交 可以使用哈希表来解决这个问题。首先...

    关于链表的一些面试题

    这个问题的关键在于理解快慢指针会相遇的原理,以及如何利用这个原理来判断链表中是否存在环。 题二检测两个单链表是否有交点的知识点: 对于检测两个链表是否有交点的问题,首先需要考虑特殊情况,即两个链表的头...

    山东科技大学《数据结构》模拟试卷(B卷).doc

    8. **AOV网和拓扑排序**:AOV网是活动-on-vertex的缩写,表示顶点间的有向无环图,通过拓扑排序可以检查图中是否存在环。 9. **二叉树遍历**:二叉树的遍历包括前序遍历(根-左-右)、中序遍历(左-根-右)和后序...

    C_C++语言程序设计笔试面试题29.pdf

    同时,存在多个`if`条件判断语句,用于检查数组中的值是否为特定的空值(假设使用null表示空指针),这些都是基础的程序设计逻辑。 3. 指针和引用 文档中的代码使用了指针来访问和操作数据结构中的元素。例如,指针...

Global site tag (gtag.js) - Google Analytics