从零开始构建二叉搜索树:父节点关系详解与可视化教程

C语言二叉树从入门到精通:数据结构、遍历与二叉搜索树实战 数据结构是计算机科学的核心基础,它定义了数据在计算机中的组织、存储和管理方式,直接影响算法的效率。其中,树形结构因其清晰的层次关系,在表达具有父子或从属关系的数据时尤为高效。二叉树作为树结构中最基本且重要的形式,其每个节点最多有两个子节点的特性,使其成为理解递归和分治思想的绝佳模型。从原理上看,二叉树通过指针链接实现动态存储,支持高效的深度优先(前序、中序、后序)和广度优先(层序)遍历,这些遍历方法是许多复杂算法的基础。其技术价值在于,基于二叉树规则衍生的二叉搜索树(BST),能将查找、插入、删除操作的平均 阅读详情

从零开始构建二叉搜索树:父节点关系详解与可视化教程

最近在辅导几位刚接触数据结构的朋友时,我发现很多人对二叉搜索树(BST)的“骨架”——也就是节点间的父子关系——理解得不够透彻。他们能背出“左小右大”的规则,但一旦要自己动手从一组数据构建出一棵树,并准确说出每个节点的父亲是谁,就常常卡壳。这其实非常正常,因为树结构是动态“生长”出来的,父亲节点的身份并非一成不变,而是随着新节点的插入,在一条从根出发的“寻家之路”的终点被确定的。理解这个过程,是真正掌握树形结构操作(查找、插入、删除)的基石。这篇文章,就是为你——无论是正在自学数据结构的学生,还是希望巩固基础的开发者——准备的一份深度实操指南。我们将抛开枯燥的理论罗列,用可视化的思路和一步步的代码构建,把“父亲节点”这个抽象概念,变成你屏幕上清晰可见的逻辑关系。

1. 二叉搜索树与父节点:动态关系的核心

在链表里,一个节点只有一个“前任”(前驱);在图里,关系更是错综复杂。而二叉搜索树提供了一种优雅的折中:每个节点最多有两个“后继”(孩子),但至关重要的,是它有且仅有一个“前任”,那就是它的父节点。这个父亲节点,是新节点融入这棵有序家族的“引路人”。

为什么父节点如此关键? 因为它定义了节点的“来路”。当我们谈论树的遍历、节点的删除、子树的旋转,甚至是内存管理中的引用计数,父节点信息都是不可或缺的导航图。想象一下,你是一个新来的数据(节点),要加入一个已经按某种规则(比如数值大小)组织好的社区(树)。你必须从社区的入口(根节点)开始,根据规则(比当前节点小就往左,大就往右)一路询问,直到找到一个空位安家。而最后接待你、并把空位指给你的那个“住户”,就是你的父节点。你的到来,也改变了它的状态——它多了一个孩子。

这个过程揭示了二叉搜索树插入操作的本质:一次从根节点开始的、基于比较的路径搜索,其终点就是新节点的父节点。理解这一点,就抓住了构建BST的核心。

注意:在标准的二叉搜索树定义中,节点通常包含指向左、右孩子以及父节点的指针。但在一些简化实现或特定问题中,父节点信息可能被隐式存储或需要额外计算。

为了更直观地对比不同数据结构中“关系”的差异,我们来看下面这个表格:

数据结构核心关系关系数量(每个元素)“父节点”的类比
数组索引顺序隐式,由索引定义无直接父节点概念
链表线性链接一个前驱,一个后继前驱节点可视为“父”
二叉搜索树层次与有序一个父节点,最多两个子节点明确的父节点指针或属性
图任意连接任意数量的邻接节点在生成树中才有父节点概念

可以看到,二叉搜索树的父子关系是明确、唯一且具有方向性的。这种特性使得许多操作可以在O(h)(h为树高)的时间内完成,前提是我们能高效地维护或访问父节点信息。

2. 构建过程可视化:一步一步看清父节点的诞生

理论说再多,不如动手画一遍。让我们用一个具体的例子,把构建一棵二叉搜索树时,父节点是如何一步步确定的过程,像播放动画一样展示出来。我们使用输入序列:[8, 3, 10, 1, 6, 14, 4, 7, 13]。

初始状态:我们有一棵空树。没有根,自然也没有任何父子关系。

