hnust 1073: 查找
题目描述
给定一个集合,查找元素是否在集合中出现。
输入
每个测试用例由多行组成,第一行是两个整数n和m,两个数范围在1到100000之间。自第二行起一共有n+m个整数,其中前面n个整数代表集合的元素,随后的m个整数是待查询的数。所有的整数在范围[-231,231)内。
输出
对于每个待查询的数,如果在集合中则输出yes,否则输出no.
样例输入 Copy
5 3
7 9 3 2 -5
4 9 -5
5 3
-2 1 0 -2 1
0 -2 3
样例输出 Copy
no
yes
yes
yes
yes
no
提示
注意,需要快速的查找算法!效率不高的查找算法可能会超时!
解题过程
1、什么是二叉搜索树
二叉搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树。
二叉搜索树:一棵二叉树,可以为空;如果不为空,满足以下性质:
非空左子树的所有键值小于其根结点的键值。
非空右子树的所有键值大于其根结点的键值。
左、右子树都是二叉搜索树。
2.二叉搜索树操作
2.1 二叉搜索树的查找
从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
最多查找高度次,走到空,还没找到,则这个值不存在。
2.2 二叉搜索树的插入
插入的具体过程如下:
树为空,则直接新增节点,赋值给root指针
树不为空,按二叉搜索树性质查找插入的位置,插入新节点(记录父节点,判断插入的节点应该在父节点的左子树还是右子树)
2.3 二叉搜索树的删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情
况:
a. 要删除的结点无孩子结点
b. 要删除的结点只有左孩子结点
c. 要删除的结点只有右孩子结点
d. 要删除的结点有左、右孩子结点
看似删除节点有4种情况,但实际上a和b和c可以合并,这样就只有2种情况了:
a:待删除的结点无孩子/只有一个孩子:删除结点并使父亲结点指向被删除结点的孩子结点(无孩子视为孩子是空结点,任意指向一个即可)
b:待删除的结点有左右孩子:采用替换法,寻找删除结点右子树的最小结点(右子树最左结点),将最小结点的值和删除结点的值替换,然后删除最小结点(此时最小结点,要么没有孩子,要么只有一个孩子,符合a情况可以直接删除)
二叉搜索树(Binary Search Tree, BST)的基本操作,包括树的创建、插入新元素、搜索特定元素以及主函数中对这些操作的测试。
以下是对代码的详细解析:
-
头文件和命名空间:
- 包含
<iostream>
、<cstdlib>
和<cstdio>
头文件。 - 使用
using namespace std;
来避免在标准库类型和函数前加std::
。
- 包含
-
宏定义:
ENDFLAG
被定义为0,但在代码中没有使用。
-
数据类型定义:
KeyType
用作二叉搜索树中节点数据的类型,这里设为int
。
-
二叉树节点结构体
BSTNode
:- 包含一个
KeyType data
成员用于存储节点数据,以及两个指向左右子节点的指针lchild
和rchild
。
- 包含一个
-
二叉搜索树类型定义:
BSTree
是指向BSTNode
的指针类型。
-
插入函数
InsertBST
:- 递归函数,用于在二叉搜索树
T
中插入新元素e
。 - 如果树为空,创建新节点并插入。
- 如果元素小于当前节点数据,递归地在左子树插入。
- 如果元素大于当前节点数据,递归地在右子树插入。
- 递归函数,用于在二叉搜索树
-
创建二叉搜索树函数
CreateBST
:- 读取一个
KeyType e
,然后调用InsertBST
函数将其插入树T
中。
- 读取一个
-
搜索函数
SearchBST
:- 递归函数,用于在二叉搜索树
T
中搜索关键字key
。 - 如果树为空或找到关键字,返回相应的状态码。
- 递归函数,用于在二叉搜索树
-
主函数
main
:- 读取两个整数
n
和k
,分别表示要插入的元素数量和搜索次数。 - 使用循环调用
CreateBST
函数n
次,构建二叉搜索树。 - 使用另一个循环读取
k
个关键字,并调用SearchBST
函数搜索它们。 - 输出每个搜索结果,找到返回1,否则返回0。
- 读取两个整数
-
程序结束:
- 输入结束后,程序返回0,表示正常结束。
代码逻辑分析:
- 这段代码通过递归的方式实现了二叉搜索树的插入和搜索操作。
- 使用了结构体和指针来表示二叉树的节点和整体结构。
潜在问题:
- 代码没有提供
swap
函数的实现,尽管在InsertBST
函数的注释中提到了它。 - 没有实现删除节点的功能,这在实际应用中可能是必需的。
改进建议:
- 考虑实现一个
swap
函数,如果需要在InsertBST
中使用。 - 考虑实现删除节点的功能,以处理二叉搜索树中不需要的元素。
- 考虑增加对输入有效性的检查,确保读取的是有效的整数。
- 考虑使用
std::vector
来自动管理内存,简化代码并减少内存管理的复杂性。
部分代码
void InsertBST(BSTree &T,KeyType e)
{//当二叉排序树T不存在关键字等于e.key的数据元素时,插入该元素
BSTree S;
if(T==NULL)
{ //找到插入位置,递归结束
S=new BSTNode; //生成新节点*S
S->data =e ;
S->lchild =S->rchild =NULL; //新节点作为叶子结点
T=S; //把新结点*S链接到已找到的插入位置
}
else if(e <T->data ) InsertBST(T->lchild,e);
else if(e >T->data ) InsertBST(T->rchild,e);
}
void CreateBST(BSTree &T)//BST的创建
{
KeyType e;
cin>>e;
InsertBST(T,e);
}
int SearchBST(BSTree T,KeyType key) //递归查找
{
if(!T) return 0;
else if(key==T->data )
return 1;
else if(key<T->data )
return SearchBST(T->lchild ,key);
else
return SearchBST(T->rchild,key);
}
AC代码
#include<iostream>
#include<cstdlib>
#include<cstdio>
using namespace std;
#define ENDFLAG 0
typedef int KeyType;
typedef struct BSTNode{
KeyType data;//节点的数据域
struct BSTNode *lchild,*rchild; //左右孩子指针
}BSTNode,*BSTree;
void InsertBST(BSTree &T,KeyType e)
{//当二叉排序树T不存在关键字等于e.key的数据元素时,插入该元素
BSTree S;
if(T==NULL)
{ //找到插入位置,递归结束
S=new BSTNode; //生成新节点*S
S->data =e ;
S->lchild =S->rchild =NULL; //新节点作为叶子结点
T=S; //把新结点*S链接到已找到的插入位置
}
else if(e <T->data ) InsertBST(T->lchild,e);
else if(e >T->data ) InsertBST(T->rchild,e);
}
void CreateBST(BSTree &T)//BST的创建
{
KeyType e;
cin>>e;
InsertBST(T,e);
}
int SearchBST(BSTree T,KeyType key) //递归查找
{
if(!T) return 0;
else if(key==T->data )
return 1;
else if(key<T->data )
return SearchBST(T->lchild ,key);
else
return SearchBST(T->rchild,key);
}
int main()
{
unsigned int n,k;
int m;
BSTree T;
T=NULL;
KeyType key;
cin>>n>>k;
for(int i=0;i<n;++i)
{
CreateBST(T);
}
for(int i=0;i<k;++i)
{
cin>>key;
m=SearchBST(T,key);
cout<<m<<" ";
}
return 0;
}