大厂面试经典单链表例题(创建有序单链表,逆置单链表,判断链表是否有环,取链表中间节点)(含核心代码与解析)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 大厂面试经典单链表例题(创建有序单链表,逆置单链表,判断链表是否有环,取链表中间节点)(含核心代码与解析)

目录


引言

创建有序单链表

题目

算法思路

代码实现

逆置单链表

题目

算法思路

代码实现

判断单链表是否有环

题目

算法思路

代码实现

取单链表中间节点的数值

题目

算法思路

代码实现

总结


引言


有关单链表的基础操作,如动态分布空间,单链表创建的思路,单链表的增、删、改、毁,笔者已经在博客中详细解析了,有兴趣的小伙伴也可以取看看,

本次介绍的是有关单链表的四道大厂面试典中典,其中的逆置单链表更是重量级,大家放心食用😁


正文


创建有序单链表


题目


创建一个升序或降序的单链表,并打印输出,例如:

输入: 1 5 6 2 3
输出: 1 2 3 5 6


算法思路


算法思路:

       s1:每获得一个数据 就创建一个数据结点

       s2:把数据写入到数据结点中去

       s3:把写好的数据结点加入到链表中去

           分情况讨论:

               从无到有

               从少到多

                   头插法

                   尾插法

                   中间插入

我们将算法思路待人代码中观察


代码实现


Node *create_sort_list()
{
  u4 d;
  Node *pnew = NULL;    //指向 新创建的节点
  Node *head = NULL;
  while(1)
  {
    scanf("%d",&d);
    if(d == 0)        //约定输入0,结束输入
      break;
    pnew = malloc(sizeof(*pnew));    //分配空间
    pnew->data = d;                  //将数据写入数据节点
    pnew->next = NULL;
        //将写好的数据节点加入到链表
    if(head == NULL)                 //从无到有
    {
      head = pnew;
    }
    else                             //从少到多
    {
      Node *p = head;
      Node *pre = NULL;
      while(p)                     //找出链表中比新节点大的数据打的节点
      {
        if(p->data > pnew->data)    //找到就返回这个节点
        {
          break;
        }
        else                        //没找到就往下遍历,直到p==NULL,即新节点的值是最大的,插到末尾
        {
          pre = p;
          p = p->next;
        }
      }
      if(p != NULL)
      {
        if(p == head)            //头插法
        {
          pnew->next = head;   //新节点指向链表的第一个,即指向head
              head = pnew;     //然后将head指向新节点
        }
        else                     //插入中间
        {
          pnew->next = p;
          pre->next = pnew;
        }
      }
      else                         //插到末尾
      {
        pre->next = pnew;
      }
    }
  }
  return head;
}


逆置单链表


题目


就地逆置一个链表(不允许申请新的结点空间)

   例子:

       h: 1 5 3 4

       =>

       h: 4 3 5 1

       要求:

           不允许申请新的结点空间


算法思路


把原链表的每一个结点 ,摘下来 ,然后按头插法 加入到新链表。

 

Node *reverse(Node *h)
{
  //创建一个指向逆置后链表的第一个结点
  //创建一个指针p为遍历指针
  while(p)
  {
      //step 1:把h指向的链表的第一个结点摘下来
    //step2: 按照头插法 把p结点 加入到逆置后的链表first
    //step2.1 从无到有
    //step2.2 从少到多
  }
      //返回逆置链表的第一个节点
}


代码实现


Node *reverrse(Node *h)
{
  Node *first = NULL;        //创建一个指向逆置后链表的第一个结点
  Node *p = h;               //创建一个指针p为遍历指针
  while(p)
  {
        //step 1:把h指向的链表的第一个结点摘下来
    h = h->next;
    p->next = NULL;
        //step2: 按照头插法 把p结点 加入到逆置后的链表first
    //step2.1 从无到有
    if(first == NULL)
    {
      first = p;
    }
    else            //step2.2 从少到多
    {
      p->next = first;
      first = p;
    }
    p = h;
  }
  return first;        //返回逆置链表的第一个节点
}


判断单链表是否有环


题目


判断一个单链表是否有环


算法思路


快慢指针

定义两个指针p和q;

让p每次走两步,q每次走一步

当p和q相遇时则说明有环,否则就没有环。


代码实现


/*
is_a_ring:判断单链表是否有环
    @h:指定的单链表的第一个节点指针
    返回值:
        1 有环
        0 无环
 */
int is_a_ring(Node *h)
{
  Node *p = NULL;//fast指针
  Node *q = NULL;//slow指针
  p = h;
  q = h;
  while(p)
  {
    p = p->next;
    if(p == NULL)
    {
        break;
    }
    p = p->next;
    q = q->next;
    if(p == q)
    {
      return 1;
    } 
  }
  return 0;
}


取单链表中间节点的数值


题目


写一个程序,获取链表中间结点的值

       例子:

           对于奇数结点 返回中间结点值

           输入 :1 2 3 4 5

           输出:3

           对于偶数结点  返回较小下标的值

           输入: 25 69 78 45 96 -21 -47 62

           输出:45


算法思路


