#include <cstdio>
#include <cstdlib>
#include <stack>
#include <queue>
using namespace std;
//二叉树结点
typedef struct buildnode{
//数据
char data;
//左右孩子指针
struct buildnode *lchild, *rchild; //struct node*
}buildnode,*buildtree; //struct node ,struct node*
//测试用例:ABC##DE#G##F###
/*
A
/
B
/ \
C D
/ \
E F
\
G
*/
//按先序序列创建二叉树(实际是个二叉链表)
int creattree(buildtree *T) //函数传参,传地址
{
char data;
scanf("%c", &data);
//按先序次序输入二叉树中结点的值(一个字符),‘#’表示空树
if(data == '#')
{
*T = NULL; //*T 是原指针T
return 0;
}
else
{ //用*T表示出原指针T,原指针T是buildtree型
*T = (buildtree )malloc(sizeof(buildnode));
//生成根结点
(*T)->data = data;
//构造左子树
creattree(&(*T)->lchild);
//构造右子树
creattree(&(*T)->rchild);
}
return 0;
}
//输出
void visit(buildtree T)
{
if(T->data != '#')
printf("%c ", T->data);
}
/
//先序遍历
void preorder(buildtree T) //把原节点(结构)的内容全部复制了过来,而不是传过来一个地址
{ //这样即使修改了节点里的值,也不会修改原节点的值,而用引用&则可以解决这个问题
if(T != NULL) //若要修改传过来的节点里的内容则要传原节点的地址过来
{ //分析参考hello world中的二叉树分析
visit(T);
preorder(T->lchild);
preorder(T->rchild);
}
else
return ;
}
//中序遍历
void inorder(buildtree T)
{
if(T != NULL)
{
inorder(T->lchild);
visit(T);
inorder(T->rchild);
}
}
//后序遍历
void postorder(buildtree T)
{
if(T)
{
postorder(T->lchild);
postorder(T->rchild);
visit(T);
}
}
///
//用栈实现
//先序遍历:【思路】:访问T->data后,将T入栈,遍历左子树;
//遍历完左子树返回时,栈顶元素应为T,出栈,再先序遍历T的右子树。
void preorder2(buildtree T)
{
stack <buildtree> stack1;
//p是遍历指针
buildtree p = T;
//栈不空或者p不空时循环
while(p || !stack1.empty())
{
if(p != NULL)
{ //存入栈中
stack1.push(p);
//访问根节点
printf("%c ",p->data);
//遍历左子树
p = p->lchild;
}
else
{ //回到上一个节点
p = stack1.top();
//把这个节点推出去,等于这个节点与数脱节,然后继续遍历右子树
stack1.pop();
p = p->rchild;
}
}
}
/* 中序遍历
思路:T是要遍历树的根指针,中序遍历要求在遍历完左子树后,访问根,再遍历右子树。
先将T入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为T,出栈,访问T->data,再中序遍历T的右子树。
*/
void inorder2(buildtree T)
{
stack <buildtree> stack2;
buildtree p = T;
while(p || !stack2.empty())
{
if(p != NULL)
{
stack2.push(p);
p = p->lchild;
}
else
{
p = stack2.top();
printf("%c ",p->data);
stack2.pop();
p = p->rchild;
}
}
}
//后序遍历, 暂时没想到其他的方法
//【思路】:T是要遍历树的根指针,后序遍历要求
//在遍历完左右子树后,再访问根。需要判断根结点的左右子树是否均遍历过。
typedef struct BiTNodePost{
buildtree biTree;
char tag;
}BiTNodePost,*BiTreePost;
void postorder2(buildtree T){
stack<BiTreePost> stack3;
//p是遍历指针
buildtree p = T;
BiTreePost BT;
//栈不空或者p不空时循环
while(p != NULL || !stack3.empty()){
//遍历左子树
while(p != NULL){
BT = (BiTreePost)malloc(sizeof(BiTNodePost));
BT->biTree = p;
//访问过左子树
BT->tag = 'L';
stack3.push(BT);
p = p->lchild;
}
//左右子树访问完毕访问根节点
while(!stack3.empty() && (stack3.top())->tag == 'R'){
BT = stack3.top();
//退栈
stack3.pop();
printf("%c ",BT->biTree->data);
}
//遍历右子树
if(!stack3.empty()){
BT = stack3.top();
//访问过右子树
BT->tag = 'R';
p = BT->biTree;
p = p->rchild;
}
}//while
}
//
//层次遍历
//思路:按从顶向下,从左至右的顺序来逐层访问每个节点,层次遍历的过程中需要用队列。
void levelorder(buildtree T)
{
buildtree p = T;
queue <buildtree> que;
//根节点入队
que.push(p);
//队列不空循环
while(!que.empty())
{
//对头元素出队
p = que.front();
//访问p指向的结点
printf("%c ",p->data);
//退出队列
que.pop();
//左子树不空,将左子树入队
if(p->lchild)
{
que.push(p->lchild);
}
//右子树不空,将右子树入队
if(p->rchild)
{
que.push(p->rchild);
}
}
}
int main()
{
buildtree T =NULL; //struct node* T
creattree(&T);
//
//(重点)
//下面都是把根节点传过去,其实是把整个树复制过去了,
//如果数据量小则ok,若数据量大,则像造树一样吧根节点的地址传过去
printf("xianxu: \n");
preorder(T);
printf("\n");
printf("zhongxu:\n");
inorder(T);
printf("\n");
printf("houxu:\n");
postorder(T);
printf("\n/\n");
printf("xianxu: \n");
preorder2(T);
printf("\n");
printf("zhongxu:\n");
inorder2(T);
printf("\n");
printf("houxu:\n");
postorder2(T);
printf("\n");
printf("ceng ci:\n");
levelorder(T);
return 0;
}
二叉树 基本操作(最初版)
最新推荐文章于 2024-05-28 20:37:16 发布