链表常见操作:环、倒数第k个、是否相交
2014-05-24 17:27
183 查看
链表常见操作:判断是否有环
链表中很常见的一问题是,是否有环?如下图:
怎么办呢?正常链表的尾节点的链域是NULL,有环就不存在NULL了!对了,用一指针轮询,不断地 p=p->next; 若是看到了p为NULL,则表明无环!否则,就是有环。这个想法挺好,但是有环,会进入死循环的。有人说,那就设置一时间点,过了时间还没结束,就是有环。我想说,那万一链表真的很长呢,时间点设置多少才够了?……
办法是有的:使用两指针,一快一慢,都从头开始轮询,若有环,则慢的肯定可以被快的反超,因为此时大家都像是在围绕着环形跑道赛跑;若是一正常链表,则肯定会遇到NULL,好了,问题解决了。
该判断函数可以这样写:
链表二是这样的:head2->4->5->6->NULL 正常链表,无环
运行:
链表常见操作:输出倒数第k个节点(最后一个节点是倒数第一个)
看着很棘手,怎么才能数到倒数第k个?首先,链表长度不知,又是单向的。怎么办?
方法一:先求出链表长度,这个大家肯定会,只要 p!=NULL 就不断地 p=p->next; 移动一次,就记数 count++; 然后的事情大家都知道,从头再轮询 n-k 次就行了。
方法二:有比方法一,更好的方法吗?有的!还是两指针,一指针先从头移动k次,此时两指针间隔k(就是要这个差距),此时两指针同时移动,快慢一样,等到先走的指针移动到NULL,第二个指针不就是倒数第k个吗?对的!
方法二比方法一高效,下面就只给出方法二的代码:
运行:
大家可以试着写写方法一的代码。多尝试,才会有进步!我写了一个在一楼,欢迎不吝赐教!
链表常见操作:是否相交
两链表相交情形如下:
看到图:其实思路就很明显了,一指针沿着其中一链表走到尾节点处等着,另一链表的指针也从头走到尾,若能在尾处相遇,则两链表在某节点处相交。逻辑比较简单,直接看代码。
测试代码如下:
构建了三个链表:
head1->1->2->3->4->NULL
head2->5->6->3->4->NULL
head3->7->8->NULL
显然,head1和head2是相交的,head3与它们俩都是不相交的。
运行:
转载请注明出处,本文地址:/article/1378998.html
若是对你有所帮助,或是觉得有意思,希望顶一个哦。
专栏目录:
数据结构与算法目录
c指针
链表中很常见的一问题是,是否有环?如下图:
怎么办呢?正常链表的尾节点的链域是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>链表一是这样的:head1->1->2->3->1 是有环的
#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;
}
链表二是这样的: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指针
相关文章推荐
- 单链表的经典操作,查找链表倒数第k个节点,判断链表是否存在环,求环节点
- 链表倒数第k个结点、链表中间节点、链表是否有环
- 链表操作之翻转链表以及求倒数第K个节点
- 【算法之链表(一)】判断单链表中是否有环、环的长度、环的入口节点,单链表的倒数第K个节点等
- 常见链表面试题之判断链表是否相交,并求交点
- 常见链表操作之判断链表是否有环
- 建立一个带附加头结点的单链表.实现测长/打印/删除结点/插入结点/逆置/查找中间节点/查找倒数第k个节点/判断是否有环
- 单链表操作之删除倒数第k个结点
- java实现单向链表CRUD,反转,排序,查找倒数第k个元素,递归输出等操作
- 20140719 找到单链表的倒数第K个节点 判断一个链表是否成为一个环形 反转
- 关于链表结构的基本操作 c 实现 (创建,插入删除,反转,合并链表,查找,是否有环,链表相交情况)
- 面试题之链表问题 - 找出倒数第k个元素(或中间元素)
- 判断单链表是否存在环,判断两个链表是否相交问题详解(zz)
- 查找链表中倒数第K个节点
- 查找链表中倒数第k个结点
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 判断两个链表是否相交
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 判断单链表是否存在环,判断两个链表是否相交问题详解
- 查找链表中倒数第k个结点