代码包含如下几个文件:
下面一一贴出来:
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; }
#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; }
#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的值不是原来的节点的值,所以后序遍历一直不对,修改了栈的数据结构,让栈存储指向二叉树节点指针的指针后,再运行就没问题了