基础算法分析实现

单链表有环问题 - 你emo了没

2022-08-10  本文已影响0人  erlich

这是个老套的问题,也是个经典的问题

有没有技术含量,我们不纠结

从最朴实的逻辑思路去分析,然后自己感觉为什么总有人要问及这个问题

...

问题:

要求:

示意图

image.png

分析

我们最直观的意识,可能就是用set遍历存储节点,由于set不能存储重复元素,所以只要在某个节点存储时,发现set中已经包含元素,则说明有环存在

但是题目要求不能额外开辟空间

剩下的条件很有限,像这样很明确的很简单的条件,往往我们考虑起来却花费很长时间,往往还想不明白,明明感觉很简单的

几何定理也只是通过5条很简单的公理推导出来的

有这种困惑,原因在于我们平时缺乏这方面的思维锻炼

思路方向的诊断

手代替脑活动

情况一:正好在环入口相遇

image.png

情况一:非环入口节点相遇,在环内的一个节点相遇

image.png

到此,分析结束,实现代码就不存在任何障碍了

实现

struct LinkList {
    int data;
    struct LinkList *next;
};

// 创建 nodeCount个节点的 单链表
struct LinkList* createLinkList(int nodeCount) {
    struct LinkList *head;
    struct LinkList *p;
    for (int i = 0; i < nodeCount; i++) {
        struct LinkList* node = (struct LinkList *)malloc(
sizeof(struct LinkList));
        node->data = i + 1;
        node->next = NULL;
        if (i == 0) {
            head = node;
            p = node;
        } else {
            p->next = node;
            p = node;
        }
    }
    return head;
}

// 打印单链表
// 最多打印 maxNodeCount 个节点
void printLinkList(struct LinkList *linkList, int maxNodeCount) {
    int index = 0;
    struct LinkList *p = linkList;
    if (p == NULL) {
        return;
    }
    while (p != NULL) {
        if (index >= maxNodeCount) {
            break;
        }
        printf("-->%i", p->data);
        p = p->next;
        index++;
    }
    

    printf("\n");
}

// 单链表构建一个环
// nodeIndex 第nodeIndex个节点 作为环入口
void configLinkCircle(struct LinkList *linkList, int nodeIndex) {
    int index = 0;
    struct LinkList *entraceNode = NULL;
    struct LinkList *p = linkList;
    if (p == NULL) {
        return;
    }
    while (p != NULL) {
        if (index == nodeIndex) {
            entraceNode = p;
        }
        if (p->next == NULL) {
            p->next = entraceNode;
            break;
        }
        p = p->next;
        index++;
    }
}

// 判断环 返回入口节点
struct LinkList *checkLinkListCircle(struct LinkList *linkList) {
    // 链表头
    struct LinkList *head = linkList;
    // 快指针
    struct LinkList *pf = linkList;
    // 慢指针
    struct LinkList *ps = linkList;
    if (linkList == NULL) {
        return NULL;
    }
    
    while (true) {
        if (pf != NULL && pf->next != NULL) {
            ps = ps->next;
            pf = pf->next->next;
            if (pf == ps) {
                break;
            }
        } else {
            printf("\n链表不存在环\n");
            return NULL;
        }
    }
    
    pf = head;
    int index = 0;
    while (pf != ps) {
        index++;
        ps = ps->next;
        pf = pf->next;
    }
    index++;
    printf("\n链表在第%i个节点处形成环,节点为:%i\n", index + 1, pf->data);
    
    return NULL;
}


int main(int argc, const char * argv[]) {
    int n = 30;
    
    int nodeCount = 20;
    struct LinkList *linkList = createLinkList(nodeCount);
    configLinkCircle(linkList, 8);
    printLinkList(linkList, nodeCount * 2);
    
    struct LinkList* entraceNode = checkLinkListCircle(linkList);
    
    return 0;
}
上一篇下一篇

猜你喜欢

热点阅读