数据结构 其五 树与二叉树学习总结

数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。

前言

树是一种非线性存储结构,通过一些方法可以用二叉树表示任意树。因此,本文重点介绍二叉树的基本操作。

1. 树与二叉树介绍

1.1 什么是树

对于数据结构的学习只需要关注两点就够了:1. 数据 2. 结构。

树(tree)是一种非线性存储结构,例如下述示意图:

树示意图

  1. 每一个方框代表一个节点(数据),连接节点的线称之为边或枝(结构)。
  2. 通过边相连的节点之间存在父子关系,位于上层的节点称之为父节点,位于下层的节点称之为子节点,具有相同父节点的节点称之为兄弟节点。
  3. 整棵树的最上层的节点(即没有父节点)称之为根节点。
  4. 从根节点到某个节点之间的边数,称之为这个节点的深度
  5. 以一个节点的一个子节点为根节点的树,称之为这个节点的子树。例如:上图中的root节点有三颗子树。
  6. 一个节点的子节点个数称之为该节点的度。例如:上图中root节点的度为3.

1.1.1 树的性质

  • 一个节点可以有多个子节点,但只能有一个父节点

  • 一颗树的节点个数 = 边数 + 1

1.2 什么是二叉树

  • 每个节点最多只有两个子节点,分别称之为左子节点、右子节点。
  • 当假设二叉树的根节点为第0层时,二叉树的第n层最多有2^n个节点。

1.2.1 二叉树的分类

  • 满二叉树 (中国版):假设一颗树的深度为d,则当这颗树在深度为d的节点个数为2^(d + 1) - 1时,称之为满二叉树
  • 完全二叉树(complete binary tree):除了最下层外,其余层的节点数都达到了该层的上限,并且最下层的节点满足从左到右依次排列(可以没有右节点,但不能在有右节点的情况下没有左节点)。
  • 全二叉树 (full binary tree): 每个节点要么没有子节点,要么同时有两个子节点。

1.3 二叉树的框架代码(C++版)

#include <iostream>

using namespace std;
// 节点
class Node {
public:
    int data;				// 数据
    Node *lchild;			// 左节点
    Node *rchild;			// 右节点
    Node (int new_data);	// 初始化节点
    ~Node ();				// 回收节点空间
};
// 二叉树
class BinaryTree {
private:
    Node *root;				// 根节点
public:
    BinaryTree();			// 初始化二叉树
    ~BinaryTree();			// 回收二叉树的空间
    void build(int n);		// 构造一棵二叉树
    void pre_order(Node *);	// 先序遍历
    void in_order(Node *);	// 中序遍历
    void post_order(Node *);// 后序遍历
};

下述的所有代码都是基于这个框架

2. 二叉树的操作

2.1 初始化节点

初始化节点是将数据封装为节点

2.1.1 步骤

  1. 将数据保存到数据域中
  2. 将左右子节点置为空

2.1.2 代码展示

Node(int new_data) {
    data   = new_data;
    lchild = NULL;
    rchild = NULL;
}
// 回收节点空间只需要依次回收左右子节点即可
~Node() {
    if (lchild != NULL) {
        delete lchild;
    }
    if (rchild != NULL) {
        delete rchild;
    }
}

2.2 初始化二叉树

初始二叉树中不存在节点

2.2.1 步骤

  1. 将根节点置空

2.2.2 代码展示

BinaryTree() {
    root = NULL;
}
// 二叉树中的节点已经通过Node类回收完毕
~BinaryTree() {
    delete root;
}

2.3 构造二叉树

void build(int n);

2.3.1 步骤

  • 首先将数据封装成节点
  • 之后根据需要将节点插入到二叉树中(本文以左子<=当前节点<右子 的规则插入)

2.3.2 代码展示

void build(Node *node) {
    root = insert(root, node);
    return;
}
Node* insert(Node *root, Node *node) {
    if (root == NULL) return node;
    if (node->data <= root->data) {
        root->lchild = insert(root->lchild, node);
    }
    else {
        root->rchild = insert(root->rchild, node);
    }
    return root;
}

2.4 先序遍历

void pre_order(Node *node)

树的访问都遵循着 先左后右的顺序,但根据节点的打印顺序分为先序遍历、中序遍历和后序遍历。

2.4.1 步骤

  • 打印当前节点
  • 打印左子节点
  • 打印右子节点

2.4.2 代码展示

void pre_order(Node *node) {
    if (node == NULL) return;
    cout << node->data << " ";
    pre_order(node->lchild);
    pre_order(node->rchild);
}

2.5 中序遍历

void in_order(Node *)

2.5.1 步骤

  • 打印左子节点
  • 打印当前节点
  • 打印右子节点

2.5.2 代码展示

void in_order(Node *node) {
    if (node == NULL) return;
    in_order(node->lchild);
    cout << node->data << " ";
    in_order(node->rchild);
}

2.6 后序遍历

void post_order(Node *)

2.5.1 步骤

  • 打印左子节点
  • 打印右子节点
  • 打印当前节点

2.5.2 代码展示

void post_order(Node *node) {
    if (node == NULL) return;
    post_order(node->lchild);
    post_order(node->rchild);
    cout << node->data << " ";
}

3. 结果展示

3.1 完整代码

1
2
3

运行结果

运行结果

总结

本文主要介绍了基础的树型结构以及二叉树的遍历。如果给二叉树的构造附加上其他的规则,那么便能衍生出更为高级的树型数据结构。

本文仅为个人的学习总结,欢迎各位大佬勘误。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页