1.概念回顾
讲二叉树的基本操作之前,我们回顾一下二叉树的概念
在讲树之前,我们的每讲一种数据结构,无外乎就是在讲它们的增删查改,但是在树这里,就有了不小变化。
2.结点的定义
既然是链式二叉树,那必须得有自己的结点类型,以下是链式二叉树结点类型的定义,为了避免过多重复的代码,下面的问题都统一使用该结点类型。
typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;
创建结点
BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");return NULL;}node->data = x;node->left = NULL;node->right = NULL;return node;
}
3.二叉树的遍历
学习二叉树结构,最简单的方式就是遍历。
所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉 树中的结点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历 是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。
讲遍历之前我们先来看基本思路啊
我们把一棵树分解成许多小树,让每个结点都成为根结点,每个根结点都有它的左右子树(可能为空),然后就像下面这样子
这样子,我们就可以按照某种特定的规则,依次对二叉 树中的每个结点进行访问左右子树的操作,并且每个节点只操作一次。
按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:
- 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
- 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
- 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。
由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为 根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。
2.1前序遍历
前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
我们还是以这个二叉树为例来展示前序遍历
我们把代码写出来
void PreOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);
}
我们通过代码来更深入的理解这个前序遍历
顺序我就不注明了,上面那个图有
3.2中序遍历
中序遍历,又叫中根遍历。
遍历顺序:左子树 -> 根 -> 右子树
void InOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}
3.3后序遍历
后序遍历,又叫后根遍历。
遍历顺序:左子树 -> 右子树 -> 根
代码:
void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}
3.4代码测试
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");return NULL;}node->data = x;node->left = NULL;node->right = NULL;return node;
}BTNode* CreatTree()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);BTNode* node7 = BuyNode(7);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;node3->right = node7;return node1;
}void PreOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);
}void InOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}int main()
{BTNode* root = CreatTree();PreOrder(root);printf("\n");InOrder(root);printf("\n");PostOrder(root);printf("\n");return 0;
}
4.结点的个数
我们采用分治的思想来统计树的结点个数,由下而上统计结点个数,遇到空结点就返回0,遇到非空结点就将其作为新的“根结点”,去访问它的左右子树,并且加1,如此以来层层递归。
int TreeSize(BTNode* root)
{return root == NULL ? 0 : TreeSize(root->left)//左子树的结点数 + TreeSize(root->right) //右子树的结点数+ 1;//根结点自己
}
5.当前树的高度
当前树的高度等于左右子树高度最大的加1
int TreeHeight(BTNode* root)
{if (root == NULL)return 0;int leftHeight = TreeHeight(root->left);int rightHeight = TreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
6.第k层结点的个数
思路:
相对于根结点的第k层结点的个数 = 相对于以其左孩子为根的第k-1层结点的个数 + 相对于以其右孩子为根的第k-1层结点的个数。
int TreeKLevel(BTNode* root, int k)
{assert(k > 0);if (root == NULL)return 0;if (k == 1)return 1;return TreeKLevel(root->left, k - 1)+ TreeKLevel(root->right, k - 1);
}
7.代码测试
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");return NULL;}node->data = x;node->left = NULL;node->right = NULL;return node;
}BTNode* CreatTree()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);BTNode* node7 = BuyNode(7);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;node3->right = node7;return node1;
}void PreOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);
}void InOrder(BTNode* root) {if (root == NULL) {printf("NULL ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}int TreeSize(BTNode* root)
{return root == NULL ? 0 :TreeSize(root->left)+ TreeSize(root->right)+ 1;
}int TreeHeight(BTNode* root)
{if (root == NULL)return 0;int leftHeight = TreeHeight(root->left);int rightHeight = TreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}int TreeKLevel(BTNode* root, int k)
{assert(k > 0);if (root == NULL)return 0;if (k == 1)return 1;return TreeKLevel(root->left, k - 1)+ TreeKLevel(root->right, k - 1);
}int main()
{BTNode* root = CreatTree();PreOrder(root);printf("\n");InOrder(root);printf("\n");PostOrder(root);printf("\n");printf("TreeSize:%d\n", TreeSize(root));printf("TreeSize:%d\n", TreeSize(root));printf("TreeSize:%d\n", TreeSize(root));printf("TreeHeight:%d\n", TreeHeight(root));printf("TreeKLevel:%d\n", TreeKLevel(root, 3));printf("TreeKLevel:%d\n", TreeKLevel(root, 4));return 0;
}