(2)先序遍历
那么这个树的分割我们直到了,它对我们的先序中序后序遍历树有什么用呢?
我们先看先序遍历,其实先序也称作先根,如下图所示,先根就很通俗易懂了,先访问根,再访问左子树,再访问右子树。
那么我们按照这个思路用先序的方式去访问一下这棵树吧,首先这棵树得先访问根节点A
然后我们开始访问左子树B,访问这颗左子树的时候,我们又先访问左子树的根,也就是B
访问完B的根了,我们就要访问它的左子树D,而它的左子树D,又要先访问它的根,也就是D
访问了D的根节点,那么我们又要访问它的左子树,而它的左子树是空
然后继续访问D的右子树,刚好它也是空
D这棵树访问完了,而D是属于B的左子树,那么我们就应该访问B的右子树E了,而它的访问也一样,先访问根节点,再访问左子树,在访问右子树
然后我们就发现,其实B这颗树也访问完成了,那么这下也就是A的左子树访问完了,该访问A的右子树了,而A的右子树C,它也是先访问根节点C,然后访问左右两颗树,而它的左右两颗树刚好都是空的
这就是我们的先序遍历了。当然有的书上没有NULL这个东西,这个其实也不影响的
(3)中序遍历
有了先序遍历的理解那么其实,中序遍历我们也很容易就能写出来了,因为中序遍历其实就是先左子树,根,最后右子树
那么我们简单的分析一下:
首先这颗树分为根节点A,左子树B,右子树C。那么我们因为是中序遍历,所以得先访问B这颗左子树。而B这颗左子树又分为根节点B,左子树D,右子树E。所以我们还得先访问D这颗树,而D这颗树,又分为根节点D,左子树NULL,右子树NULL。到了这里左子树已经到头了,所以我们该返回去了,所以目前的访问顺序就是NULL D NULL B,这样也就是B的左子树以及它的根已经访问完了,现在该访问B的右子树了,而这个根D是一样的过程,所以目前我们的访问顺序就成了NULL D NULL B NULL E NULL。这样也就意味着B这颗树访问完了,而B又是A这颗树上的左子树,所以现在将A一访问,就该访问右子树C了,而C的右子树又分为左子树NULL根C右子树NULL。
所以最终的访问顺序为NULL D NULL D NULL E NULL A NULL C NULL
(4)后序遍历
这个的访问我们就更加熟悉了,它的访问过程是
NULL NULL D NULL NULL E B NULL NULL C A
我们在看一个例子
这颗树的前序中序后序是
(5)先序中序后序的代码实现
根据了上面的分析,其实我们也不难得知这个是通过递归实现的,代码如下:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> #include<string.h> typedef char BTDateType; typedef struct BinaryTreeNode { struct BinaryTreeNode* left; struct BinaryTreeNode* right; BTDateType date; }BTNode; //先序 void PrevOrder(BTNode* root) { if (root == NULL) { printf("NULL "); return; } printf("%c ", root->date); PrevOrder(root->left); PrevOrder(root->right); } //中序 void InOrder(BTNode* root) { if (root == NULL) { printf("NULL "); return; } InOrder(root->left); printf("%c ", root->date); InOrder(root->right); } //后序 void PostOrder(BTNode* root) { if (root == NULL) { printf("NULL "); return; } PostOrder(root->left); PostOrder(root->right); printf("%c ", root->date); } int main() { BTNode* A = (BTNode*)malloc(sizeof(BTNode)); A->date = 'A'; A->left = NULL; A->right = NULL; BTNode* B = (BTNode*)malloc(sizeof(BTNode)); B->date = 'B'; B->left = NULL; B->right = NULL; BTNode* C = (BTNode*)malloc(sizeof(BTNode)); C->date = 'C'; C->left = NULL; C->right = NULL; BTNode* D = (BTNode*)malloc(sizeof(BTNode)); D->date = 'D'; D->left = NULL; D->right = NULL; BTNode* E = (BTNode*)malloc(sizeof(BTNode)); E->date = 'E'; E->left = NULL; E->right = NULL; A->left = B; A->right = C; B->left = D; B->right = E; PrevOrder(A); printf("\n"); InOrder(A); printf("\n"); PostOrder(A); printf("\n"); }
运行结果为
2.计算二叉树中结点的个数
这个也很简单,只要我们理解了递归,那么这个就很容易了,代码如下
//计算二叉树中结点的个数 int TreeSize(BTNode* root) { if (root == NULL) { return 0; } else { return 1 + TreeSize(root->left) + TreeSize(root->right); } }
这是运行结果
3.计算二叉树中叶子结点的个数
这个同样很简单,如果树是空树,那么直接返回0即可,如果该结点的左孩子和右孩子都是空指针,那么返回1就可以了,说明他是一个叶子结点,其他情况我们就采用递归的思想去计算他的左孩子和右孩子的结点就可以了,代码如下
//计算叶子结点的个数 int TreeLeftSize(BTNode* root) { if (root == NULL) { return 0; } else if (root->left == NULL && root->right == NULL) { return 1; } else { return TreeLeftSize(root->left) + TreeLeftSize(root->right); } }
这是运行结果
4.二叉树的层序遍历(广度优先遍历)
我们先说一下广度优先遍历的基本思路,他的基本思路是这样的,需要使用一个队列
如下图所示,我们先将A入队列
然后 A出队列的同时打印他并且将他的左右孩子入队列
然后继续出B,打印他 入他的左右孩子
然后我们继续出C,入他的孩子,打印C
后面的也都是同理,出队列的同时打印他并且入他的孩子,如果没有孩子,那就不用入孩子了