题型七:合并两个链表,合并后的链表依旧有序
分析:最简单的思路就是遍历两个链表,每次取出其中一个链表的节点,两个链表取出来的节点相比较,取较小值插入到新链表中。就这样一直比较,直到有一个链表为空就结束循环。但是要注意的是,当两个链表第一次比较时,将较小数据作为新的链表的头节点 ,确定之后,再创建一个节点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);
}