二叉排序树(BST)构造与应用

     
本文取自《数据结构与算法》(C语言版)(第三版)。出版社是清华大学出版社。

      本博文作为学习资料整理。

源码是VC++ 6.0上可运行程序,我挪到了VS2010中运行。

在VS2010中新建C++ Win32 控制台应用程序项目,创建结果截图:

    二叉排序树(BST):又称二叉查找树,其定义为:二叉排序树或者是空树,或者是满足下面性质的二叉树。

       (1) 若它的左子树非空。则左子树上全部记录的keyword均小于根记录的值。

(2) 若它的右子树非空,则右子树上全部记录的keyword均大于根记录的值。

(3) 左、右子树本身又各是一棵二叉排序树。

       按中序遍历BST所得到的中序序列是一个递增有序序列。

二叉排序树的类型定义:

 typedef struct BSTNode
{
KeyType key; //数据域
BSTNode *lchild;
BSTNode *rchild;
}

1.二叉排序树的插入操作

       (1)假设二叉排序树T为空,则创建一个keyword为k的结点。将其作为根结点。

(2)否则将k和根结点的keyword进行比較,假设相等则返回,假设k小于根结点的keyword则插入根结点的左子树中,否则插入根结点的右子树中。

二叉排序树的插入算法:

   int InsertBST(BSTNode *p, KeyType k)
{
if(p==NULL)
{
p=(BSTNode*)malloc(sizeof(BSTNode));
p->key=k;
p->lchild=p->rchild=NULL;
return 1;
}
else if(k==p->key)
return 0;
else if(k<p->key)
return InsertBST(p->lchild, k);
else
return InsertBST(p->rchild, k);
}

二叉排序树的生成算法:

   BSTNode *CreateBST(KeyType A[], int n)
{
BSTNode *bt=NULL;
int i=0;
while(i<n)
{
InsertBST(bt, A[i]);
i++;
}
return bt;
}

演示样例:输入{50,16,56,52,8}生成二叉排序树

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

       2.二叉排序树的查找操作

       首先将须要查找的值与根结点比較,假设相等则查找成功,算法终止。假设比根结点小则左子树中查找,假设比根结点大则到右子树查找。

       二叉排序树的查找算法的递归形式

   BSTree SearchBST(BSTree t, int k)
{
if(t==null || k==t->key)
return t;
else if(k<t->key)
return SearchBST(t->lchild, k);
else
return SearchBST(t->rchild, k);
}

二叉排序树的查找算法的非递归形式

   BSTree SearchBST2(BSTree t, int k)
{
BSTree p=t;
while(p!=null && p->key!=k)
{
if(k<p->key)
p=p->lchild;
else
p=p->rchild;
}
return p;
}

查找过程演示图:

      3.二叉排序树的删除操作

删除二叉排序树的某一个结点的过程例如以下:

        1)查找待删除的结点

         查找结点时,令*p指向其訪问到的结点,*f指向其双亲结点。若树中找不到被删结点时返回NULL,否则被删除结点是*p,返回*p。

        2)删除结点

        如果要删除二叉排序树中的一个结点*p,其双亲结点为*f,则删除结点*p时,需考虑下面3种情况:

           (1)*p为叶子结点。

           在这样的情况下,能够将*p结点直接删除。

           p为左子树:

                              f->lchild=NULL;

                              free(p);

           p为右子树:

                              f->rclild=NULl;

free(p);

操作示意图例如以下:

(2)*p仅仅有左子树,或仅仅有右子树。

            对于这样的情况,能够直接将*p的左子树或右子树与其双亲结点*f相连,然后删除*p。

            p为f的左孩子。p的左子树非空:

                             f->lchild=p->lchild;

                             free(p);

            p为f的左孩子。p的右子树非空:

                             f->lchild=p->rchild;

                             free(p); 

            p为f的右孩子,p的左子树非空:

                             f->rchild=p->lchild;

                             free(p);

            p为f的右孩子,p的右子树非空:

                             f->rchild=p->rchild;

free(p);

操作示意图例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

(3)*p有左右子树。

方法一:设*s为*p结点在中序序列中的直接前驱。将*p的左子树改为*f的左子树,将*p的右子树改为*s的右子树。

f->lchild=p->lchild;

                      s->rchild=p->rchild;

free(p);

操作示意图例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

方法二:用*p结点在中序序列中的直接前驱(或后继)*s取代*p,然后再从二叉排序树中将*s删除。

这时假设*s为*p的直接前驱,则*s仅仅有左子树(或者没有孩子),则删除*s能够依照删除*p的其余两种情况处理。假设*s为*p的直接后继,则*s仅仅有右子树(或者没有孩子)。删除*s同理能够依照删除*p的其余两种情况处理。

附录

