数据结构与算法-求二叉树某个节点的前驱节点与后继节点

数据结构与算法学习笔记(三)单向链表 一. 几个概念 0x01 链表   链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的。链表是以结点的方式存储的,是链式存储。结点可以在运行时动态生成。链表是有序的列表,但其在内存中的存储是非连续、非顺序的。 0x02 结点   在链表数据结构中,我们把一个数据元素的存储映像称为结点(Node)。而一个结点包含存储数据元素的两部分信息:数据域(Data)和指针域(Next)。 0x03 数据域、指针域 数据域:存储数据元素信息的域; 指针域:存储直接后继位置 阅读详情

二叉树的后继节点

什么是二叉树的后继节点呢? 就是这颗二叉树中序遍历顺序中,当前节点的下一个节点称为这个当前节点的后继节点。

与之相反的是前驱节点,前驱节点,就是二叉树中序遍历的顺序中,当前节点的上一个节点。

如下图:

 

 

那么下面我们来看一道具体的面试题 : 


【题目】 现在有一种新的二叉树节点类型如下,在此节点类型的二叉树中找到一个节点的后继节点

class Node(object):
    """含有父节点属性的节点类"""
    def __init__(self, elem, lchild=None, rchild=None, parent=None):
        self.elem = elem
        self.lchild = lchild
        self.rchild = rchild
        self.parent = parent
    

注:该结构比普通二叉树节点结构多了一个指向父节点的parent指针。假设有一 棵Node类型的节点组成的二叉树,树中每个节点的parent指针都正确地指向 自己的父节点,头节点的parent指向None

 

下面我们来看看这题的思路是什么?

由题目可知,我们的节点类型很特殊,再结合中序遍历的特点是(左,中,右)那么找一个节点的后继节点会有如下两种情况:

情况1:当前节点有右子树

 那么针对这个情况,结合我们的中序遍历特点,总结出一个规律 : 如果当前节点有右子树,那么其后继节点为其右子树的最左节点

情况2:当前节点没有有右子树  

针对这种情况,那么我们就要用到题目给的条件了,每个节点都有个父节点的属性,我们能通过子节点找到父节点

那么其规律是:如果当前节点没有右子树,定义第一个指针指向当前节点,然后找其父节点,用第二个指针指向它,如果指针1所指的节点是指针2的左孩子,那该指针2节点就是其后继节点,如果不是其左孩子,那么指针1指向其父节点,原来的指针2也指向他的父节点(也就是指针1和指针2都往上调一格)直到指针1所指的节点是指针2节点的左孩子,那么指针2所指的节点就是其后继节点。

所以这就是上面的两种情况,下面贴上完整的代码示例

class Node(object):
    """含有父节点属性的节点类"""
    def __init__(self, elem, lchild=None, rchild=None, parent=None):
        self.elem = elem
        self.lchild = lchild
        self.rchild = rchild
        self.parent = parent

class Tree(object):
    """二叉树"""
    def __init__(self):
        self.root = None

    def add(self, item):
        node = Node(item)
        if self.root is None:
            self.root = node
            return
        queue = [self.root] # 定义一个队列
        while queue:
            cur_node = queue.pop(0)

            if cur_node.lchild is None:
                node.parent = cur_node  # 设置当前节点的父节点是队列里弹出的节点
                cur_node.lchild = node
                return
            else:
                queue.append(cur_node.lchild)
            if cur_node.rchild is None:
                node.parent = cur_node  # 设置当前节点的父节点是队列里弹出的节点
                cur_node.rchild = node
                return
            else:
                queue.append(cur_node.rchild)

    def inorder(self, node):
        """中序遍历"""
        if node is None:
            return
        self.inorder(node.lchild)
        print(node.elem, end=" ")
        self.inorder(node.rchild)

    def getSuccessorNode(self, node):
        """获取节点的后继节点"""
        if node is None:
            return
        if node.rchild is not None: # 右子树不为空
            return  self.getLeftMost(node.rchild)
        else: # 右子树为空
            node_parent = node.parent
            while node_parent is not  None and node_parent.lchild != node: # 当前节点不是父节点的左孩子时,循环 ,当父节点为空时 直接返回空,说明没有后继节点
                    node = node_parent
                    node_parent = node.parent
            return node_parent

    def getLeftMost(self, node):
        if node is None:
            return  None
        while node.lchild is not None:
            node = node.lchild  # 找到最左节点
        return node


