超级详细二叉树(包含EASYX画图)|数据结构

发布于 2021-07-10  22 次阅读


1、二叉树程序功能

前情提要 !!!

头文件:

#include<stdio.h>
#include<graphics.h>
#include<conio.h>
#include<stdlib.h>
#include<Windows.h>
#include<math.h>
#pragma comment(lib,"Winmm.lib")                                // 引用 Windows Multimedia API

结构体:

typedef char datatype;
typedef struct node
{
    datatype data;
    struct node* lchild, * rchild;
}bitree;

宏列表:

//宏列表
#define WIDTH 864                                                //界面宽度
#define HEIGTH 553                                                //界面高度
#define MAX 100                                                    //数组大小
#define MAXROW 100                                                //最大行数
#define MAXCOL 100                                                //最大列数
#define TOPMARGIN 50                                            //上边距
#define LEFTMARGIN 50                                            //左边距
#define ALLIMAGE 450                                            //图片最大张数
#define PATH 120                                                //路径大小
#define WIDTH_1    1280                                            //动画界面宽度
#define HEIGTH_1 590                                            //动画界面高度

函数列表:

//函数列表
void Animation(bitree* t);                                        //开头动画
void MainMenu();                                                //主菜单界面
void mainmenu();                                                //主菜单实现
void SubMenu();                                                    //子菜单界面
void submenu(bitree* t);                                        //子菜单实现
void Out(bitree* t);                                            //输出(前序 中序 后序)
void Preorder(bitree* t);                                        //前序遍历
void Inorder(bitree* t);                                        //中序遍历
void Lastorder(bitree* t);                                        //后序遍历
bitree* Create();                                                //前序建表
int Heigth(bitree* t);                                            //树的高度
void Change(bitree* t);                                            //交换左右子树
void Leaf(bitree* t);                                            //统计叶子数
bitree* Copytree(bitree* t);                                    //复制二叉树
void AllPath(bitree *t, char path[], int pathLength);            //所有路径
void LongestPath(bitree* t, char path[], int pathLength, char longestPath[]);//最长路径
//void gotoxy(int x, int y);                                    //光标定位
void Start();                                                    //初始数组
void Perfect();                                                    //标志函数
void Draw(bitree* t, int root_x, int root_y, int r_c_interval, char disp_buf[][MAXCOL]);//字符二叉树
void DrawEasyx(bitree* tree,int x,int y,int xFar,int yFar);        //easyx画二叉树
void PrintUITree(bitree* tree);                                    //画图
void Root_Leaf(bitree* t);                                        //根、叶结点
bitree* GetNode(bitree* t,char node);                            //查询结点
void Genealogy(bitree* t, bitree* treenode);                    //结点族谱
bitree *Parent(bitree* t, bitree* treenode);                    //双亲结点
int Ancestors(bitree* t, bitree* treenode);                        //祖先结点
void Children(bitree* treenode);                                //孩子结点
void Descendant(bitree* treenode);                                //子孙结点
bitree* Brother(bitree* t, bitree* treenode);                    //兄弟结点
int Floor(bitree* t, bitree* treenode,int height);                //结点层数

全局变量:

//全局变量列表
static int num = 0;                                                //叶子数
bitree* treeNode;                                                //树的结点
static int longestlength = 0;                                    //最长路径下标计数
char dispbuf[MAXROW][MAXCOL];                                    //存储二叉树结构图的数组
int effective_line;                                                //记录二叉树数组中的使用过的行数
const int UI_FAR_X = 220;
const int UI_FAR_Y = 20;

1.1主菜单功能:

在这里插入图片描述

1.前序创建二叉树

在函数中调用Create()则可以进行前序遍历创建二叉树

//前序建表
bitree* Create()
{
    bitree* t;
    char ch;
    ch = getchar();
    if (ch==' ')//空格
    {
        t = NULL;
    }
    else
    {
        t = (bitree*)malloc(sizeof(bitree));
        t->data = ch;
        t->lchild = Create();
        t->rchild = Create();
    }
    return t;
}

2.前中后序输出

//输出(前序 中序 后序)
void Out(bitree* t)
{
    printf("%c ", t->data);
}

//前序遍历
void Preorder(bitree* t)
{
    if (t)
    {
        Out(t);
        Preorder(t->lchild);
        Preorder(t->rchild);
    }
}

//中序遍历
void Inorder(bitree* t)
{
    if (t)
    {
        Inorder(t->lchild);
        Out(t);
        Inorder(t->rchild);
    }
}

//后序遍历
void Lastorder(bitree* t)
{
    if (t)
    {
        Lastorder(t->lchild);
        Lastorder(t->rchild);
        Out(t);
    }
}

3.统计叶子数

//统计叶子数(先序遍历)
void Leaf(bitree* t)
{
    if (t)
    {
        if (t->lchild == NULL && t->rchild == NULL)
        {
            num++;
            printf("%c ", t->data);
        }
        Leaf(t->lchild);
        Leaf(t->rchild);
    }
}

4.复制二叉树

//复制二叉树
bitree* Copytree(bitree* t)
{
    bitree *newtree;
    if (t == NULL)
    {
        return NULL;
    }
    else
    {
        //创建新节点
        newtree = (bitree*)malloc(sizeof(bitree));
        //复制节点内容
        newtree->data = t->data;
        //复制左子树
        newtree->lchild = Copytree(t->lchild);
        //复制右子树
        newtree->rchild = Copytree(t->rchild);
        //以上两行代码先创建左子树再创建右子树,如果顺序颠倒其创建的顺序就会颠倒,但是最终创建的二叉树还是一样的
        return newtree;
    }
}

5.交换左右子树

//交换左右子树
void Change(bitree* t)
{
    bitree* p;
    if (t)
    {
        p = t->lchild;
        t->lchild = t->rchild;
        t->rchild = p;
        Change(t->lchild);
        Change(t->rchild);
    }
}

6.计算二叉树高度

//树的高度
int Heigth(bitree* t)
{
    int m, n;
    if (t==NULL)
    {
        return 0;
    }
    else
    {
        m = Heigth(t->lchild);
        n = Heigth(t->rchild);
        return(m > n) ? m + 1 : n + 1;
    }
}

7.输出叶子结点到根结点所有路径

//所有路径(先序遍历)
void AllPath(bitree* t, char path[], int pathLength)
{
    int i;
    if (t)//当T是空节点,返回上一层,不做处理
    {
        if (t->lchild == NULL && t->rchild == NULL)//当T是叶子节点,先将T加入路径中,再输出路径
        {
            path[pathLength] = t->data;
            printf("%c叶子节点到根节点的路径为: ", t->data);
            for (i = pathLength; i >= 0; i--)
                printf("%c ", path[i]);
            printf("\n");
        }
        else//当T不是叶子节点也不是空节点的时候,将该节点加入路径中
        {
            path[pathLength++] = t->data;
            AllPath(t->lchild, path, pathLength);
            AllPath(t->rchild, path, pathLength);
            pathLength--;
        }
    }
}

8.输出叶子结点到根结点最长路径

//最长路径
void LongestPath(bitree* t, char path[], int pathLength, char longestPath[])
{
    if (t)
    {
        if (t->lchild == NULL && t->rchild == NULL)
        {
            path[pathLength] = t->data;
            if (pathLength > longestlength)
            {
                for (int i = pathLength; i >= 0; i--)
                {
                    longestPath[i] = path[i];
                }
                longestlength = pathLength;
            }
        }
        else
        {
            path[pathLength++] = t->data;
            LongestPath(t->lchild, path, pathLength, longestPath);
            LongestPath(t->rchild, path, pathLength, longestPath);
            pathLength--;
        }
    }
}

9.二叉树的所有关系

这里二叉树的所有关系指的是这棵树某个结点的一些关系或者是寻找整棵树的一些结点
功能都放到子菜单里

10.字符模式画二叉树

//初始数组(初始为空格)
void Start()
{
    int i, j;
    for (i = 0; i < MAXROW; i++)
    {
        for (j = 0; j < MAXCOL; j++)
            dispbuf[i][j] = ' ';
    }
}

//标志函数(每个要画出来的字符后都加上一个|标志,代表终止改行)
void Perfect()
{
    int i, j;
    for (i = 0; i < MAXROW; ++i)
    {
        j = MAXCOL - 1;
        while (dispbuf[i][j] == ' ' && j >= 0)
            --j;
        if (j > -1)
        {
            dispbuf[i][j + 1] = '|';
            ++effective_line;
            continue;
        }
        else
            break;
    }
}

//字符二叉树(二分法)
void Draw(bitree* t, int root_x, int root_y, int r_c_interval, char disp_buf[][MAXCOL])
{
    int left_child, right_child, y;
    if (t)
    {
        if (r_c_interval != 3)
        {
            r_c_interval /= 2;
            left_child = root_x - r_c_interval;
            right_child = root_x + r_c_interval;
        }
        else
        {
            left_child = root_x - 2;
            right_child = root_x + 2;
        }
        disp_buf[root_y][root_x] = t->data;
        if (t->lchild)
            disp_buf[root_y + 1][root_x - 1] = '/';
        if (t->rchild)
            disp_buf[root_y + 1][root_x + 1] = '\\';
        root_y += 2;
        Draw(t->lchild, left_child, root_y, r_c_interval, disp_buf);
        Draw(t->rchild, right_child, root_y, r_c_interval, disp_buf);
    }
}