插入第一个元素 8:

  • 寻路过程:树为空,没有比较对象。
  • 父节点确定:8成为根节点。根据约定,根节点的父节点视为一个特殊值(例如0或null)。
  • 可视化快照:
        8 (父: 0)
       / \
    空   空
    

插入第二个元素 3:

  • 寻路过程:从根节点8开始。3 < 8,因此向左走。8的左孩子位置为空。
  • 父节点确定:路径终点是“8的左孩子空位”,因此3的父节点是8。
  • 可视化快照:
        8 (父: 0)
       / \
      3   空
    父:8
    

插入第三个元素 10:

  • 寻路过程:从根8开始。10 > 8,向右走。8的右孩子为空。
  • 父节点确定:10的父节点是8。
  • 可视化快照:
        8 (父: 0)
       / \
      3   10
    父:8 父:8
    

插入第四个元素 1:

  • 寻路过程:从根8开始。1 < 8,向左走到节点3。1 < 3,继续向左走。3的左孩子为空。
  • 父节点确定:1的父节点是3。
  • 可视化快照:
          8 (父: 0)
         / \
        3   10
       / \   / \
      1 空 空 空
    父:3
    

让我们暂停一下,用一段简单的Python代码来模拟这个“寻路”逻辑,暂时先不存储父节点信息,只关注如何找到插入位置:

class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None

def find_insert_position(root, val):
    """模拟寻找插入位置的过程,返回最终停留的节点(即父节点)"""
    if root is None:
        return None  # 树为空,插入的节点将成为根,无父节点
    current = root
    parent = None
    while current is not None:
        parent = current  # 记录可能的父节点
        if val < current.val:
            current = current.left
        else:  # 假设 val > current.val,暂不处理相等情况
            current = current.right
    return parent  # 循环结束时,parent就是新节点的父节点

# 模拟构建过程的前几步
root = TreeNode(8)
print(f"插入 8 后,根节点父节点为: 无 (0)")
parent_of_3 = find_insert_position(root, 3)
print(f"为 3 寻路,找到的父节点是: {parent_of_3.val if parent_of_3 else '无'}")
# 实际插入操作
if parent_of_3:
    if 3 < parent_of_3.val:
        parent_of_3.left = TreeNode(3)
    else:
        parent_of_3.right = TreeNode(3)

继续我们的可视化构建:

插入第五个元素 6:

  • 寻路:8 -> 3 (6>3) -> 向右。3的右孩子为空。
  • 父节点:6的父节点是3。
  • 快照:树开始展开。

插入第六个元素 14:

  • 寻路:8 -> 10 (14>10) -> 向右。10的右孩子为空。
  • 父节点:14的父节点是10。

插入第七个元素 4:

  • 寻路:8 -> 3 -> 6 (4<6) -> 向左。6的左孩子为空。
  • 父节点:4的父节点是6。

插入第八个元素 7:

  • 寻路:8 -> 3 -> 6 (7>6) -> 向右。6的右孩子为空。
  • 父节点:7的父节点是6。

插入第九个元素 13:

  • 寻路:8 -> 10 -> 14 (13<14) -> 向左。14的左孩子为空。
  • 父节点:13的父节点是14。

最终树形结构与父节点关系表: 通过上面的步骤,我们最终得到一棵树,并可以汇总所有节点的父节点信息:

          8 (父: 0)
         / \
        3   10
       / \    \
      1   6    14
         / \   /
        4   7 13

对应的父节点关系为:

  • 1 -> 3
  • 3 -> 8
  • 4 -> 6
  • 6 -> 3
  • 7 -> 6
  • 8 -> 0 (根)
  • 10 -> 8
  • 13 -> 14
  • 14 -> 10

这个可视化的构建过程清晰地表明:父节点不是由节点自身的值决定的,而是由它被插入时的“寻路路径”以及当时树的结构共同决定的。同样的数字,在不同的插入顺序下,完全可能拥有不同的父亲。

3. 父节点动态更新逻辑与存储策略

在基本的插入操作中,父节点关系在节点“安家”的一刻就确定了,并且通常不会改变(除非进行删除或旋转等结构调整)。那么,在编程实现中,我们如何存储和维护这些关系呢?主要有两种策略:

策略一:节点结构体内置父指针 这是最直观、也是最符合面向对象思想的方法。每个树节点除了值和左右孩子指针,还包含一个指向父节点的指针。

class TreeNodeWithParent:
    def __init__(self, val, parent=None):
        self.val = val
        self.left = None
        self.right = None
        self.parent = parent  # 显式存储父节点引用

def insert_with_parent(root, val):
    """向带父指针的BST中插入节点"""
    new_node = TreeNodeWithParent(val)
    if root is None:
        return new_node  # 新节点为根,parent默认为None

    current = root
    parent_node = None
    while current is not None:
        parent_node = current
        if val < current.val:
            current = current.left
        else:
            current = current.right

    # 设置新节点的父节点
    new_node.parent = parent_node
    # 将新节点挂到父节点下
    if val < parent_node.val:
        parent_node.left = new_node
    else:
        parent_node.right = new_node
    return root  # 返回根节点,根可能不变

这种方式的优点是访问父节点的效率是O(1),在需要频繁回溯(例如寻找后继节点、删除节点后调整)的场景下非常高效。缺点是每个节点需要额外的内存空间来存储父指针。

策略二:外部映射记录父节点关系 有时,我们无法修改节点结构(比如使用简单的数组模拟树,或者处理的是不可变数据)。这时,可以使用一个额外的字典(或数组)来维护值到其父节点值的映射。

def insert_with_mapping(sequence):
    """根据插入序列,构建BST并记录父节点映射"""
    root_val = sequence[0] if sequence else None
    parent_map = {root_val: 0}  # 根节点的父节点记为0
    # 这里用简单的列表模拟树的位置,仅用于演示逻辑
    # 实际处理大量数据时,需要更高效的结构(如字典存储节点对象)
    tree_nodes = {root_val: None}  # 存储节点对象,此处简化

    current_root = TreeNode(sequence[0]) if sequence else None
    tree_nodes[sequence[0]] = current_root

    for val in sequence[1:]:
        current = current_root
        parent = None
        while current is not None:
            parent = current
            if val < current.val:
                current = current.left
            else:
                current = current.right
        # 创建新节点并挂载
        new_node = TreeNode(val)
        tree_nodes[val] = new_node
        if val < parent.val:
            parent.left = new_node
        else:
            parent.right = new_node
        # 关键:在映射表中记录父节点值
        parent_map[val] = parent.val

    return parent_map

# 使用之前的序列
seq = [8, 3, 10, 1, 6, 14, 4, 7, 13]
parent_info = insert_with_mapping(seq)
print("节点值 -> 父节点值 映射:")
for node in sorted(parent_info.keys()):
    print(f"{node:2d} -> {parent_info[node]}")

这种策略的优点是灵活、非侵入式,尤其适合解决类似“给定插入序列,直接输出父节点数组”的算法问题。其缺点是需要额外的存储空间(O(n)),并且查找某个节点的父节点需要O(1)的字典查找(虽然很快,但比直接指针访问多一次间接)。

选择哪种策略,取决于你的具体需求:

  • 如果需要实现一个功能完整的、支持复杂操作的BST数据结构,内置父指针是更专业的选择。
  • 如果只是解决一次性问题或进行算法分析,外部映射更简单直接。

4. 实例验证:编写父节点查找与验证程序

理解了原理和存储策略,我们来动手写一个完整的程序。这个程序要完成以下任务:

  1. 根据给定的插入序列,构建一棵二叉搜索树。
  2. 记录并输出每个节点的父节点。
  3. 提供一个验证函数,可以查询任意指定节点的父节点。

我们将采用节点内置父指针的方式来实现,因为它更接近工程实践。

class BSTNode:
    """带父指针的二叉搜索树节点"""
    def __init__(self, key, parent=None):
        self.key = key
        self.left = None
        self.right = None
        self.parent = parent