if __name__ == '__main__':
    tree = Tree()
    tree.add(1)
    tree.add(2)
    tree.add(3)
    tree.add(4)
    tree.add(5)
    tree.add(6)
    tree.add(7)
    tree.add(8)
    tree.add(9)
    tree.add(10)
    tree.add(11)
    print("中序遍历的结果:")
    tree.inorder(tree.root) # 递归方式打印: 8 4 9 2 10 5 11 1 6 3 7
    print(" ")

    print("节点2的值是:"+ str(tree.root.lchild.elem))
    # 查找节点2 的后继节点
    # tree.root.lchild ==> 2
    node = tree.getSuccessorNode(tree.root.lchild)
    print("节点2的后继节点为:"+ str(node.elem))

    print(" ")


    print("节点8的值是:" + str(tree.root.lchild.lchild.lchild.elem))
    # 查找节点8 的后继节点
    # tree.root.lchild.lchild.lchild ==> 8
    node = tree.getSuccessorNode(tree.root.lchild.lchild.lchild)
    print("节点8的后继节点为:" + str(node.elem))

    print(" ")

    print("节点9的值是:" + str(tree.root.lchild.lchild.rchild.elem))
    # 查找节点9 的后继节点
    # tree.root.lchild.lchild.rchild ==> 9
    node = tree.getSuccessorNode(tree.root.lchild.lchild.rchild)
    print("节点9的后继节点为:" + str(node.elem))

    print(" ")

    print("节点7的值是:" + str(tree.root.rchild.rchild.elem))
    # 查找节点7 的后继节点
    # tree.root.rchild.rchild ==> 7
    node = tree.getSuccessorNode(tree.root.rchild.rchild)
    if node is not None:
        print("节点7的后继节点为:" + str(node.elem))
    else:
        print("节点7的后继节点为:None")

结果如下:

 

 

新增:求前驱节点

后增加上与求后继节点同理的求前驱节点的代码

class Node(object):
    """含有父节点属性的节点类"""
    def __init__(self, elem, lchild=None, rchild=None, parent=None):
        self.elem = elem
        self.lchild = lchild
        self.rchild = rchild
        self.parent = parent

class Tree(object):
    """二叉树"""
    def __init__(self):
        self.root = None

    def add(self, item):
        node = Node(item)
        if self.root is None:
            self.root = node
            return
        queue = [self.root] # 定义一个队列
        while queue:
            cur_node = queue.pop(0)

            if cur_node.lchild is None:
                node.parent = cur_node  # 设置当前节点的父节点是队列里弹出的节点
                cur_node.lchild = node
                return
            else:
                queue.append(cur_node.lchild)
            if cur_node.rchild is None:
                node.parent = cur_node  # 设置当前节点的父节点是队列里弹出的节点
                cur_node.rchild = node
                return
            else:
                queue.append(cur_node.rchild)

    def inorder(self, node):
        """中序遍历"""
        if node is None:
            return
        self.inorder(node.lchild)
        print(node.elem, end=" ")
        self.inorder(node.rchild)

    def getPrecursorNode(self,node):
        """获取节点的前驱节点"""
        if node is None:
            return
        if node.lchild is not None: # 左子树不为空
           return self.getRightMost(node.lchild)
        else:
            node_parent = node.parent
            while node_parent is not None and node_parent.rchild != node:
                # 当前节点是父节点的右孩子时停止循环,父节点为None时,停止循环
                    node = node_parent
                    node_parent = node.parent
            return node_parent

    def getRightMost(self, node):
        if node is None:
            return None
        while node.rchild is not None:
            node = node.rchild  # 找到最右节点
        return node

