链表相关面试题总结大全

链表面试题大全:


1.删除有序链表中重复的结点,
然后返回新链表的头结点

//由于要返回新链表的头结点,
//所以要定义一个指针保存新链表的头结点;
//然后定义三个指针,分别记录已删除重复结点的尾结点;
//当前结点,当前结点的上一个结点;
#include<iostream>
using namespace std;
#include<cassert>
struct Node
{
    int data;
    Node* next;
    Node(const int x)
        :data(x)
        ,next(NULL)
        {}
};
Node* fun(Node* head)
{ 
    assert(head);
    Node* NewHead=NULL;//新链表头结点
    Node* cur=head->next;
    Node* prev=head;
    Node* end=NULL;//新链表更新完成的尾结点
    while (cur)
    {
        if (prev->data==cur->data)
        {
            while (cur&&prev->data==cur->data)
            {
                cur=cur->next;
            }
            if (end==NULL)
            {
                end=cur;
            }
            else
            {
                end->next=cur;
            }
            if (NewHead==NULL)
            {
                NewHead=cur;
            }
            end=cur;
            prev=cur;
            if (cur)
            {
                cur=cur->next;
            }
        }
        else
        {
            if (NewHead==NULL)
            {
                NewHead=prev;
            }
            end=prev;
            prev=cur;
            if (cur)
            {
                cur=cur->next;
            }
        }
    }
    return NewHead;
}
void show(Node* head)
{
    while (head)
    {
        cout<<head->data<<" ";
        head=head->next;
    }
}
int main()
{
    Node* head=new Node(1);
    Node* node2=new Node(1);
    Node* node3=new Node(2);
    Node* node4=new Node(3);
    Node* node5=new Node(4);
    Node* node6=new Node(4);
    Node* node7=new Node(4);
    Node* node8=new Node(5);
    Node* node9=new Node(5);
    Node* node10=new Node(6);
    Node* node11=new Node(7);
    Node* node12=new Node(7);
    Node* node13=new Node(7);
    Node* node14=new Node(7);
    head->next=node2;
    node2->next=node3;
    node3->next=node4;
    node4->next=node5;
    node5->next=node6;
    node6->next=node7;
    node7->next=node8;
    node8->next=node9;
    node9->next=node10;
    node10->next=node11;
    node11->next=node12;
    node12->next=node13;
    node13->next=node14;
    show(head);
    cout<<endl;
    Node* NewHead=fun(head);
    show(NewHead);
    return 0;
}


2.传进链表的头结点,逆序打印链表

#include<iostream>
using namespace std;
#include<cassert>
#include<stack>
struct Node
{
    int data;
    Node* next;
    Node(const int x)
        :data(x)
        ,next(NULL)
    {}
};

//方法一:
//借助栈的先进后出特点,每次从链表中读取一个结点放进栈中,
//当遍历完链表,然后从栈的末尾依次打印栈中的元素
void fun(Node* head)
{
    assert(head);
    stack<int> s;
    Node* cur=head;
    while (cur)
    {
        s.push(cur->data);
        cur=cur->next;
    }
    while (!s.empty())
    {
        cout<<s.top()<<" ";
        s.pop();
    }
}
//方法二:递归打印
void fun2(Node* head)
{
    if (head==NULL)
    {
        return ;
    }
    fun2(head->next);
    cout<<head->data<<" ";
}
int main()
{
        Node* head=new Node(1);
        Node* node2=new Node(1);
        Node* node3=new Node(2);
        Node* node4=new Node(3);
        Node* node5=new Node(4);
        Node* node6=new Node(4);
        Node* node7=new Node(4);
        Node* node8=new Node(5);
        Node* node9=new Node(5);
        Node* node10=new Node(6);
        Node* node11=new Node(7);
        Node* node12=new Node(7);
        Node* node13=new Node(7);
        Node* node14=new Node(7);
        head->next=node2;
        node2->next=node3;
        node3->next=node4;
        node4->next=node5;
        node5->next=node6;
        node6->next=node7;
        node7->next=node8;
        node8->next=node9;
        node9->next=node10;
        node10->next=node11;
        node11->next=node12;
        node12->next=node13;
        node13->next=node14;
        //fun(head);
        fun2(head);
    return 0;
}


3. O(1)时间内删除链表



