代码包含如下几个文件:
下面一一贴出来:
Stack.h文件:
#ifndef STACK_H_
#define STACK_H_
#include "BinaryTree.h"
#include <stdbool.h>
#define STACK_INIT_SZIE 20
#define STACK_INCREMENT_SIZE 10
typedef struct {
int size;/** 栈的容量 */
BiTreeNode** base;/** 栈底指针,注意这里是指向二叉树节点指针的指针 */
BiTreeNode** top;/** 栈顶指针 */
}Stack;
Stack *InitStack();/** 初始化栈 */
void Push(Stack *stack, BiTreeNode* node);/** 入栈 */
BiTreeNode* GetTop(Stack *stack);/** 获取栈顶数据 */
BiTreeNode* Pop(Stack *stack);/** 栈顶元素出栈 */
bool isStackEmpty(Stack* stack);/** 判断栈是否为空 */
#endif
Stack.c文件:
#include<stdio.h>
#include <stdlib.h>
#include "Stack.h"
#include "BinaryTree.h"
/** 初始化栈 */
Stack *InitStack()
{
Stack *stack = (Stack*)malloc(sizeof(Stack));
//下面这句遇到坑了,stack->base应该申请sizeof(BiTreeNode) * STACK_INIT_SZIE的空间,开始忘了*STACK_INIT_SZIE,导致一直出错
stack->base = (BiTreeNode**)malloc(sizeof(BiTreeNode) * STACK_INIT_SZIE);
stack->top = stack->base;
stack->size = STACK_INIT_SZIE;
return stack;
}
/** 入栈 */
void Push(Stack *stack, BiTreeNode* node)
{
if (stack->top - stack->base >= stack->size)//栈满,重新分配更大的空间
{
stack->base = (BiTreeNode**)realloc(stack->base, sizeof(BiTreeNode) * (stack->size + STACK_INCREMENT_SIZE));
if (!stack->base)//分配空间失败
{
printf("stack increment size error!\n");
exit(0);
}
stack->top = stack->base + stack->size;//修改栈顶指针
stack->size += STACK_INCREMENT_SIZE;//修改新的栈容量大小
//printf("stack increment size 10, now stack size is %d\n", stack->size);
}
if(node)
*(stack->top) = node;
else//入栈的是空节点,则用值为#的节点代替空节点
{
BiTreeNode* emptyNode = (BiTreeNode*)malloc(sizeof(BiTreeNode));
emptyNode->val = '#';
emptyNode->left = NULL;
emptyNode->right = NULL;
*(stack->top) = emptyNode;
}
(stack->top)++;
//printf("push node %c to stack, now stack has %d elements, stack size is %d\n", node->val, stack->top - stack->base, stack->size);
}
/** 获取栈顶元素 */
BiTreeNode* GetTop(Stack *stack)
{
if (stack->base == stack->top)//栈空
return NULL;
//printf("get stack top: %c\n", (stack->top - 1)->val);
return *(stack->top - 1);
}
/** 出栈 */
BiTreeNode* Pop(Stack *stack)
{
if (stack->base == stack->top)//栈空
return NULL;
--(stack->top);
//printf("stack pop: %c\n", stack->top->val);
return *stack->top;
}
/** 判断栈是否为空 */
bool isStackEmpty(Stack* stack)
{
if(stack)
return stack->base == stack->top;
return true;
}
BinaryTree.h文件:
#ifndef BINARY_TREE_H_
#define BINARY_TREE_H_
#include <stdbool.h>
typedef struct Node{
struct Node *left;/** 左孩子 */
struct Node *right;/** 右孩子 */
char val;/** 节点中的数据 */
bool isPrintOut;/** 后序非递归遍历时用到,为false表示该节点未输出,为true表示该节点已输出 */
}BiTreeNode;
BiTreeNode* CreateBinaryTree();/** 创建二叉树,使用先序创建 */
void PreOrderBiTree(BiTreeNode*);/** 先序遍历递归 */
void PreOrderBiTree1(BiTreeNode*);/** 先序遍历非递归 */
void InOrderBiTree(BiTreeNode*);/** 中序遍历递归 */
void InOrderBiTree2(BiTreeNode*);/** 中序遍历非递归1 */
void InOrderBiTree3(BiTreeNode*);/** 中序遍历非递归2 */
void PostOrderBiTree(BiTreeNode*);/** 后序遍历递归 */
void PostOrderBiTree1(BiTreeNode*);/** 后序遍历非递归 */
bool IsChildsAllPrintOut(BiTreeNode*);/** 判断某个节点的孩子节点是否全部输出 */
#endif
#include <stdio.h>
#include <stdlib.h>
#include "BinaryTree.h"
#include "Stack.h"
/** 先序创建二叉树,使用递归的方式创建 */
BiTreeNode* CreateBinaryTree()
{
char c;
scanf("%c", &c);
BiTreeNode* node;
if (c == '#')
node = NULL;
else
{
node = (BiTreeNode*)malloc(sizeof(BiTreeNode));
node->val = c;
node->left = CreateBinaryTree();
node->right = CreateBinaryTree();
node->isPrintOut = false;
}
return node;
}
/** 先序遍历,递归 */
void PreOrderBiTree(BiTreeNode* root)
{
if (root)
{
printf("%c ", root->val);
PreOrderBiTree(root->left);
PreOrderBiTree(root->right);
}
}
/** 先序遍历,非递归 */
void PreOrderBiTree1(BiTreeNode* root)
{
BiTreeNode* p = root;
Stack* stack = InitStack();
while (p || !isStackEmpty(stack))
{
if (p)
{
printf("%c ", p->val);
Push(stack, p);
p = p->left;
}
else
{
p = Pop(stack);
p = p->right;
}
}
}
/** 中序遍历,递归 */
void InOrderBiTree(BiTreeNode* root)
{
if (root)
{
InOrderBiTree(root->left);
printf("%c ", root->val);
InOrderBiTree(root->right);
}
}
/** 中序遍历,非递归方法一 */
void InOrderBiTree2(BiTreeNode* root)
{
Stack *stack = InitStack();
Push(stack, root);
BiTreeNode* p;
while (!isStackEmpty(stack))
{
while ((p = GetTop(stack))->val != '#')
Push(stack, p->left);
Pop(stack);
if (!isStackEmpty(stack))
{
BiTreeNode* node = Pop(stack);
if (node)
{
printf("%c ", node->val);
Push(stack, node->right);
}
}
}
}
/** 中序遍历,非递归方法二 */
void InOrderBiTree3(BiTreeNode* root)
{
Stack* stack = InitStack();
BiTreeNode* p = root;
while (p || !isStackEmpty(stack))
{
if (p)
{
Push(stack, p);
p = p->left;
}
else
{
p = Pop(stack);
printf("%c ", p->val);
//printf("中序非递归遍历遇到节点%c,指针地址为%ld\n", p->val, p);
p = p->right;
}
}
}
/** 后序遍历,递归 */
void PostOrderBiTree(BiTreeNode* root)
{
if (root)
{
PostOrderBiTree(root->left);
PostOrderBiTree(root->right);
printf("%c ", root->val);
}
}
/** 后序遍历,非递归 */
void PostOrderBiTree1(BiTreeNode* root)
{
Stack* stack = InitStack();
BiTreeNode* p = root;
while (p || !isStackEmpty(stack))
{
if (p)
{
Push(stack, p);
p = p->left;
}
else
{
p = GetTop(stack);
if (IsChildsAllPrintOut(p))
{
printf("%c ", p->val);
/** 输出一个节点,就把该节点的isPrintOut设置为true */
p->isPrintOut = true;
p = Pop(stack);
p = NULL;
}
else
p = p->right;
}
}
}
/** 判断一个节点的所有孩子节点是否都输出了 */
bool IsChildsAllPrintOut(BiTreeNode* node)
{
bool leftPrintOut = false;
bool rightPrintOut = false;
if (!node->left)//节点为空则认为该节点已输出
leftPrintOut = true;
else
leftPrintOut = node->left->isPrintOut;
if (!node->right)
rightPrintOut = true;
else
rightPrintOut = node->right->isPrintOut;
return leftPrintOut && rightPrintOut;
}
main.c文件:
#include<stdio.h>
#include <stdlib.h>
#include "Stack.h"
void printResult(char *msg, void(*p)(BiTreeNode*), BiTreeNode* node)
{
printf("\n---------%s---------\n", msg);
p(node);
printf("\n---------%s---------\n", msg);
}
int main()
{
printf("使用先序创建二叉树,#表示空节点,请输入二叉树的数据:\n");
BiTreeNode* root = CreateBinaryTree();
printResult("先序遍历递归算法", PreOrderBiTree, root);
printResult("先序遍历非递归算法", PreOrderBiTree1, root);
printResult("中序遍历递归算法", InOrderBiTree, root);
printResult("中序遍历非递归算法1", InOrderBiTree2, root);
printResult("中序遍历非递归算法2", InOrderBiTree3, root);
printResult("后序遍历递归算法", PostOrderBiTree, root);
printResult("后序遍历非递归算法", PostOrderBiTree1, root);
return 0;
}
测试用的二叉树如下图:
代码运行结果如下图:
总结:
在实现这几个算法的过程中,遇到了一些坑:
(1)首先是栈的初始化,在为栈底指针分配内存空间时,忘了乘以栈容量,导致后来测试一直不对
(2)然后是栈的数据结构定义,栈中存储的应该是指向二叉树节点指针的指针,开始我直接定义的指向二叉树节点的指针,导致在后序非递归算法中一直出问题,修改了某个节点的isPrintOut值后,再取出来发现值没有变,问题出在Push节点到栈,如果栈中存的是二叉树节点的指针,则入栈时代码是下面这样的:
这时候入栈就相当于重新分配了空间,导致修改isPrintOut的值不是原来的节点的值,所以后序遍历一直不对,修改了栈的数据结构,让栈存储指向二叉树节点指针的指针后,再运行就没问题了