头疼的算法与数据机构——判断链表是否有环

判断链表是否有环的:

如图,如果单链表有环,则在遍历时,在通过6之后,会重新回到3,那么我们可以在遍历时使用两个指针,看两个指针是否相等。


方法一:使用p、q两个指针,p总是向前走,但q每次都从头开始走,对于每个节点,看p走的步数是否和q一样。如图,当p从6走到3时,用了6步,此时若q从head出发,则只需两步就到3,因而步数不等,出现矛盾,存在环

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

代码如下:

#include <stdio.h>


struct node{
    int data;
    struct node *next;
};
typedef struct node Node;
#define SIZE sizeof(Node)
int num=0;//节点个数

//创建节点
Node* creteNode(int d)
{
    Node* pn=(Node *)malloc(SIZE);
    pn->data=d;
    pn->next=NULL;
    return pn;
}

//创建有环链表
void creatList_hashuan(Node** h)
{
    Node* pn=NULL;
    Node* p=NULL;
    int d;
    printf("请输入数据\n");
    scanf("%d",&d);
    pn=creteNode(d);
    *h=pn;
    p=*h;
    num++;
    while(1)
    {
        printf("请输入数据\n");
        scanf("%d",&d);
        if(d==0)
            break;
        pn=creteNode(d);
        num++;
        p->next=pn;
        p=p->next;
    }
    p->next=(*h)->next->next;
}

void creatList(Node** h)
{
    Node* pn=NULL;
    Node* p=NULL;
    int d;
    printf("请输入数据\n");
    scanf("%d",&d);
    pn=creteNode(d);
    *h=pn;
    p=*h;
    num++;
    while(1)
    {
        printf("请输入数据\n");
        scanf("%d",&d);
        if(d==0)
            break;
        pn=creteNode(d);
        num++;
        p->next=pn;
        p=p->next;
    }
}

//比较步数的方法
int Loop1(Node* h)
{
    Node* p=h;
    int pos1=0;//步数1
    while(p)
    {
        Node* p1=h;
        int pos2=0;
        while(p1)
        {
            if(p==p1)
            {
                if(pos1==pos2)
                    break;
                else
                {
                    printf("环的位置在第%d个节点处\n",pos2);
                    return 1;
                }
            } 
            p1=p1->next;//如果没有发现环的存在,继续下一个节点
            pos2++; 
        }
        p=p->next;
        pos1++;
    }
    return 0;
}

//利用快慢指针的方法
int Loop2(Node* h)
{
    Node* p=h;
    Node* q=h;
    while(p!=NULL && q!=NULL && q->next!=NULL)
    {
        p=p->next;
        if(q->next->next!=NULL)
            {
                q=q->next->next;
            }
        else
        {
            printf("q指针走两步的话走出链表的范围了。所以只走一步:\n");
            q=q->next;
        }
        printf("p:%d,q:%d\n",p->data,q->data);
        if(p==q)
        {
            printf("该链表有环!\n");
            return 1;
        }  
    }
    return 0;
}

//打印有环链表
void print(Node* h)
{
    printf("list:\n");
    int i;
    for(i=0;i<num;i++)
    {
        printf("%d ",h->data);
        h=h->next;
    }
    printf("\n");
}

//打印无环链表
void print1(Node* h)
{
    printf("list:\n");
    while(h)
    {
        printf("%d ",h->data);
        h=h->next;
    }
    printf("\n");
}

int main()
{
    Node* head=NULL;
    int d;
    printf("-----------------------------\n");
    printf("---1.创建无环链表---\n");
    printf("---2.创建有环链表---\n");
    printf("-----------------------------\n");
    printf("请输入您的选项:");
    scanf("%d\n",&d);
    getchar();
    switch(d)
    {
        case 1:
        creatList_hashuan(&head); 
        print(head);
        Loop1(head);
        Loop2(head);
        break;
        case 2:
        creatList(&head);
        print1(head);
        Loop1(head);
        Loop2(head);
        break;
    }
    return 0;
}


其实我觉得最简单,最暴力,也是我的第一反应就是打印链表,如果有环,会循环打印。

void print1(Node* h)
{
    printf("list:\n");
    while(h)
    {
        printf("%d ",h->data);
        h=h->next;
    }
    printf("\n");
}
这样去打印如果是有环会循环打印。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值