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

本文计划分析的链表题目:

单链表相关

  1. 单链表创建
  2. 单链表节点删除
  3. 单链表出入节点
  4. 单链表逆转
  5. 单链表是否有环,若有,求环的第一个节点。
  6. 两个单链表是否相交,若有环,无环?
  7. 单链表排序

双链表相关

  1. 双链表创建
  2. 双链表节点删除
  3. 双链表节点插入
  4. 双链表与二元查找树

单链表:

链表节点结构

typedef struct Snode
{
    int  data;
    struct Snode* next;
} SLinkNode;

1.单链表创建

单链接的创建,采用后接方式,即后插入节点在后面,先插入节点在前面:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <memory.h>
 4 
 5 typedef struct Snode{
 6     int  data;
 7     struct Snode* next;
 8 }SLinkNode;
 9 
10 
11 int main(int argc, char *argv[])
12 {
13     int arr[] = {6,9,23,56,88,797,67,34,76,343};
14     SLinkNode* head = NULL;
15     SLinkNode* pre, *cur;
16     int i= 0,j =0;
17     for( i = 0; i<10 ; ++i ){
18         printf("%d	", arr[i]);
19     }
20     puts("
");
21 
22 
23 
24     for(i =0 ;i < 10 ; ++i ){
25         cur = (SLinkNode *) malloc(sizeof (SLinkNode));
26         cur -> data = arr[i];
27         cur -> next = NULL;
28         if(head == NULL){
29             head = pre = cur ;
30         }else{
31             pre ->next = cur;
32             pre = cur;
33         }
34     }
35 
36     cur = head;
37     while(cur != NULL){
38         printf("%d	", cur ->data);
39         cur = cur ->next;
40     }
41 
42     return 0;
43 }
创建单链表

2、单链表节点删除

单链表节点删除,单链表的节点删除方法相对简单

主要遇到的问题有:

  1. 给定链表中一个指针,要求删除该节点(若不是尾节点,与后续节点交换数据,否则,还是需要遍历)
  2. 其他

3、单链表插入节点

单链接节点插入也相对简单,主要遇到问题

  1. 在当前节点之前插入节点,如何进行(创建新节点,也当前节点交换数据)
  2. 其他。

4、单链表逆转

单链表的逆转:

 1 SLinkNode* reverseLink(SLinkNode* head)
 2 {
 3     if(head == NULL || head->next == NULL)
 4     {
 5        return head;   /*链表为空或只有一个元素则直接返回*/
 6     }
 7 
 8     SLinkNode *tmp = NULL,
 9               *pre = head,
10               *cur = head -> next;
11     while(cur  != NULL)
12     {
13       tmp = cur->next;
14       cur->next = pre;
15       if( pre == head ){
16         pre -> next = NULL;
17       }
18       pre = cur;
19       cur = tmp;
20     }
21 
22     head = pre ;
23     return head;
24 }

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/
 

单链表排序

单列一篇。

双链表相关

双链表创建

双链表节点删除

双链表节点插入

双链表与二元查找树

原文地址:https://www.cnblogs.com/xuddong/p/3322645.html