二叉树的创建
对于二叉树的创建,可能很多人不知道如何去初始化一个二叉树,其实初始化二叉树非常简单,需要引入一个扩展二叉树的概念
扩展二叉树
扩展二叉树:让二叉树的所有节点都具有左右孩子,没有孩子的,我们手动将其填满,例如#,即如下所示
扩展二叉树主要的目的是为了确定一颗二叉树,我们都知道,只有前序加中序或者后序加中序才能确定一棵树,但是我们同样可以通过扩展二叉树的前序确定一棵树,即:
ABC###DE##F##
创建二叉树代码
BiTree CreateTreeNode(void)
{
char c;
BiTree T;
scanf("%c", &c);
if (c == '#') {
T = NULL;
} else {
T = (BiTree) calloc(sizeof(BiTNode), 1);
T->data = c;
T->lchild = CreateTreeNode();
T->rchild = CreateTreeNode();
}
return T;
}
二叉树的前中后序遍历
二叉树的创建采用的是递归的方式,那么同样二叉树的遍历同样可以采取递归的方式,而且简单明了
前序遍历:若二叉树为空,则空操作返回,否则先访问根节点,然后前序遍历左子树,再前序遍历右子树。按照上面创建的二叉树,则遍历顺序为:ABCDEF
中序遍历:若二叉树为空,则空操作返回,否则从根节点开始(不是先访问根节点),中序遍历根节点的左子树,然后是访问根节点,最后中序遍历右子树。按照上面创建的二叉树,则遍历顺序为:CBAEDF
后序遍历:若二叉树为空,则空操作返回,否则从左到右先叶子后节点的方式先后遍历左右子树,最后遍历根节点。按照上面创建的二叉树,则遍历顺序为:CBEFDA
前中后序遍历代码
void PreOrderTraverse(BiTree T)
{
if (T == NULL) {
return;
}
printf("%c", T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
void InOrderTraverse(BiTree T)
{
if (T == NULL) {
return;
}
InOrderTraverse(T->lchild);
printf("%c", T->data);
InOrderTraverse(T->rchild);
}
void PostOrderTraverse(BiTree T)
{
if (T == NULL) {
return;
}
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c", T->data);
}
二叉树层次遍历(队列方式实现)
二叉树层次遍历,即按从上至下从左至右按层次遍历,这个遍历就和上面有所不同,不过采用队列也是非常容易理解和实现的
若根节点为空,直接返回;若根节点非空,则将根节点入队,然后,判断队列是否为空,若不为空,则将队首节点出队,访问,并判断其左右子节点是否为空,若不为空,则压入队列,然后循环上面操作直到队列为空
二叉树层次遍历代码
void LevelOrderTraverse(BiTree T)
{
QNode Tmp, tmp;
LinkQueue Q;
tmp.next = NULL;
Tmp.next = NULL;
Q.front = NULL;
Q.rear = NULL;
InitQueue(&Q);
tmp.Tree = T;
EnQueue(&Q, &tmp); // 根节点入队
while (DeQueue(&Q, &Tmp)) { // 依次出队,直到队列为空
printf("%c", Tmp.Tree->data);
if (Tmp.Tree->lchild != NULL) { // 若出队节点有左孩子,则左孩子入队
tmp.Tree = Tmp.Tree->lchild;
EnQueue(&Q, &tmp);
}
if (Tmp.Tree->rchild != NULL) { // 若出队节点有右孩子,则右孩子入队
tmp.Tree = Tmp.Tree->rchild;
EnQueue(&Q, &tmp);
}
}
FreeQueue(&Q);
}
完整代码
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
> Author: xiaojunyu/LunaW
> Mail : xiaojunyu@lunaw.cn
> Gmail : lunaw.cn@gmail.com
> Blog : http://blog.csdn.net/lunaw
> Web : http://lunaw.cn
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define True 1
#define False 0
typedef struct BiTNode {
int data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
BiTree CreateTreeNode(void); // 先变为扩展二叉树,前序递归输入
void PreOrderTraverse(BiTree T); // 前序遍历,递归
void InOrderTraverse(BiTree T); // 中序遍历,递归
void PostOrderTraverse(BiTree T); // 后序遍历,递归
void LevelOrderTraverse(BiTree T); // 层次遍历,队列
void DestroyTree(BiTree T); // 销毁树,后序递归
/* 队列 */
typedef struct QNode {
BiTree Tree;
struct QNode *next;
} QNode, *QueuePtr;
typedef struct Queue {
QueuePtr front, rear;
} LinkQueue;
int IsEmpt(LinkQueue * queue); // 判断是否为空
int InitQueue(LinkQueue * queue); //初始化队列
int FreeQueue(LinkQueue * queue); // 释放队列
int EnQueue(LinkQueue * queue, QueuePtr Q); // 进队列
int DeQueue(LinkQueue * queue, QueuePtr Q); // 出队列
int main(void)
{
BiTree T = NULL;
printf("请输入扩展二叉树: ");
T = CreateTreeNode();
printf("\n前序遍历: ");
PreOrderTraverse(T);
printf("\n中序遍历: ");
InOrderTraverse(T);
printf("\n后序遍历: ");
PostOrderTraverse(T);
printf("\n层次遍历: ");
LevelOrderTraverse(T);
DestroyTree(T);
return 0;
}
BiTree CreateTreeNode(void)
{
char c;
BiTree T;
scanf("%c", &c);
if (c == '#') {
T = NULL;
} else {
T = (BiTree) calloc(sizeof(BiTNode), 1);
T->data = c;
T->lchild = CreateTreeNode();
T->rchild = CreateTreeNode();
}
return T;
}
void DestroyTree(BiTree T)
{
if (T == NULL) {
return;
}
DestroyTree(T->lchild);
DestroyTree(T->rchild);
free(T); // 采用后序遍历递归销毁
T = NULL;
}
void PreOrderTraverse(BiTree T)
{
if (T == NULL) {
return;
}
printf("%c", T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
void InOrderTraverse(BiTree T)
{
if (T == NULL) {
return;
}
InOrderTraverse(T->lchild);
printf("%c", T->data);
InOrderTraverse(T->rchild);
}
void PostOrderTraverse(BiTree T)
{
if (T == NULL) {
return;
}
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c", T->data);
}
void LevelOrderTraverse(BiTree T)
{
QNode Tmp, tmp;
LinkQueue Q;
tmp.next = NULL;
Tmp.next = NULL;
Q.front = NULL;
Q.rear = NULL;
InitQueue(&Q);
tmp.Tree = T;
EnQueue(&Q, &tmp); // 根节点入队
while (DeQueue(&Q, &Tmp)) { // 依次出队,直到队列为空
printf("%c", Tmp.Tree->data);
if (Tmp.Tree->lchild != NULL) { // 若出队节点有左孩子,则左孩子入队
tmp.Tree = Tmp.Tree->lchild;
EnQueue(&Q, &tmp);
}
if (Tmp.Tree->rchild != NULL) { // 若出队节点有右孩子,则右孩子入队
tmp.Tree = Tmp.Tree->rchild;
EnQueue(&Q, &tmp);
}
}
FreeQueue(&Q);
}
int DeQueue(LinkQueue * queue, QueuePtr Q)
{
QueuePtr P;
if (IsEmpt(queue)) {
return False;
}
P = queue->front->next;
memcpy(Q, P, sizeof(QNode)); // 将队头数据保存
queue->front->next = P->next; // 队头下移一位
if (queue->rear == P) { // 若队尾是队头,则将队尾指向头节点
queue->rear = queue->front;
}
free(P);
return True;
}
int EnQueue(LinkQueue * queue, QueuePtr Q)
{
QueuePtr S = (QueuePtr) calloc(sizeof(QNode), 1);
memcpy(S, Q, sizeof(QNode));
queue->rear->next = S;
queue->rear = S;
return 0;
}
int InitQueue(LinkQueue * queue)
{
queue->front = (QueuePtr) calloc(sizeof(QNode), 1);
queue->front->next = NULL;
queue->rear = queue->front;
return 0;
}
int IsEmpt(LinkQueue * queue)
{
if (queue->front == NULL || queue->front == queue->rear) {
return True;
} else {
return False;
}
}
int FreeQueue(LinkQueue * queue)
{
QueuePtr A, B;
for (A = queue->front; A != NULL; B = A->next, free(A), A = B) ;
return 0;
}