class BinarySearchTree:
    """支持父节点维护的BST"""
    def __init__(self):
        self.root = None
        self.node_map = {}  # 可选:快速通过值找到节点对象

    def insert(self, key):
        """插入节点并维护父指针"""
        new_node = BSTNode(key)
        if self.root is None:
            self.root = new_node
            self.node_map[key] = new_node
            return

        current = self.root
        parent = None
        while current is not None:
            parent = current
            if key < current.key:
                current = current.left
            elif key > current.key:  # 忽略相等的情况
                current = current.right
            else:
                return  # 重复值不插入

        # 现在parent是new_node的父节点
        new_node.parent = parent
        if key < parent.key:
            parent.left = new_node
        else:
            parent.right = new_node
        self.node_map[key] = new_node

    def get_parent_value(self, key):
        """获取指定键值节点的父节点的键值,根节点返回None(或0)"""
        if key not in self.node_map:
            return None  # 节点不存在
        node = self.node_map[key]
        if node.parent is None:
            return 0  # 根据约定,根节点的父节点用0表示
        return node.parent.key

    def build_from_sequence(self, sequence):
        """从序列构建树"""
        for val in sequence:
            self.insert(val)

    def print_all_parents(self):
        """按节点值顺序打印所有节点的父节点"""
        if not self.node_map:
            print("树为空")
            return
        print("节点 -> 父节点")
        for key in sorted(self.node_map.keys()):
            parent_val = self.get_parent_value(key)
            print(f"{key:3d} -> {parent_val if parent_val is not None else 'N/A'}")

# 实战测试
if __name__ == "__main__":
    # 测试用例1:文章开头的例子
    print("=== 测试用例1: [8, 3, 10, 1, 6, 14, 4, 7, 13] ===")
    bst1 = BinarySearchTree()
    test_seq1 = [8, 3, 10, 1, 6, 14, 4, 7, 13]
    bst1.build_from_sequence(test_seq1)
    bst1.print_all_parents()

    # 验证特定节点
    print("\n验证特定节点:")
    for key in [1, 6, 13]:
        print(f"节点 {key} 的父节点是: {bst1.get_parent_value(key)}")

    # 测试用例2:不同的插入顺序,会导致不同的父子关系
    print("\n\n=== 测试用例2: 相同元素集,不同顺序 [1, 3, 4, 6, 7, 8, 10, 13, 14] ===")
    bst2 = BinarySearchTree()
    test_seq2 = [1, 3, 4, 6, 7, 8, 10, 13, 14]  # 升序插入,会退化成链表
    bst2.build_from_sequence(test_seq2)
    bst2.print_all_parents()
    print(f"节点 8 的父节点是: {bst2.get_parent_value(8)} (注意,这里和测试用例1不同!)")

运行这段代码,你会得到清晰的输出,验证我们之前手动推导的父节点关系。更重要的是,第二个测试用例生动地展示了插入顺序如何彻底改变树的形态和父子关系。当按升序插入时,每个新节点都成为前一个节点的右孩子,树退化成一个高度为n的链表。此时,节点8的父节点是7,而不是第一个例子中的0(根)。这个对比强烈地提醒我们,二叉搜索树的性能(操作时间复杂度O(h))高度依赖于插入顺序,而父节点关系是这种结构动态性的直接体现。

5. 从父节点关系反推树结构与高级应用

掌握了如何从构建过程得到父节点,一个自然的问题是:能否反向操作?即,给定每个节点的父节点信息,我们能重建这棵二叉搜索树吗?答案是不一定能唯一确定。父节点信息只告诉我们节点之间的直接上下级关系,但没有指明左右方向。例如,父节点信息{2:0, 1:2, 3:2}可以对应两棵不同的二叉树:

    2         2
   / \       / \
  1   3     3   1

(左子树为1,右子树为3)和(左子树为3,右子树为1)。要唯一确定一棵二叉搜索树,我们还需要知道每个节点是其父节点的左孩子还是右孩子,这通常由节点值与父节点值的大小关系决定(在BST中)。

然而,如果同时知道插入序列,那么树的结构就是唯一确定的。因为我们可以用和构建时完全相同的逻辑,模拟插入过程。这引出了一个重要的应用场景:序列化与反序列化。有时,为了传输或存储一棵树,我们可能只存储每个节点的父节点引用(或值),而不是存储整个树结构。在反序列化时,如果这是一棵BST并且我们知道节点值的大小关系,我们就可以利用父节点信息和值的大小关系来重建树。

另一个高级应用是在算法竞赛或面试题中,有一类常见问题:给定一个BST中每个节点的父节点数组(根节点的父节点标记为特殊值),要求完成诸如“判断两个节点是否在同一条路径上”、“找到某个节点的深度”或“执行某种遍历”等操作。解决这类问题的关键,就是灵活运用父指针信息进行回溯(从节点向上走到根)。

