您的位置:首页 > 职场人生

程序员面试笔试——链表题目总结分析

2013-09-15 16:09 295 查看
本文计划分析的链表题目:

单链表相关

单链表创建

单链表节点删除

单链表出入节点

单链表逆转

单链表是否有环,若有,求环的第一个节点。

两个单链表是否相交,若有环,无环?

单链表排序

双链表相关

双链表创建

双链表节点删除

双链表节点插入

双链表与二元查找树

单链表:

链表节点结构

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/

单链表排序

单列一篇。

双链表相关

双链表创建

双链表节点删除

双链表节点插入

双链表与二元查找树

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: