一、定义与性质

定义 
  二叉排序树(Binary Sort Tree)又称二叉查找(搜索)树(Binary Search Tree)。其定义为:二叉排序树或者是空树.

性质
  (1) 二叉排序树中任一结点x,其左(右)子树中任一结点y(若存在)的关键字必小(大)于x的关键字。
  (2) 二叉排序树中,各结点关键字是惟一的。
  注意:实际应用中,不能保证被查找的数据集中各元素的关键字互不相同,所以可将二叉排序树定义中BST性质(1)里的"小于"改为"大于等于",或将BST性质(2)里的"大于"改为"小于等于",甚至可同时修改这两个性质。
  (3) 按中序遍历该树所得到的中序序列是一个递增有序序列。


二、插入与删除

       插入与删除操作是二叉排序树中最常用也是最重要的两个操作。

插入过程是:
  (a)若二叉排序树T为空,则为待插入的关键字key申请一个新结点,并令其为根;
  (b)若二叉排序树T不为空,则将key和根的关键字比较:
           (i)若二者相等,则说明树中已有此关键字key,无须插入。
           (ii)若key<T→key,则将key插入根的左子树中。
           (iii)若key>T→key,则将它插入根的右子树中。
  子树中的插入过程与上述的树中插入过程相同。如此进行下去,直到将key作为一个新的叶结点的关键字插入到二叉排序树中,或者直到发现树中已有此关键字为止。

删除过程:

(1) 进行查找
       查找时,令p指向当前访问到的结点,parent指向其双亲(其初值为NULL)。若树中找不到被删结点则返回,否则被删结点是*p。
(2) 删去*p。
       删*p时,应将*p的子树(若有)仍连接在树上且保持BST性质不变。按*p的孩子数目分三种情况进行处理。

删除*p结点的三种情况
         a.*p是叶子(即它的孩子数为0)
       无须连接*p的子树,只需将*p的双亲*parent中指向*p的指针域置空即可。

b.*p只有一个孩子*child
       只需将*child和*p的双亲直接连接后,即可删去*p。
            注意:*p既可能是*parent的左孩子也可能是其右孩子,而*child可能是*p的左孩子或右孩子,故共有4种状态。

c.*p有两个孩子
       先令q=p,将被删结点的地址保存在q中;然后找*q的中序后继*p,并在查找过程中仍用parent记住*p的双亲位置。*q的中序后继*p一定是*q的右子树中最左下的结点,它无左子树。因此,可以将删去*q的操作转换为删去的*p的操作,即在释放结点*p之前将其数据复制到*q中,就相当于删去了*q。


三、代码清单