if __name__ == '__main__':
    tree = Tree()
    tree.add(1)
    tree.add(2)
    tree.add(3)
    tree.add(4)
    tree.add(5)
    tree.add(6)
    tree.add(7)
    tree.add(8)
    tree.add(9)
    tree.add(10)
    tree.add(11)
    print("中序遍历的结果:")
    tree.inorder(tree.root) # 递归方式打印: 8 4 9 2 10 5 11 1 6 3 7
    print(" ")

    print("节点2的值是:" + str(tree.root.lchild.elem))
    # 查找节点2 的后继节点
    #tree.root.lchild ==> 2
    node = tree.getPrecursorNode(tree.root.lchild)
    print("节点2的前驱节点为:" + str(node.elem))
    print(" ")

    print("节点8的值是:" + str(tree.root.lchild.lchild.lchild.elem))
    # 查找节点8 的前驱节点
    # tree.root.lchild.lchild.lchild ==> 8
    node = tree.getPrecursorNode(tree.root.lchild.lchild.lchild)
    if node is not None:
        print("节点8的前驱节点为:" + str(node.elem))
    else:
        print("节点8的前驱节点为None")
    print(" ")

    print("节点9的值是:" + str(tree.root.lchild.lchild.rchild.elem))
    # 查找节点9 的前驱节点
    # tree.root.lchild.lchild.rchild ==> 9
    node = tree.getPrecursorNode(tree.root.lchild.lchild.rchild)
    print("节点9的前驱节点为:" + str(node.elem))
    print(" ")

    print("节点10的值是:" + str(tree.root.lchild.rchild.lchild.elem))
    # 查找节点10 的前驱节点
    # tree.root.lchild.rchild.lchild ==> 10
    node = tree.getPrecursorNode(tree.root.lchild.rchild.lchild)
    print("节点10的前驱节点为:" + str(node.elem))

结果如下:

综上,就是二叉树求前驱和后继节点的全部内容啦,如有不正确的地方,还望加以评论指正。

 

 

数据结构笔记——线索二叉树找前驱/后继 目录 一、中序线索二叉树找中序后继 二、中序线索二叉树中找中序前驱 三、先序线索二叉树找先序后继 四、先序线索二叉树找先序前驱 五、后序线索二叉树找后序前驱 六、后序线索二叉树找后序后继 七、总结 一、中序线索二叉树找中序后继 在中序线索二叉树中找到指定结点*p的中序后继next ①若p->rtag == 1,则next = p->rchild ②若p->rtag == 0 //找到以P为跟的子树中,第一个被中序遍历的结点 ThreadNode *Fi 阅读详情

相关推荐

求二叉搜索树任一节点的前驱后继节点

二叉搜索树节点的前驱后继节点之前写过文章介绍了二叉搜索树以及其上的基本操作,但不包括求节点的前驱结点和后继节点。这是一个很老的问题了,首先看下某节点前驱和后继节点的定义。一个节点的 前驱结点:节点val值小于该节点val值并且值最大的节点 后继节点:节点val值大于该节点val值并且值最小的节点算法导论中给出了详细的求前驱结点和后继节点的算法,但是其中的节点数据结构包含了指向父亲节点的指针,但是

等价交换 1万+

二叉树前驱节点与后继节点

前驱节点:对一棵二叉树进行中序遍历,遍历后的顺序,当前节点的前一个节点为该节点的前驱节点; 后继节点:对一棵二叉树进行中序遍历,遍历后的顺序,当前节点的后一个节点为该节点的后继节点; 例如一颗完全二叉树(1,2,3,4,5,6,7),按照中序遍历后的顺序为:(4,2,5,1,6,3,7),1节点的前驱节点为:5,后继节点为6. 图1:二叉树 若每次遍历二叉树进行查找前驱节点或后继节点,复杂度太高...

