赞
踩
目录
这篇文章介绍数据结构中的树和二叉树
。
在计算机科学中,树(Tree)是一种抽象数据类型,用于模拟具有树状结构特征的数据集合。树是由一组节点(Nodes)和连接这些节点的边(Edges)组成的,其中一个节点被指定为根节点(Root),其余节点分层组织成子树(Subtrees)。树的每个节点除了根节点外,都恰好连接到一条来自另一个节点的边,这个节点被称为其父节点(Parent Node)。每个节点可以连接到零个或多个子节点,子节点的节点被称为父节点的孩子节点(Child Node)。
树的定义如下:
树的定义为我们提供了一种非常有用的数据结构,可用于表示层次化数据,例如文件系统、组织结构、家谱等等。树也是许多重要算法和数据结构的基础,例如二叉搜索树、堆、图等。
二叉树是一种树型结构,它的特点是每个节点至多只有两颗子树,并且二叉树的子树有左右之分,其次序不能任意颠倒。
1.在二叉树的第i层上,最多可以有2^(i-1)个节点
2.深度为k的二叉树至多有2^k-1个节点
3.对任何一二叉树T,如果其终端节点数为n0,度为2的节点数为n2,则n0 = n2+1
二叉树一般使用二叉链表表示。
我们使用data表示二叉树数据域,leftChild和rightChild表示二叉树的左右节点。
因此二叉树定义如下:
- // 二叉树节点的数据类型
- typedef char TElementType;
-
- // 二叉树结点的定义
- typedef struct BiTNode {
- TElementType data;
- struct BiTNode * leftChild, * rightChild;
- } BiTNode, * BiTree;
- // 先序遍历二叉树
- void preOrderTraverse(BiTree tree) {
- if (tree != nullptr) {
- cout << tree->data << " "; // 访问根节点
- preOrderTraverse(tree->leftChild); // 先序遍历左子树
- preOrderTraverse(tree->rightChild); // 先序遍历右子树
- }
- }
- // 中序遍历二叉树
- void inOrderTraverse(BiTree tree) {
- if (tree != nullptr) {
- inOrderTraverse(tree->leftChild); // 中序遍历左子树
- cout << tree->data << " "; // 访问根节点
- inOrderTraverse(tree->rightChild); // 中序遍历右子树
- }
- }
- // 后序遍历二叉树
- void postOrderTraverse(BiTree tree) {
- if (tree != nullptr) {
- postOrderTraverse(tree->leftChild); // 后序遍历左子树
- postOrderTraverse(tree->rightChild); // 后序遍历右子树
- cout << tree->data << " "; // 访问根节点
- }
- }
- // 判断二叉树是否为空
- bool biTreeEmpty(BiTree tree) {
- return tree == nullptr;
- }
- // 创建二叉树T
- void createBiTree(BiTree &tree) {
- TElementType data;
- cin >> data;
- if (data == '#') { // '#'表示空节点
- tree = nullptr;
- } else {
- tree = new BiTNode{data, nullptr, nullptr};
- createBiTree(tree->leftChild); // 创建左子树
- createBiTree(tree->rightChild); // 创建右子树
- }
- }
- // 返回二叉树的深度
- int biTreeDepth(BiTree tree) {
- if (tree == nullptr) {
- return 0;
- } else {
- int leftDepth = biTreeDepth(tree->leftChild); // 左子树的深度
- int rightDepth = biTreeDepth(tree->rightChild); // 右子树的深度
- return max(leftDepth, rightDepth) + 1; // 返回左右子树深度的最大值加1
- }
- }
- // 返回二叉树的根节点
- BiTNode* Root(BiTree tree) {
- return tree;
- }
- // 返回二叉树的节点个数
- int biTreeSize(BiTree tree) {
- if (tree == nullptr) {
- return 0;
- } else {
- return biTreeSize(tree->leftChild) + biTreeSize(tree->rightChild) + 1;
- }
- }
- #include <iostream>
- #include <queue>
- using namespace std;
-
- typedef char TElementType;
-
- // 二叉树节点的定义
- typedef struct BiTNode {
- TElementType data;
- struct BiTNode * leftChild, * rightChild;
- } BiTNode, * BiTree;
-
- // 先序遍历二叉树
- void preOrderTraverse(BiTree tree) {
- if (tree != nullptr) {
- cout << tree->data << " "; // 访问根节点
- preOrderTraverse(tree->leftChild); // 先序遍历左子树
- preOrderTraverse(tree->rightChild); // 先序遍历右子树
- }
- }
-
- // 中序遍历二叉树
- void inOrderTraverse(BiTree tree) {
- if (tree != nullptr) {
- inOrderTraverse(tree->leftChild); // 中序遍历左子树
- cout << tree->data << " "; // 访问根节点
- inOrderTraverse(tree->rightChild); // 中序遍历右子树
- }
- }
-
- // 后序遍历二叉树
- void postOrderTraverse(BiTree tree) {
- if (tree != nullptr) {
- postOrderTraverse(tree->leftChild); // 后序遍历左子树
- postOrderTraverse(tree->rightChild); // 后序遍历右子树
- cout << tree->data << " "; // 访问根节点
- }
- }
-
- // 判断二叉树是否为空
- bool biTreeEmpty(BiTree tree) {
- return tree == nullptr;
- }
-
- // 创建二叉树T
- void createBiTree(BiTree &tree) {
- TElementType data;
- cin >> data;
- if (data == '#') { // '#'表示空节点
- tree = nullptr;
- } else {
- tree = new BiTNode{data, nullptr, nullptr};
- createBiTree(tree->leftChild); // 创建左子树
- createBiTree(tree->rightChild); // 创建右子树
- }
- }
-
- // 返回二叉树的深度
- int biTreeDepth(BiTree tree) {
- if (tree == nullptr) {
- return 0;
- } else {
- int leftDepth = biTreeDepth(tree->leftChild); // 左子树的深度
- int rightDepth = biTreeDepth(tree->rightChild); // 右子树的深度
- return max(leftDepth, rightDepth) + 1; // 返回左右子树深度的最大值加1
- }
- }
-
- // 返回二叉树的根节点
- BiTNode* Root(BiTree tree) {
- return tree;
- }
-
- // 返回二叉树的节点个数
- int biTreeSize(BiTree tree) {
- if (tree == nullptr) {
- return 0;
- } else {
- return biTreeSize(tree->leftChild) + biTreeSize(tree->rightChild) + 1;
- }
- }
-
- // 查找以某个节点为根的子树中的最小节点
- BiTree findMin(BiTree tree) {
- while (tree->leftChild != nullptr) {
- tree = tree->leftChild;
- }
- return tree;
- }
-
- // 删除某个节点
- BiTree deleteNode(BiTree tree, TElementType key) {
- if (tree == nullptr) {
- return nullptr;
- }
-
- if (key < tree->data) { // 要删除的节点在左子树中
- tree->leftChild = deleteNode(tree->leftChild, key);
- } else if (key > tree->data) { // 要删除的节点在右子树中
- tree->rightChild = deleteNode(tree->rightChild, key);
- } else { // 找到要删除的节点
- // 如果节点是叶子节点或者只有一个子节点
- if (tree->leftChild == nullptr) {
- BiTree temp = tree->rightChild;
- delete tree;
- return temp;
- } else if (tree->rightChild == nullptr) {
- BiTree temp = tree->leftChild;
- delete tree;
- return temp;
- }
-
- // 如果节点有两个子节点,用右子树的最小节点替换当前节点
- BiTree temp = findMin(tree->rightChild);
- tree->data = temp->data;
- tree->rightChild = deleteNode(tree->rightChild, temp->data);
- }
-
- return tree;
- }
-
- // 查找二叉树中的节点
- void value(BiTree tree, TElementType & element) {
- if (tree != nullptr && tree->data == element) {
- element = tree->data;
- }
- }
-
- // 给节点赋值
- void assign(BiTree tree, TElementType & element, TElementType value) {
- if (tree != nullptr && tree->data == element) {
- tree->data = value;
- }
- }
-
- // 返回非根节点
- void parent(BiTree tree, TElementType & element) {
- if (tree == nullptr) {
- return;
- }
- queue<BiTree> q;
- q.push(tree);
- while (!q.empty()) {
- BiTree front = q.front();
- q.pop();
- if (front->leftChild != nullptr && front->leftChild->data == element) {
- element = front->data;
- return;
- }
- if (front->rightChild != nullptr && front->rightChild->data == element) {
- element = front->data;
- return;
- }
- if (front->leftChild != nullptr) {
- q.push(front->leftChild);
- }
- if (front->rightChild != nullptr) {
- q.push(front->rightChild);
- }
- }
- }
-
- // 返回左节点
- void leftChild(BiTree tree, TElementType & leftElement) {
- if (tree != nullptr && tree->leftChild != nullptr) {
- leftElement = tree->leftChild->data;
- }
- }
-
- // 返回右节点节点
- void rightChild(BiTree tree, TElementType & rightElement) {
- if (tree != nullptr && tree->rightChild != nullptr) {
- rightElement = tree->rightChild->data;
- }
- }
-
- // 返回做左兄弟节点
- void leftSibling(BiTree tree, TElementType & leftSiblingElement) {
- parent(tree, tree->data);
- if (tree->leftChild != nullptr) {
- leftChild(tree->leftChild, leftSiblingElement);
- }
- }
-
- // 返回做右兄弟节点
- void rightSibling(BiTree tree, TElementType & rightSiblingElement) {
- parent(tree, tree->data);
- if (tree->rightChild != nullptr) {
- rightChild(tree->rightChild, rightSiblingElement);
- }
- }
-
- //插入节点
- void insertChild(BiTree tree, TElementType p, TElementType LR, BiTree c) {
- queue<BiTree> q;
- q.push(tree);
- while (!q.empty()) {
- BiTree front = q.front();
- q.pop();
- if (front->data == p) {
- if (LR == 'L') {
- front->leftChild = c;
- } else {
- front->rightChild = c;
- }
- return;
- }
- if (front->leftChild != nullptr) {
- q.push(front->leftChild);
- }
- if (front->rightChild != nullptr) {
- q.push(front->rightChild);
- }
- }
- }
-
- // 层序遍历二叉树,对每个节点调用函数visit一次且仅一次
- void leveOrderTraverse(BiTree T) {
- if (T == nullptr) {
- return;
- }
- queue<BiTree> q;
- q.push(T);
- while (!q.empty()) {
- BiTree front = q.front();
- cout << front->data << " ";
- q.pop();
- if (front->leftChild != nullptr) {
- q.push(front->leftChild);
- }
- if (front->rightChild != nullptr) {
- q.push(front->rightChild);
- }
- }
- }
- // 层序遍历二叉树
- void levelOrderTraverse(BiTree tree) {
- if (tree == nullptr) {
- return;
- }
- queue<BiTree> q;
- q.push(tree);
- while (!q.empty()) {
- BiTree front = q.front();
- cout << front->data << " ";
- q.pop();
- if (front->leftChild != nullptr) {
- q.push(front->leftChild);
- }
- if (front->rightChild != nullptr) {
- q.push(front->rightChild);
- }
- }
- }
- // 测试二叉树操作
- void testBitTree() {
- // 创建二叉树
- BiTree root = nullptr;
- cout << "请输入二叉树的先序遍历序列,空节点用#表示:" << endl;
- createBiTree(root);
-
- // 先序遍历
- cout << "先序遍历结果:";
- preOrderTraverse(root);
- cout << endl;
-
- // 中序遍历
- cout << "中序遍历结果:";
- inOrderTraverse(root);
- cout << endl;
-
- // 后序遍历
- cout << "后序遍历结果:";
- postOrderTraverse(root);
- cout << endl;
-
- // 释放内存
- delete root;
- }
-
- int main() {
-
- // 创建二叉树
- BiTree root = nullptr;
-
- cout << "请输入二叉树的先序遍历序列,空节点用#表示:" << endl;
- createBiTree(root);
-
- // 先序遍历
- cout << "先序遍历结果:";
- preOrderTraverse(root);
- cout << endl;
-
- // 中序遍历
- cout << "中序遍历结果:";
- inOrderTraverse(root);
- cout << endl;
-
- // 后序遍历
- cout << "后序遍历结果:";
- postOrderTraverse(root);
- cout << endl;
-
- // 层序遍历
- cout << "层序遍历结果:";
- levelOrderTraverse(root);
- cout << endl;
-
- // 二叉树深度
- cout << "二叉树深度:" << biTreeDepth(root) << endl;
-
- // 二叉树节点个数
- cout << "二叉树节点个数:" << biTreeSize(root) << endl;
-
- // 删除节点
- TElementType key;
- cout << "请输入要删除的节点值:" << endl;
- cin >> key;
- root = deleteNode(root, key);
-
- // 层序遍历
- cout << "删除节点后的层序遍历结果:";
- levelOrderTraverse(root);
- cout << endl;
-
- // 释放内存
- delete root;
-
- return 0;
- }
控制台输入信息:ABD##E##CF##G##
控制台打印信息如下:
这里遍历二叉树有先序遍历二叉树、中序遍历二叉树、后序遍历二叉树三种方法。
若二叉树为空,则空操作;否则
1.访问根节点
2.先序遍历左子树
3.先序遍历后子树
若二叉树为空,则空操作;否则
1..中序遍历左子树
2.访问根节点
3.中序遍历右子树
若二叉树为空,则空操作;否则
1.后序遍历左子树
2.后序遍历右子树
3.访问根节点
线索二叉树是对普通二叉树进行改进的一种数据结构,它的主要目的是提高对二叉树的遍历效率。在普通二叉树中,为了实现中序遍历等操作,需要使用递归或者栈来实现,而线索二叉树则通过添加额外的线索信息,使得在遍历过程中能够直接找到下一个或上一个节点,从而减少了递归或栈的使用。
线索二叉树的节点结构通常包含原有的数据域,以及左右子树的指针,同时还包含了指向前驱节点和后继节点的线索指针。这些线索指针可以用来指向前驱节点或后继节点,从而实现在遍历过程中的快速定位。
线索二叉树分为前序线索二叉树、中序线索二叉树和后序线索二叉树。其中,中序线索二叉树应用最为广泛,因为中序线索二叉树能够实现对二叉树的中序遍历操作,并且在遍历过程中不需要使用递归或者栈,从而提高了遍历的效率。
总的来说,线索二叉树是通过添加额外的线索信息,使得在遍历过程中能够直接找到下一个或上一个节点,从而减少了递归或栈的使用,提高了对二叉树的遍历效率。
- // 二叉树节点的定义
- typedef char TElementType;
-
- // 线索二叉树节点的定义
- typedef struct ThreadNode {
- TElementType data;
- struct ThreadNode * leftChild, * rightChild;
- int ltag, rtag; // 线索标志,0表示孩子,1表示线索
- } ThreadNode, * ThreadTree;
- // 中序线索化函数
- void inThread(ThreadTree &p, ThreadNode* &pre) {
- if (p != nullptr) {
- inThread(p->leftChild, pre); // 左子树线索化
- if (p->leftChild == nullptr) { // 左孩子为空,建立前驱线索
- p->leftChild = pre;
- p->ltag = 1;
- }
- if (pre != nullptr && pre->rightChild == nullptr) { // 建立前驱的后继线索
- pre->rightChild = p;
- pre->rtag = 1;
- }
- pre = p; // 更新前驱节点
- inThread(p->rightChild, pre); // 右子树线索化
- }
- }
- // 中序遍历线索二叉树
- void inOrderTraverse(ThreadTree &tree) {
- ThreadNode *p = tree->leftChild;
- while (p != tree) {
- while (p->ltag == 0) {
- p = p->leftChild;
- }
- cout << p->data << " ";
- while (p->rtag == 1 && p->rightChild != tree) {
- p = p->rightChild;
- cout << p->data << " ";
- }
- p = p->rightChild;
- }
- }
- void createThreadBiTree(ThreadTree &tree) {
- TElementType data;
- cin >> data;
- if (data == '#') { // '#'表示空节点
- tree = nullptr;
- } else {
- tree = new ThreadNode{data, nullptr, nullptr, 0, 0};
- createThreadBiTree(tree->leftChild); // 创建左子树
- createThreadBiTree(tree->rightChild); // 创建右子树
- }
- }
- #include <iostream>
- using namespace std;
-
- // 二叉树节点的定义
- typedef char TElementType;
-
- // 线索二叉树节点的定义
- typedef struct ThreadNode {
- TElementType data;
- struct ThreadNode * leftChild, * rightChild;
- int ltag, rtag; // 线索标志,0表示孩子,1表示线索
- } ThreadNode, * ThreadTree;
-
- // 中序线索化函数
- void inThread(ThreadTree &p, ThreadNode* &pre) {
- if (p != nullptr) {
- inThread(p->leftChild, pre); // 左子树线索化
- if (p->leftChild == nullptr) { // 左孩子为空,建立前驱线索
- p->leftChild = pre;
- p->ltag = 1;
- }
- if (pre != nullptr && pre->rightChild == nullptr) { // 建立前驱的后继线索
- pre->rightChild = p;
- pre->rtag = 1;
- }
- pre = p; // 更新前驱节点
- inThread(p->rightChild, pre); // 右子树线索化
- }
- }
-
- // 中序遍历线索二叉树
- void inOrderTraverse(ThreadTree &tree) {
- ThreadNode *p = tree->leftChild;
- while (p != tree) {
- while (p->ltag == 0) {
- p = p->leftChild;
- }
- cout << p->data << " ";
- while (p->rtag == 1 && p->rightChild != tree) {
- p = p->rightChild;
- cout << p->data << " ";
- }
- p = p->rightChild;
- }
- }
-
- // 创建线索二叉树
- void createThreadBiTree(ThreadTree &tree) {
- TElementType data;
- cin >> data;
- if (data == '#') { // '#'表示空节点
- tree = nullptr;
- } else {
- tree = new ThreadNode{data, nullptr, nullptr, 0, 0};
- createThreadBiTree(tree->leftChild); // 创建左子树
- createThreadBiTree(tree->rightChild); // 创建右子树
- }
- }
-
- // 测试线索二叉树操作
- void testThreadBitTree() {
- // 创建线索二叉树
- ThreadTree root = nullptr;
- cout << "请输入二叉树的先序遍历序列,空节点用#表示:" << endl;
- createThreadBiTree(root);
-
- // 中序线索化
- ThreadNode *pre = nullptr;
- inThread(root, pre);
- // 设置线索头节点
- pre->rightChild = root;
- pre->rtag = 1;
- root->rightChild = pre;
-
- // 中序遍历线索二叉树
- cout << "中序遍历结果:";
- inOrderTraverse(root);
- cout << endl;
-
- // 释放内存
- delete root;
- }
-
- int main() {
- // 测试线索二叉树操作
- testThreadBitTree();
-
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。