链表
来源:互联网 发布:网页三剑客软件下载 编辑:程序博客网 时间:2024/05/01 23:18
另附: http://www.tuicool.com/articles/mimaEf7
链表是最基本的数据结构,面试官也常常用链表来考察面试者的基本能力,而且链表相关的操作相对而言比较简单,也适合考察写代码的能力。链表的操作也离不开指针,指针又很容易导致出错。综合多方面的原因,链表题目在面试中占据着很重要的地位。本文对链表相关的面试题做了较为全面的整理,希望能对找工作的同学有所帮助。
链表结点声明如下:
struct ListNode
{
int data;
ListNode * next;
};
题目列表:
1. 求单链表中结点的个数
2. 将单链表反转
3. 查找单链表中的倒数第K个结点(k > 0)
4. 查找单链表的中间结点
5. 从尾到头打印单链表
6. 已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序
7. 判断一个单链表中是否有环
8. 判断两个单链表是否相交
9. 求两个单链表相交的第一个节点
10. 已知一个单链表中存在环,求进入环中的第一个节点
11. 给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted
详细解答
1. 求单链表中结点的个数
这是最最基本的了,应该能够迅速写出正确的代码,注意检查链表是否为空。时间复杂度为O(n)。参考代码如下:
2. 将单链表反转
从头到尾遍历原链表,每遍历一个结点,将其摘下放在新链表的最前端。注意链表为空和只有一个结点的情况。时间复杂度为O(n)。参考代码如下:
3. 查找单链表中的倒数第K个结点(k > 0)
最普遍的方法是,先统计单链表中结点的个数,然后再找到第(n-k)个结点。注意链表为空,k为0,k为1,k大于链表中节点个数时的情况。时间复杂度为O(n)。代码略。
这里主要讲一下另一个思路,这种思路在其他题目中也会有应用。
主要思路就是使用两个指针,先让前面的指针走到正向第k个结点,这样前后两个指针的距离差是k-1,之后前后两个指针一起向前走,前面的指针走到最后一个结点时,后面指针所指结点就是倒数第k个结点。
参考代码如下:
4. 查找单链表的中间结点
此题可应用于上一题类似的思想。也是设置两个指针,只不过这里是,两个指针同时向前走,前面的指针每次走两步,后面的指针每次走一步,前面的指针走到最后一个结点时,后面的指针所指结点就是中间结点,即第(n/2+1)个结点。注意链表为空,链表结点个数为1和2的情况。时间复杂度O(n)。参考代码如下:
5. 从尾到头打印单链表
对于这种颠倒顺序的问题,我们应该就会想到栈,后进先出。所以,这一题要么自己使用栈,要么让系统使用栈,也就是递归。注意链表为空的情况。时间复杂度为O(n)。参考代码如下:
自己使用栈:
使用递归函数:
6. 已知两个单链表pHead1 和pHead2 各自有序,把它们合并成一个链表依然有序
这个类似归并排序。尤其注意两个链表都为空,和其中一个为空时的情况。只需要O(1)的空间。时间复杂度为O(max(len1, len2))。参考代码如下:
也有如下递归解法:
7. 判断一个单链表中是否有环
这里也是用到两个指针。如果一个链表中有环,也就是说用一个指针去遍历,是永远走不到头的。因此,我们可以用两个指针去遍历,一个指针一次走两步,一个指针一次走一步,如果有环,两个指针肯定会在环中相遇。时间复杂度为O(n)。参考代码如下:
8. 判断两个单链表是否相交
如果两个链表相交于某一节点,那么在这个相交节点之后的所有节点都是两个链表所共有的。也就是说,如果两个链表相交,那么最后一个节点肯定是共有的。先遍历第一个链表,记住最后一个节点,然后遍历第二个链表,到最后一个节点时和第一个链表的最后一个节点做比较,如果相同,则相交,否则不相交。时间复杂度为O(len1+len2),因为只需要一个额外指针保存最后一个节点地址,空间复杂度为O(1)。参考代码如下:
10. 已知一个单链表中存在环,求进入环中的第一个节点
首先判断是否存在环,若不存在结束。在环中的一个节点处断开(当然函数结束时不能破坏原链表),这样就形成了两个相交的单链表,求进入环中的第一个节点也就转换成了求两个单链表相交的第一个节点。参考代码如下:
11. 给出一单链表头指针pHead和一节点指针pToBeDeleted,O(1)时间复杂度删除节点pToBeDeleted
对于删除节点,我们普通的思路就是让该节点的前一个节点指向该节点的下一个节点,这种情况需要遍历找到该节点的前一个节点,时间复杂度为O(n)。对于链表,链表中的每个节点结构都是一样的,所以我们可以把该节点的下一个节点的数据复制到该节点,然后删除下一个节点即可。要注意最后一个节点的情况,这个时候只能用常见的方法来操作,先找到前一个节点,但总体的平均时间复杂度还是O(1)。参考代码如下:
=========================================================
8、 扩展:链表有环,如何判断相交
题目描述:上面的问题都是针对链表无环的,那么如果现在,链表是有环的呢?上面的方法还同样有效么?
分析:如果有环且两个链表相交,则两个链表都有共同一个环,即环上的任意一个节点都存在于两个链表上。因此,就可以判断一链表上俩指针相遇的那个节点,在不在另一条链表上。
代码如下:
//判断两个带环链表是否相交bool isIntersectWithLoop(Node *h1,Node *h2){ Node *circleNode1,*circleNode2; if(!hasCircle(h1,circleNode1)) //判断链表带不带环,并保存环内节点 return false; //不带环,异常退出 if(!hasCircle(h2,circleNode2)) return false; Node *temp = circleNode2->next; while(temp != circleNode2) { if(temp == circleNode1) return true; temp = temp->next; } return false;}
9、扩展:两链表相交的第一个公共节点
题目描述:如果两个无环单链表相交,怎么求出他们相交的第一个节点呢?
分析:采用对齐的思想。计算两个链表的长度 L1 , L2,分别用两个指针 p1 , p2 指向两个链表的头,然后将较长链表的 p1(假设为 p1)向后移动L2 - L1个节点,然后再同时向后移动p1 , p2,直到 p1 = p2。相遇的点就是相交的第一个节点。
代码如下:
//求两链表相交的第一个公共节点 思想:用两个指针扫描”两个链表“,最终两个指针到达 null 或者到达公共结点。
class
Solution {
public
:
ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2)
{
ListNode *p1 = pHead1;
ListNode *p2 = pHead2;
while
(p1!=p2)
{
p1 = (p1==NULL ? pHead2 : p1->next);
p2 = (p2==NULL ? pHead1 : p2->next);
}
return
p1;
}
};
10.从单链表中删除指定的结点
实现:
将指定结点的后继的值赋值给指定结点,然后删除其后继即可。
1: void DeleteMidNode(Node *del)
2: {
3: if (!del) {
4: return;
5: }
6:
7: Node *next = del->next;
8: if (next) {
9: del->data= next->data;
10: del->next= next->next;
11: free(next);
12: }
13: }
11.单链表的插入、删除操作
- 1、S节点插到P节点之后:
- s->next = p->next;
- p->next = s;
- 2、S节点插到p节点之前:
- s->next = p->next;
- p->next = s;
- swap(p->data, s->data);
- 3、删除*p所指节点:
- p->next = p->next->next;
11.双链表的插入、删除操作
- 1、p节点之后插入s节点:
- s->prior = p ;
- s->next = p->next;
- p->next->prior = s;
- p->next = s;
- 2、p节点之前插入s节点:
- s->next = p ;
- s->prior = p->prior;
- p->prior->next = s;
- p->prior = s;
- 3、删除*p所指节点:
- p->prior->next = p->next;
- p->next->prior = p->prior;
- void del_same(LinkList &L)
- {
- LNode *p = L->next, *q; //p为扫描指针
- while(p->next != NULL)
- {
- q = p->next; //q为后继节点
- if(p->data == q->data)
- {
- p->next = q->next;
- free(q);
- }
- else
- p=p->next;
- }
- }
13.删除单链表中特定的值
- void del(LinkList *&L,ElemType x)
- { Node *t;
- if (L==NULL) return;
- if (L->data==x)
- { t=L;
- L=L->next;
- free(t);
- return;
- }
- else del(L->next,x);
- }
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- c++中vector的用法详解
- 关于MBR病毒的一些调研及分析工作
- oracle用户创建及权限设置
- Android Studio使用framework.jar方法
- Construct the Rectangle
- 链表
- Python中的random函数
- 1030. Travel Plan (30)
- 软件版本命名规范
- python中数组的操作
- redis RDB配置和原理
- B树和B+树的区别
- Android 7.0 Gallery图库源码分析2
- [JZOJ5044]【NOI2017模拟4.4】Sone0