例如,如何求任意节点p的深度?

def get_node_depth(bst, key):
    """通过父指针回溯,计算节点的深度(根节点深度为0)"""
    if key not in bst.node_map:
        return -1  # 节点不存在
    depth = 0
    node = bst.node_map[key]
    while node.parent is not None:  # 不断向上回溯,直到根节点
        node = node.parent
        depth += 1
    return depth

这个简单的函数展示了父指针的威力——它让我们能够轻松地在树中向上导航。如果没有父指针,求深度通常需要从根开始向下搜索,或者使用递归遍历,复杂度虽然也是O(h),但实现起来可能稍显繁琐。

最后,当你对父节点的概念和操作得心应手后,可以尝试挑战更复杂的问题,比如在仅有父节点信息的情况下,如何高效地找到两个节点的最近公共祖先(LCA)?一个经典的算法是,分别从两个节点出发,沿着父指针向上走到根,记录路径,然后找两条路径最后一个相同的节点。更优的解法是使用“交替上提”法,其本质也是利用了父指针提供的向上遍历能力。

C++实现二叉树可视化打印:从核心算法到工程实践 数据结构是计算机科学的基础,其中二叉树因其高效的搜索和排序能力,在算法设计与系统开发中应用广泛。理解二叉树的层次结构与节点关系,是掌握树形算法(如二叉搜索树、堆、AVL树)的关键。然而,仅通过数值遍历输出难以直观把握树的实际形态,这给调试和验证带来了挑战。为此,将树形结构进行可视化打印,成为一种重要的工程实践手段。其核心原理通常结合广度优先搜索(BFS)进行层次遍历,并计算节点在二维空间中的坐标,最终通过字符串拼接与控制台格式控制,实现树形图的文本化渲染。这项技术能极大提升对树形数据结构的调试效率与学习直观 阅读详情

相关推荐

C++树结构实现:从BST到红黑树的工程实践与内存管理

树是计算机科学中一种基础且强大的数据结构,它通过节点间的层次关系组织数据。其核心原理在于递归与分层,这使得它在表达具有从属关系的数据时非常高效。从技术价值看,树结构支撑了众多高效算法与系统,例如数据库索引(B+树)、文件系统目录和编译器语法分析。在应用场景上,二叉搜索树(BST)提供了快速的查找、插入和删除操作,而平衡树(如AVL树和红黑树)则通过自平衡机制解决了BST在极端数据下性能退化的问题,确保了操作的稳定对数时间复杂度。本文聚焦于**C++实现**,深入探讨了如何从工程角度构建一个健壮、可复用的树模

weixin_33827590的博客 342

树中的重要概念

1 基本术语及定义 1.1 根节点 根节点:是树中唯一没有入边的节点。 1.2 父节点 父节点:一个节点是其所有子节点的父节点 1.3 子节点 子节点:一个节点通过出边与子节点相连 1.4 兄弟节点 兄弟节点:具有同一个父节点的节点称为兄弟节点 1.5 叶子节点 叶子节点:叶子节点没有子节点 1.6 层数 节点n的层数是从根节点到n的唯一路径长度 1.8 高度 高度:树的高度是其中节点层数的最大值。 1.9 树 树(Tree)是n(n≥0)个结点的有限集。n=0时称为空树。在任意一棵非空树中:(1)有且仅有

EthanChenJia的博客 2832

Fluent后台计算中Journal文件的自动化编写与优化实践

本文深入探讨了Fluent在Linux/Unix环境下进行后台计算时,Journal文件的自动化编写与优化实践。Journal文件作为Fluent后台计算的“灵魂”,是实现仿真流程自动化、保证计算可重复性与准确性的关键。文章从基础脚本骨架搭建、命令简写技巧,到进阶的参数化研究与批量计算实现,提供了详实的实战指南,帮助工程师大幅提升仿真效率。

postgres8guard的博客 757

五、树结构

如果树中每个节点最多只能有两个子节点,这样的树就成为**“二叉树”**前面,我们已经提过二叉树的重要性,不仅仅是因为简单,也因为几乎上所有的树都可以表示成二叉树的形式。

