数据结构实验三BST动态查找表Word下载.docx

上传人:b****6 文档编号:18610143 上传时间:2022-12-29 格式:DOCX 页数:24 大小:362.79KB
下载 相关 举报
数据结构实验三BST动态查找表Word下载.docx_第1页
第1页 / 共24页
数据结构实验三BST动态查找表Word下载.docx_第2页
第2页 / 共24页
数据结构实验三BST动态查找表Word下载.docx_第3页
第3页 / 共24页
数据结构实验三BST动态查找表Word下载.docx_第4页
第4页 / 共24页
数据结构实验三BST动态查找表Word下载.docx_第5页
第5页 / 共24页
点击查看更多>>
下载资源
资源描述

数据结构实验三BST动态查找表Word下载.docx

《数据结构实验三BST动态查找表Word下载.docx》由会员分享,可在线阅读,更多相关《数据结构实验三BST动态查找表Word下载.docx(24页珍藏版)》请在冰豆网上搜索。

数据结构实验三BST动态查找表Word下载.docx

3

查找成功,查找次数4

100

查找成功,查找次数5

19

查找失败

②.只有左子树的情况

10011235439554827893//10个数据

12

35

95

③.错误的节点数输入

-2//BST的节点个数

错误的结点数输入

④.错误的结点值的输入(字母)

10//BST的结点个数

1q23456789//10个数据

无效的结点输入

⑤.错误的结点值的输入(负数)

1-223456789//10个数据

输出:

二叉树中任意结点的值大于左节点的值,小于右节点的值,满足BST树的性质,所以用BST树来实现。

二.概要设计

1.抽象数据类型

二叉树中任意结点的值大于左节点的值,小于右节点的值,满足BST树的性质,同时本题在建树时需要大量的插入操作,运用链式结构比较方便,所以用链式结构的二叉树来满足BST树的构建。

2.ADT

①.二叉树的ADT:

数据对象D:

D是BinNode类的数据元素的集合

数据关系R:

若D为空集,则称为空树。

否则:

(1)在D中存在唯一的称为根的数据元素root;

(2)当n>

1时,其余结点可分为m(m>

0)个互不相交的有限集T1,T2,…,Tm,其中每一棵子集本身又是一棵符合本定义的树,称为根root的子树。

基本操作:

boolInitBST(BST*b)//初始化二叉树

boolInitBSTNode(BSTNode*&

n)//初始化节点

boolclearBST(BSTNode*&

n)//销毁BST

②结点的ADT

数据对象:

包含结点的值,同时包含结点的左右指针

数据关系:

每个结点都有各自的值

若结点左右指针为空,则该节点称为叶子结点

//结点的初始化

BinNodePtr(){lc=rc=NULL}

BinNodePtr(Eleme,BinNodePtr*l=NULL;

BinNodePtr*r=NULL)

{it=e;

lc=l;

rc=r;

}

//判断是否是叶子结点

boolisleaf(){return(lc==NULL)&

&

(rc==NULL)};

3.算法的基本思想

构建BST树:

输入节点数后,依次输入每个结点的值,将第一个结点作为根结点,插入一个数,这个数与根节点先比较,若小于则再与根结点的左子树相比较,若大于则与根节点的右子树相比较。

比较时,若小于根结点且根结点的左子树为空,则这个数为根结点左子树的值,若小于根结点又大于根结点的左子树,则运用指针将根结点的左指针指向这个值得地址,这个值地址的指针再指向原来根结点左子树;

大于的情况同理。

查找:

设置一个计数器,每查找一次则加一。

从根节点开始,在BST中检索值K。

如果根节点存储的值为K,则检索结束。

如果不是,必须检索数的更深的一层。

BST的效率在于只需检索两棵子树之一。

如果K小于根节点的值,则只需检索左子树;

若果K结点大于根结点的值,则检索右子树。

这个过程一直持续到K被知道或者遇到一个叶子结点为止。

如果叶子结点仍没有发现K,那么K就不在BST中。

4.程序的流程

程序由三个模块组成:

输入模块:

输入结点数目初始数据,构建二叉查找树

查找模块:

判断需要查找的值是否在该BST中

输出模块:

输出查找成功与否,并输出比较的次数

3、详细设计

1.物理数据类型

动态查找表的数据为小数或整数,用float类型保存。

树的ADT具体实现

//初始化二叉树

boolInitBST(BST*b){

b->

root=NULL;

returntrue;

}

//销毁BST

n)

{

if(n)

returnfalse;

if(n->

lchild)

clearBST(n->

lchild);

rchild)

rchild);

free(n);

//初始化节点

n)

n=(BSTNode*)malloc(sizeof(BSTNode));

n->

lchild=NULL;

rchild=NULL;

结点的ADT具体实现

BinNodePtr(){lc=rc=NULL}//结点的初始化

boolisleaf()

2.算法的具体步骤

①.结点输入操作:

先输入结点数,在输入每个结点的值,通过循环调用insert函数将每个结点进行插入

cout<

<

"

BST结点数目:

"

<

endl;

cin>

>

n;

for(inti=0;

i<

n;

i++)

{

cin>

p[i];

if(p[i]<

=0)

{

cout<

无效的结点输入"

system("

pause"

);

return;

}

insert(&

b,p[i]);

}

②.头结点的建立:

对于第一个调用insert函数插入的值,作为头结点建立二叉树

if(b->

root==NULL)

b->

root=n;

returntrue;

④.之后结点的插入:

插入一个数,这个数与根结点先比较,若小于则再与根结点的左子树相比较,若大于则与根节点的右子树相比较。

while

(1)//循环比较

if(e<

m->

data)//小于根节点则插入左子树

if(m->

lchild==NULL)

{

m->

lchild=n;

//给左孩子赋值

returntrue;

}

lchild!

=NULL&

e>

lchild->

data)

n->

lchild=m->

lchild;

elsem=m->

continue;

else//大于根节点则插入右子树

rchild==NULL)

rchild=n;

//给右孩子赋值

}

rchild!

e<

rchild->

rchild=m->

rchild;

else

m=m->

⑤.完整的insert插入操作:

插入元素e时,先判断该二叉树是否为空,若为空,将e作为该二叉树的根节点。

否则,从根节点开始,比较e与节点n的大小。

如果e的值更小,判断n的左子树是否为空,若为空,将e作为节点n的左孩子并返回e,否则比较e与n左孩子的值,依此循环下去;

如果e的值更大,判断n的右子树是否为空,若为空,将e作为节点n的右孩子并返回e,否则比较e与n右孩子的值,依此循环下去。

boolinsert(BST*b,ElemTypee)//把结点插入BST

BSTNode*n,*m;

InitBSTNode(n);

data=e;

if(b->

m=b->

root;

while

(1)//循环比较

continue;

}}}

②find查找操作,查找元素时,从根节点开始,比较e与节点x的大小,若相等,返回true;

如果e比节点x的值小,判断x的左子树是否为空,若为空,返回false,不为空则比较e与x左孩子的值,依次循环下去;

如果e比节点x的值大,判断x的右子树是否为空,若为空,返回false,不为空则比较e与x右孩子的值,依次循环下去。

boolfind(BST*b,ElemTypee)//查询元素e,记录比较的次数查询成功返回true,否则返回false

intcount=0;

BSTNode*x=b->

count++;

//设置计数器

x->

data)//小于根节点则在左子树中查找

if(x->

cout<

查找失败,查找次数:

count<

returnfalse;

//左子树为空则查找失败

x=x->

//继续与左孩子的值比较

if(e>

data)//大于根节点则在右子树中查找

//右子树为空则查找失败

//继续与右孩子的值比较

if(e==x->

查找成功,查找次数:

//cout<

count;

returntrue;

}}}

3.算法的时空分析

查找元素需要的比较次数由树的深度决定查找,最好时间复杂度O(logN),最坏时间复杂度O(N)(只有左子树或右子树的情况)。

4.输入和输出的格式

输入BST结点数

