数据结构C++语言版 -- 树和二叉树

本文介绍了大二学生在C++数据结构课程中,针对OpenJudge平台提交的部分代码进行回顾和分析,包括二叉树的创建、销毁、遍历及各种操作算法。通过实例展示了括号法创建二叉树、层次遍历等,并提供了交流讨论的平台。

大二学生的 C++数据结构 有部分Openjudge提交的代码没有删除

邮箱:liu_772021@yeah.net

欢迎交流讨论~

有用的话,点赞留言就可以表示感谢啦


//
//  main.cpp
//  Tree and BiTree
//
//  Created by Liu_77 on 2021/12/24.
//

#include <iostream>

using namespace std;

#define MAXSIZE 1000

typedef char ElemType;

//二叉树的链式存储结构结点声明
typedef struct tnode{
    ElemType data;
    tnode *lchild,*rchild;
}BTNode;

//二叉树的顺序存储结构的类型声明
typedef ElemType SqBinTree[MAXSIZE];
//为方便运算,通常将下标为0的位置空着,值为‘#’的结点为空结点
//对于一个下标为i的结点,如果有双亲,其双亲结点的下标为i/2;如果他有左孩子,下标为2i;如果有右孩子,下标为2i+1

//---------------------------括号法创建一个二叉树------------------------------
//算法中使用一个栈St[]保存有孩子结点的结点地址,这里直接采用数组St[]存放栈中元素
void CreateBTree(BTNode *&bt,char *str){
    BTNode *St[MAXSIZE],*p = NULL;
    //int型top变量做栈顶指针。
    int top = -1,k = 0,j = 0;
    char ch;
    //建立的二叉树初始为空
    bt = NULL;
    ch = str[j];
    //str未扫描完时,循环:
    while(ch != '\0'){
        switch(ch){
                //处理左孩子结点,标记值k设置为1,表示其后创建的结点讲作为这个结点的左孩子结点。
            case'(':
            {
                //将前面刚创建的双亲结点进栈;
                top++; St[top] = p; k = 1; break;
            }
                //处理右孩子结点,标记值k设置为2,表示其后创建的结点为右孩子结点
            case',':
            {
                k = 2; break;
            }
                //表示栈中结点的左右孩子结点处理完毕,退栈。
            case ')':
            {
                top--; break;
            }
                //其他情况,表示要创建一个结点,根据标记值k建立它与栈顶结点之间的联系。
            default:
            {
                //创建新二叉树结点
                p = (BTNode *)malloc(sizeof(BTNode));
                p->data = ch;
                p->lchild = p->rchild = NULL;
                //如果二叉树为空,p为跟结点。
                if(bt == NULL){
                    bt = p;
                }
                //二叉树不为空:
                else{
                    switch(k){
                            //k == 1,该结点是栈顶结点的左孩子
                        case 1:
                        {
                            St[top]->lchild = p;  break;
                        }
                            //k == 2,该结点是栈顶结点的右孩子
                        case 2:
                        {
                            St[top]->rchild = p; break;
                        }
                    }
                }
            }
        }
        //处理ch数组中下一位元素
        j++;
        ch = str[j];
    }
}

//销毁二叉树bt的运算算法
//递归模型如下:
//f(bt) = 不做任何事          当bt == NULL
//f(bt) = f(bt->lchild);f(bt->rchild);free(bt)      当 其他情况
void DestroyBTree(BTNode *&bt){
    //当bt == NULL
        //不做任何事情
    
    //当 其他情况
    if(bt != NULL){
        //1当前结点左右孩子结点递归调用;
        DestroyBTree(bt->lchild);
        DestroyBTree(bt->rchild);
        //2释放当前结点
        free(bt);
    }
}
//f(bt)---大问题,释放二叉树bt的全部结点空间;
//f(bt->lchild)和f(bt->rchild)---小问题,分别释放bt的左右子树的全部结点空间;

//求二叉树高度运算算法
//递归模型如下:
//f(bt) = 0          当bt == NULL
//f(bt) = MAX{f(bt->lchild),f(bt->rchild)} + 1       当 其他情况
int BTHeigh(BTNode *bt){
    int lchilddep,rchilddep;
    //空(子)树,返回0
    if(bt == NULL){
        return 0;
    }
    else{
        //求左子树的高度为lchilddep
        lchilddep = BTHeigh(bt->lchild);
        //求右子树的高度为rchilddep
        rchilddep = BTHeigh(bt->rchild);
        //返回当前最大高度 + 1作为当前结点子树的高度
        return (lchilddep > rchilddep) ? (lchilddep + 1) : (rchilddep + 1);
    }
}