#include<iostream>
using namespace std;
#include<cassert>
struct  Node
{
    int data;
    Node* next;
    Node(const int x)
        :data(x)
        ,next(NULL)
    {}
};


***********************************************************
//假定要删除的结点Node就是链表中的某个结点
void fun(Node*& Head,Node* node)
{
   assert(Head&&node);
   //1.链表只有一个结点,要删除的结点是头结点(尾结点)
   if (Head->next==NULL&&node==Head)
   {
       delete node;
       node=NULL;
       Head=NULL;
   }
   //2.链表有多个结点,删除的是非尾结点
   if (node&&node->next)
   {
       Node* next=node->next;
       Node* nnext=next->next;
       std::swap(next->data,node->data);
       delete next;
       next=NULL;
       node->next=nnext;
   }
   //3.链表有多个结点,且要删除的是链表的最后一个结点
   if (node&&node->next==NULL)
   {
       Node* cur=Head;
       while (cur->next!=node)
       {
           cur=cur->next;
       }
       cur->next=NULL;

       delete node;
       node=NULL;
   }
}
***********************************************************

void show(Node* head)
{
    assert(head);
    while (head)
    {
        cout<<head->data<<" ";
        head=head->next;
    }
}
int main()
{
    Node* head=new Node(1);
    Node* node2=new Node(2);
    Node* node3=new Node(3);
    Node* node4=new Node(4);
    Node* node5=new Node(5);
    Node* node6=new Node(6);
    Node* node7=new Node(7);
    head->next=node2;
    node2->next=node3;
    node3->next=node4;
    node4->next=node5;
    node5->next=node6;
    node6->next=node7;

    //fun(head,head);
 //   show(head);
    //
    //fun(head,node3);
    //show(head);

    fun(head,node7);
    show(head);
    return 0;
}


4.反转链表

#include<iostream>
using namespace std;
#include<cassert>
struct Node
{
    int data;
    Node* next;
    Node(const int x)
        :data(x)
        ,next(NULL)
    {}
};
Node* fun(Node* head)
{
    assert(head);
    Node* NewHead=NULL;
    Node* cur=head;
    Node* node=NULL;
    while (cur)
    {
        node=cur;
        cur=cur->next;
        node->next=NewHead;
        NewHead=node;
    }
    return NewHead;
}
void show(Node* head)
{
    assert(head);
    while (head)
    {
        cout<<head->data<<" ";
        head=head->next;
    }
}
int main()
{
        Node* head=new Node(1);
        Node* node2=new Node(2);
        Node* node3=new Node(3);
        Node* node4=new Node(4);
        Node* node5=new Node(5);
        Node* node6=new Node(6);
        Node* node7=new Node(7);
        head->next=node2;
        node2->next=node3;
        node3->next=node4;
        node4->next=node5;
        node5->next=node6;
        node6->next=node7;
    Node* NewHead=fun(head);
    show(NewHead);
    return 0;
}


5.输出链表的倒数第K个结点

#include<iostream>
using namespace std;
#include<cassert>
struct  Node
{
    int data;
    Node* next;
    Node(const int x)
        :data(x)
        ,next(NULL)
    {}
};
//假定K的值小于等于链表的总个数
void fun(Node* Head,int k)
{
    assert(Head);
    Node* first=Head;
    Node* end=Head;
    while (--k&&end)
    {
       end=end->next;
    }
    while (end->next)
    {
        first=first->next;
        end=end->next;
    }
    cout<<first->data<<endl;
}
int main()
{
    Node* head=new Node(1);
    Node* node2=new Node(2);
    Node* node3=new Node(3);
    Node* node4=new Node(4);
    Node* node5=new Node(5);
    Node* node6=new Node(6);
    Node* node7=new Node(7);
    head->next=node2;
    node2->next=node3;
    node3->next=node4;
    node4->next=node5;
    node5->next=node6;
    node6->next=node7;
    fun(head,1);
    fun(head,2);
    fun(head,3);
    fun(head,4);
    fun(head,5);    
    fun(head,6);
    fun(head,7);
    return 0;
}


6.合并两个排序的链表

