[算法天地]关于单链表的操作有环无环判断

#include <stdio.h>
#include <stdlib.h>

// 有环链表的各种函数测试
typedef struct Node
{
	int data;
	struct Node *next;
}Node;

typedef struct Node* LinkList;

/*链表初始化*/
int InitList(LinkList *L)
{
	*L = (LinkList)malloc(sizeof(Node));
	if(!(*L))
		return -1;
	(*L)->next = NULL;
	return 0;
}

/*求链表的长度*/
int ListLength(LinkList L)
{
	int i = 0;
	LinkList p = L->next;
	while(p)
	{
		i++;
		p = p->next;
	}
	return i;
}

int CreateListHead(LinkList *L, int n)
{
	LinkList p;
	int i;
	for(i=0; i<n; i++)
	{
		p = (LinkList)malloc(sizeof(Node));
		p->data = i+1;
		p->next = (*L)->next;
		(*L)->next = p;
	}
}

int CreateListTail(LinkList *L, int n)
{
	LinkList p, r;
	int i;
	r = *L;
	for(i=0; i<n; i++)
	{
		p = (LinkList)malloc(sizeof(Node));
		p->data = i+1;
		r->next = p;
		r = p;
	}
	r->next = NULL;
}

/*打印链表*/
void ListTraverse(LinkList L)
{
	LinkList p = L->next;
	while(p)
	{
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

/*单链表反转*/
LinkList ListReverse(LinkList L)
{
	LinkList current, pnext, prev;
	if(L == NULL || L->next == NULL)
		return L;
	current = L->next;
	pnext   = current->next;
	current->next = NULL;
	while(pnext)
	{
		prev = pnext->next;
		pnext->next = current;
		current = pnext;
		pnext = prev;
	}

	L->next = current;
	return L;
}

LinkList ListReverse2(LinkList L)
{
	LinkList current, p;
	if(L == NULL)
		return NULL;
	current = L->next;
	printf("current = %d\n", current->data);
	while(current->next != NULL)
	{
		/**举个例子
		*  p = current->next;       // 9个数的话调换需要八次,第一次P等于8
		*  currnet->next = p->next; // P的下一个值7,付给current的下一个
		*  p->next = L->next;       // 把L的第一个节点9赋值给P的下一个值
		*  L->next = p;             // L的下一个值为8,因为上一步P的下一个已经为9
		*/
		p = current->next;
		current->next = p->next;
		p->next = L->next;
		L->next = p;
	}
	return L;
}

int ListInsert(LinkList *L, int pos, int num)
{
	int j;
	LinkList p, s;
	p = *L;
	j = 1;
	while(p && j<pos)
	{
		p = p->next;
		++j;
	}

	if( !p || j>pos )
		return -1;

	s = (LinkList)malloc(sizeof(Node));
	s->data = num;
	s->next = p->next;
	p->next = s;
	return 0;
}

int IsEmpty(LinkList L)
{
	if(L->next)
		return -1;
	else
		return 1;
}

int BuildListLoop(LinkList *L, int num)
{
	int i = 0;
	LinkList cur = (*L)->next;
	LinkList tail= NULL;

	if(num <= 0 || L == NULL)
		return -1;

	for(i=1; i<num; ++i)
	{
		if(cur == NULL)
		{
			return -1;
		}
		cur = cur->next;
	}
	tail = cur;
	while(tail->next)
	{
		tail = tail->next;
	}
	tail->next = cur;
	return 0;

}

int ListTraveseLimit(LinkList L, int n)
{
	int i = 0;
	LinkList p = L->next;
	while(p && i<n)
	{
		printf("%d ", p->data);
		p = p->next;
		i++;
	}
	printf("\n只显示%d个\n", n);
	return 0;
}

int HasLoop(LinkList L)
{
	LinkList fast = L;
	LinkList slow = L;

	/**
	* 这里如果无环,则fast先到达终点
	* 当链表长度为奇数时,fast->next为空
	* 当链表长度为偶数时,fast为空
	*/

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

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

int LoopLength(LinkList L)
{
	if(-1 == HasLoop(L))
		return 0;

	LinkList fast = L;
	LinkList slow = L;

	int length = 0;
	bool begin = false;
	bool again = false;

	while( fast != NULL && fast->next != NULL )
	{
		fast = fast->next->next;
		slow = slow->next;

		// 超两圈后停止计数,跳出循环
		if( fast == slow && again == true )
		{
			break;
		}

		// 超一圈后开始计数
		if( fast == slow && again == false )
		{
			begin = true;
			again = true;
		}

		// 计数
		if( begin == true )
			++length;
	}
	return length;
}

// 解决入口点的问题思路
//              8 O-O 7
//               /   //            9 O     O 6
//               \   /
// O - O - O - O - O
// 1   2   3   4   5
// 相遇点到连接点的距离等于头指针到连接点的距离
// 先让快慢指针相遇,然后慢指针重新指向头结点
// 分别从相遇点、头指针开始走,相遇的那个店就是连接点
LinkList findLoopEnterace(LinkList L)
{
	LinkList fast = L;
	LinkList slow = L;

	while( fast != NULL && fast->next != NULL )
	{
		fast = fast->next->next;
		slow = slow->next;

		// 如果有环,则fast会超过slow一圈
		if(fast == slow)
			break;
	}

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

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

	return slow;
}

int GetMidNode(LinkList L, int *e)
{
	LinkList fast = L;
	LinkList slow = L;

	while( fast->next != NULL )
	{
		if( fast->next->next != NULL )
		{
			fast = fast->next->next;
			slow = slow->next;
		}
		else
		{
			fast = fast->next;
		}
	}

	*e = slow->data;
	return 0;

}

int ClearList(LinkList *L)
{
	LinkList p, q;
	p = (*L)->next;
	while(p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	(*L)->next = NULL;
	return 0;
}

int main()
{
	LinkList L;
	int i;
	int n;
	int e;

	i = InitList(&L);
	if(i != -1)
		printf("InitList() 初始化成功.\n");

	printf("链表L初始化后, ListLength(L)=%d\n", ListLength(L));

	for(i=0; i<10; i++)
	{
		ListInsert(&L, 1, i);
	}
	printf("IsEmpty = %d(1:空,-1:非空)\n", IsEmpty(L));
	printf("ListLength(L)=%d\n", ListLength(L));
	printf("打印链表:");
	ListTraverse(L);

	// 给单链表逆向反转
	ListReverse2(L);
	printf("逆向打印链表:");
	ListTraverse(L);

	// 求链表的中间节点
	GetMidNode(L, &e);
	printf("求链表的中间节点e=%d\n", e);

	printf("给链表建环, 请输入位置:");
	scanf("%d", &n);
	BuildListLoop(&L, n);
	ListTraveseLimit(L, 20);

	// 判断链表是否有环
	if( 1 == HasLoop(L) )
		printf("链表有环\n");
	else
		printf("链表无环\n");

	// 计算环长
	printf("计算环长, LoopLength(L)=%d\n", LoopLength(L));

	// 求出环的入口点
	LinkList enterance = findLoopEnterace(L);
	printf("入口点的值为: %d\n", enterance->data);

	//printf("采用头插法:\n", CreateListHead(&L, 10));
	//ListTraverse(L);

	//printf("采用尾插法\n", CreateListTail(&L, 10));
	//ListTraverse(L);

	//i = ClearList(&L);
	//if( i == 0 )
	//	printf("清空LinkList链表.\n");
	//printf("IsEmpty = %d(1:空,-1:非空)\n", IsEmpty(L));
	//printf("ListLength(L)=%d\n", ListLength(L));

	return 0;
}

  

时间: 2024-08-05 07:14:59

[算法天地]关于单链表的操作有环无环判断的相关文章

java数据结构:单链表常见操作代码实现

一.概述: 本文主要总结单链表常见操作的实现,包括链表结点添加.删除:链表正向遍历和反向遍历.链表排序.判断链表是否有环.是否相交.获取某一结点等. 二.概念: 链表: 一种重要的数据结构,HashMap等集合的底层结构都是链表结构.链表以结点作为存储单元,这些存储单元可以是不连续的.每个结点由两部分组成:存储的数值+前序结点和后序结点的指针.即有前序结点的指针又有后序结点的指针的链表称为双向链表,只包含后续指针的链表为单链表,本文总结的均为单链表的操作. 单链表结构: Java中单链表采用No

009实现一个算法来删除单链表中的一个结点,只给出指向那个结点的指针(keep it up)

呵呵,这个题不能直接删除已知的结点,因为是单链表,不知道前驱,只知道 后继结点,直接删除会使链表断开.不过我们可以删除已知结点的后继结点, 把后继结点的值赋值给已知结点. #include <iostream> struct Node { int data; Node* next; }; bool removeNode(Node* vNode) { if (vNode == NULL || vNode->next == NULL) return false; Node* pNext =

实现一个算法从一个单链表中返回倒数第n个元素(keep it up)

我们维护两个指针, 它们之间的距离为n.然后,我将这两个指针同步地在这个单链表上移动,保持它们的距离 为n不变.那么, 当第二个指针指到空时,第一个指针即为所求. #include <iostream> struct Node { int data; Node* next; }; void initList(Node* vNode) { for (int i=0; i < 20; ++i) { Node* TempNode = new Node; TempNode->data =

cc150:实现一个算法来删除单链表中间的一个结点,只给出指向那个结点的指针

实现一个算法来删除单链表中间的一个结点,只给出指向那个结点的指针. 例子: 输入:指向链表a->b->c->d->e中结点c的指针 结果:不需要返回什么,得到一个新链表:a->b->d->e 解答 这个问题的关键是你只有一个指向要删除结点的指针,如果直接删除它,这条链表就断了. 但你又没办法得到该结点之前结点的指针,是的,它连头结点也不提供.在这种情况下, 你只能另觅他径.重新审视一下这个问题,我们只能获得从c结点开始后的指针, 如果让你删除c结点后的某个结点,那

cc150:实现一个算法来删除单链表中间的一个结点,仅仅给出指向那个结点的指针

实现一个算法来删除单链表中间的一个结点,仅仅给出指向那个结点的指针. 样例: 输入:指向链表a->b->c->d->e中结点c的指针 结果:不须要返回什么,得到一个新链表:a->b->d->e 解答 这个问题的关键是你仅仅有一个指向要删除结点的指针,假设直接删除它,这条链表就断了. 但你又没办法得到该结点之前结点的指针,是的,它连头结点也不提供.在这样的情况下, 你仅仅能另觅他径.又一次审视一下这个问题,我们仅仅能获得从c结点開始后的指针, 假设让你删除c结点后的

4.2.2 算法之美--单链表实现

按照书上的要求实现了一下单链表:单链表的实现可能以前看过几次了:现在想想最主要的几个操作算法应该能够写了吧:遇到的问题: 1. 链表节点写成private;所已给出了访问的接口: 2.模板类的.h和.cpp实现写在同一个文件: 3.感觉以后的数据结构实现还是用纯c的实现好一些:然后书主要是思路 节点类: #ifndef SINGLELIST_LISTNODE_H_ #define SINGLELIST_LISTNODE_H_ template <class T> class ListNode

线性单链表的操作

#include <stdio.h> #include <stdlib.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define INFEASIBLE -1 #define OVERFLOW -2 /* #define ElemType int #define Status int */ typedef int ElemType; typedef int Status; /* #define LNo

基于单链表的操作

单链表 功能设计 1从首元结点开始输出数据域即p->data直到p->next=NULL.typedef struct Node 定义一个链式存储的单链表Node *为结构体指针类型例如对于单链表Lp=L-〉next通过p->data 访问该元素的数据值. 2creatlist(linklist *H) 从空表开始每次读入数据生成新结点将读入的数据存放到新结点的数据域中然后将新结点插入到当前链表的表头结点之后直至读入结束位置为止. 3Leng(linklist *H ) 在单链表中整个链

数据结构之自建算法库——循环单链表

本文针对数据结构基础系列网络课程(2):线性表中第13课时双链表. 按照"0207将算法变程序"[视频]部分建议的方法,建设自己的专业基础设施算法库. 双链表算法库算法库采用程序的多文件组织形式,包括两个文件: 1.头文件:clinklist.h,包含定义双链表数据结构的代码.宏定义.要实现算法的函数的声明: #ifndef CLINKLIST_H_INCLUDED #define CLINKLIST_H_INCLUDED //循环单链表基本运算函数 typedef int ElemT