实验4-树、二叉树与查找
集美大学课程实验报告-实验4-树、二叉树与查找
| 项目名称 | 内容 |
|---|---|
| 课程名称 | 数据结构 |
| 昵称 | 带带有无刺 |
| 实验项目名称 | 实验4-树、二叉树与查找 |
| 上机实践日期 | 2026/5/9 |
| 上机实践时间 | 2学时 |
一、实验目的(本次实验所涉及并要求掌握的知识点)
- 掌握创建二叉树与树及二叉树上的基本操作
- 熟练掌握熟练掌握树的递归结构及在其上的递归算法
- 掌握二叉树的层次遍历
- 掌握BST树上的搜索、创建与删除
- 掌握哈希表、平衡树的应用
二、实验内容与设计思想
以下请根据实际情况编写
题目1:先序序列创建二叉树
采用标准建树代码以先序序列建成一颗二叉树。
题目伪代码
// 二叉树结点结构
struct BiTNode {
char data;
BiTNode *lchild;
BiTNode *rchild;
};
// 全局索引变量
int index;
// 先序字符串创建二叉树
void CreateBiTree(BiTNode **T, char str[]) {
char ch = str[index++];
if (ch == '#') {
*T = NULL;
} else {
*T = 申请结点空间;
(*T)->data = ch;
CreateBiTree(&(*T)->lchild, str);
CreateBiTree(&(*T)->rchild, str);
}
}
// 中序遍历
void InOrder(BiTNode *T) {
if (T != NULL) {
InOrder(T->lchild);
输出 T->data 与空格;
InOrder(T->rchild);
}
}
// 后序释放二叉树
void FreeTree(BiTNode *T) {
if (T != NULL) {
FreeTree(T->lchild);
FreeTree(T->rchild);
释放结点空间;
}
}
// 主函数逻辑
int main() {
char str[101];
while (输入字符串 str 未到结束) {
index = 0;
BiTNode *T;
CreateBiTree(&T, str);
InOrder(T);
换行输出;
FreeTree(T);
}
return 0;
}
题目代码
//代码时间复杂度为O(n),空间复杂度为O(n).
#include <stdio.h>
#include <stdlib.h>
typedef struct BiTNode {
char data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
int index;
void CreateBiTree(BiTree *T, char str[]) {
char ch = str[index++];
if (ch == '#') {
*T = NULL;
return;
} else {
*T = (BiTNode *)malloc(sizeof(BiTNode));
(*T)->data = ch;
CreateBiTree(&(*T)->lchild, str);
CreateBiTree(&(*T)->rchild, str);
}
}
void InOrder(BiTree T) {
if (T) {
InOrder(T->lchild);
printf("%c ", T->data);
InOrder(T->rchild);
}
}
void FreeTree(BiTree T) {
if (T) {
FreeTree(T->lchild);
FreeTree(T->rchild);
free(T);
}
}
int main() {
char str[101];
while (scanf("%s", str) != EOF) {
index = 0;
BiTree T;
CreateBiTree(&T, str);
InOrder(T);
printf("\n");
FreeTree(T);
}
return 0;
}
题目二:先序输出叶结点
用左右子树是否均为空的判断方法、采用递归形式判断是否已递归到叶节点,然后直接输出叶节点即可实现先序输出。
函数伪代码
void PreorderPrintLeaves( BinTree BT ){
if (BT为空树) return;
if (BT左子树与右子树均为空){
printf(" %c", BT->Data);
}
PreorderPrintLeaves(BT->Left); //对BT左右子树递归执行
PreorderPrintLeaves(BT->Right);
}
函数代码
//上方为裁判程序//
#include <stdio.h>
#include <stdlib.h>
typedef char ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
ElementType Data;
BinTree Left;
BinTree Right;
};
BinTree CreatBinTree(); /* 实现细节忽略 */
void PreorderPrintLeaves( BinTree BT );
int main()
{
BinTree BT = CreatBinTree();
printf("Leaf nodes are:");
PreorderPrintLeaves(BT);
printf("\n");
return 0;
}
/* 函数代码如下 */
//函数时间复杂度为O(n),空间复杂度为O(n).
void PreorderPrintLeaves( BinTree BT ){
if (!BT) return;
if (!BT->Left && !BT->Right){
printf(" %c", BT->Data);
}
PreorderPrintLeaves(BT->Left);
PreorderPrintLeaves(BT->Right);
}
题目三:求二叉树高度
依靠“二叉树高度=左右子树高度的最大值+1”公式,采用后序递归思想,通过先求左子树高度再求右子树高度,进而对比出最高的子树高度再加1即可得出二叉树的高度。
函数伪代码
int GetHeight( BinTree BT ){
if (BT为空树){
return 0;
}
int leftheight = GetHeight(BT->Left); //递归执行
int rightheight = GetHeight(BT->Right);
int max;
if (leftheight > rightheight){
max = leftheight;
} else {
max = rightheight;
}
int height = max + 1;//高度每一次对比都增加一层
return height;
}
函数代码
//函数时间复杂度为O(n),空间复杂度为O(n).
int GetHeight( BinTree BT ){
if (BT == NULL){
return 0;
}
int leftheight = GetHeight(BT->Left);
int rightheight = GetHeight(BT->Right);
int max;
if (leftheight > rightheight){
max = leftheight;
} else {
max = rightheight;
}
int height = max + 1;
return height;
}
题目四:二叉树层次遍历(广度优先)
用队列对二叉树进行层次遍历,将每层的结点入队再出队即可实现层次遍历。
题目伪代码
// 结构体定义
typedef struct BiTNode {
char data;
BiTNode *lchild;
BiTNode *rchild;
} BiTNode, *BiTree;
typedef struct QNode {
BiTree data;
QNode *next;
} QNode;
typedef struct {
QNode *front;
QNode *rear;
} LinkQueue;
// 初始化链式队列
void InitQueue(LinkQueue *q) {
分配QNode类型头结点;
q->front = q->rear = 头结点地址;
q->front->next = NULL;
}
// 入队操作
void EnQueue(LinkQueue *q, BiTree t) {
新建QNode结点p;
p->data = t;
p->next = NULL;
q->rear->next = p;
q->rear = p;
}
// 出队操作
int DeQueue(LinkQueue *q, BiTree *t) {
if (q->front == q->rear) {
return 0;
}
QNode *p = q->front->next;
*t = p->data;
q->front->next = p->next;
if (q->rear == p) {
q->rear = q->front;
}
释放结点p;
return 1;
}
// 判断队列是否为空
int QueueEmpty(LinkQueue q) {
return q.front == q.rear;
}
// 按完全二叉树下标规则递归建树
void BuildTree(BiTree *T, char s[], int i, int n) {
if (i >= n || s[i] == '#') {
*T = NULL;
return;
}
分配BiTNode结点空间;
(*T)->data = s[i];
BuildTree(&(*T)->lchild, s, 2*i, n);
BuildTree(&(*T)->rchild, s, 2*i+1, n);
}
// 二叉树层序遍历
void LevelOrder(BiTree T) {
if (T == NULL) {
输出 "NULL";
return;
}
LinkQueue q;
InitQueue(&q);
EnQueue(&q, T);
int first = 1;
while (!QueueEmpty(q)) {
BiTree node;
DeQueue(&q, &node);
if (!first) {
printf 空格;
}
输出 node->data;
first = 0;
if (node->lchild != NULL) {
EnQueue(&q, node->lchild);
}
if (node->rchild != NULL) {
EnQueue(&q, node->rchild);
}
}
}
int main() {
char s[1005];
读取字符串s;
int n = 字符串长度;
BiTree T;
BuildTree(&T, s, 1, n);
LevelOrder(T);
return 0;
}
题目代码
//函数时间复杂度为O(n),空间复杂度为O(n).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct BiTNode {
char data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
typedef struct QNode {
BiTree data;
struct QNode *next;
} QNode;
typedef struct {
QNode *front, *rear;
} LinkQueue;
void InitQueue(LinkQueue *q) {
q->front = q->rear = (QNode*)malloc(sizeof(QNode));
q->front->next = NULL;
}
void EnQueue(LinkQueue *q, BiTree t) {
QNode *p = (QNode*)malloc(sizeof(QNode));
p->data = t;
p->next = NULL;
q->rear->next = p;
q->rear = p;
}
int DeQueue(LinkQueue *q, BiTree *t) {
if(q->front == q->rear) return 0;
QNode *p = q->front->next;
*t = p->data;
q->front->next = p->next;
if(q->rear == p) q->rear = q->front;
free(p);
return 1;
}
int QueueEmpty(LinkQueue q) {
return q.front == q.rear;
}
void BuildTree(BiTree *T, char *s, int i, int n) {
if(i >= n || s[i] == '#') {
*T = NULL;
return;
}
*T = (BiTree)malloc(sizeof(BiTNode));
(*T)->data = s[i];
BuildTree(&(*T)->lchild, s, 2*i, n);
BuildTree(&(*T)->rchild, s, 2*i+1, n);
}
void LevelOrder(BiTree T) {
if(T == NULL) {
printf("NULL");
return;
}
LinkQueue q;
InitQueue(&q);
EnQueue(&q, T);
int first = 1;
while(!QueueEmpty(q)) {
BiTree node;
DeQueue(&q, &node);
if(!first) printf(" ");
printf("%c", node->data);
first = 0;
if(node->lchild) EnQueue(&q, node->lchild);
if(node->rchild) EnQueue(&q, node->rchild);
}
}
int main() {
char s[1005];
scanf("%s", s);
int n = strlen(s);
BiTree T;
BuildTree(&T, s, 1, n);
LevelOrder(T);
return 0;
}
题目五:创建二叉排序树并遍历:给定一串50 30 80 20 40 90 10 25 35 85 23 88 #创建二叉排序树并对其进行中序遍历
和二叉树建立类似,只不过要按二叉排序树的顺序将元素插入二叉树。
题目伪代码
//建排序树结构体
typedef struct BSTNode {
int data;
struct BSTNode *lchild, *rchild;
} BSTNode, *BSTree;
int BSTInsert(BSTree *T, int val){
if (T为空){
*T = (BSTree)malloc(sizeof(BSTNode));//为新建T分配内存
(*T)->data = val;
(*T)->lchild = NULL;
(*T)->rchild = NULL;
return 1;
}
if (val == (*T)->data){
return 0;
} else if (val < (*T)->data) { //二叉排序树插入,比根节点小的去左子树,大的去右子树
return BSTInsert(&(*T)->lchild, val);
} else {
return BSTInsert(&(*T)->rchild, val);
}
}
void CreateBST(BSTree *T, int arr[], int n){
*T = NULL;
for (int i = 0; i < n; i++){
BSTInsert(T, arr[i]);
}
}
//中序输出
void InOrder(BSTree T){
if (T != NULL){
InOrder(T->lchild);
printf("%d ", T->data);
InOrder(T->rchild);
}
}
int main(){
int arr[] = {50, 30, 80, 20, 40, 90, 10, 25, 35, 85, 23, 88};
int n = sizeof(arr) / sizeof(arr[0]);
BSTree T;
CreateBST(&T, arr, n);
InOrder(T);
printf("\n");
return 0;
}
题目代码
//函数时间复杂度为O(n),空间复杂度为O(n).
#include <stdio.h>
#include <stdlib.h>
typedef struct BSTNode {
int data;
struct BSTNode *lchild, *rchild;
} BSTNode, *BSTree;
int BSTInsert(BSTree *T, int val){
if (*T == NULL){
*T = (BSTree)malloc(sizeof(BSTNode));
(*T)->data = val;
(*T)->lchild = NULL;
(*T)->rchild = NULL;
return 1;
}
if (val == (*T)->data){
return 0;
} else if (val < (*T)->data) {
return BSTInsert(&(*T)->lchild, val);
} else {
return BSTInsert(&(*T)->rchild, val);
}
}
void CreateBST(BSTree *T, int arr[], int n){
*T = NULL;
for (int i = 0; i < n; i++){
BSTInsert(T, arr[i]);
}
}
void InOrder(BSTree T){
if (T != NULL){
InOrder(T->lchild);
printf("%d ", T->data);
InOrder(T->rchild);
}
}
int main(){
int arr[] = {50, 30, 80, 20, 40, 90, 10, 25, 35, 85, 23, 88};
int n = sizeof(arr) / sizeof(arr[0]);
BSTree T;
CreateBST(&T, arr, n);
InOrder(T);
printf("\n");
return 0;
}
题目七:QQ帐户的申请与登陆
用C++自带的功能使用哈希映射保存 QQ 账号、密码。循环处理每组操作:N注册:先查是否已存在,不存在则存入;L登录:先查账号是否存在,再比对密码。利用哈希表快速查找,保证大量操作下的高效。
题目伪代码
调用哈希表 <string, string> mp;
char op[2];
char qq_buf[20], pwd_buf[20]; //建立QQ号和密码数组
int main()
{
int n;
scanf("%d", &n);
while (n--) //循环n次
{
输入("%s %s %s", op, qq_buf, pwd_buf);
字符化 id(qq_buf);
字符化 pwd(pwd_buf);
if (输入N注册)
{
if (哈希表中存在输入的QQ号)
{
printf("ERROR: Exist\n");
}
else
{
在哈希表中存入QQ号和密码;
printf("New: OK\n");
}
}
else if (输入L登陆)
{
if (哈希表中无输入的QQ号)
{
printf("ERROR: Not Exist\n");
}
else if (哈希表中的密码和输入的QQ号不匹配)
{
printf("ERROR: Wrong PW\n");
}
else
{
printf("Login: OK\n");
}
}
}
return 0;
}
题目代码
//函数时间复杂度为O(n),空间复杂度为O(n).
#include <iostream>
#include <unordered_map>
#include <string>
#include <cstdio>
using namespace std;
unordered_map<string, string> mp;
char op[2];
char qq_buf[20], pwd_buf[20];
int main()
{
int n;
scanf("%d", &n);
while (n--)
{
scanf("%s %s %s", op, qq_buf, pwd_buf);
string id(qq_buf);
string pwd(pwd_buf);
if (op[0] == 'N')
{
if (mp.find(id) != mp.end())
{
printf("ERROR: Exist\n");
}
else
{
mp[id] = pwd;
printf("New: OK\n");
}
}
else if (op[0] == 'L')
{
if (mp.find(id) == mp.end())
{
printf("ERROR: Not Exist\n");
}
else if (mp[id] != pwd)
{
printf("ERROR: Wrong PW\n");
}
else
{
printf("Login: OK\n");
}
}
}
return 0;
}
三、实验使用环境(本次实验所使用的平台和相关软件)
- 操作系统:Windows 11专业版
- 编程语言:C++
- 开发工具:DevC++ v5.11
- 编译器:DecC++ v5.11
四、实验步骤和调试过程
题目一:先序序列创建二叉树 运行截图

