有关链表的面试题续。

今天我们再来做一些有关链表的面试题。

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;
		}
	}
}
以上的题说简单不简单,说难也不难,只要大家好好画图想一想,应该就能掌握了。




猜你喜欢

转载自blog.csdn.net/ymk1507050118/article/details/80876458