您的位置:首页 > 编程语言 > C语言/C++

【C语言】用链表实现的堆栈来实现二叉树的前中后序遍历

2020-04-01 19:15 971 查看
/* 二叉树的前中后序遍历 */

#include <stdio.h>
#include <stdlib.h>

typedef struct treeNode *BinTree;
typedef struct stackNode *Stack;

/* 二叉树的描述结构 */
struct treeNode
{
int data;
struct treeNode *left;
struct treeNode *right;
};

/* 栈的结构 */
struct stackNode
{
BinTree node;
struct stackNode *next;
};

/* 链表实现堆栈 */
Stack createStack(){

Stack stack = (Stack)malloc(sizeof(struct stackNode));
stack->next = NULL;

return stack;
}

/* 判断栈是否为空 */
int stackIsEmpty(Stack stackTop){
if (stackTop->next)
return 0;
return 1;
}

/* 压栈 */
void stackPush(Stack stackTop, BinTree myNode){

if (myNode)
{
Stack midNode = (Stack)malloc(sizeof(struct stackNode));
midNode->node = myNode;

midNode->next = stackTop->next;
stackTop->next = midNode;
}
}

/* 出栈 */
BinTree stackPop(Stack stackTop){

if (stackIsEmpty(stackTop))
{
printf("Stack is empty!\n");
return NULL;
}

BinTree mid = stackTop->next->node;
Stack willFree = stackTop->next;
stackTop->next = willFree->next;
free(willFree);

return mid;
}

/* 建立树节点 */
BinTree buildTreeNode(int myData){

BinTree mid = (BinTree)malloc(sizeof(struct treeNode));
mid->left = NULL;
mid->right = NULL;
mid->data = myData;
return mid;
}

/* 后序时前驱节点 */
BinTree frontNode(BinTree node){

if (node->right)
return node->right;
return node->left;
}

/* 递归实现先序遍历 */
void ergodicBinTree1(BinTree myTree){

if (myTree)
{
printf("%d ", myTree->data);
ergodicBinTree1(myTree->left);
ergodicBinTree1(myTree->right);
}
}

/* 递归实现中序遍历 */
void ergodicBinTree2(BinTree myTree){

if (myTree)
{
ergodicBinTree2(myTree->left);
printf("%d ", myTree->data);
ergodicBinTree2(myTree->right);
}
}

/* 递归实现后序遍历 */
void ergodicBinTree3(BinTree myTree){

if (myTree)
{
ergodicBinTree3(myTree->left);
ergodicBinTree3(myTree->right);
printf("%d ", myTree->data);
}
}

/* 堆栈实现先序遍历 */
/*
大概思路:
1.从树根往左遍历到头,将节点的右子节点压栈;
2.到头以后说明该节点已经没有左子节点了,可以开始将右子节点当做子树头来进行出栈;
*/
void ergodicBinTree4(BinTree myTree){

Stack stackTop = createStack();

while(myTree){
/* 从根开始,往左遍历到头 */
while(myTree){
printf("%d ", myTree->data);    //遇到就进行输出
stackPush(stackTop, myTree->right);    //并将该节点的右节点进行压栈(压栈操作会自己判断数据是否有效)
myTree = myTree->left;    //将该节点的左节点当做根节点去再进行以上操作
}
/* 将最近的右孩子当做子树的根,因为此时栈里存的都是右节点,所以得考虑到只有左线性的情况,需要判断一下(其实出栈操作会判断是否为空,所以也可以不进行判断) */
if (!stackIsEmpty(stackTop))
myTree = stackPop(stackTop);
}
}

/*
堆栈实现中序遍历
思路:
1.因为先进行左子树的输出,所以当遇到节点的时候,暂时还不知道能不能输出,所以需要先将它存下来;
2.当到达左子树的最后一个的时候,就可以将节点进行出栈输出,并将该节点的右节点当做子树的根进行以上操作;
PS:由于当左边遍历到最后一个的时候,如果该节点为叶子节点,那么指向的时候也会为空,所以循环的结束条件是节点与堆栈都为空。
*/
void ergodicBinTree5(BinTree myTree){

Stack stackTop = createStack();

while(myTree || !stackIsEmpty(stackTop)){
while(myTree){
stackPush(stackTop, myTree);
myTree = myTree->left;
}
if (!stackIsEmpty(stackTop))
{
myTree = stackPop(stackTop);
printf("%d ", myTree->data);
myTree = myTree->right;
}
}
}

/*
堆栈实现后序遍历
PS:前驱节点:当前驱节点已经被弹出,那它自己也可以弹出了,叶子节点没有前驱节点;
思路:
1.与中序时一样,先遍历到左边最后一个,并进行节点压栈;
2.左边最后一个可能有右子节点,所以需要判断一下,如果没有前驱节点,就进行输出,并重置上一次输出的节点(用于判断栈中节点是否可以出栈),否则将节点当做子树根再进行遍历;

*/
void ergodicBinTree6(BinTree myTree){

Stack stackTop = createStack();
BinTree last = NULL;

while(myTree || !stackIsEmpty(stackTop)){
while(myTree){
stackPush(stackTop, myTree);
myTree = myTree->left;
}
if (!stackIsEmpty(stackTop))
{
BinTree judge = stackTop->next->node->right;
if (judge)
{
myTree = judge;    //判断是否有右子节点,有就把它当做子树的根节点先行遍历
}else{
last = stackPop(stackTop);    //如果没有右子节点,那说明为叶子节点,将其弹出
printf("%d ", last->data);
while(!stackIsEmpty(stackTop) && last == frontNode(stackTop->next->node)){    //当弹出一个叶子节点之后,需要将前驱节点已经弹出的全部都弹出
last = stackPop(stackTop);
printf("%d ", last->data);
}
myTree = NULL;    //弹出前面的节点以后,说明该子树已经遍历完,不再进行重复遍历,PS:其实进到这里的时候myTree就表明是空的,也可以不进行赋值。
}
}
}
}

int main(int argc, char const *argv[])
{
BinTree temp;
BinTree myTree = buildTreeNode(1);
myTree->right = buildTreeNode(2);
temp = myTree->right;
temp->left = buildTreeNode(3);
temp->right = buildTreeNode(4);
temp = temp->right;
temp->left = buildTreeNode(5);
temp->right = buildTreeNode(6);
temp->left->right = buildTreeNode(7);
temp->left->right->left = buildTreeNode(9);
temp = temp->right;
temp->left = buildTreeNode(8);
temp = temp->left;
temp->right = buildTreeNode(10);
temp = temp->right;
temp->right = buildTreeNode(11);

ergodicBinTree1(myTree);
printf("\n");
ergodicBinTree2(myTree);
printf("\n");
ergodicBinTree3(myTree);
printf("\n");
printf("\n");
ergodicBinTree4(myTree);
printf("\n");
ergodicBinTree5(myTree);
printf("\n");
ergodicBinTree6(myTree);
printf("\n");
return 0;
}
  • 点赞
  • 收藏
  • 分享
  • 文章举报
遨游太空 发布了4 篇原创文章 · 获赞 1 · 访问量 109 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