小蓝人的博客 2299

山东大学软件测试实验2——系统功能测试

​ 给出一个被测试的 Web 应用系统(SUT)。http://211.87.232.162:8080/注:友情链接不用延伸测试。针对被测试的 Web 应用系统进行功能测试,发现其存在的缺陷。 ​

m0_74033391的博客 2409

使用 Simulink + Simscape Electrical 对基于VSG控制的背靠背变流器整流侧进行建模与仿真

本文介绍了基于Simulink的直驱风电系统背靠背变流器整流侧虚拟同步发电机(VSG)建模方法。首先阐述了直驱风电系统结构和VSG控制的作用,然后详细指导了模型搭建过程:从创建项目、添加PMSG和变流器模块,到搭建主电路拓扑和实现VSG控制逻辑。重点说明了VSG控制器如何模拟传统同步发电机的特性,并提供了仿真设置和结果分析方法。该模型可用于研究风电系统在不同工况下的响应特性,为新能源发电系统设计提供重要参考。

amy_mhd的博客 180

节点的5种关系

1.父节点(parent) 元素的上一层的那个节点就是该元素的父节点,每个元素都有一个父节点 子节点(children) 元素下面第一层的所有节点都是该元素的子节点,一个元素可以有 >=0个节点 同胞节点(sibling) 同胞节点也叫兄弟节点,拥有相同的父节点的节点互为同胞节点 先辈节点(ancestor) 先辈节点也叫祖先节点,元素的父节点以及父节点的父节点、一次类推都是该节点的先辈节点。 后代节点(descendant) 同理,一个节点的子节点、子节点的子节点、以此类推,都是该节

EdmundBai的博客 7965

如何在非序列模式下使用类似图像模功能

如何在非序列模式下使用类似图像模功能

weixin_72050316的博客 552

数据结构树(C语言版)

树(Tree)是一种非常常见的数据结构,它模拟了一种层级或分支结构。

weixin_62345907的博客 1963

【OpenClaw从入门到精通】第17篇:OpenClaw巨头布局实战:阿里CoPaw/腾讯云/百度/火山引擎深度拆解(2026实操版)

2026年OpenClaw以22.8万星标登顶GitHub,引发阿里、腾讯、百度、字节等互联网巨头入局角逐。本文基于公开技术文档与实测经验,深度解析四大巨头的OpenClaw布局战略:阿里云CoPaw的全栈托管、腾讯云的流量入口绑定、百度智能云的搜索生态内嵌、火山引擎的极致智力供给。从核心原理、算法构建、实操流程三个维度,提供可直接落地的接入方案,包含完整代码示例与执行结果验证。通过流程图可视化核心架构,搭配避坑指南与选型矩阵,帮助新手快速上手、进阶读者实现多厂商协同部署。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1683

【SOUND】Linux音频子系统ASoC的驱动框架总分析

ALSA系统在芯片(ASoC)层的总体项目目标是为嵌入式芯片处理器(例如PXA2XX,AU1X00,IMX等)和便携式音频编解码器提供更好的ALSA支持。 在进入ASoC子系统之前,内核对SoC音频有一些支持,但是它有一些局限性:ASoC层旨在解决这些问题并提供以下内容特征 :为了实现这一切,ASoC基本上将嵌入式音频系统分为多个可重复使用的组件驱动程序:另外,这里提下OSS(Open Sound System)这个基本被弃用的音频框架。 可以参考Linux OSS架构声卡驱动框架 2.3 ASoC重要

wang 恒 的博客 1781

节点操作(Dom中父子节点)

1.节点层级 利用Dom树可以把节点划分为不同的层级关系,常见的父子兄弟关系 1.1父级节点 node.parentNode找的是关于node元素最近的父级节点(亲爸爸)如果找不到父节点就返回为null 2.子节点 2.1获取子节点 node.childnodes能够获取到node节点所有子节点的集合,该集合为即时更新的集合,但是如果之只获取nodetype值(节点类型)为3的元素节点,那么就不能使用chiildnodes来获取 <body> <ul>..

weixin_53781355的博客 2215

ransac拟合2D圆(三点定圆 c++详细版)

RANSAC(Random Sample Consensus,随机采样一致性)算法是一种基于随机采样的迭代算法,主要用于从一组包含大量噪声和异常值(外点)的数据中估计数学模型的参数。

