链表经典面试题二

题型七:合并两个链表,合并后的链表依旧有序

分析:最简单的思路就是遍历两个链表,每次取出其中一个链表的节点,两个链表取出来的节点相比较,取较小值插入到新链表中。就这样一直比较,直到有一个链表为空就结束循环。但是要注意的是,当两个链表第一次比较时,将较小数据作为新的链表的头节点 ,确定之后,再创建一个节点tail指向新链表的最后一个节点,每次取出的数据尾插在tail后面,当遇到其中有一个链表为空的情况下,就像链表的剩余节点直接链接到tail后面。

ListNode* MergeList(ListNode* List1, ListNode* List2)//归并两个有序链表,归并后依旧有序
{
     ListNode* NewList=NULL;
     ListNode* tail = NULL;
     //如果链表一为空,返回链表2
     if (List1 == NULL)
     {
          return List2;
     }
     //如果链表二为空,返回链表一
     if (List2 == NULL)
     {
          return List1;
     }
     //找头
     if (List1->data < List2->data)
     {
          NewList = List1;
          List1 = List1->pNext;
     }
     else
     {
          NewList = List2;
          List2 = List2->pNext;
     }
     tail = NewList;
     while (List1&&List2)//当两个链表都没结束时
     {
          if (List1->data < List2->data)
          {
              tail->pNext = List1;
              List1 = List1->pNext;
          }
          else
          {
              tail->pNext = List2;
              List2 = List2->pNext;
          }
          tail = tail->pNext;
     }
     //其中任有一个为空时                                                                                                                                                                                                                                                                                                                                                                
     if (List1)
     {
          tail->pNext = List1;
     }
     if (List2)
     {
          tail->pNext = List2;
     }
     return NewList;
}

测试代码为:

testMergeList()
{
     ListNode* L1 = NULL;
     ListNode* L2 = NULL;
     ListNode* NewHead;
     SListPushback(&L1, 1);
     SListPushback(&L1, 4);
     SListPushback(&L1, 6);
     SListPushback(&L1, 9);
     SListPushback(&L2, 2);
     SListPushback(&L2, 4);
     SListPushback(&L2, 7);
     SListPushback(&L2, 8);
     NewHead = MergeList(L1, L2);
     SListPrint(NewHead);
}

题型八:查找单链表的中间节点,要求只能遍历一次链表

分析:这个题需要使用快慢指针,快指针一次走两步,慢指针一次走一步,那么当快指针遍历完整个链表之后,慢指针刚好指向链表的中间位置,返回这个节点就可以求得一个链表中间节点的位置。

ListNode* FindMidNode(ListNode* pHead)//查找链表的中间节点
{
     ListNode* Slow=pHead;
     ListNode* Fast=pHead;
     while (Fast&&Fast->pNext)
     {
          Slow = Slow->pNext;
          Fast = Fast->pNext->pNext;
     }
     return Slow;
}

测试代码为:

testFindMidNode()
{
     ListNode* S = NULL;//初始化链表
     ListNode* MidNode = NULL;
     SListPushback(&S, 1);
     SListPushback(&S, 22);
     SListPushback(&S, 3);
     SListPushback(&S, 9);
     SListPushback(&S, 10);
     SListPushback(&S, 6);
     SListPushback(&S, 7);
     SListPushback(&S, 18);
     SListPrint(S);
     MidNode = FindMidNode(S);
     printf("中间节点是:%d\n", MidNode->data);
}

题型九:查找链表的倒数第K个节点,要求只能遍历一次链表

分析:这个题的思路和上一个题的思路差不多,也是快慢指针的问题,让快指针先走k步,再让快指针和慢指针一起走,当快指针指向NULL时,慢指针刚好指向倒数第k个节点。

ListNode* FindNode(ListNode* pHead, int k)//查找链表的倒数第k个节点
{
     ListNode* Slow = pHead;
     ListNode* Fast = pHead;
     int count = k;
     while (count)//先走k步
     {
          Fast = Fast->pNext;
          count--;
     }
     Fast = Fast->pNext;
     Slow = Slow->pNext;
     while (Fast)
     {
          Fast = Fast->pNext;
          Slow = Slow->pNext;
     }
     return Slow;
}

测试代码为:

testFindNode()
{
     ListNode* S = NULL;//初始化链表
     ListNode* KNode = NULL;
     SListPushback(&S, 1);
     SListPushback(&S, 22);
     SListPushback(&S, 3);
     SListPushback(&S, 9);
     SListPushback(&S, 10);
     SListPushback(&S, 6);
     SListPushback(&S, 7);
     SListPushback(&S, 18);
     SListPrint(S);
     KNode = FindNode(S, 3);
     printf("倒数第三个节点是:%d\n", KNode->data);
}

题型十:删除链表的倒数第K个节点,要求只能遍历一次链表

分析:当找到倒数第k个节点是时,用题型二的方法删除这个节点就可以了,直接上代码:

void DelKNode(ListNode** ppHead, int k)//删除倒数第k个节点
{
     ListNode* DelNode = FindNode(&ppHead, k);
     ListNode* Next = DelNode->pNext;
     DelNode->data = Next->data;
     DelNode->pNext = Next->pNext;
     free(Next);
}

猜你喜欢

转载自blog.csdn.net/ffsiwei/article/details/80695648