二叉搜索树

来源:互联网 发布:linux getconfig 编辑:程序博客网 时间:2024/06/04 17:59

1 二叉搜索树简介

二叉搜索树(Binary Search Tree)一般结构:

struct TreeNode {    int val;         //节点值    TreeNode *parent;//指向父节点    TreeNode *left;  //指向左子树    TreeNode *right; //指向右子树    TreeNode(int x) : val(x), parent(NULL),left(NULL), right(NULL) {}};

性质:对于任意节点,左子树的节点值都小于该节点值,右子树的节点值均大于该节点值。

根据该性质,对二叉搜索树做中序遍历便可以顺序(由大到小或由小到大)输出树中所有节点值。

对于一颗高为h的二叉搜索树,对二叉树的操作查询、最小、最大、后继、前驱、插入、删除的时间复杂度均为O(h)

2 查询

查询某元素、最大最小值、前驱后继

2.1 查询某元素

在二叉搜索树中查询某个元素k。

  • 若k大于当前节点值,则搜索其右子树;
  • 若k小于当前节点值,则搜索其左子树;
  • 若k等于当前节点值或当前节点为空,返回当前节点。

递归版本伪代码:

node初始化为树的根节点root

//输入:node为当前子树的根节点,k为待搜索的节点值//输出:搜索到的节点TREE-SEARCH(node,k)    if(node==NULL || k==node->val)        then return node    if(k<node->val)        return TREE-SEARCH(node->left,k)    else        return TREE-SEARCH(node->right,k)

非递归版本伪代码:

TreeNode* ITERATIVE-TREE-SEARCH(TreeNode *node,int k)    while(k!=node->val && node != NULL)        if(k<node->val)            node=node->left        else node=node->right    return node

2.2 最大最小节点值

最大节点值:二叉搜索树最右下方节点值即是树中最大节点值
最小节点值:二叉搜索树最左下方节点值即使树中最小节点值

最大节点值伪代码:

//输入:node为当前子树的根节点//输出:该子树最大值节点TreeNode* TREE-MINIMUM(TreeNode* node)    while(node->right != NULL)        node=node->right    return node

最小节点值伪代码:

//输入:node为当前子树的根节点//输出:该子树最小值节点TreeNode* TREE-MINIMUM(TreeNode* node)    while(node->left != NULL)        node=node->left    return node

2.3 前驱和后继

后继:指节点值大于某节点值的节点中,节点值最小的节点。即,对树进行中序遍历,节点值紧随其后的节点。

求某个节点的后继分为两种情况:

  • 该节点有右子树,则其后继是其右子树最左下方的节点;
  • 该节点无右子树,则其后继节点满足:该节点在后继节点的左子树中,且后继节点是符合条件的最低的父节点。

求节点后继的伪代码:

//输入:待寻找其后继节点的节点//输出:后继节点TREE-SUCCESSOR(node)    if(node->right != NULL)        return TREE-MINIMUN(node->right)    tmp=node->parent;    while(tmp!=NULL and node==tmp->right)        node=tmp        tmp=tmp->parent    return tmp

3 插入和删除

插入和删除需要在保持二叉搜索树性质的情况下,对树进行修改。

3.1 插入

若插入节点小于当前节点值,则插入其子树,大于则插入其子树,直至当前节点为叶节点,则将插入节点变为当前节点的左或右子节点。

向树中插入节点的伪代码:

//输入:root为树的根节点指针,node为当前待插入节点//输出:更新后树的根节点TREE-INSERT(root,node)    cur=root    leafNode=NULL    while(cur!=NULL)        leafNode=cur        if(node->val>=cur->val)            cur=cur->right        else            cur=cur->left    node->parent=leafNode//此处本应使用取值符    if leafNode==NULL        root=node    else        if(node->val>=leafNode->val)            leafNode->right=node        else            leafNode->left=node

3.2 删除

相比插入,删除操作较为复杂。删除操作分为三种情况:

  • 若删除节点为叶子节点,则直接将其删除;
  • 若删除节点只有一个子节点,则用子节点替代删除节点的位置,此处称该子节点为“替代节点”;
  • 若删除节点有两个子节点,则使用其后继节点替代删除节点的位置;

如下图所示的树,若要删除节点8(叶节点),则直接将其删除即可,若删除节点11(一个子节点),则使用其子节点**12替代其位置即可,若要删除节点13(两个子节点),则使用其后继节点**15替代替位置即可。

删除节点伪代码:

/** 输入:root为树根节点,node为待删除元素* 输出:替待元素*/TREE-DELETE(root,node)    //删除替代节点    if(node->left==NULL or node->right==NULL)//当前节点无子节点或只有一个子节点        tmp=node    else                              //当前节点有两个子节点        tmp=TREE-SECCESSOR(node)      //后继节点无子节点    if(tmp->left!=NULL)        childNode=tmp->left           //childNode为删除节点的子节点    else        childNode=tmp->right    if(childNode!=NULL)               //替换节点为后继节点的情况        childNode->parent=node->parent//设置替代节点的父节点,将替代节点删除    if(node->parent==NULL)        root=childNode    else if(tmp==tmp->parent->left)            childNode=tmp->parent->left        else            childNode=tmp->parent->right    if(tmp->val!=node->val)        node->val=tmp->val//拷贝节点的值    return tmp

参考资料

《算法导论》第12章 二叉查找树

原创粉丝点击