带环链表的几个问题

带环链表的几个问题

遇到了一个面试题。

题是这样的:

1、         判断一个单链表是否存在环

2、         如果存在,求环的长度

3、         如果存在,求环的起始节点

4、         如果存在,整个链表的长度

参考了

http://blog.csdn.net/liuxialong/article/details/6555850

http://blog.csdn.net/thefutureisour/article/details/8174313

记录一下:

对于问题1,使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。

对于问题2,记录下问题1的碰撞点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s。

3、问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点。

该定理的证明可参考:http://fayaa.com/tiku/view/7/

4、问题3中已经求出连接点距离头指针的长度,加上问题2中求出的环的长度,二者之和就是带环单链表的长度

下面是自己写的测试代码

#include <iostream>
using namespace std;


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


class CNode{
    private:
        struct node *head;//单链表的头
        struct node *meet;//记录相遇点
        int size;
        int loop_len;
        int total_len;
    public:
        CNode(int data[],int n,int start);
        bool isloop();
        int get_loop_len()//获取环的长度
        {
            return loop_len;
        }
        int get_total_len()//获取整个链表的长度
        {
            return total_len;
        }
        int get_start();//获取环开始的地方的元素值
};
CNode::CNode(int data[],int n,int start):meet(NULL),loop_len(0),total_len(0)//构造函数,带排序功能
{
    size = n;
    head = NULL;
    int i = 0;
    struct node *q = NULL;
    for(i = 0;i < n;i++)
    {
        struct node *p = new struct node;
        p->data = data[i];
        p->next = NULL;
        if(i == 0)
        {
            head = p;
            head->next = NULL;
        }
        else
        {
            if(p->data < head->data)//比头数据要小
            {
                p->next = head;
                head = p;
            }
            else
            {
                struct node *pre = head;
                struct node *curr = head->next;
                while(curr != NULL)
                {
                    if(p->data < curr->data)//找到合适位置
                    {
                        break;
                    }
                    pre = curr;
                    curr = curr->next;
                }
                p->next = curr;
                pre->next = p;
            }
        }
        q = p;
    }
    //下面是变成环的过程

    struct node *current = head;
    while(current != NULL)
    {
        if(current->data == start)
        {
            break;
        }
        current = current->next;
    }
    q->next = current;//形成环
}

bool CNode::isloop()//判断是否存在环
{ 
    struct node *fast = head;
    struct node *slow = head;
    int count = 0;//记录相遇的次数
    while(fast->next != NULL && fast->next->next != NULL)//C语言采用的是短路与,所以可以这样
    {
        if(fast == slow)
        {
            count++;
            if(count == 1)//第一次相遇
            {
                loop_len = 0;//开始计数
            }
            if(count == 2)
            {
                meet = slow;
                return true;
            }
        }
        loop_len++;
        fast = fast->next->next;
        slow = slow->next;
    }
    return false;
}

int CNode::get_start()
{
    struct node *p = head;
    struct node *q = meet;
    int num = 0;
    while(p != q)
    {
        num++;
        p = p->next;
        q = q->next;
    }
    total_len = num + loop_len;
    return p->data;
}


int main()
{
    int data[9] = {7,4,6,5,3,1,2,8,9};
    CNode cnode(data,9,4);
    if(cnode.isloop())
    {
        cout<<"链表存在环!"<<endl;
    }
    cout<<"环的开始点为:"<<cnode.get_start()<<endl;
    cout<<"环的长度为:"<<cnode.get_loop_len()<<endl;
    cout<<"链表的总长度为:"<<cnode.get_total_len()<<endl;
    return 0;
}

最后附上word和源代码链接 

链接:http://pan.baidu.com/s/1mhHdQkg 密码:wtyy

如果你觉得对你有用,请赞一个吧~~

原文地址:https://www.cnblogs.com/qingergege/p/7624482.html