链表常见面试题一:基本问题

本文列举出了7个链表常见的面试题,其他面试题请阅读下一篇博客

 

面试题1:删除非尾节点

删除非尾节点,只告诉一个当前节点的位置,将该位置的节点删除。

解题思路:

删除该位置的节点,由于我们不知道它的前一个节点的位置,不能直接将它的前一个节点与它的后一个节点连接起来。

因此,我们需要用另一种方法:

将该节点的后一个节点的元素赋值给该节点,然后删除该节点的后一个节点。

wKioL1agYeKyRY9hAABX5i61Bpo619.png

void EraseNotTail(pLinkNode pos)
{
 assert(pos);
 pLinkNode del = NULL;
 pos->data = pos->next->data;     //后一个节点的元素的值赋给当前节点的值
 del = pos->next;                 //当前节点的后一个节点为要删除的元素
 pos->next = pos->next->next;    
 free(del);                        // 删除该节点
 del = NULL;
}

 面试题2:逆序单链表

解题思路:

将单链表逆序的基本思想是将第一个节点的next置成NULL,然后将它的后一个节点指向它,依次循环直到将最后一个节点指向它的前一个节点。

wKioL1agbAXhpKn6AAAsawXwx6w365.png

void ReverseList(pList* pHead)
{
 assert(pHead);
 pLinkNode cur = *pHead;
 pLinkNode prev = NULL;
 pLinkNode NewHead = NULL;
 while (cur)
 {
  prev = cur;     
  cur = cur->next;
  prev->next = NewHead;  
  NewHead = prev;
     
 }
 *pHead = NewHead;
}

面试:3:排序单链表

解题思路:

排序链表可以用冒泡排序的思想,从前往后遍历链表,要是前一个元素比后一个元素大,那么就交换两个元素,遍历一次的结果 是将链表中最大的元素放在最后。

void BubbleSort(pList * pHead)
{
 assert(pHead);
 pLinkNode cur = *pHead;
 pLinkNode end = NULL;
 DataType tmp = 0;
 while (cur != end)
 {
  while (cur && cur->next != end)
  {
   if (cur->data > cur->next->data)  
   {
    tmp = cur->data;
    cur->data = cur->next->data;
    cur->next->data = tmp;
   }                //将较大元素放在后面,较小元素放到前面   cur = cur->next;
  }                 //遍历一次完成,将最大元素放在链表末尾
  end = cur;
  cur = *pHead;
 }
}

面试题4:在当前节点前插入一个数据x

解题思路:

基本思想是将x插入到当前节点之后,然后交换两个节点的元素。

wKioL1agchuAG-L7AAAZg4yyxi4386.png

void InsertFrontNode(pLinkNode pos, DataType x)
{
 assert(pos);
 pLinkNode NewNode = BuyNode(x);
 DataType tmp = 0;
 NewNode->next = pos->next; 
 pos->next = NewNode; //将要插入的元素插入到当前节点的后面
 tmp = NewNode->data;//交换两元素
 NewNode->data = pos->data;
 pos->data = tmp;
}

面试题5:合并两个有序列表

解题思路:

基本思想是首先确定一个合并以后的头结点,比较两个链表的第一个元素,较小的元素所在的节点为头结点。然后比较两个链表剩余节点的第一个节点,将较小的一个连在头结点的后面,再次比较剩余的节点,然后依次将较小的节点连在新链表的后面,直到有一个链表为空。将另一个链表的剩余节点全都连在新链表上。

有两种方法可以实现:

一、非递归的方法:

pLinkNode Merge(pList l1, pList l2)
{
 pList NewHead = NULL;
 pLinkNode cur = NULL;
//若有一个链表为空,返回不是空链表的那个链表,若都为空,返回任意一个
 if (l1 == NULL || l2 == NULL)
 {
  if (l1)
   return l1;
  else
         return l2; 
 }

 if (l1->data < l2->data)  //若l1的第一个元素比l2的第一个元素小,那么l1的第一个节点为头节点
 {
  NewHead = l1;
  l1 = l1->next;
 }
 else                                       //若l2的第一个元素比l1的第一个元素小,那么l2的第一个节点为头节点
 {                                             //若两个元素相等则任意一个做头节点都可以,这里让l2的元素做头节点
  NewHead = l2;
  l2 = l2->next;
 }
 cur = NewHead;
 while (l1 && l2)       
 {
  if (l1->data < l2->data)           {
   cur->next = l1;
   l1 = l1->next;
  }
  else
  {
   cur->next = l2;
   l2 = l2->next;
  }  //将较小的元素连在新链表的后面
  cur = cur->next;
 }
 if (l1)
 {
  cur->next = l1;         // 若l1不为空,将l1剩余的元素连接在新链表的后面
 }
 else
 {
  cur->next = l2;
 }                                 //若l2不为空,将l2剩余的元素连接在新链表的后面
 return NewHead;
}

二、递归的方法:

因为每次都是将两个链表上的较小的节点连在新链表的后面,因此可以用递归方法实现

pLinkNode _Merge(pList l1, pList l2)
{
 pList NewHead = NULL;
 pLinkNode cur = NULL;
 if (l1 == NULL || l2 == NULL)
 {
  if (l1)
   return l1;
  else
   return l2;
 }
 if (l1->data < l2->data)
 {
  NewHead = l1;
  NewHead->next = _Merge(l1->next, l2);
 }
 else
 {
  NewHead = l2;
  NewHead->next = _Merge(l1, l2->next);
 }
 return NewHead;
}

面试题6:查找中间节点

解题思路:

用两个指针同时从头节点开始向后遍历,一个快指针一次走两步,另一个慢指针一次走一步,直快指针走到结尾,则指针所在的位置就是中间节点。

pLinkNode FindMidNode(pList head)
{
 pLinkNode fast = head;
 pLinkNode slow = head;
 while (fast && fast->next)
 {
  fast = fast->next->next; //快指针一次走两步
  slow = slow->next;       //慢指针一次走一步
 }
 return slow;              //返回中间节点
}

面试题7: 删除单链表的倒数第k个节点(k > 1 && k < 链表的总长度)   时间复杂度O(N)
解题思路:

要求遍历一遍删除链表中倒数第k各节点,可以用两个指针,第一个指针先走k-1步,然后第一个指针和第二个指针一起走,当第二个指针到达链表末尾时,第一个指针所在的位置就是倒数第k各节点。

然后根据删除非尾节点的方法将它删除(删除非尾节点的方法可参考面试题1)。

void DelKNode(pList *pHead, int k)
{
 assert(k > 1);
 pLinkNode l1 = *pHead;
 pLinkNode l2 = *pHead;
 pLinkNode del = NULL;
 while (--k && l2->next) //第二个指针先走k-1步
 {
  l2 = l2->next;
 }
 if (l2->next == NULL)      //k>=链表总长度
 {
  return;
 }
 while (l2->next)       //两个指针一起走
 {
  l2 = l2->next;
  l1 = l1->next;
 }
  del = l1->next;           
  l1->data = l1->next->data;
  l1->next = l1->next->next;
  free(del);                 //删除倒数第k各节点
  del = NULL;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章