算法学习 day2--反向打印单向链表

题目

输入一个链表的头节点,从尾到头反过来打印出每个节点的值

题目分析

单向链表只能从前往后遍历,给出头节点,如果正向打印是很容易的一件事,如果反向打印,就相对麻烦了。因为单向链表的特性我们无法从后往前遍历,那么就需要一种“后进先出”的数据结构或者方法来解决这个问题。而“栈”就是这样一种数据结构。

第一种解法:通过遍历链表,将每个节点的值压入栈,然后再把栈里的值一个一个弹出即可。
第二种解法:使用递归,递归和栈的原理非常相似。
第三种解法:通过数组,先遍历一遍链表,通过累加拿到链表长度,然后创建一个数组,在遍历一次链表,将每个节点的值放入数组,最后反向打印出数组即可。

这道题放java里有太多解决方式了,但是这道题主要是考察对链表,栈,递归,循环等的了解。不是说能打印出来就完事了的。上边3种解法里,第一种为最优解,第二种的递归能不用就不用,在任何程序语言里都是一个道理,能用循环实现的就不要用递归,除非万不得以。递归每次都会创建一个栈帧,太多层递归可能栈溢出,JVM会先被无穷无尽的栈帧撑爆。递归基本上都可以转由循环实现,优先考虑循环。最后一种解法比上边2种解法多了一次遍历,虽然最终时间复杂度也是O(n),算是我自己的解法,哈哈。

代码实现
package day2;

import java.util.Stack;

/**
 * 方向打印单向链表
 * <p>面试题5:输入一个链表的头节点,从尾到头反过来打印出每个节点的值</p>
 * @author leoss
 * @version 2019/1/3 23:22
 */
public class PrintLink {


    public static void main(String[] args) {
        int size = 5;
        Node head = genLink(size);
        printLinkByLoop(head);
//        printLinkByRecursion(head);
//        printLinkByArray(head);

        size = 0;
        head = genLink(size);
        printLinkByLoop(head);
//        printLinkByRecursion(head);
//        printLinkByArray(head);

        printLinkByLoop(null);
//        printLinkByRecursion(null);
//        printLinkByArray(null);
    }

    static class Node {
        int val;
        Node next;
    }

    /**
     * 生成指定长度的链表
     *
     * @param size 链表长度
     * @return 链表
     */
    private static Node genLink(int size) {
        Node head = null;
        Node now = null;
        for (int i = 0; i < size; i++) {
            Node node = new Node();
            node.val = i;
            if (i == 0) {
                head = node;
                now = head;
            } else {
                now.next = node;
                now = node;
            }
        }
        return head;
    }

    /**
     * 递归实现反向打印链表
     *
     * @param node 链表头节点
     */
    private static void printLinkByRecursion(Node node) {
        if (node != null) {
            if (node.next != null) {
                printLinkByRecursion(node.next);
            }
            System.out.println("rec : " + node.val);
        } else {
            System.err.println("link is null");
        }
    }

    /**
     * 循环实现反向打印链表
     *
     * @param node 链表头节点
     */
    private static void printLinkByLoop(Node node) {
        if (node == null) {
            System.err.println("link is null");
            return;
        }

        Stack<Integer> stack = new Stack<>();
        while (node != null) {
            stack.push(node.val);
            node = node.next;
        }
        while (!stack.isEmpty()) {
            //注意这里是用pop,不是用peek
            System.out.println("loop : " + stack.pop());
        }
    }

    /**
     * 数组实现反向打印链表
     *
     * @param node 链表头节点
     */
    private static void printLinkByArray(Node node) {
        int size = 0;
        Node tmp = node;
        while (tmp != null) {
            size++;
            tmp = tmp.next;
        }

        Node[] nodes = new Node[size];

        for (int i = 0; i < size; i++) {
            nodes[i] = node;
            node = node.next;
        }

        for (int i = size - 1; i >= 0; i--) {
            System.out.println("arr : " + nodes[i].val);
        }

    }

}

测试用例
        int size = 5;
        Node head = genLink(size);
        printLinkByLoop(head);
//        printLinkByRecursion(head);
//        printLinkByArray(head);

        size = 0;
        head = genLink(size);
        printLinkByLoop(head);
//        printLinkByRecursion(head);
//        printLinkByArray(head);

        printLinkByLoop(null);
//        printLinkByRecursion(null);
//        printLinkByArray(null);
测试结果
loop : 4
loop : 3
loop : 2
loop : 1
loop : 0
link is null
link is null
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值