zoukankan      html  css  js  c++  java
  • 单链表操作

    问题描述:

             常见的单链表操作题目:

    • 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
  • 相关阅读:
    面试40-一个数组,有2个数字出现奇数次,其余都是偶数次,求这两个数字O(n) O(1)
    面试38-数字在排序数组中出现的个数
    面试35-删除字符串重复字符-删除出现在第二个字符串中的字符-第一个只出现一次的字符-hash表计数
    意外get接近完美的黑苹果 (UEFI + GPT)
    Windows 启用/禁用内置管理员 Administrator
    出去走走
    【搬运】Wget 命令详解
    C语言学习之插入排序
    由 UWP 版网易云音乐闪退引发的博文
    gets() 与 scanf() 的小尴尬
  • 原文地址:https://www.cnblogs.com/luosongchao/p/3570203.html
Copyright © 2011-2022 走看看