判断单链表是否有环

来源:互联网 发布:指南针炒股软件诈骗 编辑:程序博客网 时间:2024/05/22 06:41

前言:

其实这个题目是面试官给提的,由于当时在学习数据结构与算法的时候没有接触过这类问题,因此通过在网上查阅资料和自己的理解产生这篇博客,希望能帮得到大家。

如下面的单链表:

这里写图片描述

如何判断该链表中是否存在环。

方法一:

使用 p、q 两个指针,p 总是向前走,但 q 每次都从头开始走,对于每个节点,看 p 走的步数是否和 q 一样。如果对于每个节点,p、q 走过的步数都是一样的,则证明不存在环,反之,存在环。

代码(C语言实现):

// param 单链表头结点指针bool has_loop1(struct node * head){    //p、q 指针    node_t p = head,q = head;     //typedet struct node * node_t    //步数    int p_count = 0,q_count = 0;    while(q != NULL && p_count == q_count){        //重置p指针和步数        p = head;        p_count = 0;        //q继续遍历链表        q = q -> next;        q_count ++;        while(p != q){            p = p -> next;            p_count ++;        }        //当 p == q 时,判断各自走过的步数        if(p_count != q_count){            return true;        }    }    return false;}

网上也有不同的类似的解决方法:

首先从头节点开始,依次遍历单链表的每一个节点。每遍历到一个新节点,就从头节点重新遍历新节点之前的所有节点,用新节点ID和此节点之前所有节点ID依次作比较(这个节点ID直接用地址就行)。如果发现新节点之前的所有节点当中存在相同节点ID,则说明该节点被遍历过两次,链表有环;如果之前的所有节点当中不存在相同的节点,就继续遍历下一个新节点,继续重复刚才的操作。或者是将遍历过的节点放到 hash 表(数组)中,每遍历一个新节点,将新节点和 hash 表(数组)中的旧节点作比较,如果存在,则证明该链表有环。

这些方法的核心思想无非就是将新节点与遍历过的旧节点做比较,因此我就不在展开分析。

方法二:

使用 p、q 两个指针,p 每次向前走一步,q 每次向前走两步,若在某个时候 p == q,则存在环。

该方法应该算是业界中效率最高的吧,网上的博客中都会说到这个方法。

其实理解这个方法不是很难,这个方法就好比有两个人甲、乙在跑道上(环状)跑步(同时同起点出发),乙的速度是甲的两倍,总有某一个时刻乙会追上甲,此时乙跑的路程比甲多一圈。回归到我们的问题,q 的速度是 p 的两倍,那么如果存在环的话,q 和 p 在某个时刻总会相遇的(即 p == q)。

代码:

//param 单链表头结点指针bool has_loop2(struct node * head){    //同起点    node_t p = head,q = head;    while(p != NULL && q != NULL){        p = p->next;        q = q->next;        if(q != NULL){            q = q->next;        }        //这里 q=q->next->next 分开是为了防止段错误        //p 和 q 相遇        if(p != NULL && q != NULL && p == q){            return true;        }    }    return false;}

结尾:

现在我们来看看客户端代码:

#include <stdio.h>#include <stdlib.h>#include <stdbool.h>//链表长度#define LEN 8//节点结构struct node{    char var;    struct node * next;};typedef struct node * node_t;//方法一:计算步长bool has_loop1(struct node * head);//方法二:判断两个指针是否相遇bool has_loop2(struct node * head);int main(void){    node_t head = (node_t)malloc(sizeof(struct node));    node_t pre = head;    node_t link = NULL;    int i;    for(i = 0;i < LEN;i ++){        node_t new_node = (node_t)malloc(sizeof(struct node));        pre->next = new_node;        pre = pre->next;        if(i == 2){            link = pre;        }    }    pre->next = pre;    if(has_loop1(head)){        printf("存在环\n");    }else{        printf("不存在环\n");    }    if(has_loop2(head)){        printf("存在环\n");    }else{        printf("不存在环\n");    }    return 0;}

本博客参考自 http://www.cnblogs.com/shuaiwhu/archive/2012/05/03/2480509.html,加上自己的理解,如果上面代码有错的地方,欢迎指正。

0 0
原创粉丝点击