数据结构之线性表-单向循环链表的尾指针(下)-学习笔记-25

引入

上一节,我们学习了尾指针,并且利用尾指针。尾指针可以轻松的操作头结点和尾结点,可以将两个单循环链表组成了一个单循环链表,我们今天再看看,尾指针还有什么其它玩法。

单链表中的环

首先要明白,单链表有环的状态是什么样子得

其实就是,尾指针指向了链表中的某个结点。

如何判断单链表中是否有环

方法 1

  • 设置 p 、q 两个指针
  • p 向前走,q 从头走,p 向前走尾部应该会到 NULL。
  • 每个结点,p 走的步数应该和 q 一样
  • 如果不一样,就像上面的图,p 的地址等于 q
  • 但是,p 走到3用了6步,q 则用了2步
  • 步数不相等,那么就存在环

方法 2

  • 设置 p 、q 两个指针
  • p 每走一步,q 就走两步,快慢指针
  • 快指针应该很快到 NULL
  • 如果 p==q 了,则存在环

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include <stdlib.h>
#define NUM 10
#define LEN sizeof(struct Link)

struct Link{
int num;
struct Link *next;
};

struct Link *create(void){
struct Link *a,*b,*head;
a=b=(struct Link *)malloc(LEN);
int i=0;
while(i<NUM){
i++;
a->num=i;
if(i==1){
head=a;
}else{
b->next=a;
}
b=a;
a=(struct Link *)malloc(LEN);
}
b->next=head->next->next->next->next; //将尾部指向某个结点
return head;
}

int hasloop (struct Link *L){
struct Link *a,*b;
int step_a=0;
a=L;
while(a){
int step_b=0;
b=L;
while(b){
if(a==b){ //如果地址相同
if(step_a==step_b){ //如果步数相同,没事
break;
}else{ //如果步数不相同,则肯定有指针是通过环过来得
printf("第%d个结点存在环\n",step_b+1);
return step_b;
}
}
b=b->next;
step_b++;
}
a=a->next;
step_a++;
}
return 0;
}

int main(){
struct Link *test;
test=create();
hasloop(test);
return 0;
}

代码实现的主要思路就是

  • A 指针走一步
  • B 也走,循环遍历,什么时候走的地址等于 A 走的这一步的地址了
  • 就判断,A 走的这一步的步数等于不等于 B 走的步数
  • 如果地址相等、步数相等,那OK!
  • 如果地址相等,步数不等,那 B 肯定抄近路走环了
  • 就把 b 当前得步数输出出来就行了!,这就是出问题的结点

用快慢指针实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <stdio.h>
#include <stdlib.h>
#define NUM 12
#define LEN sizeof(struct Link)

struct Link{
int num;
struct Link *next;
};

struct Link *create(void){
struct Link *a,*b,*head;
a=b=(struct Link *)malloc(LEN);
int i=0;
while(i<NUM){
i++;
a->num=i;
if(i==1){
head=a;
}else{
b->next=a;
}
b=a;
a=(struct Link *)malloc(LEN);
}
b->next=NULL; //将尾部指向某个结点
return head;
}
int hasloop (struct Link *L){
struct Link *normal ,*fast;
fast=L->next; //fast 从第2个开始
normal=L; //normal 从第1个开始
while(fast){ //判断 fast 是否为 NULL
if(fast==normal){ //如果fast地址等于normal的地址
printf("存在环!\n");
return 0;
}else{
fast=fast->next; //如果地址不同,那么再让 fast 向后移动一位也就是第二位
if (!fast) { //判断 fast 是否为 NULL,如果为 NULL,则没有环
printf("没有环!\n");
}else{ //否则大家就都向后移动一位
fast=fast->next;
normal=normal->next;
}
}
}
return 0;
}


int main(){
struct Link *test;
test=create();
hasloop(test);
return 0;
}

用快慢指针的方法大概思路如下

  • 因为normal要移动1位,fast 移动2位
  • 要判断 fast 移动的这两位是否为 NULL 了
  • 如果为 NULL,则一定没有环
  • 如果不为 NULL,那就继续比较
  • 直到地址相同或者遇到 NULL 为止

尾巴

这是我的个人学习笔记,主要是应付考研复习使用,充斥着一些吐槽和个人观点,并不严谨,欢迎大家参考、指正。


-------------The End-------------
欢迎请我喝咖啡哦~!