打印节点(链表或者二叉树)工具

目录

1. 背景与目的:方便排查问题

2. 效果 

3. 工具类代码

3.1 链表数据结构定义

3.2 二叉树数据结构定义 

3.3 工具类代码

3.3.1 注意事项

4. 使用示例 

4.1 题目:leetcode第700题:二叉搜索树中的搜索

4.1.1 题目介绍

 4.1.2 代码

4.1.3 控制台 

4.2 题目:leetcode第148题:排序链表

4.2.1 题目介绍

4.2.2 代码

4.2.3 控制台

1. 背景与目的:方便排查问题

在leetcode刷题中,当出现链表题或者二叉树的题目的时候

给出的输入和输出示例通常是数组形式, 如图所示:

这样很不清晰,不知道自己返回的结构到底是怎么样的,如果能够打印出合适的格式,会方便我们排查问题。

leetcode给出的输入与输出示例都不太直观:

如下先给出两种数据结构题型的示例:

链表结构:

 二叉树结构:

2. 效果 

我们首先给出工具的效果:

给出的示例比较简单:

下文给出更详细的示例。

3. 工具类代码

首先创建一个包: definition, 用于定义链表节点和树节点:

如何定义都和leetcode上面保持一致,可以放心导入。

3.1 链表数据结构定义

package definition;

/**
 * @author: Rehse
 * @description: 定义链表结构
 * @time: 2025/7/27 12:08
 */
public class ListNode {
    public int val;
    public ListNode next;

    public ListNode() {
    }

    public ListNode(int val) {
        this.val = val;
    }

    public ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }

}

3.2 二叉树数据结构定义 

package definition;

/**
 * @author: Rehse
 * @description: 定义二叉树结构
 * @time: 2025/7/27 12:08
 */
public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;

    TreeNode() {
    }

    public TreeNode(int val) {
        this.val = val;
    }

    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

3.3 工具类代码

这个工具类定义在预先定义的工具类包utils下面,不需要的话就删掉,或者改喜欢的名字。

工具类下面有main函数, 可以打印出示例康康。

package utils;
// 导入链表和二叉树数据结构类

import definition.ListNode;
import definition.TreeNode;

import java.util.*;

/**
 * @author: Rehse
 * @description: 打印工具类
 * @time: 2025/7/27 12:10
 */
public class PrintUtils {
    /**
     * 根据传入数组参数 构建链表
     */
    public ListNode listNode;
    public TreeNode treeNode;

    /**
     * 有时候 leetcode给出的示例的某个null值, 这里用Integer的最小值来代替null节点
     */
    static final int NULL = Integer.MIN_VALUE;

    /**
     * 节点类型: 0->链表, 1->树
     */
    public static int type;
    /**
     * 节点类型: 链表
     */
    public static final int NODE_TYPE_LINKED = 0;
    /**
     * 节点类型: 树
     */
    public static final int NODE_TYPE_TREE = 1;

    /**
     * 空节点用字符串"null"表示
     */
    private static final String NULL_SYMBOL = "null";

    /**
     * @return ListNode
     * @author: Rehse
     * @description: 返回链表结构
     * @time: 2025/7/27 11:50
     */
    public ListNode getListNode() {
        return this.listNode;
    }

    /**
     * @return ListNode
     * @author: Rehse
     * @description: 返回二叉树结构
     * @time: 2025/7/27 11:50
     */
    public TreeNode getTreeNode() {
        return this.treeNode;
    }

    /**
     * @return void
     * @author: Rehse
     * @description: 构造函数: 根据传入的数组和类型(0: 链表, 还是1: 树)构造工具类
     * @param[1] nums
     * @param[2] type
     * @time: 2025/7/27 10:25
     */
    public PrintUtils(int[] nums, int type) {
        this.type = type;
        if (type == NODE_TYPE_LINKED) {
            listNode = new ListNode(nums[0]);
            ListNode cur = listNode;
            for (int i = 1; i < nums.length; i++) {
                cur.next = new ListNode(nums[i]);
                cur = cur.next;
            }
            cur.next = null;
        } else if (type == NODE_TYPE_TREE) {
            Queue<TreeNode> queue = new ArrayDeque<>();
            treeNode = new TreeNode(nums[0]);
            queue.offer(treeNode);
            for (int index = 1; index < nums.length; index++) {
                TreeNode node = queue.poll();
                if (index < nums.length && nums[index] != NULL) {
                    node.left = new TreeNode(nums[index]);
                    queue.offer(node.left);
                }
                index++;
                // 右子节点
                if (index < nums.length && nums[index] != NULL) {
                    node.right = new TreeNode(nums[index]);
                    queue.offer(node.right);
                }
            }
        } else {
            throw new IllegalArgumentException("非法的type参数,必须是0(链表)或1(树)");
        }
    }


    /**
     * @return void
     * @author: Rehse
     * @description: 自动根据类型打印链表或者树
     * @time: 2025/7/27 10:16
     */
    public void print() {
        if (type == NODE_TYPE_LINKED) {
            printListNode(listNode);
        } else {
            printTree(treeNode);
        }
    }

