二叉搜索树(Binary Search Tree)

概述

二叉搜索树(Binary Search Tree)或者称为二叉排序树(Binary Sort Tree),它是一棵空树;或者是具有下列性质的二叉树:1.若它的左子树不空,则左子树树上的所有节点的值均小于它的根节点的值;2.或者是具有下列性质的二叉树:1.若它的右子树不空,则右子树上的所有节点的值均小于它的根节点的值;3.它的左,右子树也分别为二叉搜索书(二叉排序树)[1](注:是一个递归定义)

具体结构如图:

[1]

定义数据结构

二叉树的节点

// node of tree
typedef struct Node{
    ElemType key;
    struct Node *left;
    struct Node *right;
    struct Node *p;
}Node;
二叉搜索树:root指针指向第一个插入的元素的节点即把第一个插入的节点作为树根

// root of tree
typedef struct Tree{
    struct Node *root;
} *Tree;

函数操作

1. 插入

核心思想:1.若是一棵空树,则树根指向该节点;2.若是根节点的key值大于该节点的key值,则插入根节点的左子树,否则插入根节点的右子树(注:相等的则放弃插入)。

过程如图:

              

  原始节点 插入节点值为6的节点 插入节点值为3的节点

代码

void insert(Tree tree, ElemType key) {
    // allocate Node & initial
    Node *node = (Node *) malloc(sizeof(Node));
    if(!node) {
        printf("Node allocation failed!\n");
        exit(-1);
    }
    node->key = key;
    node->left = NULL;
    node->right = NULL;

    // insert the node into the tree
    Node *p = tree->root;
    if(p == NULL) {  // a emty tree
        node->p = NULL;
        tree->root = node;
        return;
    }
    // find the parent of this node;
    Node * cur = NULL;
    while(p != NULL) {
        cur = p;
        if(p->key > key) {
            p = p->left;
        } else if(p->key < key){
            p = p->right;
        } else {
            // the elem already existed
            free(node);
            node = NULL;
            return;
        }
    }
    //point to its parent
    node->p = cur;
    // binds node
    if(cur->key > key) {
        cur->left = node;
    } else {
        cur->right = node;
    }
}

2. 寻找最小节点

核心思想:找到树根的最左子节点

// find the minimum key from this node to its sub nodes
// return the minimum node
Node * minimumFromNode(Node *node) {
    Node *p = node;
    if (p) {
        while(p->left) {
            p = p->left;
        }
    }
    return p;
}
// find the minimum node in this tree
Node * minimumInTree(Tree t) {
    return minimumFromNode(t->root);
}

3.寻找最大子节点

核心思想:寻找根节点的最右子节点

// find the maximum key from this node to its sub nodes
// return the maximum node
Node *maximumFromNode(Node *node) {
    Node *p = node;
    if (p) {
        while(p->right) {
            p = p->right;
        }
    }
    return p;
}

// find the maxmum node in this tree
Node *maximumInTree(Tree t) {
    return maximumFromNode(t->root);
}

4.寻找值为key的节点

核心思想:和插入的思想差不多,从根节点开始,key值大于根节点的key值则从根节点的右子树寻找,若小于则往根节点的左子树寻找,否则相等则直接返回该节点。

代码:

// search the tree and find whether the key is in this tree
// in this tree, return this node, else return NULL
Node* search(Tree t, ElemType key) {
    Node *p = t->root;
    while(p) {
        if(p->key > key) {
            p = p->left;
        } else if(p->key < key) {
            p = p->right;
        } else {
            return p;
        }
    }
    return NULL;
}

5.中序遍历树

直接上代码(代码比较简介):

// tracerse all tree in order
void inOrder(Node * node) {
    if(node != NULL) {
        inOrder(node->left);
        printf("%d ", node->key);
        inOrder(node->right);
    }
}
void traverseInOrder(Tree t){
    inOrder(t->root);
}

6.查找某一节点的后继节点

核心思想:主要有两种情况:1.该节点有右子树;2.该节点有右子树;3.最后一个节点(即树中最大节点)

情况1:



对于有右子树的节点,可以找它的右子节点(图中为节点值为10的节点)为根节点的最小节点(图中为值为8的节点)

情况2:


对于没有右子树的节点a(图中值为9的节点),一直往上找到它的父节点或父节点以上节点b(图中为值为5的节点),一直到节点b是它节点b父亲的左孩子,则b节点的父亲(图中为值为11的节点)作为a的后继节点。

情况3:

直接后继返回NULL

代码:

// find the successor node
Node * successor(Node * node) {
    // this node has a right node
    if (node->right) {
        return minimumFromNode(node->right);
    }
    // this node has no right node
    Node * y = node->p;
    Node * x = node;
    while (y != NULL && x == y->right) {
        x = y;
        y = y->p;
    }
    return y;
}

7删除

删除节点主要有如下3种情况

       

情况1:只有左子树,没有右子树

解决:只需要删除节点z并让其左子树和其父亲相连接,最后删除y

情况2;只有右子树,而没有左子树

解决:只需要删除节点z并让其右子树和其父亲相连接,最后删除y

情况3:既有有左子树,又有右子树

解决:找到其后继节点y,并将有的子节点和y的父节点相连,并将y的值替换z的值,最后删除y

代码:

// delete the node in tree
void delete(Tree t, Node *node) {
    Node *y = NULL;
    // node has one sub node at most
    if(node->right != NULL || node->left != NULL) {
        y = node;
    } else {    // the node has twe sub nodes
        y = successor(node);
    }
    // because y has one node at most
    // and find its sub node
    Node * x = NULL;
    if(y->left != NULL) {
        x = y->left;
    } else {
        x = y->right;
    }
    // binds x's parent node
    if(x != NULL) {
        x->p = y->p;
    }

    // x's parent binds x
    if(y->p == NULL) {  // the node, which'll be deleted, is root node
        t->root = x;
    } else if (y == y->p->left) {
        y->p->left = x;
    } else {
        y->p->right = x;
    }
    // if node has two sub nodes, copy the successor key to the node
    // and delete successor which is y
    if (node != y) {
        node->key = y->key;
    }
    // deallocate the memory
    free(y);
    y = NULL;
}




参考

[1]严蔚敏《数据结构(C语言版)》p227


注:若有参考遗漏的,请留言。


代码完全下载

转载请注明

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 二叉搜索树Binary Search Tree):是一棵空树或者具有下列性质的二叉树:若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;它的左右子树也分别为二叉搜索树。 中序遍历序列:对于任意一棵二叉树,中序遍历的结果都是一个序列,这个序列称为中序遍历序列。 因此,判断一棵二叉树是否为二叉搜索树,可以先进行中序遍历,再判断遍历结果是否为升序序列。 以下是 Python 代码实现: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def inorderTraversal(root: TreeNode) -> List[int]: res = [] if not root: return res res.extend(inorderTraversal(root.left)) res.append(root.val) res.extend(inorderTraversal(root.right)) return res def isBST(root: TreeNode) -> bool: res = inorderTraversal(root) for i in range(1, len(res)): if res[i] <= res[i-1]: return False return True ``` 其中,`TreeNode` 是二叉树的节点类,`inorderTraversal` 函数是实现二叉树中序遍历的递归函数,`isBST` 函数是判断二叉树是否为二叉搜索树的函数。 ### 回答2: 要实现这个函数,首先我们可以使用递归的方式对二叉树进行中序遍历,即先遍历左子树,再访问根节点,最后遍历右子树。遍历过程中将遍历到的节点值保存到一个数组中。 接下来,我们需要判断该数组是否是按升序排列的,即判断是否是一棵二叉搜索树。我们可以遍历数组,依次比较相邻的节点值,如果前一个节点的值大于等于后一个节点的值,则认为不是二叉搜索树。反之,如果整个数组都符合这个条件,则认为是一个二叉搜索树。 以下是一个简单的实现代码: ``` class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def inorderTraversal(root): if not root: return [] result = [] inorder(root, result) return result def inorder(root, result): if not root: return inorder(root.left, result) result.append(root.val) inorder(root.right, result) def isBST(root): inorder_result = inorderTraversal(root) for i in range(1, len(inorder_result)): if inorder_result[i] <= inorder_result[i-1]: return False return True ``` 这个函数的时间复杂度是O(n),其中n是二叉树中节点的数量,因为我们需要遍历每个节点并将节点的值保存到数组中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值