二叉搜索树（英語：binary search tree，简称BST）是一种有根二叉树数据结构。它要求每个内部节点的键值都大于其左子树中所有节点的键值，且都小于其右子树中所有节点的键值。该树各项操作时间复杂度均与树的高度成线性关系。
二叉搜索树每次比较都能排除大约一半的剩余节点，故能以对数时间查找、插入、删除数据。但其性能依赖于节点的插入顺序，插入随机键值时仍能维持对数级别，但在最坏情况下会退化成链表。为保证效率，研究者发明了多种平衡树，能将最坏查找复杂度维持在
  
    
      
        O
        (
        log
        ⁡
        n
        )
      
    
    {\displaystyle O(\log n)}
  
。
二叉搜索树最早由多位研究者独立提出，1960年被用来解决带标签数据的存储问题。其还可用来实现树排序及优先队列。


历史 二叉搜索树最早由多位研究者独立提出，包括P.F.温德利、安德鲁·唐纳德·布思、安德鲁·科林、托马斯·N·希巴德。这种数据结构常被归功于康威·柏纳-李及大卫·惠勒，他们在1960年将之用于磁带上带标签数据的存储。希巴德实现二叉搜索树的方法也是最早广为流传的一种。
若按任意顺序插入节点，树的高度可能接近节点数，导致操作效率急剧下降。研究者们发明了平衡树（即能够自平衡的二叉搜索树），将树的高度限制在
  
    
      
        O
        (
        log
        ⁡
        n
        )
      
    
    {\displaystyle O(\log n)}
  
以内。:458–459同时，相关人员也提出了多种高度平衡的二叉搜索树结构，例如AVL树、树堆、红黑树等。其中，AVL树是首类平衡树，由格奥尔吉·阿杰尔松-韦利斯基及叶夫根尼·兰迪斯于1962年发明，用于高效组织信息。


性质 二叉搜索树为有根的二叉树，其节点顺序为严格全序关系，每个节点都满足：左子树上所有节点的键值都小于该节点，右子树上所有节点的键值都大于该节点。这一结构保证可以在对数时间内定位任意键值。:298:287:161-162除查找外，其也常用于排序，但性能取决于节点的插入和删除顺序——在最坏情况下，连续操作可能使树退化为类似单链表的结构，这时的查找复杂度与链表相同。:299-302


遍历 二叉搜索树的遍历有三种基本方法：前序、中序、后序。:287:162

中序遍历：依次遍历左子树、根节点、右子树。遍历结果为键值递增顺序。
前序遍历：依次遍历根节点、左子树、右子树。
后序遍历：依次遍历左子树、右子树、根节点。
以下是递归实现的遍历伪代码：:287–289:162


操作 = 搜索 =
在二叉搜索树中查找某个特定的键，可以使用递归或迭代方式实现。
查找过程从树的根节点开始：

如果根节点为空（
  
    
      
        
          nil
        
      
    
    {\displaystyle {\text{nil}}}
  
），说明该键不存在。
如果根节点的键值与目标键值相等，返回该节点，表示查找成功。
如果目标键值小于根节点的键值，则继续在左子树中查找；
如果目标键值大于根节点的键值，则继续在右子树中查找。
重复上述步骤，直到找到该键，或者剩余子树为空。若到达空子树仍未找到，说明该键不存在于树中。:290-291:163


 递归搜索  以下伪代码展示递归方式实现的查找过程：:290:163

递归会一直进行，直到遇到
  
    
      
        
          nil
        
      
    
    {\displaystyle {\text{nil}}}
  
或是找到目标键
  
    
      
        
          key
        
      
    
    {\displaystyle {\text{key}}}
  
。


 迭代搜索  递归过程也可展开为循环形式，一般情况下循环版本的效率更高。其伪代码如下：:291:163

由于查找可能会一直到叶节点，因此时间复杂度为树的高度
  
    
      
        O
        (
        h
        )
      
    
    {\displaystyle O(h)}
  
（
  
    
      
        h
      
    
    {\displaystyle h}
  
为树的高度）。:290:163在最坏情况下，一棵严重不平衡的二叉搜索树可能退化成单链表，这时复杂度会达到
  
    
      
        O
        (
        n
        )
      
    
    {\displaystyle O(n)}
  
（
  
    
      
        n
      
    
    {\displaystyle n}
  
为树中节点总数）。但对于高度平衡的二叉搜索树而言，复杂度为
  
    
      
        O
        (
        log
        ⁡
        n
        )
      
    
    {\displaystyle O(\log n)}
  
。:458–459:403:255


 后继与前驱  在某些场景下，需要查找给定节点的「后继」或「前驱」。后继节点是大于该节点键值的节点中，键值最小的那一个；前驱节点是小于该节点键值的节点中，键值最大的那一个。以下伪代码给出求节点
  
    
      
        
          x
        
      
    
    {\displaystyle {\text{x}}}
  
