首先我们来了解一下什么是二叉树
二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树的特点:
1.每个节点最多有两棵子树,即二叉树不存在度大于2的节点
2.二叉树的子树有左右之分,其子树的顺序不能颠倒
3.满二叉树: 在一棵二叉树中,如果所有分支节点都存在左子树和右子树,并且所有叶子节点都在同一层上
4.完全二叉树:如果一棵具有N个节点的二叉树的结构与满二叉树的前N个节点的结构相同,称为完全二叉树
5.满二叉树与完全二叉树之间的关系:满二叉树是一个特殊的完全二叉树
二叉树的性质:
1.若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)(i > 0)个节点;
3.对任何一棵二叉树,如果其叶子节点个数为n0,度为2的非叶子节点个数为n2,则有n0 = n2 +1;
4.具有n个节点的完全二叉树的深度为k为log2(n+1)上取整;
5.对于具有n个节点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i的节点有:
(1)若 i>0,双亲序号:(i-1)/2 i=0,
i为根节点编号,无双亲节点
(2)若 n>2i+1,左孩子序号为2i+1,否则无左孩子
(3)若 n>2i+1,右孩子序号为2i+1,否则无右孩子
二叉树的存储结构:
二叉树主要有顺序存储结构和链式存储结构
顺序存储结构:对于一棵完全二叉树所有节点按照层序自顶向下,同一层自左向右顺序编号,就得到一个节点的顺序序列
优点:存储完全二叉树,简单省空间
缺点:存储一般二叉树尤其单支树,存储空间利用不高
链式存储结构:
二叉树的遍历:
1.先序遍历:
(1)访问根节点
(2)遍历左子树
(3)遍历右子树
2.中序遍历:
(1)遍历左子树
(2)访问根节点
(3)遍历右子树
3.后续遍历:
(1)遍历左子树
(2)遍历右子树
(3)访问根节点
4.层序遍历:
按照二叉树的层序次序,同一层中按先左子树再右子树的次序遍历二叉树下面就是对二叉树的四种遍历代码的实现:
首先是 .h 文件
#pragma once
#include<stdio.h>
typedef char TreeNodeType;
//使用孩子表示法来表示一个树
typedef struct TreeNode
{
TreeNodeType data;
struct TreeNode* lchild;
struct TreeNode* rchild;
}TreeNode;
//对于链表来说,使用链表的头节点的指针表示一个链表
//对于一个树来书,使用根节点的指针来表示一个树
void TreeInit(TreeNode** pRoot);
void TreePreOrder(TreeNode* root);//先序
void TreeInOrder(TreeNode* root);//中序
void TreePostOrder(TreeNode* root);//后序
void TreeLevelOrder(TreeNode* root);//层序
#include <stdio.h>
#include"bin_tree.h"
#include"seqqueue.h"//因为层序用到了队列,所以将前面的队列代码引用进来
#include<stdlib.h>
#include<stddef.h>
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);
}
void TreeInit(TreeNode** pRoot)//初始化
{
if(pRoot == NULL)
{
//非法输入
return;
}
if(*pRoot == NULL)
{
//空树
return;
}
*pRoot = NULL;
return;
}
- 先序遍历的实现:
void TreePreOrder(TreeNode* root)
{
if(root == NULL)
{
printf("#");
return;
}
//先访问根结点,再左子树,再右子树
printf("%c",root->data);
TreePreOrder(root->lchild);
TreePreOrder(root->rchild);
return;
}
void TestPreOrder()
{
TEST_HEADER;
TreeNode* a = CreateTreeNode('a');
TreeNode* b = CreateTreeNode('b');
TreeNode* c = CreateTreeNode('c');
TreeNode* d = CreateTreeNode('d');
TreeNode* e = CreateTreeNode('e');
TreeNode* f = CreateTreeNode('f');
TreeNode* g = CreateTreeNode('g');
a->lchild = b;
a->rchild = c;
b->lchild = d;
b->rchild = e;
e->lchild = g;
c->lchild = f;
TreePreOrder(a);
return;
}
- 中序遍历的实现:
void TreeInOrder(TreeNode* root)
{
if(root == NULL)
{
return;
}
//先遍历左子树,再遍历根节点,最后遍历右子树
TreeInOrder(root->lchild);
printf("%c",root->data);
TreeInOrder(root->rchild);
return;
}
void TestInOrder()
{
TEST_HEADER;
TreeNode* a = CreateTreeNode('a');
TreeNode* b = CreateTreeNode('b');
TreeNode* c = CreateTreeNode('c');
TreeNode* d = CreateTreeNode('d');
TreeNode* e = CreateTreeNode('e');
TreeNode* f = CreateTreeNode('f');
TreeNode* g = CreateTreeNode('g');
a->lchild = b;
a->rchild = c;
b->lchild = d;
b->rchild = e;
e->lchild = g;
c->lchild = f;
TreeInOrder(a);
return;
}
- 后序遍历的实现:
void TreePostOrder(TreeNode* root)
{
if(root == NULL)
{
return;
}
//先遍历左子树,再遍历右子树,最后访问根结点
TreePostOrder(root->lchild);
TreePostOrder(root->rchild);
printf("%c",root->data);
return;
}
void TestPostOrder()
{
TEST_HEADER;
TreeNode* a = CreateTreeNode('a');
TreeNode* b = CreateTreeNode('b');
TreeNode* c = CreateTreeNode('c');
TreeNode* d = CreateTreeNode('d');
TreeNode* e = CreateTreeNode('e');
TreeNode* f = CreateTreeNode('f');
TreeNode* g = CreateTreeNode('g');
a->lchild = b;
a->rchild = c;
b->lchild = d;
b->rchild = e;
e->lchild = g;
c->lchild = f;
TreePostOrder(a);
printf("\n");
return;
}
- 层序遍历的实现:
void TestLevelOrder()
{
TEST_HEADER;
TreeNode* a = CreateTreeNode('a');
TreeNode* b = CreateTreeNode('b');
TreeNode* c = CreateTreeNode('c');
TreeNode* d = CreateTreeNode('d');
TreeNode* e = CreateTreeNode('e');
TreeNode* f = CreateTreeNode('f');
TreeNode* g = CreateTreeNode('g');
a->lchild = b;
a->rchild = c;
b->lchild = d;
b->rchild = e;
e->lchild = g;
c->lchild = f;
TreeLevelOrder(a);
printf("\n");
return;
}
void TreeLevelOrder(TreeNode* root)
{
if(root == NULL)
{
return;
}
SeqQueue queue;
SeqQueueInit(&queue);
SeqQueuePush(&queue,root);
while(1)
{
SeqQueueType front;
int ret = SeqQueueFront(&queue,&front);
if(ret == 0)
{
//如果取队列首元素失败,说明队列为空
//如果队列为空,说明遍历已经结束
break;
}
printf("%c",front->data);
SeqQueuePop(&queue);
if(front->lchild != NULL)
{
SeqQueuePush(&queue,front->lchild);
}
if(front->rchild != NULL)
{
SeqQueuePush(&queue,front->rchild);
}
}
printf("\n");
return;
}