目录
一、实验目的
1、掌握二叉树的定义;
2.掌握二叉树的基本操作,如二叉树的建立、遍历、结点个数统计、树的深度计
算等。
二、实验原理
1. 基本概念
2. 基本操作
2.1 二叉数的定义
struct TreeNode {
    int data;
    struct TreeNode* left;//左孩子
    struct TreeNode* right;//右孩子
}; 
2.2 二叉树的建立
2.2.1 创建新节点
分配内存,且左孩子和右孩子指针置为NULL
struct TreeNode* createNode(int elem) {
    struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    if (newNode == NULL) {//未分配成功
        cout << "内存分配错误" << endl;
        exit(EXIT_FAILURE);
    }
    newNode->data = elem;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;//返回新节点
} 
2.2.2 建立二叉树
递归建立
struct TreeNode* buildTree() {
    int elem;
    cout << "输入节点的数值(-1代表空节点):";
    cin >> elem;
    if (elem == -1) {//输入的是空节点
        return NULL;
    }
    struct TreeNode* root = createNode(elem);//创建新节点
    cout << "输入" << elem << "的左节点" << endl;
    root->left = buildTree();
    cout << "输入" << elem << "的右节点" << endl;
    root->right = buildTree();
    return root;
} 
2.3 二叉树的遍历
2.3.1 先序遍历(NLR)
其遍历顺序为先访问根节点,然后递归地先序遍历左子树,最后递归地先序遍历右子树。
void preOrderTraversal(struct TreeNode* root) {
    if (root != NULL) {
        cout << root->data << " ";//访问节点
        preOrderTraversal(root->left);//访问左孩子
        preOrderTraversal(root->right);//访问右孩子
    }
} 
2.3.2 中序遍历(LNR)
其遍历顺序为先递归地中序遍历左子树,然后访问根节点,最后递归地中序遍历右子树。
void inOrderTraversal(struct TreeNode* root) {
    if (root != NULL) {
        inOrderTraversal(root->left);//访问左孩子
        cout << root->data << " ";//访问节点
        inOrderTraversal(root->right);//访问右孩子
    }
} 
2.3.3 后序遍历(LRN)
其遍历顺序为先递归后序遍历左子树,然后访问右子树,最后递归地后序遍历根节点。
void postOrderTraversal(struct TreeNode* root) {
    if (root != NULL) {
        postOrderTraversal(root->left);//访问左孩子
        postOrderTraversal(root->right);//访问右孩子
        cout << root->data << " ";//访问节点
    }
} 
2.3.4 层次遍历
层次遍历是一种按照树的层级顺序逐层访问节点的遍历方式,也称为广度优先遍历(Breadth-First Traversal)。这种遍历方法通常使用队列来实现,确保每一层的节点按顺序被访问。
struct TreeNode {
    int data;
    struct TreeNode* left;//左孩子
    struct TreeNode* right;//右孩子
};
// 定义队列节点
typedef struct QueueNode {
    struct TreeNode* treeNode;//二叉树节点的指针
    struct QueueNode* next;//下一个节点的指针
} QueueNode;
// 定义队列
typedef struct Queue {
    QueueNode* front;//队列的前端
    QueueNode* rear;//队列的后端
} Queue;
// 初始化队列
void initializeQueue(Queue* queue) {
    queue->front = queue->rear = NULL;
}
// 入队
void enqueue(Queue* queue, TreeNode* treeNode) {
    //创建一个新的队列节点
    QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
    newNode->treeNode = treeNode;
    newNode->next = NULL;
    if (queue->rear == NULL) {//如果队列为空,则此节点为第一个节点
        queue->front = queue->rear = newNode;
    }
    else {
        queue->rear->next = newNode;
        queue->rear = newNode;
    }
}
// 出队
TreeNode* dequeue(Queue* queue) {
    if (queue->front == NULL) {
        return NULL; // 空队列
    }
    TreeNode* treeNode = queue->front->treeNode;
    QueueNode* temp = queue->front;
    queue->front = queue->front->next;
    free(temp);
    if (queue->front == NULL) {//如果是空队列
        queue->rear = NULL;
    }
    return treeNode;
}
// 层次遍历
void levelOrderTraversal(TreeNode* root) {
    if (root == NULL) {
        return; // 空树
    }
    Queue queue;
    initializeQueue(&queue);//初始化队列
    enqueue(&queue, root);//入队
    while (queue.front != NULL) {//当队列不为空
        TreeNode* current = dequeue(&queue);//当前出队的节点
        cout << current->data<<" ";
        if (current->left != NULL) {//若左子树不为空
            enqueue(&queue, current->left);
        }
        if (current->right != NULL) {//若右子树不为空
            enqueue(&queue, current->right);
        }
    }
}
 