的后继与前驱方法：:292–293:164

寻找树中键值最大或最小的节点，是寻找后继与前驱过程中的重要环节。其伪代码如下：:291–292:163–164


 选择与排名  若在节点中维护以之为根节点的子树的节点总数，则可实现选择与排名操作。选择操作用于在树中直接定位排名为
  
    
      
        k
      
    
    {\displaystyle k}
  
的节点，即第
  
    
      
        k
      
    
    {\displaystyle k}
  
小的键。:406–407:257–258排名操作则与之相对，给定指定键后，其会返回小于该键的节点数。:408:258–259这两种操作的伪代码如下：:409:258–259

其中size表示子树规模信息，即子树中节点数量。


 范围查找  利用中序遍历，可以实现范围查找，即查询两个给定值之间的元素数量。其伪代码如下：:412–413:261–262

其中list是用来收集结果的列表（也可视作队列）。上述过程将所有符合条件的值加入列表中，并跳过不可能含有目标值的子树。


= 插入 =
二叉搜索树的数据结构会随插入和删除操作而变化。插入操作须保证二叉搜索树的性质不会遭到破坏，且插入的节点总是作为叶节点加入。:294–295:165–166以下伪代码给出迭代形式的插入过程：:294:165–166

过程使用变量
  
    
      
        
          y
        
      
    
    {\displaystyle {\text{y}}}
  
作为遍历节点
  
    
      
        
          x
        
      
    
    {\displaystyle {\text{x}}}
  
的父节点（追踪指针）。初始时如果
  
    
      
        
          y
        
      
    
    {\displaystyle {\text{y}}}
  
为
  
    
      
        
          nil
        
      
    
    {\displaystyle {\text{nil}}}
  
，说明树为空，新节点
  
    
      
        
          z
        
      
    
    {\displaystyle {\text{z}}}
  
即作为树的根；否则，需根据节点键值大小关系插入对应位置。:295:166


= 删除 =

从树中删除某个节点
  
    
      
        
          Z
        
      
    
    {\displaystyle {\text{Z}}}
  
时，需分三种情况处理：:295-297:166-167

  
    
      
        
          Z
        
      
    
    {\displaystyle {\text{Z}}}
  
是叶节点：直接用空指针替换即可。（如图中(a)）

  
    
      
        
          Z
        
      
    
    {\displaystyle {\text{Z}}}
  
仅有一个子节点：用
  
    
      
        
          Z
        
      
    
    {\displaystyle {\text{Z}}}
  
的子节点替换
  
    
      
        
          Z
        
      
    
    {\displaystyle {\text{Z}}}
  
。（如图中(b)、(c)）

  
    
      
        
          Z
        
      
    
    {\displaystyle {\text{Z}}}
  
有两个子节点：用
  
    
      
        
          Z
        
      
    
    {\displaystyle {\text{Z}}}
  
的中序遍历所得到的后继或前驱
  
    
      
        
          Y
        
      
    
    {\displaystyle {\text{Y}}}
  
代替
  
    
      
        
          Z
        
      
    
    {\displaystyle {\text{Z}}}
  
。此处以后继为例：
如果
  
    
      
        
          Y
        
      
    
    {\displaystyle {\text{Y}}}
  
恰好是
  
    
      
        
          Z
        
      
    
    {\displaystyle {\text{Z}}}
  
的右子节点：直接用
  
    
      
        
          Y
        
      
    
    {\displaystyle {\text{Y}}}
  
取代
  
    
      
        
          Z
        
      
    
    {\displaystyle {\text{Z}}}
  
，
  
    
      
        
          Y
        
      
    
    {\displaystyle {\text{Y}}}
  
的右子树保持不变。（如图中(d)）
如果
  
    
      
        
          Y
        
      
    
    {\displaystyle {\text{Y}}}
  
位于
  
    
      
        
          Z
        
      
    
    {\displaystyle {\text{Z}}}
  
的右子树内部：先用
  
    
      
        
          Y
        
      
    
    {\displaystyle {\text{Y}}}
  
的右子节点替换
  
    
      
        
          Y
        
      
    
    {\displaystyle {\text{Y}}}
  
，再用
  
    
      
        
          Y
        
      
    
    {\displaystyle {\text{Y}}}
  
替代
  
    
      
        
          Z
        
      
    
    {\displaystyle {\text{Z}}}
  
。（如图中(e)）
以下伪代码实现删除操作：:296-298:167-168

  
    
      
        
          BST-Delete
        
      
    
    {\displaystyle {\text{BST-Delete}}}
  
过程根据上述3种情况处理节点删除：第1种情况（叶节点）对应第2—3行；第2种情况（单个子节点）对应第4—5行；第3种情况（有两个子节点）对应第6—16行。辅助函数
  
    
      
        
          Shift-Nodes
        
      
    
    {\displaystyle {\text{Shift-Nodes}}}
  
