数据结构与算法:判断单链表中是否存在环

数据结构与算法:判断单链表中是否存在环

1. 概述

  单链表结构如下图所示:
在这里插入图片描述
  单链表就和串葫芦一样,一个接一个,那么针对一批次串葫芦,如何检查确认此串葫芦是否有劣质品和残次品呢?串葫芦中的残次品即在单链表中出现了内部环,如下图所示:
在这里插入图片描述
  本博文针对单链表中存在的此类问题,通过阐述两种方案来实现对单链表中是否存在环进行检查

  注:需要区分存在环的单链表和循环链表,见下图:
在这里插入图片描述

2. 方案一

2.1 原理

通过采用双指针pq ,在一个大前提条件:p 的下一个指向内容不为空 下对链表进行查询:

  • p 指针每次向前移动一步并记录总计行走的步数p_step
  • q 指针每次从0开始移动,出现以下条件结束
    • q 的行走步数q_step 等于p 的行走步数p_step
    • 或者出现p 的下一个指向与q 的下一个指向相同直接退出

示意图如下图所示:
在这里插入图片描述
判断单链表存在环的条件:

  • p 的下一个指向p->next 等于q 的下一个指向q->next ,但是p_step 不等于q_step

如下图所示:
在这里插入图片描述

2.2 代码实现

  1. 创建一个带环的链表,代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

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;
}
  1. 判断链表是否存在环
/**
 * @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");
    }
}
  1. 执行代码测试
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

3. 方案二

3.1 原理

通过采用 快慢指针 的方式遍历链表

  • 采用pq 两个指针,慢指针·p 每次向前移动一步,快指针q 每次向前移动两步
  • 在大前提快指针 q 的下一个指向不为空,且 q 的下一个指向的指向不为空 情况下对链表进行查询,示意图如下:
    在这里插入图片描述
    判断单链表存在环的条件:
  • p 的下一个指向p->next 等于q 的下一个指向q->next (或者p等于q),但是p_step 不等于q_step

如下图所示:
在这里插入图片描述

3.2 代码实现

  1. 创建带环的链表
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

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;
}
  1. 判断链表是否带环
/**
 * @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");
}
  1. 执行代码测试
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

猜你喜欢

转载自blog.csdn.net/qq_43332314/article/details/126692352
今日推荐