【C语言】单链表相关面试题(二)
来源:互联网 发布:域名访问升级中 编辑:程序博客网 时间:2024/06/06 02:49
上篇博客介绍了查询链表中间结点,删除非尾结点,逆序链表三个问题。
有兴趣可点击链接查看:单链表相关面试题(一)
此篇博客将介绍:
1.删除倒数第k个结点(k>1)
2.合并两个有序链表
3.判断链表是否带环,若带环求环的长度,找出环的入口点
4.判断两条链表是否相交,相交则求出交点。
一、删除倒数第k个结点
1.算法思路:
仍然通过设置快慢指针的方法解决,快指针每走一步,让k--,当k<0的时候,让慢指针也开始走,这样,当快指针走到链表尾部的时候,慢指针刚好指向倒数第k个结点。最后删除慢指针指向的那个结点。简单来说就是,让快指针先走k部,慢指针再开始走,这样快慢指针之间总是相差k步,所以,快指针指向空时,慢指针离空k个结点,即慢指针指向倒数第k个结点。
2.代码实现:
void DelKNode(pLinkList pList, int k){assert(pList);assert(k > 1);if (pList->pHead == NULL){return;}pLinkNode fast = pList->pHead;pLinkNode slow = pList->pHead;while (fast){k--;if (k < 0){slow = slow->next;}fast = fast->next;}if (k<=0) //为了防止给进去的k不符合要求,超过链表的总长{pLinkNode del = NULL;del = slow->next;slow->data = del->data;slow->next = del->next;free(del);del = NULL;}}
3.测试
test9(){LinkList list;InitLinkList(&list);PushBack(&list, 1);PushBack(&list, 2);PushBack(&list, 3);PushBack(&list, 4);PushBack(&list, 5);PushBack(&list, 6); //构建链表1->2->3->4->5->6PrintList(&list);DelKNode(&list, 5); //删除倒数第5个结点PrintList(&list);}
4.测试结果
二、合并两个有序链表
1.算法思路:
假设顺序是由小到大,先考虑异常情况,当其中一条链表为空则返回另外一条链表。当两条链表都不为空的时候,设置新的头结点,比较两条链表第一个结点的数据域大小,让新的头结点指向数据域小的结点,且用来遍历此条链表的结点指针向后移。接下来循环比较两条链表里的数据域,让新链表的尾结点的指针域指向较小的结点。直到其中一条链表指向空,则让新的链表的尾指针的指针域指向用来另外一条链表的当前指针。可能文字描述不太能懂,我们画图说明一下。2.代码实现:
pLinkNode merge(pLinkNode list1, pLinkNode list2){pLinkNode Newhead = NULL;pLinkNode Tail = NULL;pLinkNode cur1 = list1;pLinkNode cur2 = list2;if (list1 == NULL){return list2;}else if (list2 == NULL){return list2;}else{if (cur1->data > cur2->data){Newhead = cur2;cur2 = cur2->next;}else{Newhead = cur1;cur1 = cur1->next;}Tail = Newhead;while (cur1&&cur2){if (cur1->data > cur2->data){Tail->next = cur2;cur2 = cur2->next;Tail = Tail->next;}else{Tail->next = cur1;cur1 = cur1->next;Tail = Tail->next;}}if (cur1){Tail->next = cur1;}else if (cur2){Tail->next = cur2;}}return Newhead;}
3.测试
test10(){LinkList list; //构建两个链表LinkList list1;LinkList list2; pLinkNode ret = NULL;pLinkNode l1 = NULL;pLinkNode l2 = NULL;InitLinkList(&list);InitLinkList(&list1);InitLinkList(&list2);PushBack(&list, 1);PushBack(&list, 3);PushBack(&list, 5);PushBack(&list, 7);PushBack(&list1, 2);PushBack(&list1, 4);PushBack(&list1, 6);PrintList(&list);PrintList(&list1);l1 = list.pHead;l2 = list1.pHead;list2.pHead= merge(l1, l2);<span style="font-family: Arial, Helvetica, sans-serif;">//接收新的头结点</span>PrintList(&list2);DestroyList(&list);DestroyList(&list1);DestroyList(&list2);}
4.测试结果
三、判断链表是否带环,若带环求环的长度,找出环的入口点
1.算法思路:
设置快慢指针,快指针每次走两步,慢指针每次走一步,若链表带环,则快慢指针一定会在环上相遇,我们返回相遇点,若不带环,则快指针或者其指针域会为空,此时我们返回空。如何计算环的长度:从相遇点遍历一遍,通过计数器获得环的长度。
找环的入口点:
2.代码实现:
pLinkNode CheckCycle(pLinkList pList); //判断链表是否带环int GetCircleLength(pLinkNode meet); //若带环求环的长度pLinkNode FindEntryNode(pLinkList pList, pLinkNode meet);//找出环的入口点
pLinkNode CheckCycle(pLinkList pList){assert(pList);pLinkNode fast = pList->pHead;pLinkNode slow = pList->pHead;while(fast&&fast->next){slow = slow->next;fast = fast->next->next;if (fast == slow){return slow;}}return NULL;}int GetCircleLength(pLinkNode meet){assert(meet);int count = 1;pLinkNode cur = meet->next;while (cur != meet){count++;cur = cur->next;}return count;}pLinkNode FindEntryNode(pLinkList pList, pLinkNode meet){assert(pList);pLinkNode cur = pList->pHead;while (cur != meet){cur = cur->next;meet = meet->next;}return cur;}
3.测试
void test11(){LinkList list;int length=0;pLinkNode ret = NULL;pLinkNode meet = NULL;pLinkNode entry= NULL;InitLinkList(&list);PushBack(&list, 1);PushBack(&list, 2);PushBack(&list, 3);PushBack(&list, 4);PushBack(&list, 5);PushBack(&list, 6);ret = Find(&list, 6); //构造环ret->next = Find(&list, 3); //尾指针域指向3,则环的入口点应该为3meet=CheckCycle(&list);if (ret = NULL){printf("链表不带环");}else{length = GetCircleLength(meet);printf("环长%d\n", length);entry = FindEntryNode(&list, meet);printf("入口点为:%d", entry->data);}DestroyList(&list);}
4.测试结果
四、判断两条链表是否相交,相交则求出交点。
1.算法思路:
链表是否相交分为以下几种情况来讨论:1>链表不带环,不带环时相交,只要遍历两条链表,判断两条链表的尾结点是否相同,相同则说明相交,不同则不相交。相交时,通过计数器的方法求出两条链表的长度,让长的那条链表先走长度的差值个结点,然后指向两条链表指针同时向后遍历,指针相等的时候就是交点。
2>一条带环一条不带环,此种情况一定不相交。
3>两条链表都带环。调用之前的判断链表是否带环函数,判断两条链表的相遇点是否在一个环上,若不在,则不相交,在一个环上则说明相交。相交时,从环上的任意一点断开。参照不带环相交的情况求出相交点。
2.代码实现:
pLinkNode CheckCross(pLinkList list1, pLinkList list2){int count1 = 1;int count2 = 1;pLinkNode tmp1 = CheckCycle(list1);//调用现有函数检测链表是否带环pLinkNode tmp2 = CheckCycle(list2);if (tmp1 == NULL && tmp2 == NULL) //两条链表都不带环{pLinkNode cur1 = list1->pHead;pLinkNode cur2 = list2->pHead;pLinkNode pcur1 = list1->pHead;pLinkNode pcur2 = list2->pHead;while (cur1->next){cur1 = cur1->next;count1++;}while (cur2->next){cur2 = cur2->next;count2++;}if (cur1 == cur2) //链表相交,求交点{int ret = count1 - count2;if (ret > 0){while (ret--){pcur1 = pcur1->next;}}else{ret = (int)fabs(ret);while (ret--){pcur2 = pcur2->next;}}while (pcur1 != pcur2){pcur1 = pcur1->next; //1 2 3 4 5 6 // 2 4 6 8 10 2 3 4 5 6pcur2 = pcur2->next;}return pcur1;}elsereturn NULL;}else if (tmp1 != NULL && tmp2 != NULL) //两条链表都带环{pLinkNode cur1 = list1->pHead;pLinkNode cur2 = list2->pHead;int length1 = GetCircleLength(tmp1);int length2 = GetCircleLength(tmp2);if (length1 != length2){return NULL;}else{pLinkNode pcur1 = list1->pHead;pLinkNode pcur2 = list2->pHead;while (--length1){if (tmp1 == tmp2) //链表相交{tmp2->next = NULL;int count1 = 0;int count2 = 0;while (cur1){cur1 = cur1->next;count1++;}while (cur2){cur2 = cur2->next;count2++;}int ret = count1 - count2;if (ret > 0){while (ret--){pcur1 = pcur1->next;}while (pcur1 != pcur2){pcur1 = pcur1->next;pcur2 = pcur2->next;}return pcur1;}else{ret = (int)fabs(ret);while (ret--){pcur2 = pcur2->next;}while (pcur1 != pcur2){pcur1 = pcur1->next;pcur2 = pcur2->next;}return pcur1;}break;}tmp1 = tmp1->next;}if (length1 == 0){return NULL;}}} return NULL;}
3.测试
void test12(){LinkList list;LinkList list1;pLinkNode ret = NULL;pLinkNode ret1 = NULL;pLinkNode meet = NULL;InitLinkList(&list);InitLinkList(&list1);PushBack(&list, 1);PushBack(&list, 2);PushBack(&list, 3);PushBack(&list, 4);PushBack(&list, 5);PushBack(&list, 6);PushBack(&list1, 2);PushBack(&list1, 4);PushBack(&list1, 6);PushBack(&list1, 8);PushBack(&list1, 10);ret = Find(&list, 6);ret->next = Find(&list, 3); //构建环ret1 = Find(&list1, 10);ret1->next = Find(&list, 2);//设置相交meet = CheckCross(&list, &list1);if (meet != NULL){printf("交点是%d", meet->data);}else{printf("不相交");}}
4.测试结果
本文测试用例都调用了链表基础操作里的某些函数。若对此有疑惑的亲可参考博文:单链表的基本操作
0 0
- 【C语言】单链表相关面试题(二)
- 【C语言】单链表相关面试题(一)
- 单链表相关面试题(C语言实现)
- C语言面试题精粹(二)
- C语言面试题(二)
- c语言常见面试题(二)
- 嵌入式C语言面试题(二)
- 嵌入式C语言面试题(二)
- C语言面试题(二)
- C语言面试题---函数(二)
- C语言面试题---指针篇(二)
- C语言面试题总汇(二)
- 华为经典C语言面试题(二)
- 单链表的实现和相关面试题及其详解(C语言)
- 嵌入式面试题——C语言面试题(二)
- Hadoop相关面试题(二)
- 链表相关面试题(二)
- [C#]c#面试笔试题(二)
- mybatis的分页插件:mybatis-paginator、mybatis-pageHelper
- python对list中的每个元素进行某种操作
- 不同应用程序提供的数据的获取显示—自定义ContentProvider
- Android AIDL 进程间通信
- 前端,财务数据的正则表达式(一篇专门写给自己的博客)
- 【C语言】单链表相关面试题(二)
- ContextLoaderListener与DispatcherServlet
- 指针与引用的区别
- Android平台对H264视频硬解码
- 再谈线程等待函数WaitForSingleObject和CloseHandle
- oracle 10g for linux
- Weblogic服务器启动异常:unable to validate weblogic domain
- Ui listview 类
- Linux gcc 编译