题目二:先序输出叶节点 运行截图

题目三:求二叉树高度 运行截图

题目四:二叉树层次遍历(广度优先) 运行截图

题目五:创建二叉排序树并遍历 运行截图

题目七:QQ帐户的申请与登陆 运行截图
五、实验小结(实验中遇到的问题及解决过程、实验体会和收获)
遇到的问题及解决方法:
- 问题:Visual Studio编译代码总是出错,堆内存溢出,scanf函数报错。
- 解决方法:将IDE更换为DevC++。
- 问题:在编写题目七的代码时,由于IDE版本过旧导致无法使用代码中调用的哈希表库。
- 解决方法:在DevC++的编译选项中输入-std=c++11。
- 问题:在编写题目四的代码时没有正确理解题意,代码写成了将输入的数据先序遍历后再入队的形式导致答案错误。
- 解决方法:将代码改为适配顺序输入后答案正确。
实验体会和收获:
- 学会了如何调试IDE使其适配工作。
- 学习了哈希表的用法和用处。
- 练习了建立二叉树、遍历二叉树、输出结点、求树高度等二叉树相关代码书写。
- 复习了建队、入队、出队代码的书写。
- 练习了各个学过的知识点的融会贯通,加强了代码模块化处理能力。
- 首次体验了博客的书写,学会了如何编写markdown格式文本,体会到了markdown格式对于计算机行业的优越性。

浙公网安备 33010602011771号