先给出BST树的概念
二叉查找树(Binary Search Tree),简写BST,是满足某些条件的特殊二叉树。任何一个节点的左子树上的点,都必须小于当前节点。任何一个节点的右子树上的点,都必须大于当前节点。任何一棵子树,也都满足上面两个条件。另外二叉查找树中,是不存在重复节点的。
简单来说,BST树也就是一种特殊的二叉树,可以满足所有的子树的左边子树的所有数据均小于树根节点,所有右边子树均大于树根节点,这样对于一个需要查找的 x ,只需要在查找过程中判断与当前所在节点的大小关系,再决定查找方向,就可以在Ologn的复杂度之下完成完成查找。
下面探讨如何生成一棵BST树:
首先BST树上面是不存在重复的节点的,那么决定是否插入一棵一个节点的条件应该是这棵树上面没有这个节点,那么就需要用到查找的操作,通过查找判断有没有这个值。
先来看查找:
确定一棵树的节点也就是根节点root,这里设定在查找过程中parent始终指向当前查找节点的节点,初始指向root的上一级,初值NULL,p存储返回的节点,也就是需要插入值的节点的前驱,到时候找到了就插在这个p节点后面。
下面是会遇到的几种情况:
进入查找,如果当前节点就是需要查找的值,那么不用考虑插值了,查找情况返回True,表示找到了,无需操作。
如果当前指针为空,那么可以料想到已经走到最后了,因为这时候已经无路可走了,也就是找不到,返回False,将这个节点的前驱 parent 返回。
如果上面情况不满足,那么根据树的定义,对于当前节点,左边的都是小的,右边的都是大的,那么跟需要查找的值x比较,如果x大了,那么就去右子树上面找,小了就去左子树上面找。
函数
bool find(ptr pNow, int x, ptr parent, ptr &p) {
if (pNow == NULL) {
p = parent;//返回上一级节点
return 0;//找不到
}
else if (pNow->data == x) {//找到了
p = pNow;
return 1;
}
else if (pNow->data < x) {//去右边找
return find(pNow->rchild, x, pNow, p);
}
else {
return find(pNow->lchild, x, pNow, p);
}
}
接下来就是插入节点,上面说到了通过查找已经返回了需要新建节点的前驱p,那么这时候只要考虑要插在左边还是右边,根据定义,如果x大于节点值,那么插在左边,否则在右边,要注意新建节点之后最好把左右指针赋值为NULL,不然似乎默认不是NULL,会导致一些判断失效。
还有一个需要注意的就是root节点,想象一下什么时候返回值p都是空,只有整棵树为空的时候,这时候比较特殊的是要修改root节点,单独讨论好了。
//将节点放入BST树
if (p == NULL) {//返回的指针都为空,那么整棵树为空,那么需要修改根节点
root = (ptr)malloc(Size);
root->data = x;
root->lchild = NULL;
root->rchild = NULL;
}
else {//否则将该节点插入返回的节点之后
ptr px = (ptr)malloc(Size);//创建新节点
px->data = x;
px->lchild = NULL;
px->rchild = NULL;//初始化
if (x > p->data) {//要在右边
p->rchild = px;
printf("成功将%d插入到%d节点的右边\n",x,p->data);
}
else {
p->lchild = px;
printf("成功将%d插入到%d节点的左边\n",x,p->data);
}
}
完整代码
#include<stdio.h>
#include<stdlib.h>
#define Size sizeof(TreeNode)
typedef struct TreeNode {
int data;
TreeNode *lchild, *rchild;
}TreeNode, *ptr;
bool find(ptr pNow, int x, ptr parent, ptr &p) {
if (pNow == NULL) {
p = parent;//返回上一级节点
return 0;//找不到
}
else if (pNow->data == x) {//找到了
p = pNow;
return 1;
}
else if (pNow->data < x) {//取右边找
return find(pNow->rchild, x, pNow, p);
}
else {
return find(pNow->lchild, x, pNow, p);
}
}
int main()
{
int num = 0;//记录数量
ptr root = NULL;
int n; scanf("%d", &n);
int x;
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
ptr p, parent = NULL;//p存储节点位置,parent存储父亲节点,
if (find(root, x, parent, p)) {
;//可以找到就不用插入节点
printf("已经有该节点%d了\n",x);
}
else {
num++;//多了一个节点
//将节点放入BST树
if (p == NULL) {//返回的指针都为空,那么整棵树为空,那么需要修改根节点
root = (ptr)malloc(Size);
root->data = x;
root->lchild = NULL;
root->rchild = NULL;
}
else {//否则将该节点插入返回的节点之后
ptr px = (ptr)malloc(Size);//创建新节点
px->data = x;
px->lchild = NULL;
px->rchild = NULL;//初始化
if (x > p->data) {//要在右边
p->rchild = px;
printf("成功将%d插入到%d节点的右边\n",x,p->data);
}
else {
p->lchild = px;
printf("成功将%d插入到%d节点的左边\n",x,p->data);
}
}
}
}
printf("整棵树共%d个节点\n", num);
return 0;
}
演示