链表面试题

本文详细介绍了链表的各种基本操作,包括初始化、增删改查、排序、反转等,并提供了具体的实现代码。此外还探讨了链表相交问题及特殊场景如环形链表的处理方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include"LinkList.h"


PNode BuyNewNode(DateType date)
{
   PNode NewNode=(PNode)malloc(sizeof(Node));
   if(NewNode==NULL)
   {
     return NULL;
   }
   NewNode->date=date;
   NewNode->next=NULL;
   return NewNode;
}

void LinkListInit(PNode  *ppHead)
{
   assert(ppHead);
   *ppHead=NULL;
}
void LinkListPushBack(PNode  *ppHead,DateType date)
{
	PNode cur=*ppHead;
	PNode newNode=BuyNewNode(date);
	assert(ppHead);
	if(cur==NULL)
	{
	   *ppHead=newNode;
	   return ;
	}
	while(cur->next)
	{
		cur=cur->next;
	}
	cur->next=newNode;


}
void PrintLinkList(PNode pHead)
{
	//链表为空
   if(pHead==NULL)
   {
     return;
   }
   
   while( pHead)
   {
	   printf("%d---->",pHead->date);
	   pHead=pHead->next;
   }
   printf("\n");

}
void LinkListPopBack(PNode  *ppHead)
{
  PNode cur=*ppHead;
  assert(ppHead);
  //链表为空
  if(cur==NULL)
  {
    return;
  }
  //链表为一个节点
  if(cur->next==NULL)
  {
    free(cur);
	cur=NULL;
	return ;
  }
  //链表为多个节点 
  while(cur->next->next)
  {
	  cur=cur->next;
  }
  free(cur->next);
  cur->next=NULL;

}

void LinkListPushFront(PNode  *ppHead, DateType date)
{
  
    
	PNode newNode=BuyNewNode(date);
	assert(ppHead);
    //链表无节点
	if(*ppHead==NULL)
	{
	  return;
	}
	//链表不为空
	newNode->next=*ppHead;
	*ppHead=newNode;

}

void LinkListPopFront(PNode  *ppHead)
{
   PNode cur=*ppHead;
   assert(ppHead);
   //空链表
   if(*ppHead=NULL)
   {
      return;
   }
   //非空链表
   *ppHead=cur->next;
   free(cur);
   cur=NULL;

}
void LinkListPrintReverse(PNode pHead)
{
	if(pHead==NULL)
  {
    return;
  }
	LinkListPrintReverse(pHead->next);
	printf("%d-->",pHead->date);
    return ;
}


PNode SListFind(PNode pHead, DateType date)
{
	PNode cur=pHead;
  //链表为空
	if(NULL==pHead)
	{
	  return NULL;
	}
	//链表不为空
	while(cur)
	{
		if(cur->date==date)
		{
		  return cur;
		}
		cur=cur->next;
	 }
	return NULL;
 }

void SListInsert(PNode* ppHead, PNode pos, DateType date)
{
	PNode cur;
    assert(ppHead);
    cur= BuyNewNode(date);
	if(cur==NULL)
	{
	  return ;
	}
	cur->next=pos->next;
	pos->next=cur;

}

void SListErase(PNode* ppHead, PNode pos)
{
    PNode cur=*ppHead;
    assert(ppHead);
	//链表为空
	if(NULL==cur)
	{
	  return;
	}
	//链表有一个节点
	if((NULL==cur->next)&&(pos==cur))
	{
	  free(cur);
	  cur=NULL;
	  *ppHead=NULL;
	  return;
	}
	//链表有多个节点
	while((cur->next!=pos)&&(cur->next!=NULL))
	{
		cur=cur->next;
	}

	//找到了
	if(cur->next==pos)
	{
		cur->next=pos->next;
		free(pos);
		pos=NULL;
	}
	if(cur->next==NULL)
	{
	  printf("找不到!\n");
	}


}

void SListDestroy(PNode* ppHead)
{
   PNode cur=*ppHead;
   PNode cur1=NULL;
   assert(ppHead);
   while(cur)
   {
     cur1=cur;
	 cur=cur->next;
	 free(cur1);
   }
   free(cur);
   free(*ppHead);
}
int SListSize(PNode pHead)
{

  int count =0;
  PNode cur=pHead;
  while(cur)
  {
	  cur=cur->next;
	  count++;
  }
  return count;
}

void SListClear(PNode* ppHead)
{
   PNode cur=*ppHead;
   PNode cur1=NULL;
   assert(ppHead);
   while(cur)
   {
     cur1=cur;
	 cur=cur->next;
	 free(cur1);
   }
}

PNode SListBack(PNode pHead)
{
	PNode cur=pHead;
    if(pHead=NULL)
   { 
      return NULL;
   }
	while(cur->next)
	{
		cur=cur->next;
	}
	return cur;


}

// 从尾到头打印单链表 
void PrintListFromTail2Head(PNode pHead)
{
  if(NULL==pHead)
  {
    return ;
  }
  else
  {
	  PrintListFromTail2Head(pHead->next);
	  printf("%d--->",pHead->date);
  }
}




