程序员面试笔试——链表题目总结分析
2013-09-15 16:09
295 查看
本文计划分析的链表题目:
单链表相关
单链表创建
单链表节点删除
单链表出入节点
单链表逆转
单链表是否有环,若有,求环的第一个节点。
两个单链表是否相交,若有环,无环?
单链表排序
双链表相关
双链表创建
双链表节点删除
双链表节点插入
双链表与二元查找树
单链表:
链表节点结构
创建单链表
主要遇到的问题有:
给定链表中一个指针,要求删除该节点(若不是尾节点,与后续节点交换数据,否则,还是需要遍历)
其他
在当前节点之前插入节点,如何进行(创建新节点,也当前节点交换数据)
其他。
利用两一个指针,一个速度是另外一个的两倍。
即一个指针慢指针:每次移动一个结点;一个快指针,每次移动两结点。
若有环:则两指针会在某一点相遇;若无环:则快指针会先走到链表末尾。
代码如下:
求含有环单链表的环汇总第一个节点:
解法一 :
假设快指针和慢指针在蓝色圆圈所表示结点p处相遇,则它们走过的路径长度分别为:
快指针fast = 非环段链表长度L + 环上链表结点个数C + 从p到交点的弧长S
慢指针slow = 非环段链表长度L + 从p到交点的弧长S
又有fast = 2*slow
故 L = C - S
因此:设两个指针,一个从表头开始遍历,一个从p开始遍历,相遇的结点就是环的起点。代码如下:
两外一种思路,求两个链表的共同点
a、无环链表情况:
方法1:把链表的尾结点和另外一个链表的起点链接起来,然后判断是否有环。代码如下:
bool isCross(List head1, List head2)
{
assert(head1 && head2);
List p1 = head1;
while (p1->link)
p1 = p1->link;
p1->link = head2;
if (hasCircle(head1))
return true;
return false;
}
方法2:如果两个无环链表相交,其尾节点必然相等!代码如下:
bool isCross(List head1, List head2)
{
assert(head1 && head2);
while (head1->link)
head1 = head1->link;
while (head2->link)
head2 = head2->link;
if (head1 == head2)
return true;
return false;
}
b.有环链表相交
解法:有环链表相交,两必然有同一个环;可设一快指针,一慢指针,在绕环N圈后,快指针必然遇到慢指针。代码如下:
bool isCross_(List head1, List head2)
{
bool isCross = false;
assert(head1 && head2);
List fast = head1, slow = head2;
while (fast && fast->link)
{
fast = fast->link->link;
slow = slow->link;
if (slow && slow == fast)
{
isCross = true;
break;
}
}
return isCross;
}
求交点都可以转化为求环的起点问题。
无环->链表首尾相接;
有环->交点一个或者两个;
参考
http://oyjh1986.blog.163.com/blog/static/19601607620118293262941/
单链表相关
单链表创建
单链表节点删除
单链表出入节点
单链表逆转
单链表是否有环,若有,求环的第一个节点。
两个单链表是否相交,若有环,无环?
单链表排序
双链表相关
双链表创建
双链表节点删除
双链表节点插入
双链表与二元查找树
单链表:
链表节点结构
typedef struct Snode { int data; struct Snode* next; } SLinkNode;
1.单链表创建
单链接的创建,采用后接方式,即后插入节点在后面,先插入节点在前面:#include <stdio.h> #include <stdlib.h> #include <memory.h> typedef struct Snode{ int data; struct Snode* next; }SLinkNode; int main(int argc, char *argv[]) { int arr[] = {6,9,23,56,88,797,67,34,76,343}; SLinkNode* head = NULL; SLinkNode* pre, *cur; int i= 0,j =0; for( i = 0; i<10 ; ++i ){ printf("%d\t", arr[i]); } puts("\n"); for(i =0 ;i < 10 ; ++i ){ cur = (SLinkNode *) malloc(sizeof (SLinkNode)); cur -> data = arr[i]; cur -> next = NULL; if(head == NULL){ head = pre = cur ; }else{ pre ->next = cur; pre = cur; } } cur = head; while(cur != NULL){ printf("%d\t", cur ->data); cur = cur ->next; } return 0; }
创建单链表
2、单链表节点删除
单链表节点删除,单链表的节点删除方法相对简单主要遇到的问题有:
给定链表中一个指针,要求删除该节点(若不是尾节点,与后续节点交换数据,否则,还是需要遍历)
其他
3、单链表插入节点
单链接节点插入也相对简单,主要遇到问题在当前节点之前插入节点,如何进行(创建新节点,也当前节点交换数据)
其他。
4、单链表逆转
单链表的逆转:SLinkNode* reverseLink(SLinkNode* head) { if(head == NULL || head->next == NULL) { return head; /*链表为空或只有一个元素则直接返回*/ } SLinkNode *tmp = NULL, *pre = head, *cur = head -> next; while(cur != NULL) { tmp = cur->next; cur->next = pre; if( pre == head ){ pre -> next = NULL; } pre = cur; cur = tmp; } head = pre ; return head; }
5、单链表是否有环,若有,求环的第一个节点。
创建含有环的单链表SLinkNode* cycleNode ; for(i =0 ; i < 10 ; ++i ) { cur = (SLinkNode *) malloc(sizeof (SLinkNode)); cur -> data = arr[i]; cur -> next = NULL; if(head == NULL) { head = pre = cur ; } else { pre ->next = cur; pre = cur; } if(i ==5 ){ cycleNode = pre; } } cur -> next = cycleNode;
利用两一个指针,一个速度是另外一个的两倍。
即一个指针慢指针:每次移动一个结点;一个快指针,每次移动两结点。
若有环:则两指针会在某一点相遇;若无环:则快指针会先走到链表末尾。
代码如下:
int isCircleLink(SLinkNode* head) { if(head == NULL || head ->next == NULL) { return 0; } SLinkNode *slow = head, *fast = head; while (fast && fast-> next) { slow = slow ->next; fast = fast ->next -> next; if (slow == fast) { return 1; } } return 0; }
求含有环单链表的环汇总第一个节点:
解法一 :
假设快指针和慢指针在蓝色圆圈所表示结点p处相遇,则它们走过的路径长度分别为:
快指针fast = 非环段链表长度L + 环上链表结点个数C + 从p到交点的弧长S
慢指针slow = 非环段链表长度L + 从p到交点的弧长S
又有fast = 2*slow
故 L = C - S
因此:设两个指针,一个从表头开始遍历,一个从p开始遍历,相遇的结点就是环的起点。代码如下:
SLinkNode* beginOfCircle(SLinkNode *head) { if( head == NULL || head -> next == NULL) { return NULL; } SLinkNode *slow = head, *fast = head; while (fast && fast-> next) { slow = slow ->next; fast = fast ->next -> next; if (slow == fast) { break; } } if(fast == NULL || fast->next == NULL) //此时链表无环; { return NULL; } fast = head; while (slow != fast) { slow = slow-> next; fast = fast-> next; } return fast; }
两外一种思路,求两个链表的共同点
SLinkNode* beginOfCircle2(SLinkNode *head) { if( head == NULL || head -> next == NULL) { return NULL; } SLinkNode *slow = head, *fast = head; while (fast && fast-> next) { slow = slow ->next; fast = fast ->next -> next; if (slow == fast) { break; } } if(fast == NULL || fast->next == NULL) //此时链表无环; { return NULL; } fast = slow ->next ; slow -> next = NULL; int len1 = 0; int len2 = 0; slow = head ; while(slow != NULL) { len1++; slow =slow-> next; } slow = fast ; while(slow != NULL) { len2++; slow =slow-> next; } int len = 0 ; if(len1 > len2) { len = len1 -len2 ; slow = head; while(slow !=NULL && len >0) { --len; slow = slow -> next; } while(fast != NULL && slow != NULL && fast != slow ){ fast = fast ->next; slow = slow -> next; } if(fast == slow){ return fast; }else{ return NULL; } }else if(len1 < len2){ len = len2 -len1 ; while(fast != NULL && len >0 ) { -- len; fast = fast -> next; } slow = head; while(fast != NULL && slow != NULL && fast != slow ){ fast = fast ->next; slow = slow -> next; } if(fast == slow){ return fast; }else{ return NULL; } }else{ slow = head; while(fast != NULL && slow != NULL && fast != slow ){ fast = fast ->next; slow = slow -> next; } if(fast == slow){ return fast; }else{ return NULL; } } }
6、两个单链表是否相交,若有环,无环?
4、判断链表是否相交a、无环链表情况:
方法1:把链表的尾结点和另外一个链表的起点链接起来,然后判断是否有环。代码如下:
bool isCross(List head1, List head2)
{
assert(head1 && head2);
List p1 = head1;
while (p1->link)
p1 = p1->link;
p1->link = head2;
if (hasCircle(head1))
return true;
return false;
}
方法2:如果两个无环链表相交,其尾节点必然相等!代码如下:
bool isCross(List head1, List head2)
{
assert(head1 && head2);
while (head1->link)
head1 = head1->link;
while (head2->link)
head2 = head2->link;
if (head1 == head2)
return true;
return false;
}
b.有环链表相交
解法:有环链表相交,两必然有同一个环;可设一快指针,一慢指针,在绕环N圈后,快指针必然遇到慢指针。代码如下:
bool isCross_(List head1, List head2)
{
bool isCross = false;
assert(head1 && head2);
List fast = head1, slow = head2;
while (fast && fast->link)
{
fast = fast->link->link;
slow = slow->link;
if (slow && slow == fast)
{
isCross = true;
break;
}
}
return isCross;
}
求交点都可以转化为求环的起点问题。
无环->链表首尾相接;
有环->交点一个或者两个;
参考
http://oyjh1986.blog.163.com/blog/static/19601607620118293262941/
单链表排序
单列一篇。双链表相关
双链表创建
双链表节点删除
双链表节点插入
双链表与二元查找树
相关文章推荐
- 程序员面试题目总结--链表(7)【实现单链表交换任意两个元素(不包括表头)】
- 链表面试笔试题目总结
- [Leetcode][链表]相关题目汇总/分析/总结
- 链表面试笔试题目总结
- 阿里巴巴笔试题目之2013.5.5号战报交流问题分析(gossip problem)
- Leetcode链表部分题目常用方法技巧总结
- 【leetcode】链表常见题目总结
- 笔试面试中涉及位运算的题目总结(一)
- C语言链表在笔试面试中常考问题总结
- 微软2013暑期实习笔试题目第5题分析
- 163笔试资源及面试题目总结
- 阅读大量网络资料总结的常用计算机公司笔试题目(2)
- 面试大总结:Java搞定面试中的链表题目总结
- LeedCode种有关链表List题目总结二
- 程序员面试题目总结--链表(1)【单链表插入和删除】
- 面试笔试题目总结
- [总结]软件工程师笔试题目(C++)
- 关于09年迅雷面试+笔试+上机题目的总结(解答来自网络)
- 单链表常见笔试面试题总结
- 毕业找工作笔试题目总结(1)