一、4.1二叉树链式结构的遍历
所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做
的操作依赖于具体的应用问 题。 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。
前序/中序/后序的递归结构遍历:是根据访问结点操作发生位置命名
- NLR:前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
- LNR:中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
- LRN:后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。
由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为
根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。
层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在
层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层
上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
二叉树的接口实现
1、头文件
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef char BTType;
typedef struct BTNode
{
BTType _data;
struct BTNode* _left;
struct BTNode* _right;
}BTNode;
typedef BTNode* QUDataType;
typedef struct QueueNode
{
QUDataType _data;
struct QueueNode* _next;
}QueueNode;
typedef struct Queue
{
QueueNode* _front;
QueueNode* _rear;
}Queue;
void QueueInit(Queue* q);
void QueueDestory(Queue* q);
void QueuePush(Queue* q, QUDataType x);
void QueuePop(Queue* q);
int QueueSize(Queue* q);
int QueueEmpty(Queue* q);
QUDataType QueueFront(Queue* q);
QUDataType QueueBack(Queue* q);
typedef BTNode* STDataType;
typedef struct Stack
{
STDataType* _a;
int _top;
int _capacity;
}Stack;
void StackInit(Stack* ps, int n);
void StackDestory(Stack* ps);
void StackPush(Stack* ps, STDataType x);
void StackPop(Stack* ps);
STDataType StackTop(Stack* ps);
int StackSize(Stack* ps);
int StackEmpty(Stack* ps);
void StackPrint(Stack* ps);
BTNode* CreatBTree(BTType* str, int* n);
int BinaryTreeSize(BTNode* root);//二叉树节点个数
int BinaryTreeLeafSize(BTNode* root);//儿叉树的叶子节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);//二叉树第k层叶子节点个数
BTNode* BinaryTreeFind(BTNode* root, BTType val);
//递归遍历二叉树
void BinaryTreePrevOrder(BTNode* root);
void BinaryTreeInOrder(BTNode* root);
void BinaryTreePostOrder(BTNode* root);
//二叉树的层序遍历
void BinaryTreeLevelOrder(BTNode* root);
//非递归遍历二叉树
void BinaryTreePrevOrderNonR(BTNode* root);
void BinaryTreeInOrderNonR(BTNode* root);
void BinaryTreePostOrderNonR(BTNode* root);
void Test();
2、定义文件
#include "Tree.h"
BTNode* BuyTreeNode(BTType x)
{
BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
newnode->_data = x;
newnode->_left = NULL;
newnode->_right = NULL;
return newnode;
}
BTNode* CreatBTree(BTType* arr, int* n)
{
if (arr[*n] != '#')
{
BTNode* root = BuyTreeNode(arr[*n]);
(*n)++;
root->_left = CreatBTree(arr, n);
(*n)++;
root->_right = CreatBTree(arr, n);
return root;
}
else
{
return NULL;
}
}
int BinaryTreeSize(BTNode* root)
{
if(root == NULL)
return 0;
return BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right) + 1;
}
int BinaryTreeLeafSize(BTNode* root)
{
if(root == NULL)
return 0;
if(root->_left == NULL && root->_right == NULL)
return 1;
return BinaryTreeLeafSize(root->_left) + BinaryTreeLeafSize(root->_right);
}
int BinaryTreeLevelKSize(BTNode* root, int k)
{
if(root == NULL)
return 0;
if(root->_left == NULL && root->_right == NULL)
return 1;
return BinaryTreeLevelKSize(root->_left, k-1) + BinaryTreeLevelKSize(root->_right, k-1);
}
BTNode* BinaryTreeFind(BTNode* root, BTType val)
{
BTNode* ret = NULL;
if(root == NULL)
return NULL;
if(root->_data == val)
return root;
ret = BinaryTreeFind(root->_left,val);
if(ret != NULL)
return ret;
ret = BinaryTreeFind(root->_right, val);
if(ret != NULL)
return ret;
return NULL;
}
void BinaryLevelOrder(BTNode* root)
{
Queue s;
QueueInit(&s);
if(root != NULL)
{
QueuePush(&s, root);
}
while(QueueEmpty(&s) == 1)
{
BTNode* front = QueueFront(&s);
QueuePop(&s);
printf("%s ", front->_data);
if(front->_left != NULL)
QueuePush(&s, front->_left);
if(front->_right != NULL)
QueuePush(&s, front->_right);
}
printf("\n");
}
//非递归前序遍历二叉树的思想为:a.访问他的左路节点b.访问左路节点的右子树
//将所有左路节点入栈的同时并访问,然后拿出栈顶节点,同时出栈顶节点,此时在访问出栈节点的右孩子,
//若右孩子为空直接栈顶节点,若不为空继续入站,访问出栈节点的左路节点和左路节点的右子树,
void BinaryTreePrevOrderNonR(BTNode* root)
{
BTNode* cur = root;
BTNode* top = NULL;
Stack st;
StackInit(&st, 3);
while(cur != NULL || StackEmpty(&st) != 0)
{
while(cur != NULL)
{
printf("%c ", cur->_data);
StackPush(&st, cur);
cur = cur->_left;
}
top = StackTop(&st);
StackPop(&st);
cur = top->_right;
}
printf("\n");
}
//中序遍历的思路和前序遍历非递归很相似,也是分为左路节点和左路节点的右子树
//首先把左路节点入栈,不访问,当左路节点没有左左孩子时,那出栈顶节点并且访问,让后出栈顶接节点
//然后把栈节点的右孩子入栈,并且继续上面的过程。
void BinaryTreeInOrderNonR(BTNode* root)
{
BTNode* cur = root;
BTNode* top = NULL;
Stack st;
StackInit(&st, 3);
while(cur != NULL || StackEmpty(&st) != 0)
{
while(cur != NULL)
{
StackPush(&st, cur);
cur = cur->_left;
}
top = StackTop(&st);
StackPop(&st);
printf("%c ", top->_data);
cur = top->_right;
}
printf("\n");
}
//后序遍历的非递归遍历时,要判读它的右路节点是否已经被访问过,如果没有访问过就访问。
//首先把根节点入栈,如果根节点的左子树和右子树不存在,或者根节点的左子树和右子树已经
//访问过,直接拿出根节点访问,然后出栈节点,标记为上一个输出节点的prev,在把此时的站栈顶节点
//作为当前节点,若果不满足条件,就把根节点的左子树和右子树一次入栈,当前节点重置为栈顶节点,然后重复操作
void BinaryTreePostOrderNonR(BTNode* root)
{
BTNode* top = NULL;
BTNode* prev = NULL;
BTNode* cur = root;
Stack st;
StackInit(&st,3);
while(cur != NULL || StackEmpty(&st) != 0)
{
while(cur != NULL)
{
StackPush(&st, cur);
cur = cur->_left;
}
top = StackTop(&st);
if(top->_right == NULL || top->_right == prev)
{
printf("%c ",top->_data);
StackPop(&st);
prev = top;
}
else
{
cur = top->_right;
}
}
}
void BinaryTreePrevOrder(BTNode* root)
{
if(NULL == root)
return;
printf("%c ", root->_data);
BinaryTreePrevOrder(root->_left);
BinaryTreePrevOrder(root->_right);
}
void BinaryTreeInOrder(BTNode* root);
{
if(NULL == root)
return;
BinaryTreeInOrder(root->_left);
printf("%c ",root->_data);
BinaryTreeInOrder(root->_right);
}
void BinaryTreePostOrder(BTNode* root);
{
if(NULL == root)
return;
BinaryTreePostOrder(root->_left);
BinaryTreePostOrder(root->_right);
printf("%c ", root->_data);
}
void Test()
{
int i = 0;
char* arr = "ABD##E#H##CF#G##";
BTNode* tree = CreatBTree(arr,&i);
printf("%d\n", BinaryTreeLeafSize(tree));
}