集美大学课程实验报告-实验4-树、二叉树与查找

集美大学课程实验报告-实验4-树、二叉树与查找

项目名称 内容
课程名称 数据结构
班级 网安2511
学号 202521336001
实验项目名称 树、二叉树与查找
上机实践日期 2026.05.09
上机实践时间 2学时

一、目的(本次实验所涉及并要求掌握的知识点)

  • 掌握二叉树与树及二叉树的基本操作。
  • 掌握二叉树的层次遍历。
  • 掌握BST树上的搜索、创建与删除。
  • 掌握哈希表、平衡树的应用。

二、实验内容与设计思想

题目1:先序序列创建二叉树

函数相关伪代码

BuildTree(s, index):
    如果 index 超出字符串长度 或 s[index] == '#':
        index 加 1
        返回空指针

    创建新节点 root
    root.data ← s[index]
    index 加 1

    root.lchild ← BuildTree(s, index)
    root.rchild ← BuildTree(s, index)

    返回 root

InOrderTraversal(root):
    如果 root 不为空:
        InOrderTraversal(root.lchild)
        输出 root.data
        InOrderTraversal(root.rchild)

FreeTree(root):
    如果 root 不为空:
        FreeTree(root.lchild)
        FreeTree(root.rchild)
        删除 root

主程序:
    读入字符串 s
    初始化 index ← 0
    root ← BuildTree(s, index)
    调用 InOrderTraversal(root)
    调用 FreeTree(root)

函数代码

#include <iostream>
#include <string>
using namespace std;

