单链表操作

问题描述:

         常见的单链表操作题目:

  • 1、判断单链表是否有环,若有环求环的入口点         
  • 2、求单链表倒数第m个节点
  • 3、两个单链表是否相交,若相交求交点
  • 4、单链表原地逆序

 

单链表List定义如下:

#ifndef List_H
#define List_H

#include <iostream>
using namespace std;

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

class List
{
private:
    node* head;

public:

    List()
    {
        head=new node();
        head->data=-1;
        head->next=NULL;
    }

    void push_back(int v)
    {
        node* pnode=new node();
        pnode->data=v;
        pnode->next=head->next;
        head->next=pnode;
    }

    node* first()
    {
        return head->next;
    }

    node* last()
    {
        node* p=head->next;
        while (p->next!=NULL)
        {
            p=p->next;
        }
        return p;
    }

    //返回单链表第m个节点,单链表长度大于m
    node* getPtr(int m)
    {
        int i=1;
        node* p=first();
        while (i<m)
        {
            i++;
            p=p->next;
        }
        return p;
    }

    int length()
    {
        int len=0;

        node* p=first();
        while (p!=NULL)
        {
            len++;
            p=p->next;
        }
        return len;
    }

    void print()
    {
        node* p=head->next;
        while (p!=NULL)
        {
            cout<<p->data<<"-->";
            p=p->next;
        }
        cout<<"#"<<endl;
    }

    ~List()
    {
        while (head->next!=NULL)
        {
            node* p=head->next;
            head->next=p->next;
            delete p;
        }
        delete head;
    }
};

#endif

 

2、求单链表倒数第m个节点

思路:

     设置两个指针,一个指针指向单链表第1个节点,第二个指针指向单链表第m个节点,两个指针同时开始步进,

当第二个指针指向单链表最后一个节点时,第一个指针指向单链表倒数第m个节点

#ifndef MBackword_H
#define MBackword_H

#include "List.h"

/**
*    求解单链表倒数第m个节点
*/
int Mbackword(List* p,int m)
{
    node* plist=p->first();
    node* ptr=p->first();
    int i=1;

    //取得第m个节点
    /*while (ptr!=NULL && i<m)
    {
        ptr=ptr->next;
        i++;
    }*/
    ptr=p->getPtr(m);
    //cout<<"data:"<<ptr->data<<endl;

    //两个指针同时遍历,ptr[从第m个位置开始遍历]到达链表尾部时,plist指向倒数第m个节点
    while (ptr->next!=NULL)
    {
        ptr=ptr->next;
        plist=plist->next;
    }

    return plist->data;
}

#endif

 

 

3、求两个单链表是否相交,若相交求交点

思路:

       如果两个单链表相交,那么两个单链表的最后一个节点一定相同,可以对两个单链表进行遍历,比较两个链表最后一个节点的地址是否相同,

若相同则两个单链表相交。

        求相交的节点,可以先计算两个单链表的长度分别为LenA和LenB,如果LenA>LenB ,那么,单链表A从第(LenB-LenA)开始遍历,单链表B

从第一个节点开始遍历,当两个指针相同时,即为两个单链表的交点。对于LenA<LenB的情况也相同。

#ifndef _INTERSECTION_H
#define _INTERSECTION_H

/*
*    判断两链表是否相交,若相交求出交点
*/

//判断是否相交
bool isIntersection(List* listA,List* listB)
{
    bool intersect=false;

    node* pa=listA->last();
    node* pb=listB->last();
    if (pa==pb)
    {
        intersect=true;
    }
    return intersect;
}


//返回交点
int intersection(List* listA,List* listB)
{
    int value=-1;    //相交时,存储相交节点的数值,否则为-1

    if (isIntersection(listA,listB))
    {
        int lenA=listA->length();
        int lenB=listB->length();
        node* pa=listA->first();
        node* pb=listB->first();

        int distance=lenA-lenB;
        if (distance>0)    //ListA比较长
        {
            node* pa=listA->getPtr(distance+1);
            while (pa!=pb)
            {
                pa=pa->next;
                pb=pb->next;
            }
            value=pa->data;
        }
        else    //ListB比较长
        {
            node* pb=listB->getPtr(-distance+1);
            while (pa!=pb)
            {
                pa=pa->next;
                pb=pb->next;
            }
            value=pa->data;
        }
    }

    return value;
}

#endif

 

     4、单链表原地逆序

     思路:

           一次遍历单链表,将单链表逆序。使用三个指针,分别指向单链表的第1个、第2个、第3个节点,第3个节点不为NULL时,进行while循环,每次循环过程中,修改第2个指针指向节点的next节点为第1个指针指向的节点,然后修改三个指针的位置,进行下一次遍历。

 

 

     1、判断单链表是否有环,如果有环则求解环的入口点

       思路:

              判断单链表是否有环可以使用两个指针,快指针和慢指针,慢指针步进长度为1,快指针步进长度为2,遍历单链表当快指针

       不为NULL时,快指针与慢指针相等则单链表存在环,否则,不存在环

             单链表存在环的情况下,求解环的入口,可以进行如下的计算:

             1.1 首先求解使用快慢指针,单链表相交的节点。

             1.2 假设单链表环的长度为r,单链表第一个节点到环的入口点长度为a,若慢指针走了S步,则快指针走了2S步,

                   存在如下的等式:2S=S+nr;  (其中n 为快指针绕环的圈数,r为环的长度 ),也就是S=nr 

              1.3 假设快慢指针相交点,距离环入口点的距离为x ,那么存在如下等式:

                            S=a+x;   由于 S=nr 也就是 a = nr – x =( n-1 )r +( r – x )

                     这说明,单链表第1个指针从第1个节点开始遍历,第2个指针从快慢指针相遇的地方,开始遍历,步进长度为1

                      最终两个指针会在单链表的入口点相遇。

                     
                              image

 

#ifndef _ISLOOP_H
#define _ISLOOP_H

/*
*    单链表是否有环
*/
node* isLoop(List* list)
{
    node* pmeet=NULL;

    node* slow=list->first();    //慢指针,步进长度为1
    node* fast=list->first();    //快指针,步进长度为2

    while(fast!=NULL)
    {
        //先步进,防止初始时slow==fast
        slow=slow->next;
        fast=(fast->next!=NULL?fast->next->next:NULL);

        if (slow==fast)
        {
            pmeet=slow;
            break;
        }
    }
    return pmeet;
}

/*
*    求解单链表环的入口
*/
int entrace(List* list)
{
    int data=-1;
    node* pmeet=isLoop(list);

    if (pmeet!=NULL)    //存在环的情况
    {
        node* ptr=list->first();
        while(ptr!=pmeet)
        {
            ptr=ptr->next;
            pmeet=pmeet->next;
        }
        data=ptr->data;
    }
    return data;
}


#endif
posted @ 2014-02-26 21:00  罗松超  阅读(498)  评论(0编辑  收藏  举报