#include<iostream>
using namespace std;
#include<cassert>
struct  Node
{
    int data;
    Node* next;
    Node(const int x)
        :data(x)
        ,next(NULL)
    {}
};
Node* fun(Node* Head1,Node* Head2)
{
    //1.两个有序链表中有一个是空
   if (Head1&&Head2==NULL)
   {
       return Head1;
   }
   if (Head2&&Head1==NULL)
   {
       return Head2;
   }
    //2两个链表都不为空
   Node* NewHead=NULL;//新链表头
   Node* Tail=NULL;//新链表尾
   Node* cur1=Head1;//遍历链表1
   Node* cur2=Head2;//遍历链表2
    //2.1确定新链表头结点
   if (Head1->data<Head2->data)
   {
       NewHead=Head1;
       cur1=cur1->next;
   }
   else
   {
      NewHead=Head2;
      cur2=cur2->next;
   }
   Tail=NewHead;
   while (cur1&&cur2)
   {
       if (cur1->data<cur2->data)
       {
           Tail->next=cur1;
           cur1=cur1->next;
       }
       else
       {
           Tail->next=cur2;
           cur2=cur2->next;
       }
       Tail=Tail->next;
   }
   //有可能一个链表没有遍历完
   if (cur1)
   {
       Tail->next=cur1;
   }
   if (cur2)
   {
       Tail->next=cur2;
   }
   return NewHead;  
}
void show(Node* head)
{
    assert(head);
    while (head)
    {
        cout<<head->data<<" ";
        head=head->next;
    }
}
int main()
{
    Node* node1=new Node(1);
    Node* node2=new Node(3);
    Node* node3=new Node(5);
    Node* node4=new Node(7);
    Node* node5=new Node(9);
    node1->next=node2;
    node2->next=node3;
    node3->next=node4;
    node4->next=node5;

    Node* node11=new Node(2);
    Node* node22=new Node(4);
    Node* node33=new Node(6);
    Node* node44=new Node(8);
    Node* node55=new Node(10);
    node11->next=node22;
    node22->next=node33;
    node33->next=node44;
    node44->next=node55;

    Node* NewHead=fun(node1,node11);
    show(NewHead);
    return 0;
}


7.复杂链表的复制

//第一步:赋值原链表结点并插入原链表相同结点后面
//第二步:给新结点赋值随机域
//第三步:插入原链表

#include<iostream>
using namespace std;
#include<cassert>
struct  Node
{
    int data;
    Node* next;
    Node* random;
    Node(const int x)
        :data(x)
        ,next(NULL)
        ,random(NULL)
    {}
};
Node* fun(Node* Head1)
{
  assert(Head1);
  Node* cur=Head1;
  Node* next=NULL;
  //第一步:插入新结点
  while (cur)
  {
      Node* node1=new Node(cur->data);
      next=cur->next;
      cur->next=node1;
      node1->next=next;
      cur=next;
  }
  //第二步:新结点随机域赋值
  cur=Head1;
  while (cur)
  {
      if (cur->next&&cur->random)
      {
           cur->next->random=cur->random->next;
      }
      if (cur->next)
      {
          cur=cur->next->next;
      }
  }
  //第三步:拆除指针
  cur=Head1;
  Node* NewHead=cur->next;
  while (cur)
  {
      if (cur->next)
      {
          next=cur->next->next;
          if (next&&next->next)
          {
              cur->next->next=next->next;
              cur->next=next;
          }
          cur=next;
      }
  }
  return NewHead;
}
void show(Node* head)
{
    assert(head);
    while (head)
    {
        cout<<head->data<<"-";
        if (head->random)
        {
            cout<<head->random->data;
        }
        cout<<endl;
        head=head->next;
    }
}
int main()
{
    Node* node1=new Node(1);
    Node* node2=new Node(2);
    Node* node3=new Node(3);
    Node* node4=new Node(4);
    Node* node5=new Node(5);
    node1->next=node2;
    node1->random=node3;
    node2->next=node3;
    node2->random=node4;
    node3->next=node4;
    node4->next=node5;
    show(node1);
    Node* NewHead=fun(node1);
    show(NewHead);
    return 0;
}


8.求两个不带坏的链表的第一个相交结点(链表1:m个结点,链表2:n个结点)

//方法一:每次从链表1里面拿一个结点,和链表2中的所有节点比较;时间复杂度o(n*m);

//方法二:用两个栈,将两个链表结点从头开始分别压入栈中,如果两个链表相交,那么他们的尾结点绝对相同;
//所以从尾结点开始比较,直到遇到不相同的结点,那么这个结点的前一个结点就是第一个相交结点;
//时间复杂度O(m+n),空间复杂度O(m+n);

