实验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

四、实验步骤和调试过程

题目一:先序序列创建二叉树 运行截图

79b5e4826a07afc76c5bfb8332829be1

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

图片2

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

图片3

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

图片4

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

ScreenShot_2026-05-09_153507_579

题目七:QQ帐户的申请与登陆 运行截图

图片7

五、实验小结(实验中遇到的问题及解决过程、实验体会和收获)

遇到的问题及解决方法:

  1. 问题:Visual Studio编译代码总是出错,堆内存溢出,scanf函数报错。
    • 解决方法:将IDE更换为DevC++。
  2. 问题:在编写题目七的代码时,由于IDE版本过旧导致无法使用代码中调用的哈希表库。
    • 解决方法:在DevC++的编译选项中输入-std=c++11。
  3. 问题:在编写题目四的代码时没有正确理解题意,代码写成了将输入的数据先序遍历后再入队的形式导致答案错误。
    • 解决方法:将代码改为适配顺序输入后答案正确。

实验体会和收获:

  • 学会了如何调试IDE使其适配工作。
  • 学习了哈希表的用法和用处。
  • 练习了建立二叉树、遍历二叉树、输出结点、求树高度等二叉树相关代码书写。
  • 复习了建队、入队、出队代码的书写。
  • 练习了各个学过的知识点的融会贯通,加强了代码模块化处理能力。
  • 首次体验了博客的书写,学会了如何编写markdown格式文本,体会到了markdown格式对于计算机行业的优越性。

六、附件(参考文献和相关资料)

  1. 实验4-树、二叉树与查找
  2. PTA平台
  3. 豆包
  4. 《DevC++支持C++11等与其软件分辨率低的解决办法》
  5. 【Markdown 完全指南】5 分钟上手,让你的笔记永远不被软件绑架!
posted on 2026-05-09 17:01  带带有无刺  阅读(4)  评论(0)    收藏  举报