//等待输入

cout<

BST结点数:

输入BST结点数据

BST节点数据:

//等待输入

输入要查找的数据

输入要查找的数据(输入-1结束查找)"

m;

若BST结点数目输入错误:

输出“无效的结点数目输入”

if(n<

cout<

无效的结点数目输入"

system("

若BST节点数据输入错误:

输出“无效的结点输入”

if(p[i]<

若查找成功

输出查找次数:

//输出次数

if(e==x->

查找失败,查找次数:

if(x->

四.调试分析

1.本程序会将第一个输入的值作为root,如果第一个值输入过大,导致所有数据都被存放进左子树,导致树的长度n过长,接下来的查找效率过低,因为最好在输入前就大致考虑一下中间值是多少,尽量避免树过长。

2.一开始insert函数并没有考虑太多,后来发现再输入节点的值时有限制,必须输入比之前输入所有节点值的最小值还小,或者比之前输入最大值还要大。

举例输入3142,此程序生成的树为

3

/\

14,此时insert

(2)只能接在1后面,错误,错误结果如下

经过修改,3的左指针指向2,2的左指针指

向1

5.测试结果

第一组:

输入节点数10

节点数据501327865100594318

结果正确

第二组:

第三组:

第四组:

第五组:

6、用户使用说明

本程序会将第一个数作为root,所以输入前大致想好范围,第一个数尽量输入中间值,可以减少查找的时间复杂度

7.试验心得

1.试验刚开始考虑过先将输入的数进行排序,后来觉得冒泡排序对时间复杂度的影响是O(n^2),远大于查找最大时间O(n),于是放弃,本程序通过BST树,极大的优化了时间复杂度,数据结构的魅力也就在此。

2.由于对时间复杂度的不满意,查阅了有关最优二叉查找树资料

3.动态规划方法生成最优二叉查找树(参考CSDN)

基于统计先验知识,我们可统计出一个数表(集合)中各元素的查找概率,理解为集合各元素的出现频率。

比如中文输入法字库中各词条(单字、词组等)的先验概率,针对用户习惯可以自动调整词频——所谓动态调频、高频先现原则,以减少用户翻查次数。

这就是最优二叉查找树问题:

查找过程中键值比较次数最少,或者说希望用最少的键值比较次数找到每个关键码(键值)。

为解决这样的问题,显然需要对集合的每个元素赋予一个特殊属性——查找概率。

这样我们就需要构造一颗最优二叉查找树。

  n个键{a1,a2,a3......an},其相应的查找概率为{p1,p2,p3......pn}。

构成最优BST,表示为T1n,求这棵树的平均查找次数C[1,n](耗费最低)。

换言之,如何构造这棵最优BST,使得C[1,n]最小。

  动态规划法策略是将问题分成多个阶段,逐段推进计算,后继实例解由其直接前趋实例解计算得到。

对于最优BST问题,利用减一技术和最优性原则,如果前n-1个节点构成最优BST,加入一个节点an 

后要求构成规模n的最优BST。

按n-1,n-2,...,2,1递归,问题可解。

自底向上计算:

C[1,2]?

C[1,3]?

...?

C[1,n]。

为不失一般性用

C[i,j]表示由{a1,a2,a3......an}构成的BST的耗费。

其中1=i=j=n。

这棵树表示为Tij。

从中选择一个键ak作根节点,它的左子树为Tik-1,右子树为Tk+1j。

要求选择的k使得整棵树的平均查找次数C[i,j]最小。

左右子树递归执行此过程。

(根的生成过程)

递推计算式

基本算法

8.附录

#include<

iostream>

stdlib.h>

usingnamespacestd;

#include"

algorithm"

typedeffloatElemType;

typedefstructBSTNode

ElemTypedata;

structBSTNode*lchild,*rchild;

}BSTNode;

typedefstructBST

BSTNode*root;

}BST;

boolInitBST(BST*b)//初始化二叉树

n)//初始化节点

voidmain()

intn,m=0,count;

BSTb;

InitBST(&

b);

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 商业计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1