A.二叉排序树的构造算法:

注:判定一棵二叉树是二叉排序树能够採用中序遍历算法将树上的顶点输出。假设得到的中序序列是有序的。则说明这棵二叉树是二叉排序树,否则不是二叉排序树。

  #include<stdio.h>
#include<stdlib.h>
#define MAX 100
typedef struct tnode
{
int data;
struct tnode *lchild, *rchild;
}TNODE; void create();
void insert(int m); //插入二叉排序树的结点
void inOrder(TNODE *ptr); //中序遍历 TNODE *root=NULL; void inOrder(TNODE *ptr)
{
if(ptr!=NULL)
{
inOrder(ptr->lchild);
printf("%d ", ptr->data);
inOrder(ptr->rchild);
}
} void create()
{
int n, i;
int k[MAX];
printf("Please input the node number:\n");
scanf("%d", &n);
for(i=0; i<n; i++)
scanf("%d",&k[i]);
for(i=0; i<n; i++)
insert(k[i]);
} void insert(int m)
{
TNODE *p1, *p2;
if(root==NULL)
{
root=(TNODE *)malloc(sizeof(TNODE));
root->data=m;
root->lchild=root->rchild=NULL;
}
else
{
p1=root;
while(m!=p1->data)
{
if((m<p1->data) && (p1->lchild!=NULL))
p1=p1->lchild;
else if((m>p1->data) && (p1->rchild!=NULL))
p1=p1->rchild;
else if((m<p1->data) && (p1->lchild==NULL))
{
p2=(TNODE *)malloc(sizeof(TNODE));
p2->data=m;
p2->lchild=p2->rchild=NULL;
p1->lchild=p2;
return;
}
else if((m>p1->data) && (p1->rchild==NULL))
{
p2=(TNODE *)malloc(sizeof(TNODE));
p2->data=m;
p2->lchild=p2->rchild=NULL;
p1->rchild=p2;
return;
}
}
}
} int main()
{
create();
printf("\n");
inOrder(root);
printf("\n");
return 0;
}

Ctrl+F5执行SortTree.cpp输出结果例如以下:

B.求出二叉排序树T中小于x的最大元素和大于x的最小元素

在二叉排序树中。一个小于树中某个结点的最大元素,是在中序序列中这个结点的直接前驱;大于这个

结点的最小元素,是在中序序列中这个结点的直接后继。

      其程序例如以下:

 #include<stdio.h>
#include<stdlib.h>
#define MAX 100
typedef struct tnode
{
int data;
struct tnode *lchild, *rchild;
}TNODE; int last=0;
void create();
void insert(int m); //插入二叉排序树的结点
void findMaxMin(int aim, TNODE *ptr); TNODE *root=NULL; void findMaxMin(int aim, TNODE *ptr)
{
if(ptr!=NULL)
{
findMaxMin(aim, ptr->lchild);
if(last<aim && ptr->data>=aim) //找到小于aim的最大元素
printf("a=%d\n",last);
if(last<=aim && ptr->data>aim) //找到大于aim的最小元素
printf("b=%d\n",ptr->data);
last=ptr->data;
findMaxMin(aim, ptr->rchild);
}
} void create()
{
int n, i;
int k[MAX];
printf("Please input the node number:\n");
scanf("%d", &n);
for(i=0; i<n; i++)
scanf("%d",&k[i]);
for(i=0; i<n; i++)
insert(k[i]);
} void insert(int m)
{
TNODE *p1, *p2;
if(root==NULL)
{
root=(TNODE *)malloc(sizeof(TNODE));
root->data=m;
root->lchild=root->rchild=NULL;
}
else
{
p1=root;
while(m!=p1->data)
{
if((m<p1->data) && (p1->lchild!=NULL))
p1=p1->lchild;
else if((m>p1->data) && (p1->rchild!=NULL))
p1=p1->rchild;
else if((m<p1->data) && (p1->lchild==NULL))
{
p2=(TNODE *)malloc(sizeof(TNODE));
p2->data=m;
p2->lchild=p2->rchild=NULL;
p1->lchild=p2;
return;
}
else if((m>p1->data) && (p1->rchild==NULL))
{
p2=(TNODE *)malloc(sizeof(TNODE));
p2->data=m;
p2->lchild=p2->rchild=NULL;
p1->rchild=p2;
return;
}
}
}
} int main()
{
int toBeFind;
create();
printf("\n");
printf("Input the record to be finded! \n");
scanf("%d", &toBeFind);
findMaxMin(toBeFind, root);
printf("\n");
return 0;
}

Ctrl+F5执行SortTree1.cpp输出结果例如以下:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