2.4 二叉树的节点个数统计
采用递归的方式进行统计
int countNodes(TreeNode* root) {
    if (root == NULL) {//如果为空节点
        return 0;
    }
    else {
        return 1 + countNodes(root->left) + countNodes(root->right);
    }
} 
2.5 二叉树的深度计算
采用递归的方式进行计算
int calculateDepth(TreeNode* root) {
    if (root == NULL) {
        return 0;
    }
    else {
        int leftDepth = calculateDepth(root->left);//左子树的深度
        int rightDepth = calculateDepth(root->right);//右子树的深度
        if (leftDepth > rightDepth) {//如果左子树更深
            return 1 + leftDepth;
        }
        else {
            return 1 + rightDepth;
        }
    }
} 
三、实验内容
问题描述
代码
#include<iostream>
#include <vector>
using namespace std;
struct TreeNode {
    int data;
    struct TreeNode* left;//左孩子
    struct TreeNode* right;//右孩子
};
//建立节点
struct TreeNode* createNode(int elem) {
    struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    if (newNode == NULL) {//未分配成功
        cout << "内存分配错误" << endl;
        exit(EXIT_FAILURE);
    }
    newNode->data = elem;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;//返回新节点
}
//构建二叉树
struct TreeNode* buildTree() {
    int elem;
    cout << "输入节点的数值(-1代表空节点):";
    cin >> elem;
    if (elem == -1) {//输入的是空节点
        return NULL;
    }
    struct TreeNode* root = createNode(elem);//创建新节点
    cout << "输入" << elem << "的左节点" << endl;
    root->left = buildTree();
    cout << "输入" << elem << "的右节点" << endl;
    root->right = buildTree();
    return root;
}
//NLR
void preOrderTraversal(struct TreeNode* root) {
    if (root != NULL) {
        cout << root->data << " ";//访问节点
        preOrderTraversal(root->left);//访问左孩子
        preOrderTraversal(root->right);//访问右孩子
    }
}
//LNR
void inOrderTraversal(struct TreeNode* root) {
    if (root != NULL) {
        inOrderTraversal(root->left);//访问左孩子
        cout << root->data << " ";//访问节点
        inOrderTraversal(root->right);//访问右孩子
    }
}
//LRN
void postOrderTraversal(struct TreeNode* root) {
    if (root != NULL) {
        postOrderTraversal(root->left);//访问左孩子
        postOrderTraversal(root->right);//访问右孩子
        cout << root->data << " ";//访问节点
    }
}
//统计节点数
int countNodes(TreeNode* root) {
    if (root == NULL) {//如果为空节点
        return 0;
    }
    else {
        return 1 + countNodes(root->left) + countNodes(root->right);
    }
}
//统计叶节点个数
//实质统计左右子树均为空的节点
int countLeafNodes(TreeNode* root) {
    if (root == NULL) {//如果为空节点
        return 0;
    }
    else {
        if (root->left == NULL && root->right == NULL) {
            return 1 + countLeafNodes(root->left) + countLeafNodes(root->right);
        }
        else {
            return countLeafNodes(root->left) + countLeafNodes(root->right);
        }
    }
}
//统计单节点个数
int countOneNodes(TreeNode* root) {
    if (root == NULL) {//如果为空节点
        return 0;
    }
    else {
        if (((root->left == NULL) && (root->right!=NULL))||((root->right == NULL) && (root->left != NULL)) ) {//如果是单节点
            return 1 + countOneNodes(root->left) + countOneNodes(root->right);
        }
        else {
            return countOneNodes(root->left) + countOneNodes(root->right);
        }
    }
}
//计算深度
int calculateDepth(TreeNode* root) {
    if (root == NULL) {
        return 0;
    }
    else {
        int leftDepth = calculateDepth(root->left);//左子树的深度
        int rightDepth = calculateDepth(root->right);//右子树的深度
        if (leftDepth > rightDepth) {//如果左子树更深
            return 1 + leftDepth;
        }
        else {
            return 1 + rightDepth;
        }
    }
}
// 构建二叉树,并输出从叶子节点到根节点的路径
void buildTreeAndPrintPaths(TreeNode* root, vector<int>& path) {
    if (root == nullptr) {
        return;
    }
    // 将当前节点加入路径
    path.push_back(root->data);
    // 如果是叶子节点,打印路径
    if (root->left == nullptr && root->right == nullptr) {
        cout << "Path from leaf to root: ";
        for (int i = path.size() - 1; i >= 0; --i) {
            cout << path[i] << " ";
        }
        cout << endl;
    }
    // 递归处理左子树和右子树
    buildTreeAndPrintPaths(root->left, path);
    buildTreeAndPrintPaths(root->right, path);
    // 在返回之前,将当前节点从路径中移除
    path.pop_back();
}
int main() {
    struct TreeNode* root=buildTree();//建立二叉树
    cout << endl <<"中序遍历的结果为:";
    inOrderTraversal(root);
    cout << endl << "先序遍历的结果为:";
    preOrderTraversal(root);
    cout << endl << "后序遍历的结果为:";
    postOrderTraversal(root);
    cout << endl << "二叉树的深度为:" << calculateDepth(root);
    cout << endl << "二叉树的节点个数为:" << countNodes(root);
    cout << endl << "二叉树的叶子节点个数为:" << countLeafNodes(root);
    cout << endl << "二叉树中度为1的节点个数为:" << countOneNodes(root);
    vector<int> path; // 用于存储路径的数组
    // 调用函数进行构建并输出路径
    buildTreeAndPrintPaths(root, path);
    return 0;
} 
截图










