面试中必知必会的那些题——第一题 单链表倒置

简介:

  我想你去很多家公司面试的时候,遇到单链表倒置的问题可能比较多,如果一定要给面试题来一个排名,估计也能上top10吧,其实这个

题目玩的是技巧和你对单链表的理解,其实我们仔细想想也不是很难,既然是倒置,那我们一定是一定要走一遍单链表的,对吧,那么走单链

表有两种形式,递归和循环两种方式,而递归正是压栈和出栈,那么我们就想起来了,这不就是顺序和逆序的关系吗?第二种就是循环,还记

得我们曾今学习单链表的时候有一种插法叫做头插法,这种插入复杂度为O(1),不好的地方就是顺序插入的数字,出来的时候却是反的,所以这

个不就是可以将原先的链表原地倒置过来吗?

 

一:递归

  说到递归,我们脑子里面一定要有一个V型图,还有一个就是好记性不如烂笔头,算法这东西很难用脑子想的清楚的,多画画图就见青天了,

下面我就举个简单的例子:现有链表L={8,1,6,3},需要将L倒置,然后我就画好了V型图。

从图中可以看到,当我递归到3再出栈的时候,只需要将6赋给3.next,1赋给6.next,然后这样以此类推。。。最后结果就出来了,貌似

口头上描述起来很简单,但是在写代码的时候需要注意以下几个点,先上代码说话。

public LinkNode Reverse(LinkNode node)
        {
            if (node.next == null)
                return node;

            var prevNode = Reverse(node.next);

            var temp = node.next;

            temp.next = node;

            node.next = null;

            return prevNode;
        }

 

第一点:我们在走链表的时候,可以操控的只有两个结点,node和node.next,所以递归出口的时候,一定不能使用最常见的写法。

1       if (node == null)
2            return node;

    而应该像下面这么写,其实就告诉我们只需要走到6节点就行了,用6.next来判断下是不是链尾,这样做是方便我们进行node和

   node.next进行节点交换。

1             if (node.next == null)
2                 return node;

 

第二点:当我们每一次出栈的时候,其实也是退到曾今压栈时的方法环境中,进行节点交换的时候,也只能在当前的方法上下文中起效,比如

          说:出栈到1的时候,其实3和6的节点已经交换了,但是1这个方法环境不知道,它仍然指向6,但此时节点6.next再也不是3了,因为

    曾今3和6进行了交换,所以这不是我们所期望的,所以在回退的时候,一定要有一个链表保存这个所有节点交换的集合,恰巧在链表中

         有一个特征就是,只要我有一个指针始终指向头结点的地址,它就相当于一个集合的功能了,因为我不管你后面节点怎么转换,我都可以

         通过head.next依次找到后面痉挛的所有结点,比如下图中在出栈的过程中,每出栈的方法环境中都依次交换了node和node.next结

         点,而我的prevnode始终指向的是结点3,所以我通过3.next就可以找到后面所有的 变化,所以这里就是prevnode的精妙之处。

     

最后看一下倒置的输出结果:

 

二:非递归实现

  如果你知道头插法,那么循环实现真的很简单,不像递归做法很难想到那个prevnode节点,我们知道头插法是把新节点插入到链表的头部,

而我们遍历的时候又可以控制两个节点node和node.next,所以依次采用头插法,将node.next插入到node之前,有人说,那插入到node节

点之前不就乱了吗?所以在操作之前,我可以把node.next先保存起来,比如放到申请的一个叫next的节点上,为了保存新转换的节点,我们再

申请一个prev结点来保存头插法中的新节点。

 

为了好理解,画图如下,其实这里要注意,结点还是那些结点,并没有删除再添加。


public LinkNode Reserve(LinkNode node)
        {
            LinkNode prev = null;
            LinkNode next = null;

            while (node != null)
            {
                next = node.next;

                node.next = prev;

                prev = node;

                node = next;
            }
            return prev;
        }

其实我们发现,代码只有那么一点点,但是信息量还是蛮大的,这些东西要是用口头描述还是很累的。

相关文章
|
算法 Go
单链表(面试算法题2)---单链表进阶1之快慢指针
单链表(面试算法题2)---单链表进阶1之快慢指针
62 0
|
算法
单链表(面试算法题3)---两链表相交问题
单链表(面试算法题3)---两链表相交问题
49 0
|
算法 Java C++
单链表(面试算法题1)---学习链表的关键在于code
单链表(面试算法题1)---学习链表的关键在于code
44 0
|
算法
【面试必刷TOP101】链表相加 & 单链表的排序
【面试必刷TOP101】链表相加 & 单链表的排序
49 0
【基础算法】单链表的OJ练习(5) # 环形链表 # 环形链表II # 对环形链表II的解法给出证明(面试常问到)
【基础算法】单链表的OJ练习(5) # 环形链表 # 环形链表II # 对环形链表II的解法给出证明(面试常问到)
|
算法
大厂面试经典单链表例题(创建有序单链表,逆置单链表,判断链表是否有环,取链表中间节点)(含核心代码与解析)
大厂面试经典单链表例题(创建有序单链表,逆置单链表,判断链表是否有环,取链表中间节点)(含核心代码与解析)
|
程序员
数据结构面试之一——单链表常见操作
Step1:置查找标记bfound=false;判断链表是否为空,是,提示“不能查找空链表”;否,进入step2。 Step2:从链表头开始查找,判断(当前点的info是否与待查找元素值相等&&指针未指向末尾),是,“查找结束,bfound=true”,否,继续查找。 Step3:判断bfound= = true,是,“提示查找成功”,否,“提示查找失败”。 ———————————————— 版权声明:本文为CSDN博主「铭毅天下」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/laoyang360/
136 0
|
数据处理 开发者
数据结构面试之一——单链表常见操作
题注:《程序员面试宝典》有相关习题,但思路相对不清晰,排版有错误,本文对此参考相关书籍和自己观点进行了重写,供大家参考。
394 0
|
7月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
4月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!

热门文章

最新文章