您的位置:首页 > 其它

链表常见操作:环、倒数第k个、是否相交

2014-05-24 17:27 183 查看
链表常见操作:判断是否有环

链表中很常见的一问题是,是否有环?如下图:



怎么办呢?正常链表的尾节点的链域是NULL,有环就不存在NULL了!对了,用一指针轮询,不断地 p=p->next; 若是看到了p为NULL,则表明无环!否则,就是有环。这个想法挺好,但是有环,会进入死循环的。有人说,那就设置一时间点,过了时间还没结束,就是有环。我想说,那万一链表真的很长呢,时间点设置多少才够了?……

办法是有的:使用两指针,一快一慢,都从头开始轮询,若有环,则慢的肯定可以被快的反超,因为此时大家都像是在围绕着环形跑道赛跑;若是一正常链表,则肯定会遇到NULL,好了,问题解决了。

该判断函数可以这样写:

bool hasLoop(Node *head)
{
	if (head == NULL)   //链表为空
		return false;
	Node *p,*q;
	p = q = head;  //两个指针从同一点出发,当然也可以一前一后
	while (p && q)
	{
		p = p->next;  //一次一步
		q = q->next->next;  //一次两步
		if (p == q)   //相遇,肯定有环
			return true;
	}
	return false;   //出现了NULL,也就无环
}
一测试用例;

#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int data;
struct node *next;
}Node;
bool hasLoop(Node *head) { if (head == NULL) //链表为空 return false; Node *p,*q; p = q = head; //两个指针从同一点出发,当然也可以一前一后 while (p && q) { p = p->next; //一次一步 q = q->next->next; //一次两步 if (p == q) //相遇,肯定有环 return true; } return false; //出现了NULL,也就无环 }
int main()
{
//构建一有环链表
Node *head1 = NULL;
Node p1, p2, p3;
p1 = { 1, &p2 };
p2 = { 2, &p3 };
p3 = { 3, &p1 };
head1 = &p1;
printf("链表一 ");
if (hasLoop(head1))
printf("有环!\n");
else
printf("无环!\n");
//构建一正常链表(无环)
Node *head2 = NULL;
Node p4, p5, p6;
p4 = { 4, &p5 };
p5 = { 5, &p6 };
p6 = { 6, NULL };
printf("链表二 ");
if (hasLoop(head2))
printf("有环!\n");
else
printf("无环!\n");
system("pause");
return 0;
}
链表一是这样的:head1->1->2->3->1 是有环的

链表二是这样的:head2->4->5->6->NULL 正常链表,无环

运行:



链表常见操作:输出倒数第k个节点(最后一个节点是倒数第一个)

看着很棘手,怎么才能数到倒数第k个?首先,链表长度不知,又是单向的。怎么办?

方法一:先求出链表长度,这个大家肯定会,只要 p!=NULL 就不断地 p=p->next; 移动一次,就记数 count++; 然后的事情大家都知道,从头再轮询 n-k 次就行了。

方法二:有比方法一,更好的方法吗?有的!还是两指针,一指针先从头移动k次,此时两指针间隔k(就是要这个差距),此时两指针同时移动,快慢一样,等到先走的指针移动到NULL,第二个指针不就是倒数第k个吗?对的!

方法二比方法一高效,下面就只给出方法二的代码:

#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
	int data;
	struct node *next;
}Node;

void endOfK(Node *head, int k)
{
	if (head == NULL)
	{
		printf("链表为空!");
		return;
	}
	Node *p, *q;
	p = q = head;
	int count = 0;
	while (p && count < k)
	{
		p = p->next;
		count++;
	}
	if (p == NULL && count!=k)     //update : 这里原先只有 p==NULL ,更新后加上 count!=k,大家想想为什么?
	{
		printf("k值过大!\n");
		return;
	}
	while (p)
	{
		p = p->next;
		q = q->next;
	}
	printf("倒数第%d个节点是 %d\n",k,q->data);
}
void clear(Node *head)
{
	Node *q,*p = head;
	while (p)
	{
		q = p->next;
		free(p);
		p = q;;
	}
}
int main()    //32
{
	Node *p=NULL,*head = NULL;
	int data;
	printf("输入链表中的元素,以0结束!\n");
	while (scanf_s("%d", &data) && data)
	{
		if (head == NULL)
		{
			p = (Node*)malloc(sizeof(Node));
			head = p;
		}
		else
		{
			p->next = (Node*)malloc(sizeof(Node));
			p = p->next;
		}
		p->data = data;
		p->next = NULL;
	}
	int k;
	printf("输入倒数第几个 ");
	scanf_s("%d",&k);
	endOfK(head, k);
	clear(head);
	system("pause");
	return 0;
}


运行:



大家可以试着写写方法一的代码。多尝试,才会有进步!我写了一个在一楼,欢迎不吝赐教!



链表常见操作:是否相交

两链表相交情形如下:



看到图:其实思路就很明显了,一指针沿着其中一链表走到尾节点处等着,另一链表的指针也从头走到尾,若能在尾处相遇,则两链表在某节点处相交。逻辑比较简单,直接看代码。

测试代码如下:

#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
	int data;
	struct node *next;
}Node;

bool isCross(Node *head1, Node *head2)   //判断是否相交的函数
{
	if (!head1 || !head2)   //有一个为空,则不相交
		return false;
	Node *p = head1;
	while (p->next)
		p = p->next;
	Node *q = head2;
	while (q->next)
		q = q->next;
	return p == q;
}
int main()    //33
{
	Node *head1,*head2,*head3;
	head1 = head2 = head3 = NULL;
	Node p1, p2, p3, p4, p5, p6, p7, p8;
	p1 = { 1, &p2 };
	p2 = { 2, &p3 };
	p3 = { 3, &p4 };
	p4 = { 4, NULL };
	p5 = { 5, &p6 };
	p6 = { 6, &p3 };
	p7 = { 7, &p8 };
	p8 = { 8, NULL };
	head1 = &p1;
	head2 = &p5;
	head3 = &p7;
	printf("head1与head2相交与否? ");
	isCross(head1, head2) ? printf("相交!\n") : printf("不相交!\n");
	printf("head1与head3相交与否? ");
	isCross(head1, head3) ? printf("相交!\n") : printf("不相交!\n");
	system("pause");
	return 0;
}


构建了三个链表:

head1->1->2->3->4->NULL

head2->5->6->3->4->NULL

head3->7->8->NULL

显然,head1和head2是相交的,head3与它们俩都是不相交的。

运行:



转载请注明出处,本文地址:/article/1378998.html

若是对你有所帮助,或是觉得有意思,希望顶一个哦。

专栏目录:

数据结构与算法目录
c指针
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