//求二叉树结点个数
//递归模型如下:
//f(bt) = 0          当bt == NULL
//f(bt) = f(bt->lchild) + f(bt->rchild) + 1       当 其他情况
int NodeCount(BTNode *bt){
    int num1,num2;
    //当bt == NULL,空树时返回0
    if(bt == NULL){
        return 0;
    }
    
    //当 其他情况
    //当前结点左右孩子结点递归调用,返回左右孩子结点做跟结点的子树的全部结点数,再加上他们的双亲结点本身的1
    else{
        //求左子树结点个数
        num1 = NodeCount(bt->lchild);
        //求右子树结点个数
        num2 = NodeCount(bt->rchild);
        return (num1 + num2 + 1);
    }
}

//求二叉树叶子结点个数运算算法
//递归模型如下:
//f(bt) = 0          当bt == NULL
//f(bt) = 1          当bt == 叶子结点
//f(bt) = f(bt->lchild) + f(bt->rchild)       当 其他情况
int LeafCount(BTNode *bt){
    int num1,num2;
    //空树返回0
    if(bt == NULL){
        return 0;
    }
    //叶子结点,返回1
    else if(bt->lchild == NULL && bt->rchild == NULL){
        return 1;
    }
    //非空非叶子结点,返回左子树叶子结点数+右子树叶子结点数
    else{
        num1 = LeafCount(bt->lchild);
        num2 = LeafCount(bt->rchild);
        return (num1 + num2);
    }
}

//以括号表示法输出二叉树运算算法
//过程:先输出跟结点值;当存在左孩子或右孩子结点时输出‘(’,然后递归处理左子树;再输出‘,’,递归处理右子树,最后输出一个')'
void DispBTree(BTNode *bt){
    if(bt != NULL){
        printf("%c",bt->data);
        if(bt->lchild != NULL || bt->rchild != NULL){
            printf("(");
            DispBTree(bt->lchild);
            if(bt->rchild != NULL){
                printf(",");
            }
            DispBTree(bt->rchild);
            printf(")");
        }
    }
}

//----------------------------二叉树遍历------------------------------
//先序遍历
//若二叉树非空,则:
/*
 1)访问根结点
 2)先序遍历左子树;
 3)先序遍历右子树
 */
void PreOrder(BTNode *bt){
    if(bt != NULL){
        printf("%c ",bt->data);
        PreOrder(bt->lchild);
        PreOrder(bt->rchild);
    }
}

//中序遍历
//若二叉树非空,则:
/*
 1)中序遍历左子树
 2)访问根结点
 3)中序遍历右子树
 */
void InOrder(BTNode *bt){
    if(bt != NULL){
        InOrder(bt->lchild);
        printf("%d ",bt->data);
        InOrder(bt->rchild);
    }
}

//后序遍历
//若二叉树非空,则:
/*
 1)后序遍历左子树
 2)后序遍历右子树
 3)访问根结点
 */
void PostOrder(BTNode *bt){
    if(bt != NULL){
        PostOrder(bt->lchild);
        PostOrder(bt->rchild);
        printf("%d ",bt->data);
    }
}

//层次遍历算法
//按照从上向下,同一层从左向右的次序访问所有结点;采用一个【循环队列】qu实现
//实现:
/*
 1)先将跟结点进队;
 2)若队不空,出队一个结点p,访问它;
 3)若有左孩子,则左孩子结点进队;若有右孩子,右孩子结点进队
 4)重复1)2)3),直到队空为止
*/
//循环队列的实现:直接采用数组qu存放队中元素,另用两个int变量front和rear分别做对头指针和队尾指针;
void LevelPost(BTNode *bt){
    BTNode *p;
    //定义循环队列,存放二叉链结点指针
    BTNode *qu[MAXSIZE];
    //定义对头指针和队尾指针
    int front,rear;
    //置队列为空队列
    front = rear = 0;
    //跟结点指针进队
    rear++;
    qu[rear] = bt;
    //当队不空,循环
    while(front != rear){
        //出队结点p;
        front = (front + 1) % MAXSIZE;
        p = qu[rear];
        //访问该结点
        printf("%c ",p->data);
        //如果有左孩子,进队
        if(p->lchild != NULL){
            rear = (rear + 1) % MAXSIZE;
            qu[rear] = p->lchild;
        }
        //如果有右孩子,进队
        if(p->lchild != NULL){
            rear = (rear + 1) % MAXSIZE;
            qu[rear] = p->rchild;
        }
    }
}

//-----------------遍历算法的应用----------------------
//1-求单分枝结点个数
//采用后序遍历方式求解,先求左子树中单分支结点个数m,再求出右子树中单分支结点个数n;若跟结点为单位直接点,返回m+n+1;否则返回m+n;
int onenodes1(BTNode *bt){
    int m,n;
    if(bt != NULL){
        m = onenodes1(bt->lchild);
        n = onenodes1(bt->rchild);
        //单分枝结点情况
        if((bt->lchild == NULL && bt->rchild != NULL) || (bt->lchild != NULL && bt->rchild == NULL)){
            return (1 + m + n);
        }
        else return (m + n);
    }
    else return 0;
}
//直接采用递归方法:
//递归模型如下:
//f(bt) = 0          当bt == NULL
//f(bt) = 1          当bt == 单分支结点
//f(bt) = f(bt->lchild) + f(bt->rchild)       当 其他情况
int onenodes2(BTNode *bt){
    int m,n;
    //空树返回0
    if(bt == NULL){
        return 0;
    }
    m = onenodes2(bt->lchild);
    n = onenodes2(bt->rchild);
    //单分支结点
    if((bt->lchild == NULL && bt->rchild != NULL) || (bt->lchild != NULL && bt->rchild == NULL)){
        return (1 + m + n);
    }
    //其他情况
    else return m+n;
}

