二叉树 基本操作(最初版)


#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值