twnkie的博客 1047

数据结构与算法实战:gh_mirrors/le/learn中的二叉搜索树实现详解

二叉搜索树(Binary Search Tree, BST)是一种高效的数据结构,它能在平均O(log n)时间复杂度内完成插入、搜索和删除操作。在gh_mirrors/le/learn项目中,我们可以找到用Go和C++实现的二叉搜索树完整代码,这些实现不仅展示了BST的核心原理,还提供了丰富的可视化示例。本文将带你深入了解二叉搜索树的特性、实现方法及实际应用。 ## 二叉搜索树的核心特性与优势

gitblog_00274的博客 386

【漏洞复现】Palo Alto Networks PAN-OS GlobalProtect 命令注入漏洞 CVE-2024-3400

在特定PAN-OS版本和不同功能配置下,未经身份验证的攻击者可能利用此漏洞在防火墙上以root权限执行任意代码。技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害国家安全、荣誉和利益,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。本文所提供的工具仅用于学习,禁止用于其他!poc如下,注入点在Cookie中,将其中的DNSlog地址替换为你的dnslog地址,借助DNSLOG来复现,可以使用http://dnslog.pw/

失心少年 1225

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

AlgoNote 算法通关手册:二叉搜索树(BST)查找、插入、创建与删除全攻略