//2-求双分支结点数
//直接采用递归方法:
//递归模型如下:
//f(bt) = 0          当bt == NULL
//f(bt) = 1          当bt == 双分支结点
//f(bt) = f(bt->lchild) + f(bt->rchild)       当 其他情况
int twonodes(BTNode *bt){
    int m,n;
    //空树返回0
    if(bt == NULL){
        return 0;
    }
    m = twonodes(bt->lchild);
    n = twonodes(bt->rchild);
    //双分支结点
    if(bt->lchild != NULL && bt->rchild != NULL){
        return (1 + m + n);
    }
    //其他情况
    else return m+n;
}

//设计算法复制一棵二叉树
//递归模型如下:
//f(bt) :nt = NULL                 当bt == NULL
//f(bt) :由bt根结点复制产生nt根结点;   当bt != NULL
//       f(bt->lchild,nt->lchild)
//       f(bt->rchild,nt->rchild)
void CopyBTree(BTNode *bt,BTNode *&newt){
    if(bt != NULL){
        newt = (BTNode *)malloc(sizeof(BTNode));
        newt->data = bt->data;
        CopyBTree(bt->lchild, newt->lchild);
        CopyBTree(bt->rchild, newt->rchild);
    }
    else newt = NULL;
}

//设计算法,由给定的二叉树的二叉链存储结构建立其对应的顺序存储结构
//递归模型如下:
//f(bt,sb,i) :sb[i] = '#'                   当bt == NULL
//f(bt,sb,i) :sb[i] = bt->data              其他情况
//            f(bt->lchild,sb,2*i)
//            f(bt->rchild,sb,2*i+1)
void trans1(BTNode *bt,SqBinTree &sb,int i){
    //i的初值为根结点编号【1】
    if(bt != NULL){
        sb[i] = bt->data;
        trans1(bt->lchild,sb,2*i);
        trans1(bt->rchild,sb,2*i+1);
    }
    else sb[i] = '#';
}

//设计一个算法,有给定的二叉树顺序存储结构建立其对应的二叉链存储结构
void trans2(BTNode *&bt,SqBinTree sb,int i){
    //i的初值为根结点编号【1】
    if(i < MAXSIZE && sb[i] != '#'){
        bt = (BTNode *)malloc(sizeof(BTNode));
        bt->data = sb[i];
        //递归建立左子树、右子树
        trans2(bt->lchild,sb,2*i);
        trans2(bt->rchild,sb,2*i+1);
    }
    else bt = NULL;
}

//设计算法,输出每一个叶子结点的所有祖先结点
void ancestor1(BTNode *bt,ElemType path[],int pathlen){
    int i;
    if(bt != NULL){
        //bt为叶子结点:
        if(bt->lchild == NULL && bt->rchild == NULL){
            printf("  %c结点的所有祖先结点: ",bt->data);
            for(i = pathlen - 1;i >= 0;i--){
                printf("%c ",path[i]);
            }
            printf("\n");
        }
        else{
            //将当前结点放在路径中
            path[pathlen] = bt->data;
            //path中元素个数增加1
            pathlen++;
            //递归扫描左右子树
            ancestor1(bt->lchild,path,pathlen);
            ancestor1(bt->rchild,path,pathlen);
        }
    }
}
//采用层次遍历求解
void ancestor2(BTNode *bt){
    BTNode *p;
    int i;
    //qu存放队中元素
    struct{
        //存放结点指针
        BTNode *s;
        //存放起双亲结点在qu中的下标
        int parent;
    }qu[MAXSIZE];
    int front = -1,rear = -1;
    //根结点进队;它没有双亲,其parent置为-1
    rear++;
    qu[rear].s = bt;
    qu[rear].parent = -1;
    while(front != rear){
        //出队结点p,它在qu中的下标为front
        front++;
        p = qu[front].s;
        //若p为叶子结点
        if(p->lchild != NULL && p->rchild != NULL){
            printf("  %c结点的所有祖先结点:",p->data);
            i = qu[front].parent;
            while(i != -1){
                printf("%c ",qu[i].s->data);
                i = qu[i].parent;
            }
            printf("\n");
        }
        //p有左孩子,将左孩子进队
        if(p->lchild != NULL){
            rear++;
            qu[rear].s = p->lchild;
            //双亲为front结点
            qu[rear].parent = front;
        }
        if(p->rchild != NULL){
            rear++;
            qu[rear].s = p->rchild;
            qu[rear].parent = front;
        }
    }
}

int main(){
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值