    /**
     * @return void
     * @author: Rehse
     * @description: 打印链表
     * @param[1] head
     * @time: 2025/7/27 10:16
     */
    public static void printListNode(ListNode head) {
        System.out.println("打印链表:");
        ListNode cur = head;
        while (cur != null) {
            System.out.print(cur.val + "->");
            cur = cur.next;
        }
        System.out.print("null\n");
        System.out.println("-----------------------------------------------------------------------------------------");
    }

    /**
     * @return void
     * @author: Rehse
     * @description: 打印树 分层地打印出来 可打印出空节点
     * @param[1] root
     * @time: 2025/7/27 10:16
     */
    public static void printTree(TreeNode root) {
        System.out.println("打印树:");
        if (root == null) {
            System.out.println("树为空");
            return;
        }
        int height = getHeight(root);
        int maxValLength = getMaxValueLength(root);
        int spaceWidth = maxValLength + 2; // 每个节点的显示宽度

        List<List<String>> levels = new ArrayList<>();
        buildLevels(root, height, maxValLength, levels);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < levels.size(); i++) {
            List<String> level = levels.get(i);
            int leadingSpace = (int) (spaceWidth * Math.pow(2, height - i - 1) - spaceWidth / 2);
            sb.append(" ".repeat(leadingSpace));

            for (String node : level) {
                sb.append(node).append(" ".repeat(spaceWidth * (int) Math.pow(2, height - i) - spaceWidth));
            }
            sb.append("\n");
        }
        System.out.print(sb);
        System.out.println("-----------------------------------------------------------------------------------------");
    }

    /**
     * @return void
     * @author: Rehse
     * @description: 构建树层
     * @param[1] node
     * @param[2] height
     * @param[3] maxLen
     * @param[4] levels
     * @time: 2025/7/27 11:19
     */

    private static void buildLevels(TreeNode node, int height, int maxLen, List<List<String>> levels) {
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(node);
        for (int i = 0; i < height; i++) {
            int levelSize = queue.size();
            List<String> currentLevel = new ArrayList<>();

            for (int j = 0; j < levelSize; j++) {
                TreeNode curr = queue.poll();
                if (curr == null) {
                    currentLevel.add(String.format("%" + maxLen + "s", NULL_SYMBOL));
                    queue.offer(null);
                    queue.offer(null);
                } else {
                    currentLevel.add(String.format("%" + maxLen + "d", curr.val));
                    queue.offer(curr.left);
                    queue.offer(curr.right);
                }
            }
            levels.add(currentLevel);
        }
    }

    /**
     * @return int
     * @author: Rehse
     * @description: 获取树的高度
     * @param[1] root
     * @time: 2025/7/27 11:19
     */
    private static int getHeight(TreeNode root) {
        if (root == null) return 0;
        return 1 + Math.max(getHeight(root.left), getHeight(root.right));
    }

    /**
     * @return int
     * @author: Rehse
     * @description: 获取最大数值的长度
     * @param[1] root
     * @time: 2025/7/27 11:19
     */
    private static int getMaxValueLength(TreeNode root) {
        if (root == null) return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int maxLength = 0;

        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if (node != null) {
                // 计算当前节点值的字符串长度(考虑负数)
                int currentLength = String.valueOf(node.val).length();
                maxLength = Math.max(maxLength, currentLength);

                queue.offer(node.left);
                queue.offer(node.right);
            }
        }
        return maxLength;
    }

    /**
     * @return void
     * @author: Rehse
     * @description: 获取节点并打印
     * @time: 2025/7/27 12:39
     */
    public void getAndPrint() {
        if (type == NODE_TYPE_LINKED) {
            ListNode listNode = this.getListNode();
        } else {
            TreeNode treeNode = this.getTreeNode();
        }
        this.print();
    }

    /**
     * @author: Rehse
     * @description: 使用示例
     * @param[1] args
     * @time: 2025/7/27 10:14
     */
    public static void main(String[] args) {
        PrintUtils utils1 = new PrintUtils(new int[]{1, 2, 3, 4, 5}, 0);
        utils1.print();
        PrintUtils utils2 = new PrintUtils(new int[]{1, 2, 3, 4, 5}, 1);
        utils2.print();
        PrintUtils utils3 = new PrintUtils(new int[]{1, 2, 3, 4, NULL, 5}, 1);
        utils3.print();
        PrintUtils utils4 = new PrintUtils(new int[]{1, 2, 3, 4, NULL, 5, 6, 7, 8, 9}, 1);
        utils4.print();
        PrintUtils utils5 = new PrintUtils(new int[]{1, 2, 3, 4, NULL, 5, 6, 7, 8, 9}, 2);
        utils5.print();
    }
}

3.3.1 注意事项

如上代码块中的main函数,

先通过一个数组以及一个type参数(0代表链表,1代表二叉树)构造工具类。

然后调用工具类对象的print()方法即可

注:在leetcode有些二叉树的题在给出的输入示例总是会出现空节点, 用null来表示的

在工具类代码中用一个静态常量NULL来作为替代,

