二叉树的概念及结构
每个结点最多有两颗子树,即二叉树不存在度大于 2 的结点。
任何一颗二叉树可以看成三个部分:①根节点②左子树③右子树
遍历的三种方法
以下面的二叉树为例介绍遍历的方法。
图片.png
先序遍历(前序)
先序遍历的方法是:“根左右”依次遍历,即先访问根结点,再访问左子树,再访问右子树。
以上面的二叉树为例,肯定要先访问根结点 A,然后访问左子树,但 A 的左子树是以 B 为根结点的一颗子树,如下图。
图片.png
那么在这颗子树里我们又要根据“根左右”进行遍历,先访问根结点 B,然后左子树 D,但在这我想让你思考 D 还有没有子树?看样子是没有,不过严格意义我们可以写上 NULL(空),然后就是 B 的右子树,结点 E。
到此为止 A 的左子树已经访问完了,可以写 A B D NULL NULL E NULL NULL,有时候题目不要求我们写空的话,可以直接写 ABDE(接下来为了方便大家看我就不写 NULL 了)。
然后再访问 A 的右子树 C。
先序遍历完成,顺序为:ABDEC
中序遍历
中序遍历的方法是:“左根右”依次遍历,即先访问左子树,再访问根结点,再访问右子树。
以上面二叉树为例,先看 A 有无左子树,有!是根结点为 B 的子树! 再看 B 有无左子树,有!是结点 D。
D 还有左子树吗?没有,是 NULL(空,我们这里暂且不算)那就先访问 D,然后 D 作为 B 的左子树,接下来就该访问根结点 B。
接着访问 B 的右子树 E,E 有左子树吗?没有。现在我们看到 A 的所有左子树已经遍历完了,接着就是访问根结点 A。
到此为止的顺序为:DBEA
然后再访问 A 的右结点 C。
所以中序遍历的顺序为:DBEAC
可以自己试着把空(NULL)也给算上写出中序遍历:
NULL D NULL B NULL E NULL A NULL C NULL
后序遍历
后序遍历的方法是:“左右根”依次遍历,即先访问左子树,再访问右子树,再访问根结点。
以上面二叉树为例,先看 A 有无左子树,有!是根结点为 B 的子树! 再看 B 有无左子树,有!是结点 D。D 无子树了,再看 B 是否有右子树,有!是结点 E。
好的那就先访问 D 和 E,然后再访问 B,接着就是 A 的右子树。然后 A 的右子树只有一个 C,最后再访问 A,访问完毕。
后序遍历的顺序为:DEBCA
遍历例题
写出下面二叉树的三种遍历结果
图片.png
严格上可以写 NULL,读者可以自己加以理解,大多数情况会忽略 NULL。
前序遍历:A B NULL D F NULL NULL NULL C E NULL NULL NULL
中序遍历:B F D A E C
后序遍历:F D B E C A
三种遍历方法的代码实现
结构体的定义
typedef char BTDataType;typedef struct BinaryTreeNode{ struct BinaryTreeNode* left; //左孩子 struct BinaryTreeNode* right; //右孩子 BTDataType data;}BTNode;
复制代码
解释:
①typedef char BTDataType; 是将 char 字符类型重新命名为 BTDataType,目的是为了方便代码的可维护性,比如我后面发现 char 不是我想要的类型了,但我已经打了好几个 char 了,就不方便更改了。而用此方法,只需要把 typedef char BTDataType 里的 char 改成 int 就行。
②下面是结构体的定义
前序遍历代码实现
void PrevOrder(BTNode* root) //前序遍历{ if (root == NULL) //空树 return; printf("%c ", root->data); PrevOrder(root->left); PrevOrder(root->right);}
复制代码
这里就是先打印根结点,毕竟这是前序遍历,然后就访问左子树,即 root->left。
如果遍历的时候想严格打印 NULL 那么就这样写.
void PrevOrder(BTNode* root) //前序遍历{ if (root == NULL) //空树 { printf("NULL "); return; } printf("%c ", root->data); PrevOrder(root->left); PrevOrder(root->right);}
复制代码
中序遍历代码实现
void InOrder(BTNode* root) //中序遍历{ if (root == NULL) //空树 return; InOrder(root->left); printf("%c ", root->data); InOrder(root->right);}
复制代码
后序遍历代码实现
void PostOrder(BTNode* root) //后序遍历{ if (root == NULL) //空树 return; PostOrder(root->left); PostOrder(root->right); printf("%c ", root->data);}
复制代码
所有函数和 main 函数
#include<stdio.h>#include<stdlib.h>typedef char BTDataType;typedef struct BinaryTreeNode{ struct BinaryTreeNode* left; //左孩子 struct BinaryTreeNode* right; //右孩子 BTDataType data;}BTNode; void PrevOrder(BTNode* root) //前序遍历{ if (root == NULL) //空树 return; printf("%c ", root->data); PrevOrder(root->left); PrevOrder(root->right);} void InOrder(BTNode* root) //中序遍历{ if (root == NULL) //空树 return; InOrder(root->left); printf("%c ", root->data); InOrder(root->right);} void PostOrder(BTNode* root) //后序遍历{ if (root == NULL) //空树 return; PostOrder(root->left); PostOrder(root->right); printf("%c ", root->data);} int main(){ BTNode* A = (BTNode*)malloc(sizeof(BTNode)); A->data = 'A'; A->left = NULL; A->right = NULL; BTNode* B = (BTNode*)malloc(sizeof(BTNode)); B->data = 'B'; B->left = NULL; B->right = NULL; BTNode* C = (BTNode*)malloc(sizeof(BTNode)); C->data = 'C'; C->left = NULL; C->right = NULL; BTNode* D = (BTNode*)malloc(sizeof(BTNode)); D->data = 'D'; D->left = NULL; D->right = NULL; BTNode* E = (BTNode*)malloc(sizeof(BTNode)); E->data = '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"); printf(""); return 0;}
复制代码
这里还是以最上面的二叉树为例。
主函数里我使用了动态内存开辟,使用一次就开一次,不要浪费内存。
评论