zoukankan      html  css  js  c++  java
  • 程序员面试笔试——链表题目总结分析

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

    单链表相关

    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/
     

    单链表排序

    单列一篇。

    双链表相关

    双链表创建

    双链表节点删除

    双链表节点插入

    双链表与二元查找树

  • 相关阅读:
    ffmpeg rtmp推流 视频转码
    java日志发展史 log4j slf4j log4j2 jul jcl 日志和各种桥接包的关系
    nginx stream 流转发,可以转发rtmp、mysql访问流,转发rtmp、jdbc请求
    java web http 转https 通过nginx代理访问
    linux 服务器磁盘挂载
    novnc 通过websockify代理 配置多点访问
    linux 文件服务 minio 安装部署配置
    AOP实现原理,手写aop
    java 泛型
    JAVA反射getGenericSuperclass()用法
  • 原文地址:https://www.cnblogs.com/xuddong/p/3322645.html
Copyright © 2011-2022 走看看