鏈表常見面試題一:基本問題

本文列舉出了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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章