//方法三:求两个链表的长度,然后求两个链表的长度的差;将长链表的长度减去差值,然后从
//该位置开始和短链表从头开始,依依向后比较,直到遇到的第一个相同结点,就是所求的两个链表的第一个相交结点;
//时间复杂度O(2(m+n))
//方法四:将一个链表的头结点连接到另一个链表的尾结点之后;如果两个链表相交,那么这就会形成一个带坏链表;
//然后求这个带坏链表的环入口点;即就是两个链表的第一个相交点;
#include<iostream>
using namespace std;
#include<cassert>
#include<stack>
struct  Node
{
    int data;
    Node* next;
    Node(const int x)
        :data(x)
        ,next(NULL)
    {}
};
//方法1
Node* fun1(Node* Head1,Node* Head2)
{
    if (Head1==NULL||Head2==NULL)
    {
        return NULL;
    }
    Node* cur1=Head1;
    Node* cur2=Head2;
    while (cur1)
    {
        while(cur2&&cur1!=cur2)
        {
            cur2=cur2->next;
        }
        if (cur2==NULL)
        {
            cur2=Head2;
            cur1=cur1->next;
        }
        else
        {
            return cur1;
        }
    }
    return NULL;
}
//方法2
Node* fun2(Node* Head1,Node* Head2)
{
    //别忘了
    if (Head1==NULL||Head2==NULL)
    {
        return NULL;
    }
    Node* cur1=Head1;
    Node* cur2=Head2;
    Node* meet=NULL;
    stack<Node*>  s1;
    stack<Node*>  s2;
    while (cur1)
    {
        s1.push(cur1);
        cur1=cur1->next;
    }
    while (cur2)
    {
        s2.push(cur2);
        cur2=cur2->next;
    }
    while (!s1.empty()&&!s2.empty())
    {
        if (s1.top()==s2.top())
        {
            meet=s1.top();
            s1.pop();
            s2.pop();
        }
        else
        {
            return meet;
        }
    }
    return NULL;
}

//方法3
Node* fun3(Node* Head1,Node* Head2)
{
    //别忘了
    if (Head1==NULL||Head2==NULL)
    {
        return NULL;
    }
    int count1=0;
    int count2=0;
    int del=0;
    Node* cur1=Head1;
    Node* cur2=Head2;
    while (cur1)
    {
        count1++;
        cur1=cur1->next;
    }
    while (cur2)
    {
        count2++;
        cur2=cur2->next;
    }
    cur1=Head1;
    cur2=Head2;
    if (count1>count2)
    {
        del=count1-count2;
        while (del--)
        {
            cur1=cur1->next;
        }
    }
    else
    {
        del=count2-count1;
        while (del--)
        {
            cur2=cur2->next;
        }
    }
    while (cur1&&cur2)
    {
        if (cur1==cur2)
        {
            return cur1;
        }
        else
        {
            cur1=cur1->next;
            cur2=cur2->next;
        }
    }
    return NULL;
}

//方法四:
Node* fun4(Node* Head1,Node* Head2)
{
    //别忘了
    if (Head1==NULL&&Head2==NULL)
    {
        return NULL;
    }
    //1.构坏
    Node* cur1=Head1;
    while (cur1->next)
    {
        cur1=cur1->next;
    }
    cur1->next=Head2;

    //2.判断一个链表是否带环(通过此判断可以断定两个链表是否相交)--快慢指针法
    cur1=Head1;//走一步
    Node* cur2=Head1;//走两步
    Node* meet=NULL;
    while(cur1&&cur2)
    {
        cur1=cur1->next;
        if (cur2->next)
        {
            cur2=cur2->next->next;
        }
        if (cur1==cur2)
        {
            meet=cur1;//环内相交点
            break;
        }
    }
    //根据相交点是否为空,判断是否形成坏,而后就可以得出两个链表是否相交
    //形成环,两个链表相交,求环的入口点(即两个链表的第一个相交点)
    if (meet)
    {
        //求环的入口点:cur从链表头开始走,meet从坏内快慢指针相遇处开始走;
        //**两个指针每次都是走一步;必相交于一点(即环的入口点,也就是要求的两链表第一个相交点)
        cur1=Head1;
        while (meet!=cur1)
        {
            meet=meet->next;
            cur1=cur1->next;
        }
        //必相交一点(环的入口点,两链表的相交点)
        return  cur1;
    }
    //没有形成环,两个链表不相交
    else
    {
        return NULL;
    }
}
int main()
{
    Node* node1=new Node(1);
    Node* node2=new Node(2);
    Node* node3=new Node(3);
    Node* node4=new Node(4);
    Node* node5=new Node(5);
    node1->next=node2;
    node2->next=node3;
    node3->next=node4;
    node4->next=node5;

    Node* node111=new Node(1);
    Node* node222=new Node(2);
    Node* node333=new Node(3);
    Node* node444=new Node(1);
    Node* node555=new Node(2);
    Node* node666=new Node(3);
    Node* node11=new Node(1);
    Node* node22=new Node(2);
    Node* node33=new Node(3);
    node111->next=node222;
    node222->next=node333;
    node333->next=node444;
    node444->next=node555;
    node555->next=node666;
    node666->next=node11;
    node11->next=node22;
    node22->next=node33;
    node33->next=node4;
    node4->next=node5;
    Node* NewHead=fun4(node1,node111);
    cout<<NewHead->data<<endl;

    return 0;
}


