【剑指offer刷题】JZ57:给定二叉树和某个结点,找到中序遍历顺序的下一个结点

本文详细介绍了如何在给定二叉树和特定结点的情况下,找到中序遍历顺序的下一个结点。文章分别讨论了暴力解法和找规律的方法,分析了不同情况下的解决方案,并提供了相应的代码实现。暴力解法通过中序遍历整棵树来找到目标结点,时间复杂度和空间复杂度均为O(n)。而找规律的方法只需追溯,时间复杂度仍为O(n),但空间复杂度降低为O(1)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处:https://blog.youkuaiyun.com/loiter2/article/details/107448160

【剑指offer刷题】JZ57:给定二叉树和某个结点,找到中序遍历顺序的下一个结点


该文章只是用来记录一下刷题过程中不会的点,但是自己太菜,做不出来的部分,有参考牛客网剑指offer部分的官方解答和各种大神的解答。本文的记录和解答用的Java语言。

1、题目分析

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

//二叉树结点,其中next是指父亲结点
public class TreeLinkNode {
   
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
   
        this.val = val;
    }
}

上述代码是题目给出的二叉树结点
很有趣的是,牛客网官方解答,直接提出,这道题作为笔试题和面试题的两种解答方式。

  • 作为笔试题,自然是求思路清晰、解答简单,追求accept,自然可能不是最优解,时间复杂度和空间复杂度可以不是最好的。
  • 作为面试题,面试官自然想听到的就是最优解

因此本文也把两种方式的解答都记录下来

1.1 暴力解法思路

最直接暴力的方法,要求某个结点中序遍历顺序的下一个结点,那直接得到整棵二叉树的中序遍历结果,然后在中序遍历结果中,找到要求的结点的下一个结点即可
具体思路为:

  • 基于给出的结点,不断找父结点,直到找到整棵二叉树的根结点
  • 基于根结点,中序遍历整棵二叉树,将遍历结果存入数组中
  • 从数组中找到需要的目标结点

这种做法的思路还是很明确的,也比较容易想到,时间复杂度也没有特别高,找到父结点为O(n),遍历二叉树为O(n),找到目标节点为O(n),总体为3*O(n);空间复杂度为存储遍历结果O(n)。
时间复杂度:O(n);
空间复杂度:O(n);

1.2 类似找规律

据说面试时,你能给面试官图解解释,面试官会比较高兴。本题没有啥特别的算法套路可以用,因此就自己画个二叉树找找规律呗,分析分析总共有几种情况,分情况给出结果即可。
二叉树中序遍历示例
上图给出了一个简单的二叉树,数字即为中序遍历的顺序
下面就分析每一个结点与下一个结点的关系:

  • 1–>2:1没有子结点,下一结点是其父结点,并且1是其父结点的左子结点;
  • 2–>3:2有左右两个子结点,下一结点是其右子结点;
  • 3–>4:3没有子结点,下一结点是父结点的父结点(爷爷结点),并且其父结点是爷爷结点的左子结点;
  • 4–>5:4有左右两个子结点,下一结点是右子
在C语言中,构建一棵线索二叉树并进行中序遍历的过程可以分为以下几个步骤: 1. **构造线索二叉树**[^1]: 线索二叉树通过在节点结构中添加额外指针(通常称为前驱后继指针),使得遍历更容易。这里以二叉搜索树为例,假设有一个`struct TreeNode`定义如下: ```c typedef struct TreeNode { int val; struct TreeNode* left; struct TreeNode* right; struct TreeNode* prev; struct TreeNode* next; // 前驱后继指针 } TreeNode; ``` 2. **插入结点**: 当插入新结点时,不仅更新常规的左右子节点,还要设置线索,保证线索的正确性。 3. **中序遍历**: - 中序遍历是按照"左->根->右"的顺序访问节点,对于线索二叉树,可以通过当前节点的`prev``next`指针来方便地找到左孩子右孩子。 ```c void inorderTraversal(TreeNode* root) { if (root == NULL) return; inorderTraversal(root->left); printf("%d ", root->val); // 输出结点值 inorderTraversal(root->right); } ``` 完整的C语言代码示例: ```c // 创建新节点 TreeNode* createNode(int val) { TreeNode* node = malloc(sizeof(TreeNode)); node->val = val; node->left = NULL; node->right = NULL; node->prev = NULL; node->next = NULL; return node; } // 插入结点到线索二叉树 void insertIntoTree(TreeNode** root, int val) { TreeNode* newNode = createNode(val); if (*root == NULL) { *root = newNode; newNode->prev = newNode->next = NULL; } else if (val < (*root)->val) { newNode->prev = (*root)->prev; newNode->next = (*root); if ((*root)->prev != NULL) (*root)->prev->next = newNode; (*root)->prev = newNode; } else { newNode->prev = (*root); newNode->next = (*root)->right; if ((*root)->right != NULL) (*root)->right->prev = newNode; (*root)->right = newNode; } } // 中序遍历线索二叉树 void inorderTraversal(TreeNode* root) { inorderTraversal(root->left); printf("%d ", root->val); // 输出结点值 inorderTraversal(root->right); } ``` 运行`inorderTraversal(*root)`即可完成中序遍历并打印二叉树的每个结点值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值