11.easyx画二叉树

//easyx画二叉树
void DrawEasyx(bitree *tree, int x, int y, int xFar, int yFar)
{
    if (tree->lchild)
    {
        line(x, y, x - xFar, y + yFar);
        DrawEasyx(tree->lchild, x - xFar, y + yFar, xFar / 2, yFar * 1.2);
    }
    if (tree)
    {
        setfillcolor(BLUE);
        fillcircle(x, y, 10);
        TCHAR num[10];
        /*_stprintf_s(num, _T("%c"), tree->data);*/
        outtextxy(x - 5, y - 5, tree->data);
    }
    if (tree->rchild)
    {
        line(x, y, x + xFar, y + yFar);
        DrawEasyx(tree->rchild, x + xFar, y + yFar, xFar / 2, yFar * 1.2);
    }
}

//画图
void PrintUITree(bitree* tree)
{    
    DrawEasyx(tree, WIDTH / 2, 10, UI_FAR_X, UI_FAR_Y);
}

1.2子菜单功能:

在这里插入图片描述

1.根、叶节点

//根、叶节点
void Root_Leaf(bitree* t)
{
    printf("\n树中有以下叶子结点:");
    Leaf(t);//调用Leaf子函数来得出叶子节点
    if (t)
    {

        printf("\n树的根结点为:%c ", t->data);
    }
}

2.结点的双亲 祖先 孩子 子孙 兄弟

完成寻找结点的家人的思路:
1、先创建一个查询结点函数找到你现在要查询的结点,把找到的结点作为参数传给下面要用到的函数(族谱函数)
2、再创建一个族谱函数,用来调用双亲 祖先 孩子 子孙 兄弟 等五个子函数

//查询结点
bitree *GetNode(bitree* t,char node)//查找策略:优先左,如果是空树,返回NULL;如果查找的是根,直接返回根的地址,先去左子树中找,如果找到了,返回结果,如果左子树也没有找到,再去找右子树。
{
    if (t==NULL)//树为空树
    {
        return NULL;
    }
    if (t->data==node)//找到的条件
    {
        return t;
    }

    treeNode = GetNode(t->lchild, node);
    if (treeNode!=NULL)//在左子树中找到了
    {
        return treeNode;
    }

    treeNode = GetNode(t->rchild, node);
    if (treeNode!=NULL)//在右子树中找到了
    {
        return treeNode;
    }
    else//遍历整个树发现找不到
    {
        return NULL;
    }
}
//结点族谱 (结点的双亲 祖先 孩子 子孙 兄弟)
void Genealogy(bitree* t, bitree* treenode)
{
    bitree* parent;
    bitree* brother;
    //双亲结点
    if (treenode->data == t->data)
    {
        printf("%c无双亲结点\n", treenode->data);
    }
    else
    {
        parent = Parent(t, treenode);
        printf("%c的双亲结点是:%c\n", treenode->data, parent->data);
    }
    //祖先结点
    if (treenode->data==t->data)
    {
        printf("%c无祖先结点\n", treenode->data);
    }
    else
    {
        printf("%c的祖先结点有:", treenode->data);
        Ancestors(t, treenode);
        putchar('\n');
    }
    //孩子结点
    Children(treenode);
    //子孙结点
    Descendant(treenode);
    //兄弟结点
    brother=Brother(t,treenode);
    if (brother==NULL)
    {
        printf("%c无兄弟结点",treenode->data);
    }
    else
    {
        printf("%c的兄弟结点是:%c\n", treenode->data, brother->data);
    }
}
//双亲结点
bitree *Parent(bitree* t, bitree* treenode)
{
    bitree* ans;
    int x = 0;
    if (t == NULL)
        return NULL;
    if (t->lchild == NULL && t->rchild == NULL)
        return NULL;
    else
    {   //目的是找出左右孩子中是否是双亲的孩子
        /*if (t->lchild->data == treenode->data || t->rchild->data == treenode->data)
            return t;*/
        if (t->lchild == NULL && t->rchild != NULL)//左空,右孩子存在并且是双亲的孩子
        {
            if (t->rchild->data == treenode->data)
            {
                return t;
            }
            x++;
        }
        if (t->rchild == NULL && t->lchild != NULL)//右空,左孩子存在并且是双亲的孩子
        {
            if (t->lchild->data == treenode->data)
            {
                return t;
            }
            x++;
        }
        if (t->rchild && t->lchild)
        {
            if (t->lchild->data == treenode->data || t->rchild->data == treenode->data)
            {
                return t;
            }
            x++;
        }
        if (x==1)
        {
            ans = Parent(t->lchild, treenode);
            if (ans)
            {
                return ans;
            }
            ans = Parent(t->rchild, treenode);
            if (ans)
            {
                return ans;
            }
            return NULL;
        }
    }
}
//祖先结点
int Ancestors(bitree* t, bitree* treenode)
{
    int left, right;
    if (t==NULL)
    {
        return 0;
    }
    if (t->data == treenode->data)
    {
        return 1;
    }
    else
    {
        left = Ancestors(t->lchild, treenode);
        right = Ancestors(t->rchild, treenode);
        if (left + right > 0)
        {
            printf("%c ", t->data);
        }
        return (left+right);
    }
}
//孩子结点(连递归都不用)
void Children(bitree* treenode)
{
    if (treenode->lchild==NULL&& treenode->rchild==NULL)
    {
        printf("%c无孩子结点\n", treenode->data);
    }
    else
    {
        printf("%c的孩子结点有:", treenode->data);
        if (treenode->lchild)
        {
            printf("%c ", treenode->lchild->data);
        }
        if (treenode->rchild)
        {
            printf("%c ", treenode->rchild->data);
            putchar('\n');
        }
    }

}
//子孙结点(先序遍历)
void Descendant(bitree* treenode)
{
    if (treenode->lchild||treenode->rchild)
    {
        printf("%c的子孙结点有:",treenode->data);
        if (treenode->lchild)
        {
            Preorder(treenode->lchild);
        }
        if (treenode->rchild)
        {
            Preorder(treenode->rchild);
        }
        printf("\n");
    }
    else
    {
        printf("%c无子孙结点\n", treenode->data);
    }
}
//兄弟结点
bitree* Brother(bitree* t, bitree* treenode)
{
    bitree* ans;
    if (t == NULL)
        return NULL;
    if (t->lchild == NULL && t->rchild == NULL)
        return NULL;
    else
    {
        if (t->lchild->data == treenode->data)
        {
            if (t->rchild)
            {
                return t->rchild;
            }
            else
            {
                return NULL;
            }
        }
        if (t->rchild->data == treenode->data)
        {
            if (t->lchild)
            {
                return t->lchild;
            }
            else
            {
                return NULL;
            }
        }
        else
        {
            ans = Brother(t->lchild, treenode);
            if (ans)
                return ans;
            ans = Brother(t->rchild, treenode);
            if (ans)
                return ans;
            return NULL;
        }
    }
}