二叉排序树(BST)构造与应用的更多相关文章

  1. 二叉排序树(BST)创建,删除,查找操作

    binary search tree,中文翻译为二叉搜索树.二叉查找树或者二叉排序树.简称为BST 一:二叉搜索树的定义 他的定义与树的定义是类似的,也是一个递归的定义: 1.要么是一棵空树 2.如果 ...

  2. 二叉排序树的构造 && 二叉树的先序、中序、后序遍历 && 树的括号表示规则

    二叉排序树的中序遍历就是按照关键字的从小到大顺序输出(先序和后序可没有这个顺序) 一.以序列 6 8 5 7 9 3构建二叉排序树: 二叉排序树就是中序遍历之后是有序的: 构造二叉排序树步骤如下: 插 ...

  3. 哈夫曼树;二叉树;二叉排序树(BST)

    优先队列:priority_queue<Type, Container, Functional>Type 为数据类型, Container 为保存数据的容器,Functional 为元素比 ...

  4. 【数据结构】简单谈一谈二分法和二叉排序树BST查找的比较

    二分法查找: 『在有序数组的基础上通过折半方法不断缩小查找范围,直至命中或者查询失败.』   二分法的存储要求:要求顺序存储,以便于根据下标随机访问   二分法的时间效率:O(Log(n))   二分 ...

  5. 二叉排序树BST代码(JAVA)

        publicclassTest{     publicstaticvoid main(String[] args){         int[] r =newint[]{5,1,3,4,6,7 ...

  6. 二叉排序树BST+求树深度算法

    #include "stdio.h" #include "malloc.h" typedef struct node { int key; struct nod ...

  7. 判断二叉树是否二叉排序树(BST)

    算法思想:由于二叉排序树的中序遍历可以得到一个有序的序列,因此,我们可以使用中序遍历进行求解. 代码如下: #include <stack> using namespace std; ty ...

  8. 二叉排序树BST

    注意:对一个二叉排序树进行中序遍历时,得到的序列是一个按值从小到大排列的有序序列 查找性能的分析:

  9. 关于二叉排序树 BST

    #include<stdio.h> #include<stdlib.h> typedef struct node { double w; struct node *l,*r; ...

随机推荐

  1. 让盒子两端对齐小技巧 => inline-block

    今天在项目中碰到了设计盒子两端对齐的栗子,咱们用inline-block方法轻松的解决了,下面是我的经验: 原理: 利用文字text-align:justify; 操纵inline-block盒子,能 ...

  2. javascript 二维(多维)数组的复制问题

    最近在项目中遇到一个动画暂停的效果,需要在动画停止的时候检测当前坐标和已经运行的时间,从而调节时间轴为再次运行时加速. 但是在数组保存方面折腾了半天. var orbitArray = [], lin ...

  3. 通讯框架 t-io 学习——websocket 部分源码解析

    前言 前端时间看了看t-io的websocket部分源码,于是抽时间看了看websocket的握手和他的通讯机制.本篇只是简单记录一下websocket握手部分. WebSocket握手 好多人都用过 ...

  4. 准备冲锋 golang入坑系列

    史前摘要: 本来想写读前必读,但连续几篇博文都写读前必读,感觉就没有了新意. 所以换成史前摘要,反正是一个意思. 此摘要的目的仍然是提醒点击而来的同学,本系列最新文章在这里.放到博客园的目的是为了方便 ...

  5. LKD: Chapter 5 System Call

    在Linux中,处理器所作的事可以归纳为3种情况: 1.In user-space, executing user code in a process; 2.In kernel-space, in p ...

  6. 书籍推荐系列之一 -- 《凤凰项目:一个IT运维的传奇故事》

    博客已经完全更新了名字,新的名字,新的开始,想让自走向新的道路是很难的,走出舒适圈说了好久,也是时候开始行动了,今天就从写博客开始. 今天给大家推荐一本书,<凤凰项目:一个IT运维的传奇故事&g ...

  7. Ubuntu安装pyenv实现多版本控制

    Ubuntu安装pyenv实现多版本控制 git clone git://github.com/yyuu/pyenv.git ~/.pyenv echo 'export PYENV_ROOT=&quo ...

  8. tcp并发服务器(c20w)

    ** 原创文章,请勿转载 ** 并发服务器是一个老生常谈的话题,今天这里也写一个. 1. 目标: 同时在线连接20万(c20w). 开发语言:重要的事情说三遍,GOLANG, GOLANG, GOLA ...

  9. border-radio属性

    boreder-radio属性是css3的新增属性,可以设置圆角的边框. <head>  <style type="text/css"> *{ margin ...

  10. 罗培羽—C语言简单游戏编程教学

    编写许多软件都需要有菜单,那么如果我们使用tc之类的软件来编译程序的话,我们该怎么编写菜单呢?让我们一起来试试吧!第一步:简单例子       我们先来写个最简单的例子:#include<std ...