9.判断一个链表是否带坏,如果带环,求环的长度

//第一步:求快慢指针在环内的相交点meet
//第二步:从meet开始计算坏内的的长度

#include<iostream>
using namespace std;
#include<cassert>
struct  Node
{
    int data;
    Node* next;
    Node(const int x)
        :data(x)
        ,next(NULL)
    {}
};
//判断一个链表是否带坏
Node* fun(Node* Head1)
{
    if (Head1==NULL)
    {
        return NULL;
    }
    Node* cur1=Head1;
    Node* cur2=Head1;
    while (cur1&&cur2)
    {
        cur1=cur1->next;
        if (cur2->next)
        {
            cur2=cur2->next->next;
        }
        if (cur1==cur2)
        {
            return cur1;//相遇结点
        }
    }
    return  NULL;
}
//求坏的长度
int count(Node* Head1)
{
    if (Head1==NULL)
    {
        return 0;
    }
   Node* meet=fun(Head1);
   //meet不为空,带环,求坏的长度
   if (meet)
   {
      Node* node=meet->next;
      int count=1;
      while(node!=meet)
      {
         count++;
         node=node->next;
      }
      return count;
   }
   //meet为空,不带环,环长度为0
   else
   {
       return 0;
   }
}
int main()
{
    Node* node1=new Node(1);
    Node* node2=new Node(2);
    Node* node3=new Node(3);
    Node* node4=new Node(4);
    Node* node5=new Node(5);
    Node* node6=new Node(6);
    Node* node7=new Node(7);
    Node* node8=new Node(8);
    Node* node9=new Node(9);
    Node* node10=new Node(10);
    node1->next=node2;
    node2->next=node3;
    node3->next=node4;
    node4->next=node5;
    node5->next=node6;
    node6->next=node7;
    node7->next=node8;
    node8->next=node9;
    node9->next=node10;
    node10->next=node5;

    cout<<count(node1)<<endl;
    return 0;
}


9.约瑟夫杯

//什么是约瑟夫杯:给一个循环单链表,从第一个结点开始每走num个结点,删除该节点,从
//下一个结点开始有每走num个结点删除该节点,直到剩余一个结点,这个结点就是约瑟夫,
//他活着;
#include<iostream>
using namespace std;
#include<cassert>
struct Node
{
    int data;
    Node* next;
    Node(const int x)
        :data(x)
        ,next(NULL)
    {}
};

Node* fun(Node* Head,int k)
{
    if (Head==NULL)
    {
        return NULL;
    }
    Node* cur=Head;
    Node* prev=NULL;
    int num=k;
    while (cur->next!=cur)
    {
        while (--num)
        {
            prev=cur;
            cur=cur->next;
        }
        prev->next=cur->next;
        delete cur;
        cur=prev->next;
        num=k;
    }
    return cur;
}
int main()
{
    Node* node1=new Node(1);
    Node* node2=new Node(2);
    Node* node3=new Node(3);
    Node* node4=new Node(4);
    Node* node5=new Node(5);
    Node* node6=new Node(6);
    node1->next=node2;
    node2->next=node3;
    node3->next=node4;
    node4->next=node5;
    node5->next=node6;
    node6->next=node1;
    cout<<fun(node1,3)->data<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/gogogo_sky/article/details/78018226