用于把节点
  
    
      
        
          u
        
      
    
    {\displaystyle {\text{u}}}
  
替换成
  
    
      
        
          v
        
      
    
    {\displaystyle {\text{v}}}
  
。:296-298:167-168
若在第3种情况中，仅选用后继或前驱节点中的一种，则并未考虑到树的对称性，可能会导致性能问题。若要避免此问题，可以随机选择使用后继或前驱。:410:260


平衡树 普通的二叉搜索树中，若不加以平衡，插入或删除操作可能会导致树退化。若是使用随机键值构建二叉搜索树，那么平均高度仍能维持在对数级别（当节点数
  
    
      
        n
      
    
    {\displaystyle n}
  
足够大时，高度趋近于
  
    
      
        2.99
        lg
        ⁡
        n
      
    
    {\displaystyle 2.99\lg n}
  
）；:413:263但在最坏情况下，高度会达到节点数
  
    
      
        n
      
    
    {\displaystyle n}
  
，查找性能退化至线性搜索的水平。要保持二叉搜索树的高效，关键在于通过「自平衡」机制，使树的高度始终维持在
  
    
      
        O
        (
        log
        ⁡
        n
        )
      
    
    {\displaystyle O(\log n)}
  
级别。:458–459:50:414:263


= 高度平衡树 =
若一棵树的任意节点，其左右子树高度之比都被某个常数所限制，就称其为高度平衡树。这一思想最早在AVL树中使用，后续的红黑树也沿用了类似机制。:50-51每次执行插入或删除操作后，需要沿着从根到修改节点的路径，检查并修正各节点的高度，以维持平衡。:52


= 加权平衡树 =

在加权平衡树中，平衡条件不再以高度衡量，而是以子树的叶节点数量为准。叶节点数量即代表权重，左右子树的权重差最多为常数
  
    
      
        1
      
    
    {\displaystyle 1}
  
。:61但单纯依靠差值，难以在插入和删除时用
  
    
      
        O
        (
        log
        ⁡
        n
        )
      
    
    {\displaystyle O(\log n)}
  
的代价维护，因此引入比例因子
  
    
      
        α
      
    
    {\displaystyle \alpha }
  
，要求左右子树的权重各自至少占整棵子树权重的
  
    
      
        α
      
    
    {\displaystyle \alpha }
  
比例，由此形成
  
    
      
        α
      
    
    {\displaystyle \alpha }
  
-权重平衡树族。:62


= 其他类型 =
常见的自平衡二叉搜索树包括：T树、树堆、红黑树:273:174、B树、2-3树:483、伸展树。


应用 = 排序 =

二叉搜索树可用于树排序：先将所有元素插入二叉搜索树中，然后对树做中序遍历，即可得到有序序列。在快速排序的某些实现中，也可借助二叉搜索树来提高性能。


= 优先队列 =

二叉搜索树也可用来实现优先队列，借助节点的键值来表示优先级。插入操作与普通的二叉搜索树相同，但删除操作取决于优先队列的类型：

升序优先队列：移除最低优先级元素时，从根节点向左一路遍历即可找到最小键。
降序优先队列：移除最高优先级元素时，从根节点向右一路遍历即可找到最大键。


参见 脚注 = 注释 =


= 来源 =


延伸阅读 本条目引用的公有领域材料。材料来自NIST的文档：Black, Paul E. Binary Search Tree. 演算法與資料結構辭典. 
Cormen, Thomas H.; Leiserson, Charles E.; Rivest, Ronald L.; Stein, Clifford. 12: Binary search trees, 15.5: Optimal binary search trees. Introduction to Algorithms 2nd. MIT Press. 2001: 253–272, 356–363. ISBN 0-262-03293-7 （英语）. 
Jarc, Duane J. Binary Tree Traversals. Interactive Data Structure Visualizations. University of Maryland. 2005-12-03  [2006-04-30]. （原始内容存档于2014-02-27） （英语）. 
Knuth, Donald. 6.2.2: Binary Tree Searching. The Art of Computer Programming. 3: "Sorting and Searching" 3rd. Addison-Wesley. 1997: 426–458. ISBN 0-201-89685-0 （英语）. 
Long, Sean. Binary Search Tree (PPT). Data Structures and Algorithms Visualization-A PowerPoint Slides Based Approach. SUNY Oneonta （英语）. 
Parlante, Nick. Binary Trees. CS Education Library. Stanford University. 2001. （原始内容存档于2022-01-30） （英语）. 


外部链接 哈尔沙·苏利亚纳拉亚纳的教学视频：YouTube上的Data structures: Binary Search Tree（英文）
Ben Pfaff: An Introduction to Binary Search Trees and Balanced Trees. (PDF; 1675 kB) 2004. （英語）