本文是 [AlgoNote 算法通关手册](https://link.gitcode.com/i/90209c2f67b7f68f121787d625caca6e) 中「树」专题的核心章节之一,系统讲解二叉搜索树(Binary Search Tree, BST)的定义、性质,以及查找、插入、创建、删除四大基本操作的算法思路、递归代码实现与复杂度分析。读完本文,你将掌握 BST「左小右大」有序性的本

gitblog_00341的博客 633

Devexpress16.2.6破解工具

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

AVL树C++实现详解:新手友好型平衡二叉搜索树教学

平衡二叉搜索树(BBST)是理解动态数据结构平衡机制的核心概念,其本质是通过局部调整(如旋转)维持全局高度平衡,从而保障O(log n)查询与更新效率。AVL树以直观的平衡因子(BF = 左子树高 - 右子树高)为判定依据,结合四种机械可推演的旋转操作(LL/RR/LR/RL),构成最适合作为首个BBST学习模型的技术路径。相比红黑树的多约束规则,AVL将‘数值反馈→动作响应’显性化,大幅降低初学者的认知负荷。本内容聚焦C++原生指针实现,强调高度维护、BF联动、递归回溯修复等关键原理,适用于已掌握二叉树遍

weixin_33796177的博客 320

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

二叉搜索树核心解析:高效查找与有序遍历的实现与工程实践

数据结构是计算机科学的基础,而二叉搜索树(BST)则是理解更复杂树形结构的关键跳板。它通过在每个节点中维护“左小右大”的有序规则,让查找操作具备接近二分查找的效率,在平衡状态下将时间复杂度从线性级别降至对数级别。同时,对BST进行中序遍历,能够直接得到有序序列,无需额外排序,这一特性在构建有序集合、范围查询、内存索引等场景中极具工程价值。无论是应对算法面试中的高频题目,还是在实际系统中实现缓存或字典结构,掌握BST的插入、查找、删除和遍历操作都是不可或缺的基本功。本文从零开始拆解BST的节点结构与核心操作,

weixin_42699679的博客 223

C语言数据结构教程:从内存管理到链表、树、图的底层实现

数据结构是计算机科学的核心基础,它研究数据在计算机中的组织、存储和操作方式。其核心原理在于通过特定的逻辑结构(如线性、树形、图状)和物理存储结构(如顺序、链式),实现对数据的高效管理。掌握数据结构对于编写高性能、可扩展的软件至关重要,是算法设计、数据库系统、编译器开发乃至人工智能等领域的基石。在工程实践中,理解数据结构的底层实现,尤其是通过C语言手动管理内存和指针,能从根本上提升对程序性能与资源消耗的洞察力。本教程聚焦于链表、二叉树、堆、哈希表等常用结构,通过热门的【内存管理】和【指针操作】实践,手把手带你

weixin_30664615的博客 335

堆排序动画可视化:从下标公式到动态结构理解

堆排序作为经典基于比较的排序算法,其核心在于完全二叉树的层序映射与隐式父子关系维护。理解关键不在于背诵parent=(i-1)//2等下标公式,而在于掌握‘空间折叠术’如何将一维数组转化为动态堆结构,并通过上浮/下沉实现O(n log n)时间复杂度的高效调整。这种‘隐式结构+级联动作’特性,使纯代码阅读极易停留在语法层,难以建立结构直觉。借助Python+Matplotlib构建帧级可交互动画,可精准呈现每一步比较、交换与重绘背后的决策逻辑,显著提升对建堆起点(n//2-1)、下沉路径、边界条件等关键机制

weixin_30899023的博客 240

从零手写AVL树:Python实现平衡二叉搜索树的核心技巧与避坑指南

平衡二叉搜索树是数据结构与算法中的核心概念,通过旋转操作维持左右子树高度差不超过1,从而保证查找、插入、删除操作的时间复杂度稳定在O(log n)。AVL树作为最严格的平衡二叉搜索树,是理解平衡机制的理想入口。在Python中实现AVL树,能够清晰展示递归回溯、节点高度维护与四种旋转场景的工程细节。掌握AVL树不仅有助于面试中手写代码,也能在需要有序数据结构的场景中提供稳定性能。本文基于北京大学2020公开课资料,逐行拆解AVL树的Python实现,并整理常见问题与排查技巧。

weixin_31856057的博客 307

Janus-Pro-7B数据结构与算法教学助手:动态图解与代码实现详解

本文介绍了如何利用星图GPU平台,一键自动化部署Janus-Pro-7B镜像,快速构建一个智能数据结构与算法教学助手。该助手能够动态讲解算法原理、生成可执行代码,并指导用户创建排序算法等过程的动态可视化动画,显著提升教学与学习的互动性和效率。

weixin_35671843的博客 245

手撕一颗AVL树:从理论到代码的完整指南

✅ 深入理解了AVL树的平衡机制。✅ 掌握了旋转操作的实际应用场景。🔧 添加删除操作的实现。🔧 增加树的可视化输出,便于调试。

m0_72134995的博客 324

The Algorithms - PHP:从零开始掌握PHP算法与数据结构的完整指南

The Algorithms - PHP 是一个用 PHP 编程语言编写的算法与数据结构库,它为各种计算任务提供了丰富的算法实现,旨在帮助开发者轻松掌握和应用这些强大工具。无论是排序、搜索还是复杂的数据结构操作,该项目都能为 PHP 开发者提供清晰易懂的实现示例。 ## 📚 项目核心价值:为什么选择 PHP 算法库? 在 PHP 开发中,高效的算法和数据结构是提升应用性能的关键。The Al

gitblog_00472的博客 598

KD-Tree实战指南:构建、搜索与动态维护

本文提供了一份全面的KD-Tree实战指南,详细阐述了其构建原理、高效搜索算法以及动态维护方法。通过二维示例和Python伪代码,手把手教你实现KD-Tree的构建与最近邻搜索,并深入探讨了动态插入时的平衡优化技巧,帮助开发者应对多维空间数据检索的挑战,显著提升搜索效率。

weixin_29230805的博客 100

C++ STL map/set底层实现:红黑树封装与核心原理详解

在C++编程中,关联容器是解决高效查找与键值映射问题的核心数据结构。其底层通常基于平衡二叉搜索树(如红黑树)实现,通过维护元素的有序性,确保插入、删除和查找操作的时间复杂度稳定在O(log n)。这种设计不仅提供了稳定的性能保障,还支持高效的范围查询和有序遍历,在字典、缓存、去重等场景中具有重要技术价值。理解其封装原理,特别是迭代器设计、模板应用和内存管理,是深入掌握STL的关键。本文以红黑树为例,剖析map和set的底层实现,探讨自定义比较器、异常安全等工程实践问题,帮助开发者从API使用者转变为容器设计

weixin_34101229的博客 322
上一篇: 别再为加密PDF烦恼了!教你用Windows自带功能轻松绕过编辑限制
下一篇: QT QByteArray在串口通信中的进制转换实战:十进制与十六进制的灵活应用
cuda7parallel
博客等级 码龄1天 0粉丝 1273原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值