链表面试题大全:
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;
}