hpcds的博客 3万+

左神课堂之寻找二叉树的前驱节点和后继节点

前驱节点:二叉树中序遍历完成后和这个节点相邻的前面的节点为该节点的前驱节点 后继节点:二叉树中序遍历完成后和这个节点相邻的后面的节点为该节点的后继节点 中序遍历顺序:8->4->9->2->10->5->1->6->3->7 4号节点的前驱节点为8号节点,后继节点为9号节点。 正常的二叉树的数据结构: struct node {...

qq_40938077的博客 4144

求二叉树中节点x的后继节点和前驱结点

1)画个图摸清楚,x节点的后继节点,x节点的前驱节点,它的本质是哪一个?这和左头右的中序遍历息息相关。 2)搞懂了核心思想,找前驱节点和后继节点并不难,分清楚x有没有左右树,这样就很快确定该怎么求。 3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。

weixin_46838716的博客 2202

《数据结构》—— 遍历线索二叉树

中、先、后序线索二叉树的遍历查找,代码实现遍历中序线索二叉树

博樽 7346

[数据结构]二叉搜索树的中序前驱和后继的定义及编程方法

前驱和后继的应用很多,比如重载‘++’和‘--’时节点的跳跃,删除节点时需要找到前驱或后继作为顶替。本笔记主要记录了二叉搜索树的前驱的定义、位置和编程方法,对于后继其实只是一种‘反向操作’,写出了前驱后其实可以通过仿写简单得到后继的程序。

weixin_43977587的博客 7685

数据结构(离散 | 链式存储--链表)

定义 n个结点离散分配,彼此通过指针相连,每个结点只有一个前驱结点,每个结点只有一个后继结点,首结点没有前驱结点,尾结点没有后继结点。 专业术语: (1)首结点:第一个有效结点 (2)尾结点:最后一个有效结点 (3)头结点:头结点的数据类型和首结点的类型一样;第一个有效结点之前的结点;头结点并不存放有效数据;加头结点的目的主要是为了方便对链表的操作 (4)头指针:指向头结点的指针变量 (5)尾指针...

水里的鱼 1502

线索二叉树寻找前驱和后继

/左孩子的最后一个节点为前驱。if (start <= end && temp->lchild == NULL)//创建左孩子。if (start <= end && temp->rchild == NULL)//创建右孩子。if (Public->lchild->ltag == 1)//证明左孩子为叶子结点。if (T->rchild->rtag == 1)//证明右孩子是叶子结点。

2301_76768601的博客 953

在线索二叉树中找前驱后继

在线索二叉树中,每个节点除了左右子节点指针外,还增加了两个标记位:ltag和rtag。其中,ltag表示左子节点是否为前驱,rtag表示右子节点是否为后继。通过这两个标记位,我们可以方便地找到任意节点的前驱和后继节点。

m0_64055811的博客 3188

线索化二叉树-实现中序遍历和查找前驱后继节点

一、线索化二叉树简介 1.线索二叉树:对于n个节点的二叉树,在二叉链存储结构中有n+1个空链域,利用这些空链域存放在某种遍历次序下该节点的前驱节点和后继节点的指针,这些指针称为线索,加上线索的二叉树称为线索二叉树 2.线索二叉树分类:这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。 3.前驱结点:一个结点的前一个结点 4. 后继结点:一个结点的后一个结点 二、中序线索化二叉树逻辑结构示意图 说明:当线

Passer-Go 1535

数据结构——十七、线索二叉树找前驱与后继(王道408)

摘要:本文详细介绍了中序和先序线索二叉树中查找指定节点的前驱和后继的方法。对于中序线索二叉树,当rtag=1时后继为右孩子,rtag=0时需找到右子树最左下节点;前驱同理通过ltag判断。先序线索二叉树中,后继根据左右孩子存在情况决定,前驱则需通过三叉链表或逆向遍历实现。文章提供了各场景下的算法思路和完整代码实现,包括非递归的中序/先序遍历方法。

