二叉树,顾名思义,是有每个结点有两个分支的树,我们将结点称为根节点,将它的两个分支称为它的左子树、右子树,所以我们用以下结构来定义二叉树的结构。
typedef char TreeNodeType;
typedef struct TreeNode//树的结点
{
TreeNodeType data;//数据
struct TreeNode* lchild;//左子树
struct TreeNode* rchild;//右子树
}TreeNode;
树的基本实现:
void TreeInit(TreeNode** proot)//初始化
{
if(proot == NULL)//非法输入
return;
*proot = NULL;
return;
}
TreeNode* CreateTreeNode(TreeNodeType value)//创造一个新结点
{
TreeNode* new_node = (TreeNode*)malloc(sizeof(TreeNode));
new_node->data = value;
new_node->lchild = NULL;
new_node->rchild = NULL;
return new_node;
}
void DestroyTreeNode(TreeNode* node)//销毁结点
{
free(node);
return;
}
对于二叉树,最最基本的操作就是对二叉树进行遍历。而二叉树的遍历方式我们有先序遍历、中序遍历、后序遍历、层次遍历这几种,且遍历二叉树最重要的就是做到“
不重不漏”。
1. 先序遍历(先访问根节点,再访问左子树,最后访问右子树)
如图,即我们对图中二叉树进行了一个先序遍历。
(1)我们对整棵树的根节点进行访问,也就是图中的1即结点A;
(2)然后访问整棵树的左子树即2,对于2子树,我们再访问它的根节点也就是B,再访问它的左子树也就是3;
(3)我们可以看到3子树,只有根结点而无子树,所以我们访问了根结点D就可以返回到2树;
(4)返回到2树之后,按先序遍历的顺序接下来该访问2的右子树即4树;
(5)访问4树的根节点E,再访问它的左子树,因为它的左子树只有根结点G,所以我们访问完G就可以返回,而4树也无右子树,所以我们继续返回;
(6)上步最后我们应该返回到1树,去访问它的右子树5,对于5树先访问它的根节点C;
(7)访问完C后,应该访问C的左子树,但它左子树为空,所以我们直接访问右子树F;
(8)至此,该树已遍历完,所以先序遍历的结果是:A B D E G C F
整个过程,利用代码我们可以用递归实现,实现代码如下:
void TreePreOrder(TreeNode* root)//先序遍历
{//根左右
//树为空也是遍历结束的条件
if(root == NULL)//空树
{
printf("[%c] ",'#');
return;
}
//访问根结点
printf("[%c] ",root->data);
//递归访问左子树
TreePreOrder(root->lchild);
//递归访问右子树
TreePreOrder(root->rchild);
return;
}
2. 中序遍历(先访问左子树,再访问根节点,最后访问右子树)
中序遍历的思想与先序遍历一样,只是访问顺序改变了。针对上图的二叉树,我们进行中序访问: