今天我们再来做一些有关链表的面试题。
1.单链表实现约瑟夫环。
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<Windows.h>
typedef int DataType;
typedef struct SListNode{
DataType data;
struct SListNode *pNext;
}SListNode;
SListNode * JocephCircle(SListNode *pFirst, int k)
{
SListNode *pNode=pFirst; //定义两个指针分别指向头指针和空指针。
SListNode *q=NULL;
int n=k;
while(pNode!=pNode->pNext) //循环直到剩下一个节点。
{
while(--n){
pNode=pNode->pNext; //找到要删除的节点。
}
q=pNode->pNext; //先用空指针保存下来要删的指针。
pNode->data=q->data; //将pNode赋为要删的下一个节点。
pNode->pNext=q->pNext;
free(q); //最后释放q。
}
return pNode; //返回剩下的最后一个节点。
}
2.合并两个有序链表,合并后依然有序。
void HebingList(SListNode *p1First,SListNode *p2First)
{
SListNode *p1=p1First; //定义两个指针指向头结点。
SListNode *p2=p2First;
int n=0;
SListNode *pNewNode=(SListNode *)malloc(sizeof(SListNode)); //开辟一个新空间。
while(p1!=NULL && p2!=NULL) //当两个指针不为空。
{
if(p1->data<p2->data) //如果当第一个小于第二个时。
{
if(n=0){
pNewNode->data=p1->data; //将第一个值放进新的空间里。
pNewNode->pNext=NULL;
n+=1;}
else{
SListInesrt(pNewNode,p1->data); //放了一个之后,其它数都按照尾插来进行。
}
p1=p1->pNext;
}
else
{
if(n=0){
pNewNode->data=p2->data; //如果第一个大于等于第二个。
pNewNode->pNext=NULL;
n+=1;}
else{
SListInesrt(pNewNode,p2->data);
}
p2=p2->pNext;
}
}
SListNode *NoEmpty=p1; //假设p1没空。
if(p1==NULL) //如果p1为空,则令p2不空。
{
NoEmpty=p2;
}
while(NoEmpty)
{
SListInesrt(pNewNode,NoEmpty->data); //这是将没空的链表后续的节点继续尾插到新空间里。
NoEmpty=NoEmpty->pNext;
}
}
3.查找单链表的中间节点,要求只能遍历一次链表。
SListNode *FindSList(SListNode *pFirst)
{
SListNode *Sslow=pFirst; //定义一个慢指针,一个快指针。
SListNode *Sfast=pFirst;
assert(pFirst);
while(Sfast)
{
Sfast=Sfast->pNext; //当快指针不为空时,快指针往后走一步。
if(Sfast==NULL) //如果此时快指针为空,则退出。
{
break;
}
Sfast=Sfast->pNext; //否则快指针继续向后走一步。
if(Sfast==NULL) //此时在判断是否为空。
{
break;
}
Sslow=Sslow->pNext; //此时慢指针再走一位。
}
return Sslow; //返回慢指针就是链表的中间节点位置。
}
4.查找单链表的倒数第k个节点,只能遍历一边。
SListNode *FindDao(SListNode *pFirst,int k)
{
int i=0;
SListNode *pNode=pFirst; //定义两个指针指向头指针。
SListNode *n=pFirst;
assert(pFirst);
if(k==1) //如果查倒数第一个节点,就直接循环往后到最后一个节点。
{
while(pNode->pNext!=NULL)
{
pNode=pNode->pNext;
}
return pNode;
}
for(i=0;i<k-1;i--) //否则,先让一个指针走上k-1个节点,然后两个指针一起往后走。
{
pNode=pNode->pNext;
}
while(pNode->pNext!=NULL) //直到先走的指针为空,那这时另一个指针就是倒数第k个节点。
{
pNode=pNode->pNext;
n=n->pNext;
}
return n;
}
5.遍历一次,删除倒数第 k 个结点(k从1开始),不能用替换删除法
void RemoveK(SListNode *pFirst, int k)
{
SListNode *fast=pFirst;
SListNode *slow=pFirst; //定义两个指针。
while(k)
{
fast=fast->pNext; //先让快指针走k个节点。
}
while(fast->pNext!=NULL) //然后两个指针一起走直到快指针为空。
{
fast=fast->pNext;
slow=slow->pNext;
}
slow->pNext=slow->pNext->pNext; //此时慢指针指向的是倒数第k个的前一个节点,此时令它的pNext为它的后一个的节点即可完成删除。
}
6.求两个已排序的单链表中相同的数据。
SListNode *UnionSet(SListNode *l1,SListNode *l2)
{
SListNode *p1=l1; //定义两个指针分别指向两个链表。
SListNode *p2=l2;
while(p1!=NULL && p2!=NULL) //当它们都不为空时
{
if(p1->data<p2->data) //如果第一个小于第二个,第一个向后走。
{
p1=p1->pNext;
}
else if(p1->data>p2->data) //第二个向后走。
{
p2=p2->pNext;
}
else{
printf("%d\n",p1->data); //相等时直接输出这个值。两个指针一起往后走。
p1=p1->pNext;
p2=p2->pNext;
}
}
}
以上的题说简单不简单,说难也不难,只要大家好好画图想一想,应该就能掌握了。