集美大学课程实验报告-实验4-树、二叉树与查找
集美大学课程实验报告-实验4-树、二叉树与查找
项目名称 | 内容 |
---|---|
课程名称 | 数据结构 |
班级 | 网安2413 |
指导教师 | 郑如滨 |
学生姓名 | 林沁茹 |
学号 | 202421336067 |
实验项目名称 | 实验4-树、二叉树与查找 |
上机实践日期 | |
上机实践时间 | 2学时 |
一、目的(本次实验所涉及并要求掌握的知识点)
以下内容请根据实际情况编写
- 掌握二叉排序树的创建、查找、插入与删除
- 掌握二叉树层次遍历(广度优先)
- 掌握哈希法中链地址法的应用
- 掌握随机数的生成
二、实验内容与设计思想
题目1:先序序列创建二叉树
函数相关伪代码
1.定义树节点的基本结构
2.创建树的基本节点
3.创建树(递归)
4.中序遍历展示树(左-父-右)
5.用getline()来接收字符串,之后开始建树
函数代码
#include<iostream>
#include<vector>
#include<string>
using namespace std;
struct BiNode {
char k;
struct BiNode* rchild;
struct BiNode* lchild;
};
BiNode* Create(char k)
{
BiNode* node = new BiNode;
node->k = k;
node->lchild = NULL;
node->rchild = NULL;
return node;
}
BiNode* buildTree(string& b, int& l) {
if (l>=b.length() || b[l] == '#') {
l++;
return NULL;
}
BiNode* node = Create(b[l]);
l++;
node->lchild = buildTree(b,l);
node->rchild = buildTree(b,l);
return node;
}
BiNode* Showtree(BiNode* root)
{
if (root != NULL) {
Showtree(root->lchild);
cout << root->k<<" ";
Showtree(root->rchild);
}
return NULL;
}
int main()
{
string b;
int l=0;
while(getline(cin, b)){
l=0;
BiNode* root=buildTree(b, l);
Showtree(root);
cout<<endl;
}
return 0;
}
时间复杂度O(n),空间复杂度O(n)
题目2:先序输出叶结点
函数相关伪代码
1.递归实现叶子结点的打印,遍历树的所有节点
2.当节点的左右孩子都为空时,即叶子节点,打印输出
函数代码
void PreorderPrintLeaves( BinTree BT ){
if(BT!=NULL){
if(BT->Left==NULL&&BT->Right==NULL){
printf(" %c",BT->Data);
}
PreorderPrintLeaves(BT->Left);
PreorderPrintLeaves(BT->Right);
}
}
时间复杂度O(n),空间复杂度O(n)
题目3:求二叉树高度
函数相关伪代码
1.递归实现,遍历所有节点,l来存储不断向左的高度,r来存储不断向右的高度
2.当节点为NULL时返回0,不为NULL,则判断l和r,返回高的值并加1
函数代码
int GetHeight( BinTree BT ){
if(BT==NULL){
return 0;
}
int l=GetHeight(BT->Left);
int r=GetHeight(BT->Right);
if(l>r){
return l+1;
}else{
return r+1;
}
}
时间复杂度O(n),空间复杂度O(n)
题目4:jmu-ds-二叉树层次遍历
函数相关伪代码
1.定义树的节点
2.创建树节点的函数
3.递归创建树,左孩子为顺序表下标中为偶数的,右孩子为顺序表下标为奇数
4.队列存储,当一个节点被输出,队列在存储此节点的左右孩子,循环实现,直到队列为空
函数代码
#include<iostream>
#include<string>
#include<vector>
#include<queue>
using namespace std;
struct tree {
char a;
tree* lchild;
tree* rchild;
};
tree* Createtree(string k, int i)
{
tree* node = new tree;
node->a = k[i];
node->lchild = NULL;
node->rchild = NULL;
return node;
}
tree* Buildtree(string k, int i)
{
if (k.empty()||k.length() <=i || k[i] == '#') {
return NULL;
}
tree* root = Createtree(k,i);
root->lchild = Buildtree(k, 2 * i);
root->rchild = Buildtree(k, 2 * i + 1);
return root;
}
void Showtree(tree* node)
{
if (node == NULL) {
cout << "NULL";
return;
}
queue<tree*> q;
q.push(node);
int f = 1;
while (!q.empty()) {
tree* current = q.front();
q.pop();
if (f != 1) {
cout << " ";
}
f = 0;
cout << current->a;
if (current->lchild != NULL) {
q.push(current->lchild);
}
if (current->rchild != NULL) {
q.push(current->rchild);
}
}
cout << endl;
}
int main()
{
string k;
tree* root = NULL;
getline(cin, k);
root = Buildtree(k, 1);
Showtree(root);
return 0;
}
时间复杂度O(n),空间复杂度O(n)
题目5:创建二叉排序树并遍历
函数相关伪代码
1.定义树的节点
2.创建树节点的函数
3.递归创建树,通过i来判断是左孩子还是右孩子
4.中序遍历展示树(左-父-右),不断递归输出
函数代码
#include<iostream>
using namespace std;
struct tree {
int a;
tree* lchild;
tree* rchild;
};
tree* Createtree(int k)
{
tree* node = new tree;
node->a = k;
node->lchild = NULL;
node->rchild = NULL;
return node;
}
tree* Buildtree(tree* root, int i)
{
if (root == NULL) {
root = Createtree(i);
return root;
}
if (i < root->a) {
root->lchild = Buildtree(root->lchild, i);
}
else {
root->rchild = Buildtree(root->rchild, i);
}
return root;
}
void Showtree(tree* node)
{
if (node == NULL) {
return;
}
Showtree(node->lchild);
cout << node->a << " ";
Showtree(node->rchild);
}
int main()
{
int k, i;
tree* root = NULL;
for ( i = 0; i < 12; i++) {//题目已给要创建的树,确定了节点个数
cin >> k;
root = Buildtree(root, k);
}
Showtree(root);
return 0;
}
时间复杂度O(n),空间复杂度O(n)
题目6:BST(二叉排序树)的查找、插入与建树与删除
函数相关伪代码
1.定义树的节点
2.创建树节点的函数
3.递归创建树,遇到-1停止建树,根据key来判断左右孩子
4.制作菜单,用switch选择选项来实行操作,do while来实现循环,直到退出
5.寻找节点函数,传递头指针root,递归实现寻找,最后要返回root
6.插入函数,对于key的判断进行递归,直到找到NULL,插入节点
7.删除函数,递归找到被删除节点,
如果左孩子为NULL,直接删除,返回其右节点,
如果右孩子为NULL,直接删除,返回其左节点,
如果左右孩子都不为NULL,找到右子树中的最左节点,把找到的最左孩子的值赋给被删除节点,删除最左孩子节点
函数代码
#include<iostream>
using namespace std;
struct tree {
int a;
tree* lchild;
tree* rchild;
};
tree* menue(tree* root);
tree* Createtree(int k);
tree* Findtree(int key, tree* root);
tree* Inserttree(tree* root, int key);
tree* Deletetree(tree* root, int key);
tree* Showtree(tree* node);
tree* Createtree(int k)
{
tree* node = new tree;
node->a = k;
node->lchild = NULL;
node->rchild = NULL;
return node;
}
tree* Findtree(int key, tree* root)
{
if (root == NULL) {
cout << "没有找到该节点" << endl;
return NULL;
}
else if (key == root->a) {
cout << "找到该节点" << endl;
return root;
}
else if (key < root->a) {
root->lchild = Findtree(key, root->lchild);
}
else {
root->rchild=Findtree(key, root->rchild);
}
return root;
}
tree* Buildtree(tree* root, int key)
{
if (root == NULL) {
root = Createtree(key);
return root;
}
if (key < root->a) {
root->lchild = Buildtree(root->lchild, key);
}
else {
root->rchild = Buildtree(root->rchild, key);
}
return root;
}
tree* Inserttree(tree* root, int key) {
if (root == NULL) {
root = Createtree(key);
cout << "成功插入"<<endl;
return root;
}
if (key < root->a) {
root->lchild = Inserttree(root->lchild, key);
}
if (key > root->a) {
root->rchild = Inserttree(root->rchild, key);
}
return root;
}
tree* Deletetree(tree* root, int key)
{
if (root == NULL) {
cout << "没有找到该节点" << endl;
}
else if (key < root->a) {
root->lchild = Deletetree(root->lchild, key);
}
else if (key > root->a) {
root->rchild = Deletetree(root->rchild, key);
}
else {
if (root->lchild == NULL) {
tree* temp = root->rchild;
delete root;
cout << "删除成功" << endl;
return temp;
}
else if (root->rchild == NULL) {
tree* temp = root->lchild;
delete root;
cout << "删除成功" << endl;
return temp;
}
else {
tree* temp = root->rchild;
while (!temp && temp->lchild != NULL) {
temp = temp->lchild;
}
root->a = temp->a;
root->rchild = Deletetree(root->rchild, temp->a);
}
}
return root;
}
tree* menue(tree * root) {
int s, key;
do {
cout << "欢迎使用BST" << endl << "请选择以下功能" << endl << "1.查找" << endl << "2.插入" << endl << "3.删除" << endl <<"4.中序遍历展示树"<<endl << "5.退出程序" << endl << "请选择你要实现的功能" << endl; cin >> s;
switch (s) {
case 1:
cout << "请输入要查找的节点:";
cin >> key;
root = Findtree(key, root);
break;
case 2:
cout << "请输入要插入的节点:";
cin >> key;
root = Inserttree(root, key);
break;
case 3:
cout << "请输入要删除的节点:";
cin >> key;
root = Deletetree(root, key);
break;
case 4:
root=Showtree(root);
cout << endl;
break;
case 5:
cout << "退出程序";
break;
default:
cout << "输入错误,请重新输入";
break;
}
} while (s != 5);
return root;
}
tree* Showtree(tree* node)
{
if (node == NULL) {
return NULL;
}
Showtree(node->lchild);
cout << node->a << " ";
Showtree(node->rchild);
return node;
}
int main()
{
int k, i;
tree* root = NULL;
cout << "遇到-1停止建树" << endl;
cin >> k;
while(k!=-1){
root = Buildtree(root, k);
cin >> k;
}
menue(root);
return 0;
}
时间复杂度O(n),空间复杂度O(n)
题目7:QQ账户查询
函数相关伪代码
1.定义客户的结构
2.创建客户节点函数
3.制作菜单
4.哈希函数构建,使用哈希法中的链地址法,有7个基本结构,顺序存储着链表的头节点地址,通过输入名字字符长度来实现连接
5.注册函数,输入名字和密码,随机生成账户,并输出
6.查询函数,通过输入名字和密码来查询账户号
函数代码
#include <iostream>
#include <string>
#include <vector>
#include <random>
using namespace std;
struct kehu {
string name;
string mima;
int zhanghu;
kehu* next=NULL;
};
vector<kehu*>number(7);
kehu* Createkehu(string name, string mima);
void zhuce(string name, string mima);
void menue(int n);
void chaxun(string name, string mima);
kehu* haxi(string name);
kehu* Createkehu(string name,string mima,int randomnumber) {
kehu* p = new kehu;
p->name = name;
p->mima = mima;
p->zhanghu = randomnumber;
p->next = NULL;
return p;
}
void menue(int n) {
int i;
string name, mima;
do {
cout << "欢迎使用QQ账户查询系统" << endl;
cout << "1.注册" << endl;
cout << "2.查询账户号" << endl;
cout << "3.退出" << endl;
cout << "请输入你的选择:";
cin >> i;
switch (i) {
case 1:
cout << "请输入用户名:";
cin >> name;
cout << "请输入密码:";
cin >> mima;
zhuce(name, mima);
break;
case 2:
cout << "请输入用户名:";
cin >> name;
cout << "请输入密码:";
cin >> mima;
chaxun(name, mima);
break;
case 3:
cout << "退出" << endl;
break;
default:
cout << "输入错误,请重新输入" << endl;
break;
}
} while (i != 3);
}
kehu* haxi(string name) {
int h = name.length() % 7;
return number[h];
}
void zhuce(string name,string mima) {
kehu* p = haxi(name);
while (p->next != NULL) {
if (p->name == name&&p->mima==mima) {
cout << "用户名已存在,注册失败" << endl;
return;
}
p = p->next;
}
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> dis(100000, 999999);
int randomnumber = dis(gen);
kehu* newnumber = Createkehu(name, mima,randomnumber);
p->next = newnumber;
cout << "注册成功,账号为" <<randomnumber<< endl;
}
void chaxun(string name, string mima) {
kehu* p = haxi(name);
while (p!= NULL) {
if (p->name == name && p->mima == mima) {
cout << "查询成功,该用户账号为" <<p->zhanghu<< endl;
return;
}
p = p->next;
}
cout << "查询失败,用户名或密码错误" << endl;
}
int main()
{
int k;
for (k = 0;k < 7;k++) {
number[k] = new kehu;
number[k]->next = NULL;
}
menue(1);
return 0;
}
时间复杂度O(n),空间复杂度O(n)
三、实验使用环境(本次实验所使用的平台和相关软件)
以下请根据实际情况编写
- 操作系统:Windows 11专业版
- 编程语言:C++
- 开发工具:[Visual Studio 2022(https://code.visualstudio.com/)]
四、实验步骤和调试过程(实验步骤、测试数据设计、测试结果分析)
以下请根据实际情况编写
题目1:先序序列创建二叉树
本机运行截图
无
PTA提交截图
![PTA提交截图]
题目2:先序输出叶结点
本机运行截图
![本机截图]
无
PTA提交截图
![PTA提交截图]
题目3:求二叉树高度
本机运行截图
![本机截图]
无
PTA提交截图
![PTA提交截图]
题目4: jmu-ds-二叉树层次遍历
本机运行截图
![本机截图]
PTA提交截图
![PTA提交截图]
题目5:创建二叉排序树并遍历
本机运行截图
![本机截图]
PTA提交截图
![PTA提交截图]
无
题目6:BST(二叉排序树)的查找、插入与建树与删除
本机运行截图
![本机截图]
PTA提交截图
![PTA提交截图]
无
题目7:QQ账户查询
本机运行截图
![本机截图]
PTA提交截图
![PTA提交截图]
无
五、实验小结(实验中遇到的问题及解决过程、实验体会和收获)
以下请根据实际情况编写
遇到的问题及解决方法:
- 问题:程序崩溃找不到原因,终端崩溃
- 解决方法:使用断点进行调试的方法。
- 问题:树不能返回正确节点
- 解决方法:修改代码,断点调试。
实验体会和收获:
- 掌握了树的应用
- 掌握了哈希算法
- 掌握了随机数的生成