编程之美8:链表常见面试笔试题集合
来源:互联网 发布:灯光设计软件 编辑:程序博客网 时间:2024/05/18 22:50
楼楼这篇文章决定把面试中关于链表的常见面试题或者笔试题整理一下,现在目前为止只整理了四个题目,后面如果楼主看到还有什么题目需要记录的话,会一直更新的。楼楼略菜,如果有什么错误或不对的地方,希望各位看官留言指出,谢谢啦!
今天又是福来day了,好伤心啊,一周又过去了。
第一题:单链表是否存在环?环的入口是什么?
解法:设置两个快慢指针fast和slow指针,fast指针一下走两步,slow指针一下走一步,若最终fast == slow,那么就证明单链表中一定会有环。如果没有环的话,fast比slow指针走的快,那么fast一定先到达尾节点。
简单证明:利用相对运动的观念,fast指针一下走两步,slow指针一下走一步。那么slow指针相对于是静止的。当fast超过slow之后,那么fast指针以1步一下的速度追赶slow,如果链表有环的话,那么最后fast一定会追赶上slow。证明就这么从概念上理解一下就OK了吧。
代码见后面
如何找出环的入口点?
下面看一张图:
假设环入口到链表头节点的距离为a,蓝色轨迹为fast指针所走的距离设为2s,黑色轨迹为slow指针所走的距离设为s,假设环长为r,并假设fast和slow相遇时fast已经走过n圈,假设链表长度为L。那么
有
最后有
其中
如何确定带环链表的长度?
如上图可知,第一次相遇,有
代码见后面
第二题:判断两个链表是否相交,若相交求出相交的第一个点(链表有环或者无环)?
一、判断链表是否相交
1. 链表无环
我们先来讨论链表无环的情况。有两种方法可以用来判断无环链表是否相交。
1)将链表A挂在链表B后面,如果AB有交点的话,那么将A挂在B后面,则会构成一个有环的单链表,则只需要利用第一题判断一个链表是否有环的函数,就可以判断出AB是否相交。
2)分别获得链表A和B的尾节点,若两个尾节点相等的话,那么证明AB相交。
2.链表有环
1)其中一个链表有环,另外一个链表没环。则两个链表不可能相交。
2)两个链表都有环。
检测A链表环的入口点,判断这个点是否在B链表的环内(有前驱节点)。因为两个相交的有环链表,环都是公共的。
二、求相交的第一个节点
1. 链表无环
方法一:同样可以使用前面的办法,将链表A挂在链表B后面,如果AB有交点的话,那么将A挂在B后面,则会构成一个有环的单链表,且环的入口点就是相交的第一个节点。
方法二:假设A链表的长度为lenA,B链表的长度为lenB,假设lenA > lenB,反过来类似。那么使用两个节点指针,ptrA和ptrB,ptrA一下走lenA -lenB步,ptrByi一下走一步,ptrA = ptrB的那个节点就是链表相交的第一个节点。
2. 链表有环
两个链表都有环,可以使用方法二来确定相交的第一个节点。带环链表的长度可以使用题目一种的方法来确定。
第三题:求单链表的倒数第K个节点.
- 方法一:
假设链表的长度为N,链表节点从0开始,第0个节点,第1个节点,倒数第0个节点,倒数第一个节点这样子。那么倒数第K个节点,顺着数过去就是第N−K−1 个节点。这样需要遍历链表两遍,第一遍获得链表的长度N,第二遍获取倒数第K个节点,效率比较差。 - 方法二:
使用两个指针都指向链表的头结点,设两个指针分别为ptrA和ptrB,ptrA先走K步,之后ptrA和ptrB分别每次走一步。那么当ptrA到达尾节点的时候,ptrB所指向的节点恰好是倒数第K个节点。
代码见后面
第四题:链表逆序
如图所示,蓝色箭头为初始化的位置,红色箭头为第一次改变节点指向后的三个节点指针。这里为什么要使用三个指针呢?这是因为在我将A2的next指针指向A1之后,如果不使用A3来保存A2的下一个节点,那么这个节点就丢失了,下面就进行不下去了。
看代码见后面
附录:代码
此部分代码包括链表的创建,链表的反转,找出链表的第K个节点,创建带环链表,判断链表是否有环,找出环的入口点等部分的内容。代码主体来源于http://387929.blog.51cto.com/377929/1332211,我只是在这个代码的基础上写了一些和本篇文章相关的内容,在此表示感谢。
/****************************************** * 文件名称:reverse.c * 文件描述:单链表逆序 请注意:没有添加链表释放的函数, 这个文件会造成内存泄露,请自己完善 * 文件作者:by wangluojisuan, in 2013.11.27 * 文件版本:1.2 * 修改记录:*******************************************/#include <stdio.h>#include <stdlib.h>//定义链表节点,包含数据域data与指针域nexttypedef struct _link_node_ { int data; //数据域 struct _link_node_ *next; //指针域}linknode_t;//定义链表,包含链表头及链表最大长度,当前长度//链表头head不存储内容,head->next为第一个节点//建议采用这种链表定义方式,可以包含更多的链表信息typedef struct _link_list_ { int m_len; //链表最大长度 int c_len; //链表当前长度 linknode_t *head; //链表头}linklist_t;linklist_t * init_linklist(int len); //初始化链表linknode_t * _create_linknode(int value); //创建节点int insert_linklist(linklist_t *list, int value); //链表中插入节点void show_linklist(linklist_t *list); //显示链表内容void reverse_linklist(linklist_t *list); //反转链表顺序linknode_t* findKthNode(linklist_t *list, int K); //找出倒数第K个节点void create_CirculList(linklist_t* list); //创建一个循环链表bool IsExitsLoop(linklist_t *list); //判断链表是否存在环linknode_t* FindLoopPort(linklist_t *list); //找出环的入口点int main(void){ //初始化链表 //输出内容 //反转链表 //输出反转结果 int i = 0; linklist_t *list = NULL; list = init_linklist(10); if (NULL == list) exit(-1); for (i = 0; i < 10; i++) { if (0 != insert_linklist(list, i)) printf("error\n"); } show_linklist(list); reverse_linklist(list); show_linklist(list); //找出链表的倒数第K个节点 int K = 3; linknode_t* kthNode = findKthNode(list, K); printf("链表倒数第%d个节点的值为%d\n", K, kthNode->data); //构造一个循环链表 create_CirculList(list); //判断是否存在环 if (IsExitsLoop(list)) { printf("链表有环\n"); } else { printf("链表无环\n"); } //找出环的入口点 linknode_t *circleEntry = FindLoopPort(list); printf("环的入口点处data的值为:%d\n", circleEntry->data); return 0;}linknode_t* findKthNode(linklist_t *list, int K){ linknode_t* fast = list->head; linknode_t* slow = list->head; //让快指针先走K步 for (int i = 0; i < K; i++) fast = fast->next; //此后两个指针每次走一步,等到快指针到达尾节点的时候,慢指针所指向的就是倒数第K个节点了,倒数从第0个算起。 while (fast->next != NULL) { fast = fast->next; slow = slow->next; } return slow;}linknode_t* FindLoopPort(linklist_t *list) { linknode_t *slow = list->head; linknode_t *fast = list->head; while ( fast && fast->next ) { slow = slow->next; fast = fast->next->next; if ( slow == fast ) break; } if (fast == NULL || fast->next == NULL) return NULL; slow = list->head; while (slow != fast) { slow = slow->next; fast = fast->next; } return slow; } /*===================================================== * 函数名称:IsExitsLoop * 函数功能:判断是否链表是否存在环 * 函数参数:list * 返 回 值:void * 创 建 人:by duanxiaoxia,in 2015.04.24 * 修改记录:======================================================*/bool IsExitsLoop(linklist_t *list) { linknode_t *slow = list->head; linknode_t *fast = list->head; while ( fast && fast->next ) { slow = slow->next; fast = fast->next->next; if ( slow == fast ) break; } return !(fast == NULL || fast->next == NULL); } /*===================================================== * 函数名称:create_CirculList * 函数功能:创建一个循环链表,环随便指的 * 函数参数:list * 返 回 值:void * 创 建 人:by duanxiaoxia,in 2015.04.24 * 修改记录:======================================================*/void create_CirculList(linklist_t* list){ //随意设置一个环的入口点 linknode_t *circleEntry = list->head->next->next; linknode_t *listEnd = list->head; //循环遍历到链表的尾节点,将尾节点的next节点指向circleEntry while (listEnd->next != NULL) { listEnd = listEnd->next; } listEnd->next = circleEntry;}/*===================================================== * 函数名称:_create_linknode * 函数功能:创建链表节点,节点next指向NULL * 函数参数:int value 节点数据域的内容 * 返 回 值:linknode * 创建好的链表节点,如果出错返回NULL * 创 建 人:by wangluojisuan,in 2013.11.27 * 修改记录:======================================================*/linknode_t * _create_linknode(int value){ linknode_t *node = NULL; node = (linknode_t *)malloc(sizeof(linknode_t)); if (NULL == node) return NULL; node->data = value; node->next = NULL; return node;}/*======================================================= * 函数名称:init_linklist * 函数功能:初始化一个链表,并设置最大链表长度 * 函数参数:int len 链表的最大长度 * 返 回 值:linklist * 成功 初始化好的链表 失败 NULL * 创 建 人:by wangluojisuan,in 2013.11.27 * 修改记录:========================================================*/linklist_t * init_linklist(int len){ linklist_t *list = NULL; list = (linklist_t *)malloc(sizeof(linklist_t)); if (NULL == list) return NULL; list->m_len = len; //设置最大长度 list->c_len = 0; //设置当前长度 list->head = _create_linknode(0); //头结点赋值 return list;}/*======================================================= * 函数名称:insert_linklist * 函数功能:向链表中插入数据,使用头插法,每次新插入的节点都 放在head的后面 * 函数参数:linklist_t *list 链表 int value 插入节点数据域值 * 返 回 值:int 成功 0 失败 -1 * 创 建 人:by wangluojisuan,in 2013.11.27 * 修改记录:========================================================*/int insert_linklist(linklist_t *list, int value){ linknode_t *node = NULL; if (list->c_len >= list->m_len) return -1; node = _create_linknode(value); node->next = list->head->next; list->head->next = node; (list->c_len)++; return 0;}/*======================================================= * 函数名称:show_linklist * 函数功能:显示链表的内容 * 函数参数:linklist_t *list 链表 * 返 回 值:void * 创 建 人:by wangluojisuan,in 2013.11.27 * 修改记录:========================================================*/void show_linklist(linklist_t *list){ linknode_t *node = NULL; node = list->head->next; while (NULL != node) { printf("%d ", node->data); node = node->next; } printf("\n");}/*======================================================= * 函数名称:reverse_linklist * 函数功能:反转链表节点 * 函数参数:linklist_t *list 链表 * 返 回 值:void * 创 建 人:by duanxiaoxia, 2015.4.23 * 修改记录:========================================================*/void reverse_linklist(linklist_t *list){ linknode_t *A1 = list->head->next; linknode_t *A2 = A1->next; linknode_t *A3 = A2->next; while (A3->next != NULL) { A2->next = A1; if (A1 == list->head->next) A1->next = NULL; A1 = A2; A2 = A3; A3 = A3->next; } //到达最后一个节点,那么直接将A2指向A1,A3指向A2 A2->next = A1; A3->next = A2; list->head->next = A3;}
- 编程之美8:链表常见面试笔试题集合
- 常见面试笔试题
- 编程之美:常见面试题思想方法整理
- java常见面试笔试题
- unity常见面试笔试题
- 面试笔试题集合(c++)
- 编程之美—面试题16 反转链表
- 常见的面试笔试题 及其解答
- 一些常见的面试笔试题
- 编程之美面试题1
- 编程之美面试题2
- 编程之美面试题12
- 计算机网络之面试笔试题总结
- 常见面试题之链表操作
- 数据结构之链表常见面试题
- 125条常见的java面试笔试题大汇总
- 125条常见的java面试笔试题大汇总
- 125条常见的java面试笔试题汇总(一)
- 第十六章 内存管理(1)====高质量程序设计指南C/C++编程
- zoj 1648 Grandpa's Estate(判断线段是否相交(不考虑端点相交))
- ADB操作常见问题汇总
- 关于react native运用的简单总结
- mysql数据备份导入导出详解
- 编程之美8:链表常见面试笔试题集合
- NuGet来管理你的包——成绩登统系统
- 组合测试法中的全对偶测试法
- 字符串 Substring with Concatenation of All Words
- 关于类似“Can't bind to local 8602 for debugger”错误的解决方案
- 《从非结构化数据到大数据》有感
- eclipse调试多线程
- kali可用的更新源
- java web中的内容