typedef char ElemType;
typedef struct BiTNode {
    ElemType data;
    struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;

BiTree BuildTree(string& s, int& index) {
    if (index >= s.size() || s[index] == '#') {
        index++; 
        return nullptr;
    }
    BiTree root = new BiTNode; 
    root->data = s[index];  
    index++; 
    root->lchild = BuildTree(s, index); 
    root->rchild = BuildTree(s, index);
    return root;
}
//中序
void InOrderTraversal(BiTree root) {
    if (root != NULL) {
        InOrderTraversal(root->lchild); 
        cout << root->data << " ";  
        InOrderTraversal(root->rchild); 
    }
}

void FreeTree(BiTree root) {
    if (root != NULL) {
        FreeTree(root->lchild);
        FreeTree(root->rchild);
        delete root;
    }
}
int main() {
    string s;
    while (cin >> s) { 
        int index = 0;
        BiTree root = BuildTree(s, index);
        InOrderTraversal(root);
        cout << endl;
        FreeTree(root);
    }
    return 0;
}

题目2:先序输出叶结点

函数相关伪代码

PreorderPrintLeaves(BT):
    如果 BT 为空:
        返回

    如果 BT 是叶结点:
        输出 " " + BT.Data

    PreorderPrintLeaves(BT.Left)
    PreorderPrintLeaves(BT.Right)

函数代码

void PreorderPrintLeaves( BinTree BT ) {
    if (BT == NULL) {
        return;
    }
    if (BT->Left == NULL && BT->Right == NULL) {
        printf(" %c", BT->Data);
        return;
    }
    PreorderPrintLeaves(BT->Left);
    PreorderPrintLeaves(BT->Right);
}

题目3:求二叉树高度

函数相关伪代码

FUNCTION GetHeight(BT):
    IF BT IS NULL THEN
        RETURN 0
    END IF
    
    left_height = GetHeight(BT.Left)
    right_height = GetHeight(BT.Right)
    
    IF left_height > right_height THEN
        RETURN left_height + 1
    ELSE
        RETURN right_height + 1
    END IF
END FUNCTION

函数代码

int GetHeight( BinTree BT ) {
    if (BT == NULL) {
        return 0;
    }
    
    int leftHeight = GetHeight(BT->Left);
    int rightHeight = GetHeight(BT->Right);
    
    if (leftHeight > rightHeight) {
        return leftHeight + 1;
    } else {
        return rightHeight + 1;
    }
}

题目4:二叉树层次遍历

函数相关伪代码

BuildTree(index):
    if index > n 或 s[index] == '#':
        return NULL
    node = new TreeNode(s[index])
    node.left = BuildTree(2 * index)
    node.right = BuildTree(2 * index + 1)
    return node

LevelOrder(root):
    if root == NULL:
        print "NULL"
        return
    queue ← root
    first ← true
    while queue 非空:
        node ← queue.pop()
        if first:
            print node.data
            first ← false
        else:
            print " " + node.data
        if node.left != NULL:
            queue.push(node.left)
        if node.right != NULL:
            queue.push(node.right)

函数代码

#include <iostream>
#include <queue>
#include <string>
using namespace std;

struct TreeNode {
    char data;
    TreeNode* left;
    TreeNode* right;
    TreeNode(char d) : data(d), left(NULL), right(NULL) {}
};

string s;

// 根据顺序存储构建二叉链表
TreeNode* buildTree(int index) {
    if (index >= s.length() || s[index] == '#')
        return NULL;
    TreeNode* node = new TreeNode(s[index]);
    node->left = buildTree(2 * index);
    node->right = buildTree(2 * index + 1);
    return node;
}

// 层次遍历
void levelOrder(TreeNode* root) {
    if (!root) {
        cout << "NULL";
        return;
    }

    queue<TreeNode*> q;
    q.push(root);
    bool first = true;

    while (!q.empty()) {
        TreeNode* cur = q.front();
        q.pop();
        if (first) {
            cout << cur->data;
            first = false;
        } else {
            cout << " " << cur->data;
        }
        if (cur->left) q.push(cur->left);
        if (cur->right) q.push(cur->right);
    }
}

int main() {
    cin >> s;
    TreeNode* root = buildTree(1); // 从下标1开始
    levelOrder(root);
    return 0;
}

题目5:创建二叉排序树并遍历

函数相关伪代码

定义节点:存数字,左、右指针
函数 add(树, x):
空就新建节点
小就放左边
大放右边
函数 in(树):
左 → 输出 → 右
主函数:
读数字,加入树
中序遍历输出

函数代码

#include <iostream>
using namespace std;
struct Node {
    int data;
    Node *l, *r;
};
void add(Node* &t, int x) {
    if(!t) {
        t=new Node;
        t->data=x;
        t->l=t->r=NULL;
    } else if(x<t->data) add(t->l,x);
    else add(t->r,x);
}
void in(Node* t) {
    if(t) {
        in(t->l);
        cout<<t->data<<" ";
        in(t->r);
    }
}
int main() {
    Node* root=NULL;
    int x;
    while(cin>>x) add(root,x);
    in(root);
    return 0;
}

题目6:BST的查找与插入

函数相关伪代码

定义节点结构
数据 data
左孩子 left
右孩子 right
函数 查找(根, 关键字)
如果 根为空 或 找到关键字
返回 根
如果 关键字 < 根数据
返回 查找左子树
否则
返回 查找右子树
函数 插入(根, 新数据)
如果 根为空
新建节点并赋值
如果 新数据 < 根数据
插入到左子树
如果 新数据 > 根数据
插入到右子树

函数代码

#include <iostream>
using namespace std;
struct Node {
    int data;
    Node *left, *right;
};
Node* search(Node* root, int key) {
    if (!root || root->data == key)
        return root;
    if (key < root->data)
        return search(root->left, key);
    else
        return search(root->right, key);
}
void insert(Node* &root, int key) {
    if (!root) {
        root = new Node;
        root->data = key;
        root->left = root->right = NULL;
        return;
    }
    if (key < root->data) {
        insert(root->left, key);
    } else if (key > root->data) {
        insert(root->right, key);
    }
}
int main() {
     Node* root = NULL;
    int a[] = {50, 30, 80, 20, 40, 90, 10, 25, 35, 85, 23, 88};
    int n = sizeof(a) / sizeof(a[0]);
    for (int i = 0; i < n; i++) {
        insert(root, a[i]);
    }
    int key;
    cout << "请输入要查找的数字:";
    cin >> key;
    if (search(root, key))
        cout << "找到 " << key << endl;
    else
        cout << "未找到 " << key << endl;
    return 0;
}

题目7:哈希表、平衡树的应用

函数相关伪代码

定义结构体 VIP:
编号 id
姓名 name
创建哈希表数组 h,大小 N
创建标记数组 used,标记位置是否被占用
函数 哈希函数(s):
把字符串每个字符加起来 → 对 N 取模 → 返回下标
函数 插入(id, name):
计算位置 p
当位置 p 已被占用:
p = (p+1) % N
存入 id 和 name
标记 used[p] = 已占用
函数 查询(id):
计算位置 p
当位置 p 已被占用:
如果 h[p].id == 输入id
输出姓名,返回
p = (p+1) % N
输出 无此客户
主函数:
初始化 used 全部为 未占用
循环输入操作:
1 → 插入 id 和 name
2 → 查询 id
0 → 退出

函数代码

#include <iostream>
using namespace std;
const int N = 20;
struct VIP {
    string id, name;
} h[N];
bool used[N];
int getHash(string s) {
    int x = 0;
    for(char c : s) x += c;
    return x % N;
}
void insert(string id, string name) {
    int p = getHash(id);
    // 用 !used[p] 表示未被占用
    while(used[p]) p = (p+1) % N;
    h[p].id = id;
    h[p].name = name;
    used[p] = true;
}
void find(string id) {
    int p = getHash(id);
    while(used[p]) {
        if(h[p].id == id) {
            cout << "找到:" << h[p].name << endl;
            return;
        }
        p = (p+1) % N;
    }
    cout << "无此客户" << endl;
}
int main() {
   for(int i=0; i<N; i++) used[i] = false;
    int op;
    string id, name;
    while(cin >> op) {
        if(op == 1) {
            cin >> id >> name;
            insert(id, name);
        }
        else if(op == 2) {
            cin >> id;
            find(id);
        }
        else break;
    }
    return 0;
}


三、实验使用环境(本次实验所使用的平台和相关软件)

  • 操作系统:Microsoft Windows [版本 10.0.26200.8246]
  • 编程语言:C++
  • 开发工具Visual Studio 2022
  • 编译器:VS2022

四、实验步骤和调试过程(实验步骤、测试数据设计、测试结果分析)

题目1:先序序列创建二叉树

本机运行截图
image

PTA提交截图
image

题目2:先序输出叶结点

PTA提交截图
image

题目3:求二叉树高度

PTA提交截图
image

题目4:二叉树层次遍历

本机运行截图
image

PTA提交截图
image

题目5:创建二叉排序树并遍历

本机运行截图
image

题目6:BST的查找与插入

本机运行截图
image

题目7:哈希表、平衡树的应用

本机运行截图
image

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

遇到的问题及解决方法:

  1. 问题:程序崩溃找不到原因
    • 解决方法:使用打断点进行调试的方法。
  2. 问题:层次遍历队列空指针访问。
    • 解决方法:入队前判断结点是否为空。

实验体会和收获:

  • 掌握了二叉树的递归创建、遍历。
  • 掌握队列实现层次遍历的方法。
  • 理解哈希表O(1)平均查找效率。

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

  1. 二叉搜索树的节点删除(OJ)
  2. 倒排索引
  3. 二叉搜索树(OJ)
posted @ 2026-05-09 00:39  Wujee  阅读(20)  评论(0)    收藏  举报