数据结构二叉排序树.ppt
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.查找关键字k=21 的情况 (1) low:=1;high:=11;mid:=(1+11) div 2=6
05 13 19 21 37 56 64 75 80 88 92
low
mid
high
因为r[mid].key>k,所以向左找,令high=mid-1=5
(2) low=1;high=5;mid=(1+5) / 2=3
★ 基本概念 查找表:是一种以集合为逻辑结构,以查找为核心运算,
同时包括其他运算的数据结构。
关键字:用来标识数据元素的数据项,简称键。
主关键字:可以唯一标识一个数据元素的关键字。
次关键字:可以标识若干数据元素的关键字。
查找:根据某个给定的K值,在查找表中寻找 一 个键值等于K的元素,若找到这样的元素, 则称查找成功,此时的运算结果为该数据元 素在查找表中的位置,否则称查找不成功, 运算结果为一特殊标志。
while (r[i]!=k) i++; if (i<n) printf(“succ, i=%d”,i);//查找成功,i指示待查元素在表中位置 else printf(“unsucc”);//i=n时表明查找不成功 }
平均查找长度:为确定某元素在表中某位置所进行的比 较次数的期望值。
在长度为n的表中找某一元素,查找成功的平均查找长度:
★ 动态查找表
二叉排序树:或者是一棵空树,或者是具有下列 性质的二叉树:1)若它的左子树不空,则它的左 子树上所有结点的值均小于根结点的值;2)若它 的右子树不为空,则它的右子树上所有结点的值 均大于或等于它的根结点的值;3)它的左、右子 树均为二叉排序树。 二叉排序树的构造方法:
设R={R1,R2,…,Rn}为一数列,按下面的原则建立二叉树: 1)令R1为二叉树的根; 2)若R2<R1,则令R2为R1的左子树的根结点,否则令R2为
RL型的第二次旋转(逆时针)
一般情况下,假设由于二叉排序树上插入结点而失去 平衡的最小子树的根结点指针为a(即a是离插入结点最 近,且平衡因子绝对值超过1的祖先结点),则失去平衡 后进行调整的规律可归纳为下列四种情况:
⒈RR型平衡旋转:
a -2 h-1 a1 b -1
h-1 b1 br h 插入节点
a2
2a
-1 b ar h-1 h-1 b1 1 c
LR(逆时针)
2 c ar h-1 0 b cr h-2
c1 cr h-2 h-1
h-1 bl c1 h-1
再以c为轴心,把a从c的左上方转到c的右下方,使得
c的右是a,左是b,原c的右子树变成a的左。
2a
2c
ar h-1
0c 0 b a -1
0 b cr h-2
R1的右子树的根结点; 3)对R3,R4,…Rn重复上述步骤2);
二叉排序树的平衡化
假设表中的关键字序列为(13,24,37,90,53) ①空树和一个结点 13 的二叉树显然是平衡二叉树 . ②插入24后仍平衡 13 -1
24 0
③插入 37 后结点 13的平衡因子为0-2=-2,不平衡
13 -2
low=1; high=n;//置初值 while(low<=high) { mid=(low+high)/2;
if (k==r[mid].key) {printf(“succ i=%d\n”,mid);break;} else if ( k>r[mid].key) { low=mid+1;//向右找 if (low>high){ printf("no succ\n");break; } }
查找表
1.建表:Create(st)
静态查找表 2.查找:Search(st,k)
3.读表元:Get(st,pos)
1.初始化:Initiate(st) 2.查找:Search(st,k)
动态查找表 3.读表元:Get(st,pos)
4.插入:Insert(st,k) 5.删除:Delete(st,k)
顺序查找过程:假定该查找表有n个记录,首先将要查找 的那个关键字赋给实际上并不存在的第n个记录的关键 字域(0..n-1存放数据) ,然后从头开始一个一个的向下查 找,用i来计数,查到就送出来看i是第几个,若i<=n, 则查找成功,若i=n则查找失败。
void seqsrch(sqtable r,keytype k) //在长度为n的表r中查找关键字为k的元素,r[n]为表尾的扩充; i指示查找结果 { r[n].key=k; i=0;//给监督哨赋值
05 13 19 21 37 56 64 75 80 88 92
low
mid
high
因为r[mid].key<k,所以向右找,令low:=mid+1=4
(3) low=4;high=5;mid=(4+5) div 2=4
05 13 19 21 37 56 64 75 80 88 92
low mid high
把 24 从 13 的右下侧
24 -1
左转到 13 的右上侧
37 0
原来 24 的左为 13 的右, 新的 24 的左为 13
RR型即逆时针旋转
24 13 37
④插入90,53后,又失去平衡, 可经过下列步骤转化为平衡二叉树
24 _ 2
0 13
37 _ 2
90 1
24 13 37
53
24 13 53
⑴在查找s节点的插入位置的过程中,记下离s节点最近, 且平衡因子不等于0的节点,令指针a指向该节点。 ⑵修改自a到s的路径上所有的节点的平衡因子值; ⑶判别树是否失去平衡,即在插入节点之后,a节点的平 衡因子的绝对值是否大于1,若是,则需要判别旋转类型, 并做相应处理,否则插入过程结束。
void AVL-insert(x,y,t) //把标志符x插入树根为t的AVL树中。设每个结点具有 四个域:data、Lchild、Rchild和一个2位的平衡因子 bf。将y置成y->data=x,t=NULL
(2) low=7;high=11;mid=(7+11) / 2=9
05 13 19 21 37 56 64 75 80 88
low
mid
因为r[mid].key<k,所以向右找,令low:=mid+1=10
(3) low=10;high=11;mid=(10+11) / 2=10
high
92
high
b0
RR
0 a br h
h-1 a1 b1 h-1
把结点b从a的右下侧逆时针(左转)转到a的右上侧, 原b的左成为a的右,新b的左为a
2.LL型平衡旋转:
a2
LL
1 b ar h-1
b0 h b1 a 0
h b1 br h-1
h-1 br ar
把结点b从左下侧顺转(右转)转到a的左上侧,原b的右 成为a的左,新b的右为a。
h-1 a1 c -1
RL(逆时针)
c0
0a
b -1
h-1 c1 b -1
h-2 cr br h-1
h-1 a1 c1 cr br h-1 h-2
以c为轴心,把a从c的左上方,转到c的左下方,使 得c的左是a,右是b,原c的左子树变成a的右。 4.LR型平衡旋转:
以c为轴心把b从c的左上侧,逆时针(左转)到c的左 下侧,从而a的左是c,c的左是b,原c的左变成新b的右。
else { high=mid-1;//向左找
if (low>high){printf(“no succ\n”);break;} }
}
}
递归算法描述如下:
void Binsrch (sqtable r, KeyType,int low,int high) {
low=l; high=h; if (high<low) {printf(‘Unsucc’);Return;} mid=(low+high) / 2; if (k>r[mid].key)
顺序查找表的缺点:平均查找长度比较大,特别是当n 较大时,查找效率较低。
2)折半查找(有序表上进行查找):
基本思想:设三个指针low,high和mid分别指示待查有 序表的表头,表尾和中间元素,在开始查找时,三个 指针的初值分别为:low:=1;high:=n;mid:=(low+high) div 2 。折半查找是从表的中间元素开始,用待查元 素的关键字k和r[mid].key比较,此时有三种情况 (假 设该查找表按关键字的非递减次序排列) :
3.RL型平衡旋转: a -2
h-1 a1 b 1
RL(顺时针)
a -2
h-1 a1 c -1
1 c br h-1
h-1 c1 b -1
h-1 c1 cr h-2
h-2 cr br h-1
以c为轴心,把b从c的右上侧顺时针(右转)到c的右 下侧,从而a的右是c,c的右是b,原c的右变成b的左。
a -2
1)若r[mid].key=k,则查找成功;
2) 若r[mid].key>k,则k必在较低标号的那一半表中, 令 high=mid-1
3) 若r[mid].key<k,则k必在较高标号的那一半表中, 令low=mid+1
再取中间项进行比较,直到查找成功或low>high (查找失败)为止。
例:给出表元素关键字为:{05,13,19,21,37,56,64,75,80,88,92}
⑴判别插入节点之后是否产生不平衡; ⑵找到失去平衡的最小子树; ⑶判别旋转类型并作相应调整处理。
从平衡树的定义可知,平衡树上所有节点的平衡因子的 绝对值都不超过1,在插入节点之后,若排序树上的某个 节点的平衡因子的绝对值大于1,则说明出现不平衡。同 时,失去平衡的最小子树的根节点必为离插入节点
最近,而且插入之前的平衡因子的绝对值大于0(在插入节点之 后,其平衡因子的绝对值才大于1)的祖先节点。为此需要做到:
05 13 19 21 37 56 64 75 80 88 92
low mid high 因为r[mid].key>k,所以向左找,high=mid-1=9 因为low>high,所以查找失败
void Binsrch(sqtable r,keytype k) //在长度为n的有序表r中查找关键字为k的元素,查到后输出 {
ASL=∑PiCi
Pi :为查找表中第i个元素的概率 Ci :为查到表中第i个元素时已经进行的比较次数
在顺序查找时, Ci取决于所查元素在表中的位置, Ci =i,设每个元素的查找概率相等,即Pi=1/n,则:
ASL=∑PiCi=(n+1)/2
查找不成功的查找长度为n+1。
顺序查找表的优点:算法简单且适应面广,对表的结 构无任何要求,无论元素是否按关键字有序都可应用。
★ 静态查找表
1)顺序表上的查找:以顺序表作为存储结构,然后在这 个存储结构上实现静态查找表的基本运算。
顺序表类型定义如下:
#define maxsize 静态查找表的表长 typedef struct {
keytype key;//关键字 ……… //其他域 } rec; typedef struct rec sqtable[maxsize+1];
37 90
53 0
90
Leabharlann Baidu
第一次旋转(顺时针)以 53 为轴心,把 90 从 53 的右上,转到 53 的右下,37 的右是 53 , 53 的右为90 ,原 53 的右变成新 90 的左。
RL型的第一次旋转(顺时针)
以 53 为轴心,把 37 从 53 的左上转到 53 的左下,使得 53 的左 是37 ;右是 90 ,原 53 的左变成了 37 的右。
LR(顺时针) h-1 bl c1 cr ar h-1
h-1 bl c1 h-1
h-2
上述四种情况,1与2对称,3与4对称,旋转的正确 性容易由“遍历所得中序序列不变”证明之。
从上面的例子可见,平衡旋转是当排序树在 插入节点后产生不平衡时进行的。由此,为了使 从关键字序列得到的排序树为平衡树,则需对建 立二叉排序树的插入过程算法做如下修改。
因为r[mid].key=k,查找成功,所查元素在表中的序号为mid 的值
2.查找关键字k=85 的情况 (1) low=1;high=11;mid=(1+11) / 2=6
05 13 19 21 37 56 64 75 80 88 92
low
mid
因为r[mid].key<k,所以向右找,令low:=mid+1=7
{low=mid+1;Binsrch(r,k,low,high);} else if(k==r[mid].key)
{printf(mid);Return;} else if (k<r[mid].key)
{high=mid-1; Binsrch(r,k,low,high);} }
05 13 19 21 37 56 64 75 80 88 92
low
mid
high
因为r[mid].key>k,所以向左找,令high=mid-1=5
(2) low=1;high=5;mid=(1+5) / 2=3
★ 基本概念 查找表:是一种以集合为逻辑结构,以查找为核心运算,
同时包括其他运算的数据结构。
关键字:用来标识数据元素的数据项,简称键。
主关键字:可以唯一标识一个数据元素的关键字。
次关键字:可以标识若干数据元素的关键字。
查找:根据某个给定的K值,在查找表中寻找 一 个键值等于K的元素,若找到这样的元素, 则称查找成功,此时的运算结果为该数据元 素在查找表中的位置,否则称查找不成功, 运算结果为一特殊标志。
while (r[i]!=k) i++; if (i<n) printf(“succ, i=%d”,i);//查找成功,i指示待查元素在表中位置 else printf(“unsucc”);//i=n时表明查找不成功 }
平均查找长度:为确定某元素在表中某位置所进行的比 较次数的期望值。
在长度为n的表中找某一元素,查找成功的平均查找长度:
★ 动态查找表
二叉排序树:或者是一棵空树,或者是具有下列 性质的二叉树:1)若它的左子树不空,则它的左 子树上所有结点的值均小于根结点的值;2)若它 的右子树不为空,则它的右子树上所有结点的值 均大于或等于它的根结点的值;3)它的左、右子 树均为二叉排序树。 二叉排序树的构造方法:
设R={R1,R2,…,Rn}为一数列,按下面的原则建立二叉树: 1)令R1为二叉树的根; 2)若R2<R1,则令R2为R1的左子树的根结点,否则令R2为
RL型的第二次旋转(逆时针)
一般情况下,假设由于二叉排序树上插入结点而失去 平衡的最小子树的根结点指针为a(即a是离插入结点最 近,且平衡因子绝对值超过1的祖先结点),则失去平衡 后进行调整的规律可归纳为下列四种情况:
⒈RR型平衡旋转:
a -2 h-1 a1 b -1
h-1 b1 br h 插入节点
a2
2a
-1 b ar h-1 h-1 b1 1 c
LR(逆时针)
2 c ar h-1 0 b cr h-2
c1 cr h-2 h-1
h-1 bl c1 h-1
再以c为轴心,把a从c的左上方转到c的右下方,使得
c的右是a,左是b,原c的右子树变成a的左。
2a
2c
ar h-1
0c 0 b a -1
0 b cr h-2
R1的右子树的根结点; 3)对R3,R4,…Rn重复上述步骤2);
二叉排序树的平衡化
假设表中的关键字序列为(13,24,37,90,53) ①空树和一个结点 13 的二叉树显然是平衡二叉树 . ②插入24后仍平衡 13 -1
24 0
③插入 37 后结点 13的平衡因子为0-2=-2,不平衡
13 -2
low=1; high=n;//置初值 while(low<=high) { mid=(low+high)/2;
if (k==r[mid].key) {printf(“succ i=%d\n”,mid);break;} else if ( k>r[mid].key) { low=mid+1;//向右找 if (low>high){ printf("no succ\n");break; } }
查找表
1.建表:Create(st)
静态查找表 2.查找:Search(st,k)
3.读表元:Get(st,pos)
1.初始化:Initiate(st) 2.查找:Search(st,k)
动态查找表 3.读表元:Get(st,pos)
4.插入:Insert(st,k) 5.删除:Delete(st,k)
顺序查找过程:假定该查找表有n个记录,首先将要查找 的那个关键字赋给实际上并不存在的第n个记录的关键 字域(0..n-1存放数据) ,然后从头开始一个一个的向下查 找,用i来计数,查到就送出来看i是第几个,若i<=n, 则查找成功,若i=n则查找失败。
void seqsrch(sqtable r,keytype k) //在长度为n的表r中查找关键字为k的元素,r[n]为表尾的扩充; i指示查找结果 { r[n].key=k; i=0;//给监督哨赋值
05 13 19 21 37 56 64 75 80 88 92
low
mid
high
因为r[mid].key<k,所以向右找,令low:=mid+1=4
(3) low=4;high=5;mid=(4+5) div 2=4
05 13 19 21 37 56 64 75 80 88 92
low mid high
把 24 从 13 的右下侧
24 -1
左转到 13 的右上侧
37 0
原来 24 的左为 13 的右, 新的 24 的左为 13
RR型即逆时针旋转
24 13 37
④插入90,53后,又失去平衡, 可经过下列步骤转化为平衡二叉树
24 _ 2
0 13
37 _ 2
90 1
24 13 37
53
24 13 53
⑴在查找s节点的插入位置的过程中,记下离s节点最近, 且平衡因子不等于0的节点,令指针a指向该节点。 ⑵修改自a到s的路径上所有的节点的平衡因子值; ⑶判别树是否失去平衡,即在插入节点之后,a节点的平 衡因子的绝对值是否大于1,若是,则需要判别旋转类型, 并做相应处理,否则插入过程结束。
void AVL-insert(x,y,t) //把标志符x插入树根为t的AVL树中。设每个结点具有 四个域:data、Lchild、Rchild和一个2位的平衡因子 bf。将y置成y->data=x,t=NULL
(2) low=7;high=11;mid=(7+11) / 2=9
05 13 19 21 37 56 64 75 80 88
low
mid
因为r[mid].key<k,所以向右找,令low:=mid+1=10
(3) low=10;high=11;mid=(10+11) / 2=10
high
92
high
b0
RR
0 a br h
h-1 a1 b1 h-1
把结点b从a的右下侧逆时针(左转)转到a的右上侧, 原b的左成为a的右,新b的左为a
2.LL型平衡旋转:
a2
LL
1 b ar h-1
b0 h b1 a 0
h b1 br h-1
h-1 br ar
把结点b从左下侧顺转(右转)转到a的左上侧,原b的右 成为a的左,新b的右为a。
h-1 a1 c -1
RL(逆时针)
c0
0a
b -1
h-1 c1 b -1
h-2 cr br h-1
h-1 a1 c1 cr br h-1 h-2
以c为轴心,把a从c的左上方,转到c的左下方,使 得c的左是a,右是b,原c的左子树变成a的右。 4.LR型平衡旋转:
以c为轴心把b从c的左上侧,逆时针(左转)到c的左 下侧,从而a的左是c,c的左是b,原c的左变成新b的右。
else { high=mid-1;//向左找
if (low>high){printf(“no succ\n”);break;} }
}
}
递归算法描述如下:
void Binsrch (sqtable r, KeyType,int low,int high) {
low=l; high=h; if (high<low) {printf(‘Unsucc’);Return;} mid=(low+high) / 2; if (k>r[mid].key)
顺序查找表的缺点:平均查找长度比较大,特别是当n 较大时,查找效率较低。
2)折半查找(有序表上进行查找):
基本思想:设三个指针low,high和mid分别指示待查有 序表的表头,表尾和中间元素,在开始查找时,三个 指针的初值分别为:low:=1;high:=n;mid:=(low+high) div 2 。折半查找是从表的中间元素开始,用待查元 素的关键字k和r[mid].key比较,此时有三种情况 (假 设该查找表按关键字的非递减次序排列) :
3.RL型平衡旋转: a -2
h-1 a1 b 1
RL(顺时针)
a -2
h-1 a1 c -1
1 c br h-1
h-1 c1 b -1
h-1 c1 cr h-2
h-2 cr br h-1
以c为轴心,把b从c的右上侧顺时针(右转)到c的右 下侧,从而a的右是c,c的右是b,原c的右变成b的左。
a -2
1)若r[mid].key=k,则查找成功;
2) 若r[mid].key>k,则k必在较低标号的那一半表中, 令 high=mid-1
3) 若r[mid].key<k,则k必在较高标号的那一半表中, 令low=mid+1
再取中间项进行比较,直到查找成功或low>high (查找失败)为止。
例:给出表元素关键字为:{05,13,19,21,37,56,64,75,80,88,92}
⑴判别插入节点之后是否产生不平衡; ⑵找到失去平衡的最小子树; ⑶判别旋转类型并作相应调整处理。
从平衡树的定义可知,平衡树上所有节点的平衡因子的 绝对值都不超过1,在插入节点之后,若排序树上的某个 节点的平衡因子的绝对值大于1,则说明出现不平衡。同 时,失去平衡的最小子树的根节点必为离插入节点
最近,而且插入之前的平衡因子的绝对值大于0(在插入节点之 后,其平衡因子的绝对值才大于1)的祖先节点。为此需要做到:
05 13 19 21 37 56 64 75 80 88 92
low mid high 因为r[mid].key>k,所以向左找,high=mid-1=9 因为low>high,所以查找失败
void Binsrch(sqtable r,keytype k) //在长度为n的有序表r中查找关键字为k的元素,查到后输出 {
ASL=∑PiCi
Pi :为查找表中第i个元素的概率 Ci :为查到表中第i个元素时已经进行的比较次数
在顺序查找时, Ci取决于所查元素在表中的位置, Ci =i,设每个元素的查找概率相等,即Pi=1/n,则:
ASL=∑PiCi=(n+1)/2
查找不成功的查找长度为n+1。
顺序查找表的优点:算法简单且适应面广,对表的结 构无任何要求,无论元素是否按关键字有序都可应用。
★ 静态查找表
1)顺序表上的查找:以顺序表作为存储结构,然后在这 个存储结构上实现静态查找表的基本运算。
顺序表类型定义如下:
#define maxsize 静态查找表的表长 typedef struct {
keytype key;//关键字 ……… //其他域 } rec; typedef struct rec sqtable[maxsize+1];
37 90
53 0
90
Leabharlann Baidu
第一次旋转(顺时针)以 53 为轴心,把 90 从 53 的右上,转到 53 的右下,37 的右是 53 , 53 的右为90 ,原 53 的右变成新 90 的左。
RL型的第一次旋转(顺时针)
以 53 为轴心,把 37 从 53 的左上转到 53 的左下,使得 53 的左 是37 ;右是 90 ,原 53 的左变成了 37 的右。
LR(顺时针) h-1 bl c1 cr ar h-1
h-1 bl c1 h-1
h-2
上述四种情况,1与2对称,3与4对称,旋转的正确 性容易由“遍历所得中序序列不变”证明之。
从上面的例子可见,平衡旋转是当排序树在 插入节点后产生不平衡时进行的。由此,为了使 从关键字序列得到的排序树为平衡树,则需对建 立二叉排序树的插入过程算法做如下修改。
因为r[mid].key=k,查找成功,所查元素在表中的序号为mid 的值
2.查找关键字k=85 的情况 (1) low=1;high=11;mid=(1+11) / 2=6
05 13 19 21 37 56 64 75 80 88 92
low
mid
因为r[mid].key<k,所以向右找,令low:=mid+1=7
{low=mid+1;Binsrch(r,k,low,high);} else if(k==r[mid].key)
{printf(mid);Return;} else if (k<r[mid].key)
{high=mid-1; Binsrch(r,k,low,high);} }