二叉树:
二叉树的遍历实现
声明文件Bintree.h
#ifndef _BINTREE_H_
#define _BINTREE_H_
#include<stdio.h>
#include<string.h>
#include<Windows.h>
#define ENDTAG '#'
typedef char BTDataType;
typedef struct BinaryTreeNode
{
BTDataType _data;//当前节点的值域
struct BinaryTreeNode* _left;//指向当前节点的左孩子
struct BinaryTreeNode* _right;//指向当前节点的右孩子
}BTNode;
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a);
void BinaryTreeDestory(BTNode* root);
// 递归遍历//深度优先遍历
void BinaryTreePrevOrder(BTNode* root);
void BinaryTreeInOrder(BTNode* root);
void BinaryTreePostOrder(BTNode* root);
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);//广度优先遍历
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);
//非递归先中后序遍历
void _BinaryTreePrevOrderNonR(BTNode* root);
void _BinaryTreeInOrderNonR(BTNode* root);
void _BinaryTreePostOrderNonR(BTNode* root);
#endif
实现文件Bintree.c
#include"bintree.h"
#include"queue.h"
#include"stack.h"
// 构造一棵树
BTNode* BinaryTreeCreate(BTDataType* a)//构造一棵树
{
static int i = 0;
if (a[i] == ENDTAG)
{
i++;
return NULL;
}
else
{
BTNode* cur = (BTNode*)malloc(sizeof(BTNode));
cur->_data = a[i];
i++;
cur->_left = BinaryTreeCreate(a);
cur->_right = BinaryTreeCreate(a);
return cur;
}
}
//递归型:前中后序遍历************************************************************************************************************************
void BinaryTreePrevOrder(BTNode* root)//二叉树的先序遍历
{
if (root != NULL)
{
printf("%c", root->_data);
BinaryTreePrevOrder(root->_left);
BinaryTreePrevOrder(root->_right);
}
}
void BinaryTreeInOrder(BTNode* root)//二叉树的中序遍历
{
if (root != NULL)
{
BinaryTreeInOrder(root->_left);
printf("%c", root->_data);
BinaryTreeInOrder(root->_right);
}
}
void BinaryTreePostOrder(BTNode* root)//二叉树的后序遍历
{
if (root != NULL)
{
BinaryTreePostOrder(root->_left);
BinaryTreePostOrder(root->_right);
printf("%c", root->_data);
}
}
//层次遍历************************************************************************************************************************
void BinaryTreeLevelOrder(BTNode* root)//层序遍历(树的广度优先搜索)
{
Queue qu;
BTNode *tmp;//定义的tmp始终指向队头的data,以此来判断是否有左右孩子,是否需要进行插入操作
QueueInit(&qu);
QueuePush(&qu, root);//在队列初始化后,先插入根节点,才能继续下列操作
while (!QueueEmpty(&qu))//是空返回1,(!1)是表示为假,退出循环
{
tmp = QueueFront(&qu); //QueueFront的返回值data是BTNode *类型的,里面包含了一个树节点的data,_left, _right
printf("%c", tmp->_data);//打印节点的值
if (tmp->_left)//得到tmp为队列的第一个节点,判断其左孩子是否为空,不为空就让其左孩子进队列
{
QueuePush(&qu, tmp->_left);
}
if (tmp->_right)//得到tmp为队列的第一个节点,判断其右孩子是否为空,不为空就让其右孩子进队列
{
QueuePush(&qu, tmp->_right);
}
QueuePop(&qu);//删除队头(已经打印过),更换队头
}
QueueDestory(&qu);//摧毁队列
}
//非递归型:前中后序遍历************************************************************************************************************************
//非递归先序遍历
void BinaryTreePrevOrderNonR(BTNode* root)//根左右
{
Stack st;
BTNode* cur = root;
StackInit(&st);
while (cur||StackEmpty(&st))
{
printf("%c", cur->_data);//打印根
if (cur->_right)//如果有右孩子,就让右孩子进栈
{
StackPush(&st, cur->_right);
}
if (cur->_left)//如果有左孩子,就让左孩子继续遍历
{
cur = cur->_left;
}
else//如果左孩子为空时,就让cur取栈顶,并释放原来的栈顶
{
cur = StackTop(&st);
StackPop(&st);
}
}
StackDestory(&st);
}
//非递归中序遍历
void BinaryTreeInOrderNonR(BTNode* root)
{
BTNode * cur = root;
Stack st;
StackInit(&st);
while (cur || StackEmpty(&st))//当cur为空且栈为空时,循环跳出,代表树遍历完毕
{
for (; cur; cur = cur->_left)
//1,把目前的根及其所有的左孩子压栈,直到左孩子为空为止
//2,以目前的右孩子为根,继续将它的左孩子压栈
{
StackPush(&st, cur);
}
//if (StackEmpty(&st))
//{
cur = StackTop(&st);
//1,左孩子遍历完毕后,第一个没有左孩子的结点就是中序的第一个输出
//2,如果右孩子为空,此时栈里将会是下一个要访问的结点,如果有右孩子,那么此时栈里将会是以那个右孩子
putchar(cur->_data);
//1,由于没有左孩子了,所以打印根(左根右)
StackPop(&st);//出栈
cur = cur->_right;
//1,左孩子和根遍历结束后,遍历它的右子树
//}
}
StackDestory(&st);
}
//非递归后序遍历
void BinaryTreePostOrderNonR(BTNode* root)//左右根
{
BTNode * cur = root;
Stack st;
int tag[32] = { 0 };
StackInit(&st);
while (cur || StackEmpty(&st))//当cur为空且栈为空时,循环跳出,代表树遍历完毕
{
for (; cur; cur = cur->_left)//类似中序,将左孩子入栈,cur为空时,代表上一个节点的右孩子为空,只有这种情况才能进行打印
{
StackPush(&st, cur);//push操作会导致size+1
tag[st._top] = 0;//由于入栈的是左孩子,所以这里的左孩子遍历标签置为0,(是否遍历完毕)
}
//只要上面的for只要执行一次,就不能进入while中
while (StackEmpty(&st) && tag[st._top] == 1)//左孩子没有遍历完毕,不能进行打印
//所以这里确保了只有左右子树都遍历完成后,才能进行打印
{
cur = StackTop(&st);
putchar(cur->_data);//打印根
StackPop(&st);//pop操作会导致size-1
cur = NULL;//为了循环正常跳出
}
if (StackEmpty(&st))
{
tag[st._top] = 1;//进入这里证明左子树遍历完毕,左子树标签置1
cur = StackTop(&st)->_right;//进入右子树继续遍历
}
}
StackDestory(&st);
}
//判断一棵树是不是完全二叉树
int BinaryTreeComplete(BTNode* root)
{
Queue qu;
BTNode *tmp;
int leafflag = 0;
QueueInit(&qu);
QueuePush(&qu, root);
while (!QueueEmpty(&qu))
{
tmp = QueueFront(&qu);
printf("%c", tmp->_data);
QueuePop(&qu);
if (leafflag )//当出现有左孩子没有右孩子时,队列里剩余的值都只能有叶子节点,一旦出现左右孩子直接退出
{
if (tmp->_left || tmp->_right)
{
return 0;
}
continue;
}
if (tmp->_left&&tmp->_right)
{
QueuePush(&qu, tmp->_left);
QueuePush(&qu, tmp->_right);
}
else if (tmp->_right&&!tmp->_left)//有右孩子没有左孩子时,一定不是完全二叉树,直接退出
{
return 0;
}
else
{
leafflag = 1;
if (tmp->_left)
{
QueuePush(&qu, tmp->_left);
}
}
}
QueueDestory(&qu);
}
void BinaryTreeDestory(BTNode* root)//通过前序遍历来摧毁树
{
BTNode *left;
BTNode *right;
if (root)
{
left = root->_left;
right = root->_right;
free(root);
BinaryTreeDestory(left);
BinaryTreeDestory(right);
}
}
测试文件test.c
#include"bintree.h"
#include"queue.h"
#include"stack.h"
int main()
{
//BTNode *BT = BinaryTreeCreate("ABD##E#H##CF##G##");
BTNode *BT = BinaryTreeCreate("ABD##EJ###CF##G##");
BinaryTreePrevOrder(BT);
putchar('\n');
BinaryTreeInOrder(BT);
putchar('\n');
BinaryTreePostOrder(BT);
putchar('\n');
BinaryTreeLevelOrder(BT);
putchar('\n');
BinaryTreePrevOrderNonR(BT);
putchar('\n');
BinaryTreeInOrderNonR(BT);
putchar('\n');
BinaryTreePostOrderNonR(BT);
putchar('\n');
//printf("%d", BinaryTreeComplete(BT));
//putchar('\n');
BinaryTreeDestory(BT);
system("pause");
return 0;
}
由于二叉树的遍历需要用到一些接口,因此我们引入了以下接口
二叉树的层次遍历需要通过队列来实现,所以我们将队列的接口放到项目中
//queue.h(具体可将上一博客)
#ifndef _QUEUE_H_
#define _QUEUE_H_
#include"bintree.h"
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<Windows.h>
typedef BTNode * QuDataType;//需要传入整个节点,对他进行push和pop操作
typedef struct QueueNode
{
struct QueueNode* next;
QuDataType data;
}QueueNode;
typedef struct Queue
{
QueueNode* _front;
QueueNode* _rear;
}Queue;
void QueueInit(Queue * pq);//对队列进行初始化
void QueueDestory(Queue* pq);//对队列进行摧毁
QueueNode* BuyQueueNode(QuDataType x);//申请一个队列节点
void QueuePush(Queue* pq, QuDataType x);//队列的尾插操作(先进先出的结构)
void QueuePop(Queue* pq);//队列的头删操作(先进先出的结构)
QuDataType QueueFront(Queue* pq);//得到头结点
int QueueEmpty(Queue* pq);//判断队列是否为空
#endif
//queue.c
#include"queue.h"
//对队列进行初始化
void QueueInit(Queue * pq)
{
pq->_front = NULL;
pq->_rear = NULL;
}
//对队列进行摧毁
void QueueDestory(Queue* pq)
{
QueueNode* tmp;
for (; pq->_front != NULL; pq->_front = pq->_front->next)
{
tmp = pq->_front->next;
free(pq->_front);
pq->_front = tmp;
}
pq->_front = NULL;
pq->_rear = NULL;
}
//申请一个队列节点
QueueNode* BuyQueueNode(QuDataType x)
{
QueueNode* tmp = (QueueNode*)malloc(sizeof(QueueNode));
tmp->data = x;
tmp->next = NULL;
return tmp;
}
//队列的尾插操作(先进先出的结构)
void QueuePush(Queue* pq, QuDataType x)
{
QueueNode* tmp = BuyQueueNode(x);
if (pq->_rear == NULL)//如果pq->rear为空的话,就说明这个队列还没有一个节点
{
pq->_front = tmp;
pq->_rear = tmp;
}
else
{
pq->_rear->next = tmp;
pq->_rear = tmp;
}
}
//队列的头删操作(先进先出的结构)
void QueuePop(Queue* pq)
{
QueueNode* tmp;
if (pq->_front == NULL)
{
return;
}
else
{
tmp = pq->_front->next;
free(pq->_front);
pq->_front = tmp;
}
}
//得到头结点,返回的data是BTNode *类型的,里面包含了一个树节点的data,_left,_right
QuDataType QueueFront(Queue* pq)
{
if (pq->_front == NULL)
{
return 0;
}
else
{
return pq->_front->data;
}
}
//判断队列是否为空
int QueueEmpty(Queue* pq)
{
return pq->_front == NULL;//是空返回1,不是空返回0
}
//返回队列节点个数
由于非递归的前中后序遍历需要通过栈来实现,因此我们需要引入栈的接口
//stack.h*************************************************************************************
#ifndef _STACK_H_
#define _STACK_H_
#include"bintree.h"
#include<stdio.h>
#include<Windows.h>
#include<assert.h>
#define N 20
typedef BTNode * STDataType;
typedef struct Stack
{
STDataType *_a;//指向动态开辟的数组
int _top;//栈顶
int _capacity;//容量
}Stack;
void StackInit(Stack *ps);//栈的初始化
void StackDestory(Stack *ps);//摧毁栈
void StackPush(Stack *ps, STDataType x);//栈的尾插操作(是一种先进后出的结构)
void StackPop(Stack *ps);//栈的尾删操作(是一种先进后出的结构)
STDataType StackTop(Stack *ps);//返回栈顶的值
int StackEmpty(Stack *ps);
int StackSize(Stack *ps);
#endif
//stack.c**********************************************************
#include"stack.h"
//栈的初始化
void StackInit(Stack *ps)
{
assert(ps);
ps->_capacity = N;
ps->_a = (STDataType*)malloc(ps->_capacity*sizeof(STDataType));
ps->_top = 0;
}
//摧毁栈
void StackDestory(Stack *ps)
{
assert(ps);
if (ps->_a)//防止重复释放
{
free(ps->_a);
ps->_a = NULL;
ps->_top = 0;
ps->_capacity = 0;
}
}
//栈的尾插操作(是一种先进后出的结构)
void StackPush(Stack *ps, STDataType x)
{
assert(ps);
if (ps->_top == ps->_capacity)
{
ps->_capacity *= 2;
ps->_a = (STDataType*)malloc(ps->_capacity*sizeof(STDataType));
assert(ps->_a);
}
ps->_a[ps->_top] = x;
ps->_top++;
}
//栈的尾删操作(是一种先进后出的结构)
void StackPop(Stack *ps)
{
assert(ps);
if (ps->_top > 0)
{
ps->_top--;
}
else
{
return NULL;
}
}
//返回栈顶的值
STDataType StackTop(Stack *ps)
{
assert(ps);
if (ps->_top != 0)
{
return ps->_a[ps->_top - 1];
}
else
{
return NULL;
}
}
//检查是否栈空
int StackEmpty(Stack *ps)
{
assert(ps);
if (ps->_top == NULL)
{
return 0;//如果为空就返回0
}
else
{
return 1;//如果不为空就返回1
}
}
//检查当前栈的大小
int StackSize(Stack *ps)
{
return ps->_top;
}