2026.6.10 数据结构 二叉树

#pragma once

typedef char ElemType;

//二叉链表

typedef struct BTNode

{

ElemType data;//1.数据域

struct BTNode* leftchild;//2.左孩子指针域

struct BTNode* rightchild;//3.右孩子指针域

}BTNode;

/*

//三叉链表

typedef struct BTNode

{

ElemType data;//1.数据域

struct BTNode* leftchild;//2.左孩子指针域

struct BTNode* rightchild;//3.右孩子指针域

struct BTNode* parent;//4.双亲指针

}BTNode;

*/

//前中后序遍历(递归方式实现)

void preOrder(BTNode* root);

void inOrder(BTNode* root);

void postOrder(BTNode* root);

//二叉树的构建函数1(按图索骥)

BTNode* Create1();

//购买新节点

BTNode* BuyNode(ElemType val);

//前中后序遍历(非递归方式实现)

void preOrder_NoRecursion(BTNode* root);

void inOrder_NoRecursion(BTNode* root);

void postOrder_NoRecursion1(BTNode* root);

void postOrder_NoRecursion2(BTNode* root);

//层序遍历

void Level_Traverse(BTNode* root);

void S_Level_Traverse(BTNode* root);//正S

void ReverseS_Level_Traverse(BTNode* root);//倒S

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <assert.h>

#include <memory.h>

#include "BinaryTree.h"

//前中后序遍历(递归方式实现)

void preOrder(BTNode* root) //根左右

{

if (root == NULL)

return;

printf("%c ", root->data);//处理根

preOrder(root->leftchild);//处理左

preOrder(root->rightchild);//处理右

}

void inOrder(BTNode* root)//左根右

{

if (root == NULL)

return;

inOrder(root->leftchild);//处理左

printf("%c ", root->data);//处理根

inOrder(root->rightchild);//处理右

}

void postOrder(BTNode* root)

{

if (root == NULL)

return;

postOrder(root->leftchild);//处理左

postOrder(root->rightchild);//处理右

printf("%c ", root->data);//处理根

}

//二叉树的构建函数1(按图索骥)

BTNode* Create1()

{

BTNode* root = BuyNode('A');

root->leftchild = BuyNode('B');

root->rightchild = BuyNode('G');

root->leftchild->leftchild = BuyNode('C');

root->leftchild->rightchild = BuyNode('D');

root->rightchild->rightchild = BuyNode('H');

root->leftchild->rightchild->leftchild = BuyNode('E');

root->leftchild->rightchild->rightchild = BuyNode('F');

return root;

}

//购买新节点

BTNode* BuyNode(ElemType val)

{

BTNode* pnewnode = (BTNode*)malloc(sizeof(BTNode));

if (NULL == pnewnode)

exit(EXIT_FAILURE);

pnewnode->data = val;

pnewnode->leftchild = pnewnode->rightchild = NULL;

return pnewnode;

}

//前中后序遍历(非递归方式实现)

#include <stack>

using namespace std;

void preOrder_NoRecursion(BTNode* root)

{

//0.assert

if (root == NULL)

return;

//用一个栈(单栈法)

//1.申请一个栈,并将根节点入栈

std::stack<BTNode*> st;

st.push(root);

//2.进入while循环中,循环条件是栈不空即可

while (!st.empty())

{

//3.将此时栈顶节点取出,并将其值打印处理

BTNode* tmp = st.top();

st.pop();

printf("%c ", tmp->data);

//4.再将刚处理的节点的两个孩子按照先右再左的循

// 序进行判断,如果存在则压入栈中

if (tmp->rightchild != NULL)

st.push(tmp->rightchild);

if (tmp->leftchild != NULL)

st.push(tmp->leftchild);

}

//5.当while进不去,栈空的时候,此时整体遍历结束

}

void inOrder_NoRecursion(BTNode* root)

{

if (root == NULL)

return;

//要一个栈(单栈法)

//1.申请一个栈,并将根节点入栈,额外申请一个标签bool tag(用来表示栈顶

// 节点是不是第一次遇见)

std::stack<BTNode*> st;

st.push(root);

bool tag = true;

//2.进入while循环,循环条件是栈不空即可

while (!st.empty())

{

//3.需要对当前栈顶节点进行判定,如果该栈顶节点是第一次遇见,则说明

// 其"左"未被处理过,则先对其"左"半边处理一遍(处理一遍指的是将

// 其左半绺捋一边)

while (tag && st.top()->leftchild != NULL)

st.push(st.top()->leftchild);

//6.如果此时栈顶节点不是第一次遇见,则说明其左半边已经被处理过了,此时

// 是回退回来第二次遇见该节点,则其"左"相当于也处理完了,则此时也可以

// 将该节点取出打印

//4.当捋完之后,停下来,此时的栈顶节点一定左孩子为NULL,则此时相当于

// 其"左"已经处理了,此时可以将其取出打印(处理其"根")

BTNode* tmp = st.top();

st.pop();

printf("%c ", tmp->data);

//5.再对刚取出打印的节点的右孩子做判断是否存在,如果存在则压入栈中

//如果该节点有右孩子,则压入栈中,并将tag赋值为true

//如果该节点没有右孩子,则while重新进入后的栈顶节点一定是老东西,说

// 明其左半边已经被处理过了,则将tag赋值头false

if (tmp->rightchild != NULL)

{

st.push(tmp->rightchild);

tag = true;

}

else

tag = false;

}

//7.当while循环进不去,即栈为空时,则整体遍历结束

}

void postOrder_NoRecursion1(BTNode* root)

{

if (root == NULL)

return;

//1.申请一个栈,额外申请一个bool tag,再额外申请一个BTNode * preNode

std::stack<BTNode*> st;

bool tag = true;

BTNode* preNode = NULL;

//2.将根节点入栈,tag给true, preNode给NULL

st.push(root);

//3.进入while循环,循环条件是栈不空即可

while (!st.empty())

{

//4.此时栈顶节点不能立刻取出打印,而是先得对其"左"进行判定

//4.1如果当前tag为true,则说明栈顶节点是新节点(第一次遇见),则需要将其

// 左半绺捋一遍,当捋完时,则标志着当前最新栈顶节点的左孩子不存在,相当于

// 其"左"已经被处理完了,则接下来该处理其"右"了

while (tag && st.top()->leftchild!=NULL)

st.push(st.top()->leftchild);

//4.2如果当前tag为false,则说明栈顶节点是老节点(不是第一次遇见),则标志

// 着当前最新栈顶节点的左孩子存在但是已经被处理过了,则接下来该该处理

// 其"右"了

//5.此时栈顶节点处理其"右"的前提是先对其"右"做判定

//5.1如果当前栈顶节点的右孩子存在但是不等于preNode,则说明栈顶节点

// 的"右"还没有被处理过,则接下来将右孩子压入栈中(别忘了修改tag为真)

if (st.top()->rightchild != NULL && st.top()->rightchild != preNode)

{

st.push(st.top()->rightchild);

tag = true;

}

//5.2如果当前栈顶节点的右孩子不存在或者存在但是等于preNode,则说明栈顶

// 节点的"右"已经被处理过了,则接下来该处理栈顶节点的"根"

else

{

//6.左右都处理完之后,此时该处理栈顶节点的根,则此时可以将栈顶节点取出并打

// 印(别忘了修改tag为假,并且别忘了修改preNode为刚打印处理的节点)

BTNode* tmp = st.top();

st.pop();

printf("%c ", tmp->data);

tag = false;

preNode = tmp;

}

}

//7.当while循环结束,表示栈此时为空,也标志着整体遍历结束

}

void postOrder_NoRecursion2(BTNode* root)

{

if (root == NULL)

return;

//要两个栈:

//1.申请两个栈S1和S2 S1用来遍历全部的节点S2用来存储后序遍历结果

std::stack<BTNode*> S1, S2;

//2.将根节点入栈到S1

S1.push(root);

//3.进入while循环,循环条件为栈S1不空即可

while (!S1.empty())

{

//4.将S1的栈顶节点取出,放到S2里面去(此时先不打印处理)

BTNode* tmp = S1.top();

S1.pop();

S2.push(tmp);

//5.再对刚刚存储到S2里面的节点的两个孩子按照先左再右的顺序判断是否存

// 在,如果存在则压入栈S1

if (tmp->leftchild != NULL)

S1.push(tmp->leftchild);

if (tmp->rightchild != NULL)

S1.push(tmp->rightchild);

}

//6.当while循环结束,说明栈S1此时空了,也说明我们要的后序遍历结果刚好在

// S2里面存在,则对栈S2将值依次取出打印即可

while (!S2.empty())

{

printf("%c ", S2.top()->data);

S2.pop();

}

}

#include <queue>

//层序遍历

void Level_Traverse(BTNode* root)

{

if (root == NULL)

return;

//1.申请一个队列,并将根节点入队

std::queue<BTNode*> qu;

qu.push(root);

//2.进入while循环,循环条件是队列不空即可

while (!qu.empty())

{

//3.取出队头结点将其打印处理,然后将其两个孩子按照

// "先左再右"的顺序进行判定,如果存在则压入队列中

BTNode* tmp = qu.front();

qu.pop();

printf("%c ", tmp->data);

if (tmp->leftchild != NULL)

qu.push(tmp->leftchild);

if (tmp->rightchild != NULL)

qu.push(tmp->rightchild);

}

//4.当while循环进不去,也就是队列空的时候,整体遍历结束

}

void S_Level_Traverse(BTNode* root)//正S

{

if (root == NULL)

return;

//1.申请两个栈S1和S2, 分别用来描述奇数层和偶数层的运行规则

std::stack<BTNode*> S1, S2;

//2.将根节点入栈到S1里

S1.push(root);

//3.进入while循环,循环条件栈S1和栈S2只要有一个不空即可

while (!S1.empty() || !S2.empty())

{

//4.具体分辨是哪一个栈空了,哪一个栈没空

//5.如果是栈S1不空,栈S2空,则此时需要将栈S1里面的节点依次取出打印,并顺

// 带着将取出处理的每一个节点的两个孩子都按照"先右再左"的顺序进行判定,如

// 果存在则压入栈S2

while (!S1.empty())

{

BTNode* tmp = S1.top();

S1.pop();

printf("%c ", tmp->data);

if (tmp->rightchild != NULL)

S2.push(tmp->rightchild);

if (tmp->leftchild != NULL)

S2.push(tmp->leftchild);

}

//6.如果是栈S2不空,栈S1空,则此时需要将栈S2里面的节点依次取出打印,并顺

// 带着将取出处理的每一个节点的两个孩子都按照"先左再右"的顺序进行判定,如

// 果存在则压入栈S2

while (!S2.empty())

{

BTNode* tmp = S2.top();

S2.pop();

printf("%c ", tmp->data);

if (tmp->leftchild != NULL)

S1.push(tmp->leftchild);

if (tmp->rightchild != NULL)

S1.push(tmp->rightchild);

}

}

//7.当while循环进不去,则表示栈S1和栈S2都空了,也标志着整体遍历结束

}

void ReverseS_Level_Traverse(BTNode* root)//倒S

{

if (root == NULL)

return;

//1.申请两个栈S1和S2, 分别用来描述奇数层和偶数层的运行规则

std::stack<BTNode*> S1, S2;

//2.将根节点入栈到S1里

S1.push(root);

//3.进入while循环,循环条件栈S1和栈S2只要有一个不空即可

while (!S1.empty() || !S2.empty())

{

//4.具体分辨是哪一个栈空了,哪一个栈没空

//5.如果是栈S1不空,栈S2空,则此时需要将栈S1里面的节点依次取出打印,并顺

// 带着将取出处理的每一个节点的两个孩子都按照"先左再右"的顺序进行判定,如

// 果存在则压入栈S2

while (!S1.empty())

{

BTNode* tmp = S1.top();

S1.pop();

printf("%c ", tmp->data);

if (tmp->leftchild != NULL)

S2.push(tmp->leftchild);

if (tmp->rightchild != NULL)

S2.push(tmp->rightchild);

}

//6.如果是栈S2不空,栈S1空,则此时需要将栈S2里面的节点依次取出打印,并顺

// 带着将取出处理的每一个节点的两个孩子都按照"先右再左"的顺序进行判定,如

// 果存在则压入栈S2

while (!S2.empty())

{

BTNode* tmp = S2.top();

S2.pop();

printf("%c ", tmp->data);

if (tmp->rightchild != NULL)

S1.push(tmp->rightchild);

if (tmp->leftchild != NULL)

S1.push(tmp->leftchild);

}

}

//7.当while循环进不去,则表示栈S1和栈S2都空了,也标志着整体遍历结束

}

int main()

{

BTNode* root = Create1();

printf("前中后序遍历打印(递归版)\n");

preOrder(root); printf("\n");

inOrder(root); printf("\n");

postOrder(root); printf("\n");

printf("前中后序遍历打印(非递归版)\n");

preOrder_NoRecursion(root); printf("\n");

inOrder_NoRecursion(root); printf("\n");

postOrder_NoRecursion2(root); printf("\n");

postOrder_NoRecursion1(root); printf("\n");

printf("层序遍历打印(非递归版)\n");

Level_Traverse(root); printf("\n");

S_Level_Traverse(root); printf("\n");

ReverseS_Level_Traverse(root); printf("\n");

return 0;

}

相关推荐
CHHH_HHH2 小时前
【C++】哈希表原理与实战:从冲突解决到性能优化
开发语言·数据结构·c++·学习·算法·哈希算法·散列表
Irissgwe2 小时前
数据结构-排序
数据结构·算法·排序算法
青山木2 小时前
Hot 100 --- 滑动窗口最大值
java·数据结构·算法·leetcode·动态规划
青山木3 小时前
Hot 100 --- 除自身以外数组的乘积
java·数据结构·算法
彼岸星光ぐ>3 小时前
排序算法对比
数据结构·算法·排序算法
Y_Bk4 小时前
第十七届蓝桥杯C/C++A组省赛
c语言·数据结构·c++·算法·蓝桥杯
RH2312115 小时前
2026.5.24 数据结构 KMP算法实现
数据结构·算法
悠仁さん5 小时前
数据结构 图(概念篇)
数据结构
带土15 小时前
1. 数据结构简单复习回顾(线性结构)
数据结构