0
点赞
收藏
分享

微信扫一扫

数据结构-树(C++)

343d85639154 2024-01-12 阅读 19

目录

一、实验目的

二、实验原理

1. 基本概念

2. 基本操作

2.1 二叉数的定义

2.2 二叉树的建立

2.2.1 创建新节点

2.2.2 建立二叉树

2.3 二叉树的遍历

2.3.1 先序遍历(NLR)

2.3.2 中序遍历(LNR)

2.3.3 后序遍历(LRN)

2.3.4 层次遍历

2.4 二叉树的节点个数统计

2.5 二叉树的深度计算

三、实验内容

问题描述

代码

截图


一、实验目的

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;
}

截图

 

举报

相关推荐

0 条评论