#include<stdio.h>
#include<stdlib.h>
#define maxSize 20
#define maxWidth 20  typedef int KeyType; //假定关键字类型为整数
typedef struct node { //结点类型KeyType key; //关键字项struct node *lchild,*rchild;//左右孩子指针
} BSTNode,BSTree;
//typedef BSTNode *BSTree; //BSTree是二叉排序树的类型//先序遍历
void preOrder(BSTree *BT)
{  if(BT!= NULL)  {  printf("%d-",BT->key);  preOrder(BT->lchild);  preOrder(BT->rchild);  }
}  //中序遍历
void inOrder(BSTree *BT)
{  if(BT!= NULL)  {  inOrder(BT->lchild);  printf("%d-",BT->key);  inOrder(BT->rchild);  }
}  //后序遍历
void postOrder(BSTree *BT)
{  if(BT!= NULL)  {  postOrder(BT->lchild);  postOrder(BT->rchild);  printf("%d-",BT->key);  }
} //层次法打印二叉排序树
/* 以先序遍历的方式打印二叉排序树 */
void dispTree(BSTree *BT)
{  BSTree *stack[maxSize],*p;  int level[maxSize][2],top,n,i,width=4;  if(BT!=NULL)  {  printf("Display a tree by hollow means.\n");  top=1;  stack[top]=BT;//push root point to stack.  level[top][0]=width;  while(top>0)  {  p=stack[top];  n=level[top][0];  for(i=1;i<=n;i++)  printf(" ");  printf("%d",p->key);  for(i=n+1;i<maxWidth;i+=2)  printf("--");  printf("\n");  top--;  if(p->rchild!=NULL) //右子树先入栈,后出栈 {  top++;  stack[top]=p->rchild;  level[top][0]=n+width;  level[top][1]=2;  }  if(p->lchild!=NULL)  //左子树后入栈,先出栈{  top++;  stack[top]=p->lchild;  level[top][0]=n+width;  level[top][1]=1;  }  //if}  //while}  //if
} //dispTree() /* 向二叉排序树中加入一个结点
要改变指针,需要传递指针的指针*/
/* return 0表示插入成功, return -1表示插入失败 */
int InsertNode(BSTree **tree, KeyType key)
{BSTNode *p= NULL, *parent = NULL;BSTNode *pNewNode = (BSTNode *)malloc(sizeof(BSTNode));if (pNewNode==NULL){return -1;}/* 新建结点赋值,特别是左右子结点指针要赋值为NULL,叶子节点 *//* 二叉排序树新插入的结点都是叶子节点 */ pNewNode->key = key;pNewNode->lchild = NULL;pNewNode->rchild = NULL;/* 二叉排序树是空树 */if (*tree==NULL){*tree = pNewNode;return 0;}else{p = *tree;/* 寻找插入位置 */while (NULL != p) /* 待插入的结点以叶子节点方式插入 */{/* key值已在二叉排序树中 */if (p->key == key){return 0;}else{parent = p;p = (p->key < key) ? p->rchild : p->lchild; //key是待插入结点 }} //while,结束时NULL == p,此时已经到了叶子节点位置 if (parent->key < key){parent->rchild = pNewNode;}else{parent->lchild = pNewNode;} //else return 0;} //else
} //InsertNode //删除节点/* 通过值查找并删除一个结点 */int delNode(BSTree **tree, KeyType key){BSTNode *p = NULL, *q = NULL, *parent = NULL, *child = NULL;p = *tree;/* parent为NULL表示根结点的父亲为NULL */while (NULL != p){if (p->key == key) //此时找到待删除的结点p {break;}else{ parent = p;p = (p->key < key) ? p->rchild : p->lchild;}} //while /* p为NULL时, 表示没有找到结点值为key的结点 */if (NULL == p) /* 到达叶子节点仍未查找到要删除的结点 */ {return -1;}/* p, q现在都是保存了待删结点指针 */q = p; //此时p->key == key /* 待删结点有两个儿子结点,进行一下转化 */if (NULL != p->lchild && NULL != p->rchild){//找中序后继,先右拐,然后左走到底parent = p;p = p->rchild; /* 进入右子树 */while (NULL != p->lchild){parent = p;p = p->lchild;}/* p中保存了待删结点右子树中最左下的结点指针, parent中就保存了该结点父亲指针 */child = p->rchild;}else if(NULL == p -> lchild)child = p -> rchild;elsechild = p -> lchild; /* parent保存待删结点的父亲结点指针, child保存了待删结点的儿子结点//实际删除的是待删节点的直接后继,下面是删除直接后继的过程,(待删结点至多只有一个儿子, 有两个会转化为0个或1个右结点)*/// 待删结点是根结点,且只有一个儿子if (NULL == parent){if(p->lchild!=NULL) *tree = p->lchild;else *tree = p->rchild;}else{/*待删结点是父亲结点的左儿子*/if (parent->lchild == p){parent->lchild = child;}else{parent->rchild = child;}//将实际删除的节点的key值赋给原先要删除的节点if (p != q){q->key = p->key;}}free(p);return 0;} //delNode//二叉排序树查找
BSTNode* SearchBST(BSTree *T,KeyType key)
{ //在二叉排序树T上查找关键字为key的结点,成功时返回该结点位置,否则返回NUllif(T==NULL) //递归的终结条件return NULL; //T为空,查找失败;if(key==T->key)//成功,返回找到的结点位置{printf("Got it!");return T;}if(key<T->key)return SearchBST(T->lchild,key);elsereturn SearchBST(T->rchild,key);//继续在右子树中查找
} //SearchBSTint main()
{int n; BSTree *B=NULL;printf("Input number to initialize a BSTree:");while(1){scanf("%d",&n);if(n==0) break; //遇到0时停止输入,0并不入树 InsertNode(&B, n);}   dispTree(B); printf("PreOrder:");preOrder(B);printf("\n");printf("Search a node:");scanf("%d",&n);SearchBST(B,n);printf("\n");printf("Delete a node:");scanf("%d",&n);delNode(&B,n);dispTree(B); printf("PreOrder:");preOrder(B);printf("\n");system("pause");return 1;
}

四、程序运行结果

出处:http://blog.csdn.net/silangquan/article/details/8065243

二叉排序树的建立、先序/中序/后序遍历、查找相关推荐

  1. 已知一棵二叉树的中序序列和后序序列,写一个建立该二叉树的二叉链表存储结构的算法...

    已知一棵二叉树的中序序列和后序序列,写一个建立该二叉树的二叉链表存储结构的算法 #define N 10 //二叉树节点的个数 char postorderstr[]={};//后序序列 char i ...

  2. 二叉树的构造(前序+中序)---(后序 + 中序)

    二叉树的构造(前序+中序)-(后序 + 中序) 思路:要对前序+中序(后序+中序)的构建树的动态过程要了解,思路比较简单,在了解了这个过程之后,理解下面代码就容易了. 过程 参考图: 前序 + 中序: ...

  3. 非递归先、中、后序遍历二叉树(C语言)

    文章目录 前言 一.二叉树非递归遍历算法 1.先序遍历 2.中序遍历 3.后序遍历 二.完整程序 三.运行结果实例 前言 本程序采用C语言编写,栈和二叉树的基本操作函数基于严蔚敏老师的<数据结构 ...

  4. pandas使用fillna函数并设置bfill参数使用列中的后序值填充缺失值

    pandas使用fillna函数并设置bfill参数使用列中的后序值填充缺失值(replace missing values with following values in column in da ...

  5. Algorithm Gossip (22) 中序式转后序式(前序式)

    前言 This Series aritcles are all based on the book <经典算法大全>; 对于该书的所有案例进行一个探究和拓展,并且用python和C++进行 ...

  6. PAT甲级1020 Tree Traversals:[C++题解]树的遍历、由中序序列和后序序列递归建树

    文章目录 题目分析 题目链接 题目分析 题意重述:给定一棵二叉树的后序遍历序列和中序遍历序列,让求层次遍历的序列. 分析: 后序遍历:先 左子树.右子树 ,最后再遍历根结点. 中序遍历:先左子树,再根 ...

  7. 栈的应用--中序表达式转后序表达式

    栈的应用--中序表达式转后序表达式 infix : a+b*c+(d*e+f)*g postfix : abc*+de*f+g*+ 有以下四种情况: 操作数->直接输出 操作符->将栈顶输 ...

  8. 7-10 先序序列创建二叉树,输出先序序列、中序序列、后序序列并输出叶子结点数 (10 分)

    7-10 先序序列创建二叉树,输出先序序列.中序序列.后序序列并输出叶子结点数 (10 分) 对于给定的二叉树,输出其先序序列.中序序列.后序序列并输出叶子结点数. 输入格式: 二叉树的先序遍历序列. ...

  9. java中二叉树_Java工程师面试1000题224-递归非递归实现二叉树前、中、后序遍历...

    224.使用递归和非递归实现二叉树的前.中.后序遍历 使用递归来实现二叉树的前.中.后序遍历比较简单,直接给出代码,我们重点讨论非递归的实现. class Node { public int valu ...

  10. Algs4-1.3.10中序表达式转为后序表达式(第二次实现)

    1.3.10编写一个过滤器InfixToPostfix,将算术表达式由中序表达式转为后序表达式.  答:本次做这个题时离上次做这个题有一个半月了,已经忘记了当时的算法.经过两个小时的研究(远低于第一次 ...

最新文章

  1. Java8 Stream流递归,几行代码搞定遍历树形结构
  2. 数学之美 系列一 -- 统计语言模型
  3. springboot使用EntityManager执行自定义SQL
  4. How to resolve ASSERTION_FAILED error when you register the odata service expose
  5. SciSharpCube:容器中的SciSharp,.NET机器学习开箱即用
  6. Jan 09 - Count Primes; Mathematics; Optimization; Primes; DP;
  7. Linux课程第二十四天学习笔记
  8. css3ps—ps直接生成css3 使用方法
  9. Paper 已经过时——计算机时代科学传播方式的变革
  10. 什么是运维工程师?运维工程师应该具备的素质
  11. 2021动画渲染农场排名出炉,渲染101综合领先,赛诚和瑞云Renderbus紧随其后!
  12. 基于python的招聘信息可视化系统
  13. Flak 自定义URL转换器
  14. 采用两块半球体U235金属的原子弹
  15. 【线上活动】中秋诗词接龙!
  16. 套料排版代码python_钣金制造管理系统Fabcost自动套料排版设置
  17. 学习1368个单词 - 有关物和人的名词
  18. Java多线程--并发中集合的使用PriorityBlockingQueue
  19. 埃森哲java开发怎么样_花费2亿,耗时2年,网站还没建完,咨询公司埃森哲被告上法庭!...
  20. Excel工资表通过宏的录制形成工资条形式

热门文章

  1. 30年来我只坚持三件事
  2. elementui表格复制_Element-UI中关于table表格的那些骚操作
  3. Spring-AOP @AspectJ进阶之访问连接点信息
  4. 用计算机弹剪刀刺客,刺客伍六七:阿七使用过的四种武器,剪刀最常用,这个需要臂力!...
  5. linux7 security,SECURITY-centos7下NFS使用与配置
  6. java消息通信_原生 Java 客户端进行消息通信
  7. Error: vue-loader requires @vue/compiler-sfc to be
  8. php ca 校验,PHP和SSL CA验证 – 操作系统独立
  9. js json对象转字符串_Mock.js模拟数据实现前端独立开发
  10. Kotlin1.6.20好用的新特性:多receiver扩展函数,绝不可空类型,并行编译kotlin减少编译时间