// 在无头单链表pos位置前插入值为结点data的结点 
void InsertPosFront(PNode* ppHead,PNode pos, DateType date)
{
	int tmp=0;
	PNode tmp1=NULL;
	assert(ppHead);
  //2,将新节点插入POS的后面
	 SListInsert( ppHead, pos,  date);


  //3,将pos与新节点进行交换
		 
		 tmp=pos->date;
		 pos->date=pos->next->date;
		 pos->next->date=tmp;


}

void JosephCircle(PNode* ppHead, const int M)
{
	PNode cur2=NULL;
	int count=0;
	PNode cur1=NULL;
	PNode cur=*ppHead;
  assert(ppHead);

  //约瑟夫环

  cur1=SListBack(*ppHead);//找到最后一个节点的地址
  cur1->next=cur;
  
  //报数 删除节点
  while(cur!=cur->next)
  { 
       count=M;
	  while(--count)
	  {
		  cur=cur->next;
	  }
		  cur2=cur->next;
	  cur->date=cur2->date;
	  cur->next=cur2->next;
	  free(cur2);
	  
  }
  *ppHead=cur;


  //解环
 /* cur->next=NULL;*/
  cur->next=NULL;

}

// 删除无头单链表的非尾结点,要求:不能遍历链表 
void DeleteNotTailNode(PNode pos)
{
  PNode cur=pos->next;
  if(NULL==pos)
  {
    return ;
  }
  assert(pos->next);
  pos->date=cur->date;
  pos->next=cur->next;
  free(cur);
  cur=NULL;
}

void BubbleSort(PNode pHead)
{
  PNode pPerCur=NULL;
  PNode pCur=NULL;
  PNode pTail=NULL;
  int tmp=0;

  pPerCur=pHead;
  pCur=pHead->next;
  if(pHead==NULL||pHead->next==NULL)
  {
    printf("节点不够,无法排序!\n");
	return ;
  }
  while(pHead->next!=pTail)
  {
			 int Ischange=0;
			 pPerCur=pHead;
			 pCur=pHead->next;
			while(pCur!=pTail)
		  {
			  if(pPerCur->date>pCur->date)
			  {
				tmp=pCur->date;
				pCur->date=pPerCur->date;
				pPerCur->date=tmp;
			  }
				pPerCur= pCur;
				pCur= pCur->next;
				Ischange=1;
		  }
			if(!Ischange)
			{
			  return ;
			}
			pTail=pPerCur;

  }

}

// 单链表的逆序---三个指针 
ListNode* ReverseList(ListNode* pHead) {
        if(pHead==NULL || pHead->next==NULL)
        {
            return pHead;
        }
        ListNode* pPer=NULL;
        ListNode* pCur=pHead;
        ListNode* pAft=NULL;
        while(pCur)
        {
           pAft=pCur->next;
           pCur->next=pPer;
           pPer=pCur;
           pCur=pAft;
        }
        return pPer;
    }



// 单链表的逆序---使用递归法 
ListNode* ReverseList(ListNode* pHead) {
        if(pHead==NULL || pHead->next==NULL)   //条件一仅处理头节点为空情况,
        {
            return pHead;
        }
        ListNode* newHead=ReverseList(pHead->next);//这个返回值仅用来返回头结点
        pHead->next->next=pHead;
        pHead->next=NULL;
        return newHead;
}


// 判断两个单链表是否相交---链表不带环 
int IsCrossWithoutCircle(PNode pHead1, PNode pHead2)
{
  PNode pCur1;
  PNode pCur2;
	  if(pHead1==NULL||pHead2==NULL)
	  {
		return -1;//无交点
	  }
  pCur1=SListBack(pHead1); 
  pCur2=SListBack(pHead2); 
	  if(pCur1==pCur2)
	  {
		return 0;//表示有交点
	  }
      return -1;//无交点

}

// 如果相交 获取交点 
PNode GetCrossNode(PNode pHead1, PNode pHead2)
{
	int ret1=0;
	int ret2=0;
	int retsub=0;
	int ret=0;
	// 判断两个单链表是否相交---链表不带环 
	 ret=IsCrossWithoutCircle( pHead1,  pHead2);
	 if(ret!=0)
	 {
	   printf("不相交 !\n");
	   return NULL;
	 }

	// 求链表中结点的个数 
	ret1=SListSize(pHead1); 
	ret2=SListSize(pHead2); 
	retsub=ret1-ret2;
	if(retsub>0)//链表1长
	{
	 while(retsub)
	 {
		 pHead1=pHead1->next;
		 retsub--;
	 }

	}
		if(retsub<0)//链表2长
	{
	
	  while(retsub++)
	  {
		  pHead2=pHead2->next;
	  }
	}
	while(pHead1!=pHead2)//寻找交点
	{
		pHead1=pHead1->next;
		pHead2=pHead2->next;
	}
	return pHead1;
	
}