定义两个指针p和q;

让p每次走两步 q走一步

当p走到链表末尾时 此时q刚好走到链表的中间结点。


代码实现


void get_middle_v(Node *h)
{
  Node *pk = h;    //快指针
  Node *pm = h;    //慢指针
  while(1)
  {
    if(pk->next == NULL)    //快指针已经到了最后一个(奇数个)
    {
      printf("%d\n",pm->data);
      break;
    }
    else
    {
      pk = pk->next->next;        //快指针的下一个是最后一个(偶数个)
      if(pk == NULL)
      {
        printf("%d\n",pm->data);
        break;
      }
      pm = pm->next;
    }
  }
}


总结


这些题目其实总体难度不高,更重要的是体会其中的算法思路,分类思想,利用好单链表本身的空间余节点取解决问题。

相关文章
|
2月前
Leetcode第21题(合并两个有序链表)
这篇文章介绍了如何使用非递归和递归方法解决LeetCode第21题,即合并两个有序链表的问题。
51 0
Leetcode第21题(合并两个有序链表)
|
2月前
|
存储 算法
【❤️算法笔记❤️】-每日一刷-21、合并两个有序链表
【❤️算法笔记❤️】-每日一刷-21、合并两个有序链表
104 0
|
18天前
|
存储 算法 C语言
【C语言】深入浅出:C语言链表的全面解析
链表是一种重要的基础数据结构,适用于频繁的插入和删除操作。通过本篇详细讲解了单链表、双向链表和循环链表的概念和实现,以及各类常用操作的示例代码。掌握链表的使用对于理解更复杂的数据结构和算法具有重要意义。
130 6
|
17天前
|
PHP 开发者 容器
PHP命名空间深度解析:避免命名冲突与提升代码组织####
本文深入探讨了PHP中命名空间的概念、用途及最佳实践,揭示其在解决全局命名冲突、提高代码可维护性方面的重要性。通过生动实例和详尽分析,本文将帮助开发者有效利用命名空间来优化大型项目结构,确保代码的清晰与高效。 ####
18 1
|
25天前
|
机器学习/深度学习 存储 人工智能
强化学习与深度强化学习:深入解析与代码实现
本书《强化学习与深度强化学习:深入解析与代码实现》系统地介绍了强化学习的基本概念、经典算法及其在深度学习框架下的应用。从强化学习的基础理论出发,逐步深入到Q学习、SARSA等经典算法,再到DQN、Actor-Critic等深度强化学习方法,结合Python代码示例,帮助读者理解并实践这些先进的算法。书中还探讨了强化学习在无人驾驶、游戏AI等领域的应用及面临的挑战,为读者提供了丰富的理论知识和实战经验。
50 5
|
1月前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
128 10
|
1月前
|
前端开发 JavaScript 开发者
揭秘前端高手的秘密武器:深度解析递归组件与动态组件的奥妙,让你代码效率翻倍!
【10月更文挑战第23天】在Web开发中,组件化已成为主流。本文深入探讨了递归组件与动态组件的概念、应用及实现方式。递归组件通过在组件内部调用自身,适用于处理层级结构数据,如菜单和树形控件。动态组件则根据数据变化动态切换组件显示,适用于不同业务逻辑下的组件展示。通过示例,展示了这两种组件的实现方法及其在实际开发中的应用价值。
37 1
|
2月前
|
机器学习/深度学习 人工智能 算法
揭开深度学习与传统机器学习的神秘面纱:从理论差异到实战代码详解两者间的选择与应用策略全面解析
【10月更文挑战第10天】本文探讨了深度学习与传统机器学习的区别,通过图像识别和语音处理等领域的应用案例,展示了深度学习在自动特征学习和处理大规模数据方面的优势。文中还提供了一个Python代码示例,使用TensorFlow构建多层感知器(MLP)并与Scikit-learn中的逻辑回归模型进行对比,进一步说明了两者的不同特点。
95 2
|
2月前
|
存储 搜索推荐 数据库
运用LangChain赋能企业规章制度制定:深入解析Retrieval-Augmented Generation(RAG)技术如何革新内部管理文件起草流程,实现高效合规与个性化定制的完美结合——实战指南与代码示例全面呈现
【10月更文挑战第3天】构建公司规章制度时,需融合业务实际与管理理论,制定合规且促发展的规则体系。尤其在数字化转型背景下,利用LangChain框架中的RAG技术,可提升规章制定效率与质量。通过Chroma向量数据库存储规章制度文本,并使用OpenAI Embeddings处理文本向量化,将现有文档转换后插入数据库。基于此,构建RAG生成器,根据输入问题检索信息并生成规章制度草案,加快更新速度并确保内容准确,灵活应对法律与业务变化,提高管理效率。此方法结合了先进的人工智能技术,展现了未来规章制度制定的新方向。
43 3
|
2月前
|
SQL 监控 关系型数据库
SQL错误代码1303解析与处理方法
在SQL编程和数据库管理中,遇到错误代码是常有的事,其中错误代码1303在不同数据库系统中可能代表不同的含义

推荐镜像

更多
下一篇
DataWorks