2301_80201235的博客 1376

二叉树/堆

数据结构--二叉树/堆 二叉树 实现一个二叉查找树,并且支持插入、删除、查找操作 实现查找二叉查找树中某个节点的后继、前驱节点 实现二叉树前、中、后序以及按层遍历 并完成leetcode上的验证二叉搜索树(98)及二叉树 层次遍历(102,107)!(选做)(保留往期第四天任务)注:这个跟下面的习题有重复 堆 实现一个小顶堆、大顶堆、优先级队列 实现堆排序 利用优先级队列合并 K 个有序数组 ...

qq_36047533的博客 653

转子动力学 | 临界速度与稳定性分析

本文深入探讨了转子动力学中的核心问题——临界速度与稳定性分析。临界速度是旋转机械发生共振的危险转速,通过模态分析和坎贝尔图可进行预测。文章还剖析了油膜涡动等稳定性问题,并结合ANSYS仿真案例,详细阐述了从建模、分析到设计优化的完整工程实践流程,为旋转机械的可靠设计与安全运行提供关键指导。

weixin_29313239的博客 518

中序线索二叉树的遍历、寻找结点前驱和后继

中序线索二叉树的遍历 笔者在学习过程中,借鉴博客: https://blog.youkuaiyun.com/One_castle/article/details/102968998 遍历 观察图中箭头指向。因为右孩子有可能指向后继,而且即使右孩子不是后继,我们也可以先去到右孩子的最左边,这样后继就是这个结点。所以遍历的核心思想是:先找到最左边的节点,然后判断其右子树是否为线索,如果是线索,那么就遍历后继结点,如果右子树是右孩子,那么就进入到右孩子的最左边的节点,进行同样的判断,知道遍历完了整棵树为止。 void tr

Daphne_Liu的博客 8797

keil+Jlink GD32调试记录

Jlink+keil,GD32调试记录,踩坑及解决,持续更新。

SUN_BW的博客 2956

(8)机器人动力学

机器人是一个具有多输入多输出的复杂动力学系统,存在严重的非线性,需要非常系统的方法对机器人进行动力学研究。常用的机器人动力学建模方法有:Lagrange(拉格朗日)动力学方法、Newton-Euler(牛顿-欧拉)动力学方法、Gauss(高斯)动力学方法、Kane(凯恩)动力学方法等。机器人动力学研究的是机器人的运动和作用力之间的关系。机器人的动力学问题包括动力学正问题和动力学逆问题。动力学正问题是对于给定的关节驱动力......

rouyu308的博客 9500

数据结构与算法---树---二叉树的前驱节点、后继节点

前驱节点 何为前驱节点? 前驱节点,指的是以中序遍历,遍历二叉树,某一个节点的前一个节点,被称为其前驱节点。 也就是,某一节点的左子树的右子节点的右子节点的右节点。。。 特殊情况,如果是二叉搜索树,则前驱节点是按从小到大的顺序,比其前面一个节点。 思路: 如果node.left != null; 则循环,node.left.right.right.right…直至为空,则找到了其前驱节点。 如果node.left == null; 如果node.parent == null;则没有前驱 如果node.par

IOSSHAN的博客 4500

微信4.1.5.16升级后,你的自动化脚本失灵了?手把手教你用C#让UI树“复活”

微信4.1.5.16版本更新导致自动化脚本失效?本文深入解析微信UI树隐藏的原因,并提供C#实战解决方案,通过UIAutomation技术恢复UI树结构,帮助开发者重新实现自动化操作。涵盖技术原理、代码实现及优化策略,适合RPA开发者和自动化脚本编写者参考。

weixin_30879169的博客 519

分析线索二叉树的前驱、后继求法