//判断一个链表是否带环,若带环,求入环点
PNode IsLoopAndEnterNode(PNode pHead)
{
	PNode pFast=pHead;
	PNode pSlow=pHead;
	PNode pCross=NULL;
	
	while(pFast&&pFast->next)//快慢指针,快的走两步,慢的走一步
						     //如果无环呢  所以必须判断pFast是否为空
	{
		pFast=pFast->next->next;
		pSlow=pSlow->next;
		if(pFast==pSlow)
		{
		  break;
		}

	}
	if(pFast!=pSlow)//不知道是有环退出还是无环退出,所以进行判断
		{
		 return NULL;
		}


	//因为交点到入点的距离和起点到入点的距离相同
	pCross=pFast;//将将交点赋给pCross
	pSlow=pHead;//将起点赋给pSlow
	while(pCross!=pSlow)//相同速度跑
	{
	  pCross=pCross->next;
	  pSlow=pSlow->next;
	}
	return pSlow;
}


// 合并两个有序链表,合并起来依然要有序 
PNode MergeSList(PNode pHead1, PNode pHead2)
{
  PNode pCur1=pHead1;
  PNode pCur2=pHead2;
  PNode TailNode=NULL;//标记指针
  PNode NewNode=NULL;//新链表
  

  if(pCur2==NULL||pCur1==NULL)
  {
	  return NULL==pCur1?pCur2:pCur1;//1为空返回2的指针,2为空返回1的指针
  }
  if(pCur1->date>pCur2->date)
  {
		TailNode=pCur2;
		pCur2=pCur2->next;
  }
  else
  {
		TailNode=pCur1;
		pCur1=pCur1->next;

  }
		NewNode=TailNode;

		

  //因为最后需要返回头指针,所以需要在循环外标记好
  while(pCur2!=NULL&&pCur1!=NULL)//1或2 移动到空了 就退出
  {
		if(pCur1->date>pCur2->date)
	  {
		  
		  TailNode->next=pCur2;
		 
			pCur2=pCur2->next;

			
	  }
	  else
	  {
		  
		 TailNode->next=pCur1;
		 
			pCur1=pCur1->next;
	  }
		TailNode=TailNode->next;
  }
	if((pCur2==NULL)&&(pCur1!=NULL))//退出之后 让没有到空的链表直接连接到新链表上
	{
		TailNode->next=pCur1;
		
	}
	else
	{
	    TailNode->next=pCur2;
		
	}
	//排序完成,下面进行返回,不知道第一个节点的地址,要判断
	return NewNode;

}

// 查找链表的中间结点,要求只能遍历一次链表 
PNode FindMiddleNode(PNode pHead)
{
  PNode pFast=pHead;
  PNode pSlow=pHead;
  PNode pPer=NULL;

  
  while(pFast&&pFast->next)
  {
	  pFast=pFast->next->next;
	  pPer=pSlow;
	  pSlow=pSlow->next;
  }
  //如果节点有偶数个,要求得到前面的节点
 if(!pFast)
  {
    return pPer;
  }

  return pSlow;

}

// 查找链表的倒数第K个结点 
PNode FindLastKNode(PNode pHead, int K)
{
  PNode pFast=pHead;
  PNode pSlow=pHead;
  PNode pPer=NULL;
	//假设倒数第k个节点 存在
    //若需判断,有查看节点个数的函数,大于k即可
  while(--K)
  {
	  pFast=pFast->next;
  }
  while(pFast->next)
  {
      pFast=pFast->next;
	  pSlow=pSlow->next;
  }
  return  pSlow;

}

// 判断链表是否相交,链表可能带环 
int IsListCrossWithCircle(PNode pHead1, PNode pHead2)
{		
     PNode PMNode1;
	 PNode PMNode2;

	 PNode PBNode1;
	 PNode PBNode2;
	 if((pHead1==NULL)&&(pHead2==NULL))
	 {
	     return 0;
	 }

  //1, 判断链表的带环情况
	  PMNode1=IsLoopAndEnterNode(pHead1);
      PMNode2=IsLoopAndEnterNode(pHead2);
	// 两个都不带环
		if(PMNode1==NULL&&PMNode2==NULL)
		{
		 PBNode1=SListBack(pHead1);
		 PBNode2=SListBack(pHead2);
		 if(PBNode1==PBNode2)//相交
		 {
		    return 1;
		 }
		}
	
	//两个都带环
	if(PMNode1!=NULL&&PMNode2!=NULL)
	{
		//要防止找到自己而相等退出的情况
		//处理一开始两个指针相等的情况
			if(PMNode1==PMNode2)
		   {
		     return 2;
		   } 
			//直接从第二个节点开始

		do{
		   PMNode1=PMNode1->next;
		   if(PMNode1==PMNode2)
		   {
		     return 2;
		   } 
		  

		}while(PMNode1->next!=PMNode2);//如果下一个是本身就退出
	}
	//一个带环,,不会相交
	return 0;
}




  


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值