单链表结构如下图所示:
单链表就和串葫芦一样,一个接一个,那么针对一批次串葫芦,如何检查确认此串葫芦是否有劣质品和残次品呢?串葫芦中的残次品即在单链表中出现了内部环,如下图所示:
本博文针对单链表中存在的此类问题,通过阐述两种方案来实现对单链表中是否存在环进行检查
通过采用双指针p
和 q
,在一个大前提条件:p 的下一个指向内容不为空
下对链表进行查询:
p
指针每次向前移动一步并记录总计行走的步数p_step
q
指针每次从0开始移动,出现以下条件结束
q
的行走步数q_step
等于p
的行走步数p_step
p
的下一个指向与q
的下一个指向相同直接退出p
的下一个指向p->next
等于q
的下一个指向q->next
,但是p_step
不等于q_step
#include
#include
#include
typedef struct node {
int data;
struct node *next;
} node_t;
node_t *create_ring_list(int number)
{
node_t *head = NULL;
node_t *p = NULL, *s = NULL;
int cnt = 0;
if (number <= 3)
return NULL;
head = (node_t *)malloc(sizeof(node_t));
if (head == NULL)
return NULL;
p = head;
while (cnt < number) {
s = (node_t *)malloc(sizeof(node_t));
s->data = cnt + 1;
s->next = NULL;
p->next = s;
p = s;
cnt ++;
}
p->next = head->next;
free(head);
head = p->next;
p->next = p->next->next->next; /* 形成环 最后一个指针指向第三个数据 */
return head;
}
/**
* @brief 判断链表是否存在环
*
* @note 采用p q指针方案实现 p每次走一步,q每次从头往后走
* @param list 链表指针
*/
void judge_list_exist_ring(node_t *list)
{
node_t *p = NULL, *q = NULL;
int p_step = 0, q_step = 0;
p = q = list;
while (p->next != NULL) {
p_step ++;
p = p->next;
q = list;
for (q_step = 1; q_step <= p_step; q_step++) {
q = q->next;
if (q->next == p->next)
break;
}
if (q_step != p_step)
break;
}
if (p->next != NULL) {
printf("This list exist ring, localtion is:%d.\n", q_step + 1);
} else {
q_step = 0;
printf("This list not exist ring.\n");
}
}
int main(void)
{
node_t *node = create_ring_list(5);
int cnt = 0;
judge_list_exist_ring(node);
while (node->next != NULL && cnt < 10) {
printf("%d ", node->data);
node = node->next;
cnt ++;
}
return 0;
}
执行结果如下:
This list exist ring, localtion is:2. 1 2 3 4 5 3 4 5 3 4
通过采用 快慢指针
的方式遍历链表
p
和 q
两个指针,慢指针·p
每次向前移动一步,快指针q
每次向前移动两步快指针 q 的下一个指向不为空,且 q 的下一个指向的指向不为空
情况下对链表进行查询,示意图如下:p
的下一个指向p->next
等于q
的下一个指向q->next
(或者p
等于q
),但是p_step
不等于q_step
#include
#include
#include
typedef struct node {
int data;
struct node *next;
} node_t;
node_t *create_ring_list(int number)
{
node_t *head = NULL;
node_t *p = NULL, *s = NULL;
int cnt = 0;
if (number <= 3)
return NULL;
head = (node_t *)malloc(sizeof(node_t));
if (head == NULL)
return NULL;
p = head;
while (cnt < number) {
s = (node_t *)malloc(sizeof(node_t));
s->data = cnt + 1;
s->next = NULL;
p->next = s;
p = s;
cnt ++;
}
p->next = head->next;
free(head);
head = p->next;
p->next = p->next->next->next; /* 形成环 最后一个指针指向第三个数据 */
return head;
}
/**
* @brief 判断链表是否存在环
*
* @note 采用快慢指针方案实现
* @param list 链表指针
*/
void judge_list_exist_ring2(node_t *list)
{
node_t *p = NULL, *q = NULL;
int cnt = 0;
p = q = list;
while (q->next != NULL && q->next->next != NULL) {
p = p->next;
q = q->next->next;
if (p->next == q->next)
break;
}
if (q->next == q->next)
printf("This list exist ring.\n");
else
printf("This list not exist ring.\n");
}
int main(void)
{
node_t *node = create_ring_list(5);
int cnt = 0;
judge_list_exist_ring2(node);
while (node->next != NULL && cnt < 10) {
printf("%d ", node->data);
node = node->next;
cnt ++;
}
return 0;
}
执行结果如下:
This list exist ring. 1 2 3 4 5 3 4 5 3 4