图1 如图可以得到该二叉树的 先序:1 2 4 5 7 8 10 3 6 9 中序:4 2 7 5 10 8 1 3 9 6 后序:4 7 10 8 5 2 9 6 3 1   给出该线索二叉树的结构体: typedefint ElemType;   // 线索二叉树结构体 typedefstruct Clue_binary_tree_n

Coding_Life 8684

【S32K3 MCAL配置】-3.4-CANFD配置-接收特定的“经典CAN/CANFD标准帧”和“经典CAN/CANFD扩展帧”(基于MCAL+FreeRTOS)

【S32K3 MCAL配置】-3.4-CANFD配置-接收特定的“经典CAN/CANFD标准帧”和“经典CAN/CANFD扩展帧”(基于MCAL+FreeRTOS)

「汽车电子助手」的博客 696

CKA-题库-简洁参考答案-反复练习20遍-必过!!!

新版CKA考试已于2020年9月1日正式上线! 考试模式:线上考试 考试时间:2小时 认证有效期:3年 软件版本:Kubernetes v1.19 重考政策:可接受1次重考 经验水平:中級 题目数量:17题 题库量小:随机的题目重复率极高 考试时可打开两个浏览器Tab,一个是考试窗口,一个用来查阅官方文档](https://kubernetes.io/docs/) 01 Task - 英文 Create a new ClusterRole named deployment-clusterrole tha.

随笔记录-分享&记忆 7318

中序线索二叉树(构建,遍历和找前驱后继节点)附c++详细解释代码!

在二叉树的结点上加上线索的二叉树称为线索二叉树,对二叉树以某种遍历方式(如先序、中序、后序或层次等)进行遍历,使其变为线索二叉树的过程称为对二叉树进行线索化 线索化二叉树的本质,实际上是对原始二叉树中的指向为空(NULL)的指针域进行利用,我们让其指向为NULL的指针域指向前驱(左孩子)或者是后继(右孩子),但是我们怎么来辨别是树节点还是指向其前驱还是后继呢? 核心思想: 我们为每一个树节点增加两...

One_castle的博客 5524

【CASS精品教程】006:CASS7.1 道路设计参数文件打开无响应,提示roadpara解决办法,权威解决办法汇总

在用CASS7.1 软件进行断面法土方量计算,在生成断面图后,需要进行道路设计参数文件的设计,打开断面设计参数文件的时候,无响应,提示roadpara,如下所示: 道路设计参数文件 解决办法有三种 第一种方法:Win+R (1)64位系统:输入regsvr32 C:\Windows\SysWOW64\CellCtrl5.ocx,回车 (2)32位系统输入regsvr32 C:...

智慧空间实验室 1万+

数据结构:线索二叉树怎么找到前驱和后继,如何遍历输出?

上一篇博客介绍了线索二叉树的构造,以及简单的递归输出方法 https://blog.youkuaiyun.com/hpu2022/article/details/107234190 阅读本文可以先大致了解一下上一篇文章 线索二叉树定义 typedef struct ThreadNode{ ElemType data; // 前驱线索->左孩子、后继线索->右孩子 struct ThreadNode *lchild, *rchild; // tag为0表示孩子,

成龙大侠的博客 1973

模型实战(16)之StrongSort (OSNET)配合YOLOv5、v7、v8 实现多目标跟踪详解

StrongSort (OSNET)配合YOLOv5、v7、v8 实现多目标跟踪详解

yohnyang的博客 1771

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

二叉搜索树的前驱和后继

前言推出一个新系列,《看图轻松理解数据结构和算法》,主要使用图片来描述常见的数据结构和算法,轻松阅读并理解掌握。本系列包括各种堆、各种队列、各种列表、各种树、各种图、各种...

远洋号 2903

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

上一篇: 数据结构与算法-二叉树的遍历(含非递归)
下一篇: 01-复杂度分析
LELELED
博客等级 码龄9年 3粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值