二叉排序树(Binary Sort Tree)或者是一棵空树;或者是具有下列性质的二叉树:(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;(3)左、右子树也分别为二叉排序树;
中文名称 | 二叉排序树 | 外文名称 | Binary Sort Tree |
---|---|---|---|
别 称 | 二叉查找树、二叉搜索树 | 别称外文名 | Binary Search Tree |
若根结点的关键字值等于查找的关键字,成功。
否则,若小于根结点的关键字值,递归查左子树。
若大于根结点的关键字值,递归查右子树。
若子树为空,查找不成功。
插入算法:
首先执行查找算法,找出被插结点的父亲结点。
判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。
若二叉树为空。则首先单独生成根结点。
注意:新插入的结点总是叶子结点。
void InsertBST(t,key)
//在二叉排序树中插入查找关键字key
{
if(t==NULL){
t=new BiTree;
t->lchild=t->rchild=NULL;
t->data=key;
return; }
if(keydata ) InsertBST(t->lchild,key);
else InsertBST (t->rchild, key );
}
void CreateBiTree(tree,d【 】,n)
//n个数据在数组d中,tree为二叉排序树根
{tree=NULL;
for(i=0;i InsertBST(tree,d);
}
击【分部整理】,会显示下方窗口,如图一: 钩选分部规则后点击“执行分部整理”即可。 点击【分部整理】,会显示下方窗口,如图二: 点击“执行子目排序”即可
使用08定额,建筑与装饰最好分开(分两个预算)做,就不会出现借用定额的代号了,直接点分部整理即可排序,如果不想分为两个预算,装饰部分可以按鼠标右键插入分部输入编号、分部名称,然后将该分部的子目用上下移...
二叉树在计算机科学中,二叉树是每个结点最多有两个子树的有序树。通常子树的根被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用作二叉查找树和二叉堆。二叉...
分层模式在软件开发中有着广泛的应用,必然使各层之间产生频繁的数据交互,从而导致软件性能大大下降。针对上述问题,本文提出一种基于有序二叉树的变量池的解决方案,软件的配置信息以及各层之间的交互数据保存在变量池中,对变量的所有操作都基于变量池,通过变量池的使用,既方便了各层之间数据交互,也简化了各层之间的接口设计。基于该方案,本文最后实现了一个银行自助终端系统。
第 8 章 排序 1.选择题 ( 1)从未排序序列中依次取出元素与已排序序列中的元素进行比较, 将其放入已排序序 列的正确位置上的方法,这种排序方法称为( )。 A.归并排序 B.冒泡排序 C.插入排序 D.选择排序 答案: C ( 2)从未排序序列中挑选元素,并将其依次放入已排序序列(初始时为空)的一端的方 法,称为( )。 A.归并排序 B.冒泡排序 C.插入排序 D.选择排序 答案: D ( 3)对 n 个不同的关键字由小到大进行冒泡排序,在下列( )情况下比较的次数最 多。 A.从小到大排列好的 B.从大到小排列好的 C.元素无序 D.元素基本有序 答案: B 解释:对关键字进行冒泡排序,关键字逆序时比较次数最多。 ( 4)对 n 个不同的排序码进行冒泡排序, 在元素无序的情况下比较的次数最多为 ( )。 A. n+1 B. n C. n-1 D. n(n-1)/2 答案:
1.二叉排序树的概念:
二叉排序树是一种动态树表。
二叉排序树的定义:二叉排序树或者是一棵空树,
或者是一棵具有如下性质的二叉树:
⑴ 若它的左子树非空,则左子树上所有结点的值均小于根结点的值;
⑵ 若它的右子树非空,则右子树上所有结点的值均大于根结点的值;
⑶ 左、右子树本身又各是一棵二叉排序树。二叉排序树的性质: 按中序遍历二叉排序树,所得到的中序遍历序列是一个递增有序序列。
2.二叉排序树的插入:
在二叉排序树中插入新结点,要保证插入后的二叉树仍符合二叉排序树的定义。
插入过程:若二叉排序树为空,则待插入结点*S作为根结点插入到空树中;
当非空时,将待插结点关键字S->key和树根关键字t->key进行比较,
若s->key = t->key,则无须插入,若s->key< t->key,则插入到根的左子树中,
若s->key> t->key,则插入到根的右子树中。而子树中的插入过程和在树中的插入过程相同,
如此进行下去,直到把结点*s作为一个新的树叶插入到二叉排序树中,或者直到发现树已有相同关键字的结点为止。
3. 二叉排序树生成:
从空的二叉排序树开始,经过一系列的查找插入操作以后,生成了一棵二叉排序树。
说明:
① 每次插入的新结点都是二叉排序树上新的叶子结点。
② 由不同顺序的关键字序列,会得到不同二叉排序树。
③ 对于一个任意的关键字序列构造一棵二叉排序树,其实质上对关键字进行排序。
4.二叉排序树查找的程序实现:
5. 二叉排序树的删除:
假设被删结点是*p,其双亲是*f,不失一般性,设*p是*f的左孩子,下面分三种情况讨论:
⑴ 若结点*p是叶子结点,则只需修改其双亲结点*f的指针即可。
⑵ 若结点*p只有左子树PL或者只有右子树PR,则只要使PL或PR 成为其双亲结点的左子树即可。
⑶ 若结点*p的左、右子树均非空,先找到*p的中序前趋结点*s(注意*s是*p的左子树中的最右下的结点,它的右链域为空),然后有两种做法:
① 令*p的左子树直接链到*p的双亲结点*f的左链上,而*p的右子树链到*p的中序前趋结点*s的右链上。
② 以*p的中序前趋结点*s代替*p(即把*s的数据复制到*p中),将*s的左子树链到*s的双亲结点*q的左(或右)链上。
6. 删除算法演示 :
7. 二叉排序树的查找:
在二叉排序树中进行查找的过程和二分查找类似,也是一个逐步缩小查找范围的过程。若查找成功,则是走了一条从根结点到待查结点的路径;若查找失败,则是走了一条根结点到某个叶子结点的路径。因此,查找过程中和关键字比较的次数不超过树的深度。
由于含有n个结点的二叉排序树不唯一,形态和深度可能不同。故含有n个结点的二叉排序树的平均查找长度和树的形态有关。
最好的情况是: 二叉排序树和二叉判定树形态相同。
最坏的情况是: 二叉排序树为单支树,这时的平均查找长度和顺序查找时相同。
最坏情况示例
就平均性能而言,
二叉排序树上的查找和二分查找相差不大,并且二叉排序树上的插入和删除结点十分方便,无须大量移动结点。
二叉排序树查找
二叉排序树(Binary Sort Tree:BST)
1、二叉排序树的定义
二叉排序树(Binary Sort Tree)又称二叉查找(搜索)树(Binary Search Tree)。其定义为:二叉排序树或者是空树,或者是满足如下性质的二叉树:
①若它的左子树非空,则左子树上所有结点的值均小于根结点的值;
②若它的右子树非空,则右子树上所有结点的值均大于根结点的值;
③左、右子树本身又各是一棵二叉排序树。
上述性质简称二叉排序树性质(BST性质),故二叉排序树实际上是满足BST性质的二叉树。
2、二叉排序树的特点
由BST性质可得:
(1) 二叉排序树中任一结点x,其左(右)子树中任一结点y(若存在)的关键字必小(大)于x的关键字。
(2) 二叉排序树中,各结点关键字是惟一的。
注意:
实际应用中,不能保证被查找的数据集中各元素的关键字互不相同,所以可将二叉排序树定义中BST性质(1)里的"小于"改为"小于等于",或将BST性质(2)里的"大于"改为"大于等于",甚至可同时修改这两个性质。
(3) 按中序遍历该树所得到的中序序列是一个递增有序序列。
【例】下图所示的两棵树均是二叉排序树,它们的中序序列均为有序序列:2,3,4,5,7,8。
3、二叉排序树的存储结构
typedef int KeyType; //假定关键字类型为整数
typedef struct node { //结点类型
KeyType key; //关键字项
InfoType otherinfo; //其它数据域,InfoType视应用情况而定,下面不处理它
struct node *lchild,*rchild,*parent; //左右孩子指针
} BSTNode;
typedef BSTNode *BSTree; //BSTree是二叉排序树的类型
二叉排序树的基本操作(pascal):
1.中序遍历所有元素
procedure tree_walk(x:longint);
begin
if x<>0 then
begin
tree_walk(left[x]);
write(key[x]);
tree_walk(right[x]);
end;
2.查找给定的元素
function tree_search(x,k:longint):longint;
begin
if (x=0) or (k=key[x]) then exit(x);
if k end; 非递归版本 function tree_search(x,k:longint):longint; begin while (x<>0) and (k<>key[x]) do begin if k end; exit(x); end; 3.查找最小元素 function tree_minimum(x:longint):longint; begin while left[x]<>0 do x:=left[x]; exit(x); end; 查找最大元素 function tree_maximum(x:longint):longint; begin while right[x]<>0 do x:=right[x]; exit(x); end; 4. 求后继 function tree_successor(x:longint):longint; var y:longint; begin if right[x]<>0 then exit(tree_minimum(right[x]));//若右子树不空,则返回右子树中的最小值 y:=p[x];//若右子树为空,则后继y为x的最低祖先节点,且y的左儿子也是x的祖先 while (y<>0) and (x=right[y]) do begin x:=y; y:=p[y]; end; exit(y);//注意,若y为0,则x无后继 end; //注意,函数返回值为节点编号,并不是节点本身的值 5.插入 procedure tree_insert(z:longint);//注意z为节点编号,并非树中的值 var x,y:longint; begin y:=0; x:=root; while x<>0 do//查找z的父节点,y记录 begin y:=x; if key[z] end; p[x]:=y; if y=0 then root:=z//若z为根节点 else begin if key[z] end; end; 6.删除 删除操作是最麻烦的,分3种情况: (1)若z无子树,则就删除z节点,更新p[z]的值为空 (2)若z有一个子树,删除z节点,更新p[z]的值为z的儿子节点,更新left[p[z]] 或 right[p[z]] (3)若z有两棵子树,先找到z的后继y(后继节点无左子树,可证),删除y节点,更新p[y]与left[p[y]] 或 right[p[y]],最后用节点y的数据覆盖z节点 procedure tree_delete(z:longint); var x,y:longint; begin if (left[z]=0) or (right[z]=0) then y:=z else y:=tree_successor(z); if left[y]<>0 then x:=left[y] else x:=right[y]; if x<>0 then p[x]:=p[y]; if p[y]=0 then root:=x else begin if y=left[p[y]] then left[p[y]]:=x else right[p[y]]:=x; end; if z<>y then key[z]:=key[y]; end; 7.查找数中第k大元素 需要对每个节点新开一个域v[x],记录该节点的有多少子节点, 查找时分三种情况: (1)k=v[left[x]] 1 则当前x节点为所求 (2)k<=v[left[x]] 则在左子树中继续查找 (3)k>v[left[x]] 1 则在右子树中继续查找,k更新为k-left[x]-1; function find(x,k:longint):longint; begin if v[left[x]] 1=k then exit(key[k]) else if v[left[x]]>=k then exit(find(left[x],k)) else exit(find(right[x],k-v[left[x]]-1)); end;