这个NULL值为Integer.MIN_VALUE

在构造工具类前可以预先定义一下:

static final int NULL = Integer.MIN_VALUE;

在控制台中的效果如下:

type只能是0(链表)或者1(二叉树), 否则抛出异常

4. 使用示例 

我在做题的时候一般是这样用的:

4.1 题目:leetcode第700题:二叉搜索树中的搜索

4.1.1 题目介绍

给定二叉搜索树(BST)的根节点 root 和一个整数值 val

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。

示例 1:

输入:root = [4,2,7,1,3], val = 2
输出:[2,1,3]

 4.1.2 代码

main函数里面调用这道题中的函数的时候 先将函数返回类型前面加上static字段。

完整代码如下:

package leetcode.tree;

import definition.TreeNode;
import utils.PrintUtils;

/**
 * @author: Rehse
 * @description: 二叉搜索树中的搜索
 * @date: 2025/7/27
 */
public class Leetcode_700_SearchInABinarySearchTree {
    /**
     * @author: Rehse
     * @description: 递归
     * @param[1] root
     * @param[2] val
     * @return TreeNode
     * @time: 2025/7/27 12:17
     */
    public static TreeNode searchBST(TreeNode root, int val) {
        if (root == null) {
            return null;
        }
        if (val == root.val) {
            return root;
        }
        return searchBST(val < root.val ? root.left : root.right, val);
    }

    public static void main(String[] args) {
        // 1.可以根据数组构造工具类 第二个参数为1 代表这是树结构
        PrintUtils utils = new PrintUtils(new int[]{4, 2, 7, 1, 3}, 1);
        // 2.通过工具类返回这个二叉树的结构
        TreeNode root = utils.getTreeNode();
        // 3.通过工具类对象可以打印出来本题示例看看 这个print()则是根据节点类型type自动调用第5条的打印树的函数
        utils.print();
        // 第2步和第3步 可以只用下面这个函数 合并了两个操作 得到并打印
        // utils.getAndPrint();
        // 4.调用本题函数 返回一个结果树
        TreeNode resultTree = searchBST(root, 2);
        // 5.通过工具类的静态函数.打印树, 打印出这个结果树的结构
        PrintUtils.printTree(resultTree);
    }

}

4.1.3 控制台 

这道题有点简单,返回的结果子树也比较简单,读者可以用更复杂的题试试。

4.2 题目:leetcode第148题:排序链表

4.2.1 题目介绍

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

示例 :

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

    4.2.2 代码

    main函数里面调用这道题中的函数的时候 先将函数返回类型前面加上static字段。

    完整代码如下:

    package leetcode.linkedlist;
    
    import definition.ListNode;
    import utils.PrintUtils;
    
    /**
     * @author: Rehse
     * @description: 排序链表
     * @date: 2025/7/27
     */
    public class Leetcode_148_SortList {
        public static ListNode sortList(ListNode head) {
            return sortList(head, null);
        }
    
        public static ListNode sortList(ListNode head, ListNode tail) {
            if (head == null) {
                return head;
            }
            if (head.next == tail) {
                head.next = null;
                return head;
            }
            ListNode slow = head, fast = head;
            while (fast != tail) {
                slow = slow.next;
                fast = fast.next;
                if (fast != tail) {
                    fast = fast.next;
                }
            }
            ListNode mid = slow;
            ListNode list1 = sortList(head, mid);
            ListNode list2 = sortList(mid, tail);
            ListNode sorted = merge(list1, list2);
            return sorted;
        }
    
        public static ListNode merge(ListNode head1, ListNode head2) {
            ListNode dummyHead = new ListNode(0);
            ListNode temp = dummyHead, temp1 = head1, temp2 = head2;
            while (temp1 != null && temp2 != null) {
                if (temp1.val <= temp2.val) {
                    temp.next = temp1;
                    temp1 = temp1.next;
                } else {
                    temp.next = temp2;
                    temp2 = temp2.next;
                }
                temp = temp.next;
            }
            if (temp1 != null) {
                temp.next = temp1;
            } else if (temp2 != null) {
                temp.next = temp2;
            }
            return dummyHead.next;
        }
    
        public static void main(String[] args) {
            // 1.可以根据数组构造工具类 第二个参数为0 代表这是链表结构
            PrintUtils utils = new PrintUtils(new int[]{-1,5,3,4,0}, 0);
            // 2.通过工具类返回这个二叉树的结构
            ListNode head = utils.getListNode();
            // 3.通过工具类对象可以打印出来本题示例看看 这个print()则是根据节点类型type自动调用第5条的打印树的函数
            utils.print();
            // 第2步和第3步 可以只用下面这个函数 合并了两个操作 得到并打印
            // utils.getAndPrint();
            // 4.调用本题函数 返回一个链表
            ListNode result = sortList(head);
            // 5.通过工具类的静态函数.打印链表, 打印出这个结果链表的结构
            PrintUtils.printListNode(result);
        }
    }
    

    4.2.3 控制台

    屎山代码仅供参考,觉得我拉的屎有用的话,点个赞么么哒!

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值