3.结点的层次

//结点层数
int Floor(bitree* t,bitree* treenode,int height)
{
    int l;
    if (t == NULL)
        return (0);
    else if (t->data == treenode->data)
        return (height);
    else
    {
        l = Floor(t->lchild, treenode, height + 1);
        if (l != 0)
            return (l);
        else
            return (Floor(t->rchild, treenode, height + 1));
    }
}

4.树的深度

实现方法与主菜单中二叉树的高度是一样的

//树的高度
int Heigth(bitree* t)
{
    int m, n;
    if (t==NULL)
    {
        return 0;
    }
    else
    {
        m = Heigth(t->lchild);
        n = Heigth(t->rchild);
        return(m > n) ? m + 1 : n + 1;
    }
}

5.以某个结点为根的子树的深度

利用先前写的查询结点函数
bitree GetNode(bitree t,char node)先找到你要查询的结点,再利用Height函数查询该结点为根的子树的深度

//查询结点
bitree *GetNode(bitree* t,char node)//查找策略:优先左,如果是空树,返回NULL;如果查找的是根,直接返回根的地址,先去左子树中找,如果找到了,返回结果,如果左子树也没有找到,再去找右子树。
{
    if (t==NULL)//树为空树
    {
        return NULL;
    }
    if (t->data==node)//找到的条件
    {
        return t;
    }

    treeNode = GetNode(t->lchild, node);
    if (treeNode!=NULL)//在左子树中找到了
    {
        return treeNode;
    }

    treeNode = GetNode(t->rchild, node);
    if (treeNode!=NULL)//在右子树中找到了
    {
        return treeNode;
    }
    else//遍历整个树发现找不到
    {
        return NULL;
    }
}
//树的高度
int Heigth(bitree* t)
{
    int m, n;
    if (t==NULL)
    {
        return 0;
    }
    else
    {
        m = Heigth(t->lchild);
        n = Heigth(t->rchild);
        return(m > n) ? m + 1 : n + 1;
    }
}

1.3其他以及下载

由于做的时候还搞了点花里胡哨的开头动画是kda的more,但是呢,跟二叉树无关就没放上来,所以呢可能上面有些多余的函数

全部源代码在这下载:超级详细二叉树.rar