数据结构实验:树和二叉树(附c++源码:实现树有关算法)

news2024/11/16 10:51:40

目录

一、实验目的

二、问题分析及数据结构设计

三、算法设计(伪代码表示)

1. 输入字符序列 创建二叉链表

2. 递归前序遍历

3. 递归中序遍历

4. 递归后序遍历

5. 非递归前序遍历

6. 非递归中序遍历

7. 非递归后序遍历

8. 层次遍历

9. 求二叉树的高度

10. 求二叉树的结点数

11. 求二叉树的叶子数

12. 交换左右子树

四、功能模块程序流程图

1. 功能选择菜单

2. 输入字符序列 创建二叉链表

3. 先序遍历-递归法

4. 中序遍历-递归法

5. 后序遍历-递归法

6. 先序遍历-非递归法

7. 中序遍历-非递归法

8. 后序遍历-非递归法

9. 层次遍历

11. 求二叉树的结点数

12. 求二叉树的叶子数

13. 交换二叉树每个结点的左子树和右子树

五、实验结果

1. 菜单功能

2. 建立二叉链表:

3. 先序遍历-递归算法:

4. 先序遍历-非递归算法:

5. 中序遍历-递归算法:

6. 中序遍历-非递归算法:

7. 后序遍历-递归算法:

8. 后序遍历-非递归算法:

9. 层次遍历:

10. 求二叉树的高度:

11. 求二叉树的结点数:

12. 求二叉树的叶子数:

13. 交换二叉树每个结点的左右子树:

六、算法分析

七、操作说明

八、源码


实验内容

1.编写函数,输入字符序列,建立二叉树的二叉链表。

2.编写函数,实现二叉树的中序递归遍历算法。(最好也能实现前缀和后缀遍历算法)

3.编写函数,实现二叉树的中序非递归遍历算法。

4.编写函数,借助队列实现二叉树的层次遍历算法。

5.编写函数,求二叉树的高度。

6.编写函数,求二叉树的结点个数。

7.编写函数,求二叉树的叶子个数。

8.编写函数,交换二叉树每个结点的左子树和右子树。

9.编写一个主函数,在主函数中设计一个简单的菜单,分别调试上述算法。


一、实验目的

掌握二叉树的基础知识,掌握二叉树的链表存储,遍历的递归与非递归算法,层次遍历、计算结点数、叶子数等二叉树有关算法的代码实现。理解递归算法的执行步骤,学会字符类型数据在输入时的处理,理解如何利用栈结构实现非递归算法。


二、问题分析及数据结构设计

  1. 问题分析:需要输入字符序列,建立二叉树的二叉链表。实现二叉树的中序递归及非递归遍历算法。借助队列实现二叉树的层次遍历算法。求二叉树的高度、结点个数、叶子个数。交换二叉树每个结点的左子树和右子树。需要我们思考如何用字符序列来表示一棵树,理解二叉树遍历的递归及非递归思想,判断是叶子还是结点,如有孩子的是结点,左右都无孩子的就是叶子。需要我们知道队列的相关知识,实现用队列的方法进行层次遍历。
  2. 数据结构设计:二叉链表结点类型-char字符型。树的定义:树-BiTNode,数据data-char字符型,左子树-指针BiTNode * lchild,右子树-指针BiTNode * rchild。队列的定义:队列-Quene,头指针front-int整型,尾指针rear-int整型。树的高度Hight-int整型,左子树的高度hL-int整型,右子树的高度hR-int整型。叶子数count-int整型,结点数count-int整型。用户输入选择要进行的算法序号num-int整型。

三、算法设计(伪代码表示)

1. 输入字符序列 创建二叉链表

Function createNode(BiTree & T)

Begin

输入字符

IF 字符 = ’#’

树为空

ELSE

分配BiTree大小的内存空间给T

T->data = e

递归createNode(T的左子树)

递归createNode(T的右子树)

End

2. 递归前序遍历

Function preOrder(BiTree root)

Begin

IF 树的根!=空

打印根的data

递归preOrder(根的左子树)

递归preOrder(根的右子树)

End

3. 递归中序遍历

Function midOrder(BiTree root)

Begin

IF 树的根!=空

递归midOrder(根的左子树)

打印根的data

递归midOrder(根的右子树)

End

4. 递归后序遍历

Function lastOrder(BiTree root)

Begin

IF 树的根!=空

递归preOrder(根的左子树)

递归preOrder(根的右子树)

打印根的data

End

5. 非递归前序遍历

Function lastOrderByStack(BiTree root)

Begin

IF 树的根==空

retutn

ELSE

定义栈stack

栈顶标记stackTop = -1

移动指针pMove = 树的根

WHILE 树根 != NULL || 栈顶 != -1

WHILE 树根 != NULL

打印当前结点pMove

栈顶标志++

pMove结点入栈

结点 = 结点->左子树

IF 栈顶 != -1

pMove = 栈顶

栈顶标志--

结点 = 结点->右子树

End

6. 非递归中序遍历

Function midOrderByStack(BiTree root)

Begin

IF 根 == NULL

return

建立栈stack

初始化结点指针pMove = 根root

WHILE 结点 != NULL || 栈顶 != -1

WHILE 结点 != NULL

栈顶标志++

结点入栈

结点 = 结点->左子树

IF 栈顶 != -1

结点 = 栈顶元素

栈顶标志--

打印结点

结点 = 结点->右子树

End

7. 非递归后序遍历

Function lastOrderByStack(BiTree root)

Begin

IF 根 == NULL

return

建立栈stack

初始化结点指针pMove = 根root

WHILE 结点 != NULL

栈顶标志++

结点入栈

结点 = 结点->左子树

WHILE 栈顶 != -1

结点 = 栈顶元素

栈顶标志--

IF 结点->左子树 == NULL || 结点->右子树 被访问过

打印结点

标记结点被访问

ELSE

栈顶标志++

栈顶 = 根结点

结点 = 结点->右子树

WHILE 结点 != NULL

栈顶标志++

结点入栈

结点 = 结点->左子树

End

8. 层次遍历

Function levelOrder(BiTree T)

Begin

定义队列q

初始化队列

IF 根!=NULL

结点入队列

WHILE 队!=NULL

节点出队

cout结点->data

IF 节点->左子树!=NULL

节点->左子树入队

IF 节点->右子树!=NULL

节点->右子树入队

End

9. 求二叉树的高度

Function int treeHeight(BiTree T)

Begin

IF 树根 == NULL

retutn 0

ELSE

左子树高度 = treeHeight(结点->左子树)

右子树高度 = treeHeight(结点->左右子树)

IF 左子树高度 > 右子树高度

return 左子树高度 + 1

ELSE

return 右子树高度 + 1

End

10. 求二叉树的结点数

Function int nodeCount(BiTree T)

Begin

IF 树根 == NULL

return 0

ELSE IF 结点->左子树 != NULL || 结点->右子树 != NULL

结点数++

nodeCount(结点->左子树)

nodeCount(结点->右子树)

return 结点数

End

11. 求二叉树的叶子数

Function int leafCount(BiTree T)

Begin

IF 树根 == NULL

return 0

ELSE IF 结点->左子树 == NULL && 结点->右子树 == NULL

结点数++

leafCount(结点->左子树)

leafCount(结点->右子树)

return 叶子数

End

12. 交换左右子树

Function swap(BiTree T)

Begin

IF 树根 != NULL

temp = 结点->左子树

结点->左子树 = 结点->右子树

结点->右子树 = temp

swap(结点->左子树)

swap(结点->右子树)

End


四、功能模块程序流程图

1. 功能选择菜单

   

说明:菜单功能首先提示用户输入数字。输入数字1,提示用户输入二叉树的每个结点值,以此建立二叉链表;输入数字2,提示输出的结果为“先序遍历二叉树-递归”;输入数字3,提示输出的结果为“先序遍历二叉树-非递归”;输入数字4,提示输出的结果为“中序遍历二叉树-递归”;输入数字5,提示输出的结果为“中序遍历二叉树-非递归”;输入数字6,提示输出的结果为“后序遍历二叉树-递归”;输入数字7,提示输出的结果为“后序遍历二叉树-非递归”;输入数字8,提示输出的结果为“层次遍历”;输入数字9,提示输出的结果为“二叉树的高度”;输入数字10,提示输出的结果为“二叉树的结点数”;输入数字11,提示输出的结果为“二叉树的叶子数”;输入数字12,完成交换二叉树的每个结点的左子树和右子树,提示用户“交换成功!可以通过选择遍历方法来查看交换后的遍历结果”;输入数字13,系统退出,提示用户“退出成功!”;

2. 输入字符序列 创建二叉链表

说明:该函数目的为建立二叉链表,提醒用户输入二叉树的每个结点的序列,如“AB#D##C##”,即可生成一个以链表为存储结构的二叉树,之后可以通过遍历方法来查看二叉树的构造结果。

3. 先序遍历-递归法

说明:该函数为实现二叉树的递归法的先序遍历功能,返回值为二叉树的前序遍历结果,传入根节点开始调用即可输出二叉树的先序遍历结果。

4. 中序遍历-递归法

说明:该函数为实现二叉树的递归法的中序遍历功能,返回值为二叉树的中序遍历结果,传入根节点开始调用即可输出二叉树的中序遍历结果。

5. 后序遍历-递归法

说明:该函数为实现二叉树的递归法的后序遍历功能,返回值为二叉树的后序遍历结果,传入根节点开始调用即可输出二叉树的后序遍历结果。

6. 先序遍历-非递归法

说明:该函数为实现二叉树的非递归法的先序遍历功能,返回值为二叉树的前序遍历结果,传入根节点开始调用即可输出二叉树的先序遍历结果,与递归法的先序遍历结果一样。

7. 中序遍历-非递归法

说明:该函数为实现二叉树的非递归法的中序遍历功能,返回值为二叉树的中序遍历结果,传入根节点开始调用即可输出二叉树的中序遍历结果,与递归法的中序遍历结果一样。

8. 后序遍历-非递归法

说明:该函数为实现二叉树的非递归法的后序遍历功能,返回值为二叉树的后序遍历结果,传入根节点开始调用即可输出二叉树的后序遍历结果,与递归法的后序遍历结果一样。

9. 层次遍历

说明:该函数为实现二叉树的层次遍历功能,返回值为二叉树的层次遍历结果,传入根节点开始调用即可输出二叉树的层次遍历结果。

10. 求二叉树的高度

说明:该函数为实现求二叉树的高度功能,返回值为二叉树的高度,传入根节点开始调用即可输出二叉树的高度。

11. 求二叉树的结点数

说明:该函数为实现求二叉树的结点数功能,返回值为二叉树的结点数,传入根节点开始调用即可输出二叉树的结点数。

12. 求二叉树的叶子数

说明:该函数为实现求二叉树的叶子数功能,返回值为二叉树的叶子数,传入根节点开始调用即可输出二叉树的叶子数。

13. 交换二叉树每个结点的左子树和右子树

说明:该函数为实现交换二叉树的每个结点的左子树与右子树的功能,传入已有的二叉链表的二叉树的根节点开始调用,即可交换二叉树的每个结点的左子树和右子树,交换成功后,用户通过调用遍历方法即可查看交换完成后的二叉树的遍历结果。

14. 退出

说明:该功能为退出系统功能,调用后即可退出系统,并得到提示“退出成功!”。


五、实验结果

1. 菜单功能

分析:该菜单通过序号1-13来实现不同的有关二叉树的功能,通过提示用户“请输入您要选择的计算”,来引导用户输入1-13的数字来获取想要的结果。

2. 建立二叉链表:

分析:输入数字1后进入该输入字符序列,建立二叉链表的功能。首先提示用户输入二叉树各结点的值,例如AB#D##C##,来建立二叉树,接着继续提示用户选择想要的计算。用户可以通过选择遍历算法来查看二叉树的建立结果。

3. 先序遍历-递归算法:

分析:输入数字2后进入该先序遍历-递归算法的功能,提示先序遍历二叉树-递归的结果为什么,接着提示用户继续选择想要实现的运算。该结果应该与先序遍历-非递归算法的输出结果一致。

4. 先序遍历-非递归算法:

分析:输入数字3后进入该先序遍历-非递归算法的功能,提示先序遍历二叉树-非递归的结果为什么,接着提示用户继续选择想要实现的运算。经结果检验,该结果确实与先序遍历-递归算法的输出结果一致。

5. 中序遍历-递归算法:

分析:输入数字4后进入该中序遍历-递归算法的功能,提示中序遍历二叉树-递归的结果为什么,接着提示用户继续选择想要实现的运算。该结果应该与中序遍历-非递归算法的输出结果一致。

6. 中序遍历-非递归算法:

分析:输入数字5后进入该中序遍历-非递归算法的功能,提示中序遍历二叉树-非递归的结果为什么,接着提示用户继续选择想要实现的运算。经结果检验,该结果确实与中序遍历-非递归算法的输出结果一致。

7. 后序遍历-递归算法:

分析:输入数字6后进入该后序遍历-递归算法的功能,提示后序遍历二叉树-递归的结果为什么,接着提示用户继续选择想要实现的运算。该结果应该与后序遍历-非递归算法的输出结果一致。

8. 后序遍历-非递归算法:

分析:输入数字7后进入该后序遍历-非递归算法的功能,提示后序遍历二叉树-非递归的结果为什么,接着提示用户继续选择想要实现的运算。经结果检验,该结果确实与后序遍历-递归算法的输出结果一致。

9. 层次遍历:

分析:输入数字8后进入该通过队列实现层次遍历的功能,提示层次遍历二叉树的结果为什么,接着提示用户继续选择想要实现的运算。

10. 求二叉树的高度:

分析:输入数字9后进入该通过队列实现求二叉树的高度的功能,提示二叉树的高度的结果为什么,接着提示用户继续选择想要实现的运算。

11. 求二叉树的结点数:

分析:输入数字10后进入该通过队列实现求二叉树的结点数的功能,提示二叉树的结点数的结果为什么,接着提示用户继续选择想要实现的运算。

12. 求二叉树的叶子数:

分析:输入数字11后进入该通过队列实现求二叉树的叶子数的功能,提示二叉树的叶子数的结果为什么,接着提示用户继续选择想要实现的运算。

13. 交换二叉树每个结点的左右子树:

分析:输入数字12后进入该交换二叉树的每个结点的左右子树的功能,提示用户交换成功,接着提示用户可以继续选择遍历算法来查看二叉树交换左右子树后的遍历结果。

分析:交换成功后,通过调用先序,中序,后序遍历的结果来看,遍历结果已经改变,结果正是原子树AB#D##C##将各结点左右子树交换后所得到的遍历结果。

14. 退出:

分析:输入数字13后进入该退出系统的功能,提示用户退出成功。退出成功后,不会再出现提示用户继续输入想要选择的运算。


六、算法分析

1. 遍历的递归算法:前序,中序,后序的算法都是通过递归调用传入左子树及右子树调用自身来实现,根据前、中、后来决定打印根结点的时机。

2. 遍历的非递归算法:核心是通过栈的运用来实现。前序思想是从根结点开始找到最左下角的结点,若结点不为空,则将这期间走过的结点入栈,将当前指针变为当前结点的左子树,重复上述操作,以此找到最左下角的结点。当左边的结点都找完则开始找右边,若栈顶不为空,则结点为栈顶元素,栈顶元素出栈,将当前指针变为当前结点的右子树,重复上述操作。

中序思想与前序思想大致相同,差别在于前序是在每次找最左结点时即打印根结点的元素,而中序是在找右结点时打印根结点的元素。

后序核心是要设立一个结点是否已经被访问过的标志。首先找到最左边的结点,不断将结点入栈,再将指针变为当前结点的左子树,重复上述操作。找到最左下角的结点后即开始回退,遇到根就判断根的左右是否被访问过或为空,若右子树已经被访问了或为空,则打印该右结点。若右结点存在且未被访问过,则重复找到最左边的结点的操作。继续进入循环。

3. 层次遍历:思想是把结点依次入队列再出列,输出该节点。判断该节点是否有孩子,若有,先将左孩子递归调用层次遍历的函数,重复入队出队、判断是否有孩子的操作。再将右孩子递归调用层次遍历的函数,重复入队出队、判断是否有孩子的操作。

4. 求二叉树的高度:思想是传入树的根结点,用该结点的左子树和右子树递归调用求高度的方法,从最下面开始依次向上输出左子树和右子树的高度,并返回左高与右高之间的较大者,将最后返回的结果再加1(即加上根结点的高度),即得到树的真正高度。

5. 求二叉树的结点数及叶子数:求结点数的思想是判断结点是否有左孩子或有右孩子,若满足其实一个,则令结点数++。求叶子数则是判断结点是否无左孩子且无右孩子,若满足则令叶子数++。

6. 交换左右子树:思想是通过临时变量temp来交换节点的左右子树,再利用结点的左右子树,递归调用该交换方法。


七、操作说明

编译后先出现一个菜单,1-13有文字信息描述二叉树的相关算法,提示用户输入1-13之间的数字。

输入数字1,提示用户输入二叉树的每个结点值,以此建立二叉链表;

输入数字2,提示输出的结果为“先序遍历二叉树-递归”;

输入数字3,提示输出的结果为“先序遍历二叉树-非递归”;

输入数字4,提示输出的结果为“中序遍历二叉树-递归”;

输入数字5,提示输出的结果为“中序遍历二叉树-非递归”;

输入数字6,提示输出的结果为“后序遍历二叉树-递归”;

输入数字7,提示输出的结果为“后序遍历二叉树-非递归”;

输入数字8,提示输出的结果为“层次遍历”;

输入数字9,提示输出的结果为“二叉树的高度”;

输入数字10,提示输出的结果为“二叉树的结点数”;

输入数字11,提示输出的结果为“二叉树的叶子数”;

输入数字12,完成交换二叉树的每个结点的左子树和右子树,提示用户“交换成功!可以通过选择遍历方法来查看交换后的遍历结果”;

输入数字13,系统退出,提示用户“退出成功!”;


八、源码

#include <iostream>
#include <string>
#include <stack>
using namespace std;

#define ElemType char // 二叉链表结点类型

#define MAX_SIZE 128

// 定义树
typedef  struct  BiTNode {
	ElemType  data;
	struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;

// 建立二叉链表
void createNode(BiTree& T)
{
    ElemType e;
    cin >> e;

    if (e == '#') {
        T = NULL;
    }
    else {
        T = (BiTree)malloc(sizeof(BiTNode));
        T->data = e;
        createNode(T->lchild);
        createNode(T->rchild);
    }
}

// 打印节点中的数据
void printNodeData(BiTree Node) {
    cout << Node->data;
}

// 递归法遍历

// 1. 前序
void preOrder(BiTree root) {
    if (root != NULL) {
        printNodeData(root);    // 打印根
        preOrder(root->lchild); // 递归左子树
        preOrder(root->rchild); // 递归右子树
    }
}

// 2. 中序
void midOrder(BiTree root) {
    if (root != NULL) {
        midOrder(root->lchild); // 递归左子树
        printNodeData(root);    // 打印根
        midOrder(root->rchild); // 递归右子树
    }
}

// 3. 后序
void lastOrder(BiTree root) {
    if (root != NULL) {
        lastOrder(root->lchild); // 递归左子树
        lastOrder(root->rchild); // 递归右子树
        printNodeData(root);    // 打印根
    }
}

// 非递归法

// 1. 前序
void preOrderByStack(BiTree root) {
    if (root == NULL) {
        return;
    }

    // 定义栈
    BiTree stack[10]; // 存储每次打印节点的位置
    int stackTop = -1; // 栈顶标记
    BiTree pMove = root; // 移动指针代表当前节点 从root开始

    while (stackTop != -1 || pMove != NULL) { // 栈不为空或当前节点不为空

        // 从根开始找到最左边
        while (pMove) { // 如果当前节点不为空
            printNodeData(pMove); // 打印当前节点
            stackTop++;
            stack[stackTop] = pMove; // 走过的节点入栈
            pMove = pMove->lchild; // 当前指针变为左子节点 继续上述操作
        }

        // 上面的左边操作找完 找右边
        if (stackTop != -1) {
            pMove = stack[stackTop]; // 获取栈顶元素
            stackTop--; // 栈顶元素出栈
            pMove = pMove->rchild; // 当前指针变为右子节点 继续上述操作
        }
    }
}

// 2. 中序
void midOrderByStack(BiTree root) {
    if (root == NULL) {
        return;
    }

    BiTree stack[10];
    int stackTop = -1;
    BiTree pMove = root;

    while (stackTop != -1 || pMove != NULL) {
        // 找到最左边
        while (pMove) {
            stackTop++;
            stack[stackTop] = pMove;
            pMove = pMove->lchild;
        }

        // 左边找完
        if (stackTop != -1) {
            pMove = stack[stackTop];
            stackTop--;
            printNodeData(pMove);
            pMove = pMove->rchild;
        }
    }
}

// 3. 后序
void lastOrderByStack(BiTree root) {
    if (root == NULL) {
        return;
    }

    BiTree stack[10];
    int stackTop = -1;
    BiTree pMove = root;
    BiTree isVist = NULL; // 判断是否被访问过的标志

    // 找到最左边
    while (pMove) {
        stackTop++;
        stack[stackTop] = pMove;
        pMove = pMove->lchild;
    }

    // 回退 遇到根先判断根的左右是否被访问过或为空
    while (stackTop != -1) {
        pMove = stack[stackTop];
        stackTop--;

        // 已经走到最左边 所以不可能再有左边 只用判断右边

        // 右节点为空或已经被访问
        if (pMove->rchild == NULL || pMove->rchild == isVist) {
            printNodeData(pMove); // 打印当前节点
            isVist = pMove; // 改变标志位置
        }
        else { //右节点没被访问过
            stackTop++;
            stack[stackTop] = pMove; // 回退的当前节点的根节点
            pMove = pMove->rchild; // 找到根节点的右节点
            while (pMove) { // 重复找到最左边的操作
                stack[++stackTop] = pMove;
                pMove = pMove->lchild;
            }
        }
    }
}

// 定义顺序队
typedef struct Quene {      
    int front;          // 队头指针
    int rear;           // 队尾指针
    BiTree data[MAX_SIZE]; // 存放队中元素
}SqQueue;

// 初始化队列
void initQueue(SqQueue** q) {
    if (!((*q) = (SqQueue*)malloc(sizeof(SqQueue)))) {
        cout << ("内存分配失败!");
        exit(-1);
    }
    (*q)->front = (*q)->rear = -1; // 置 -1
}

// 判断队列是否为空
bool emptyQueue(SqQueue* q) {

    // 首指针和尾指针相等 为空 返回真
    if (q->front == q->rear) {
        return true;
    }

    // 不为空 返回假
    return false;
}

// 进队列
bool enQueue(SqQueue* q, BiTree node) {

    // 队列满了 插入失败 返回假,
    if (q->rear == MAX_SIZE - 1) {
        return false;
    }

    // 队列没满 插入成功 返回真
    q->rear++;               // 头指针加 1
    q->data[q->rear] = node; // 传值
    return true;
}

// 出队列
bool deQueue(SqQueue* q, BiTree* node) {

    // 队列为空 取出失败 返回假
    if (q->front == q->rear) {
        return false;
    }

    // 队列不为空 取出成功 返回真
    q->front++;                // 尾指针+ 1
    *node = q->data[q->front]; // 取值
    return true;
}

// 层次遍历
void levelOrder(BiTree T) {
    SqQueue* q;       // 定义队列
    initQueue(&q);    // 初始化队列

    if (T != NULL) { // 根节点指针进队列
        enQueue(q, T);
    }

    // 一层一层的把节点存入队列,当没有孩子节点时就不再循环
    while (!emptyQueue(q)) {      // 队不为空

        deQueue(q, &T);          // 出队时的节点
        cout << (T->data);   // 输出节点存储的值

        if (T->lchild != NULL) { // 有左孩子时将该节点进队列
            enQueue(q, T->lchild);
        }
        if (T->rchild != NULL) { // 有右孩子时将该节点进队列
            enQueue(q, T->rchild);
        }
    }
}

// 求二叉树的高度
int treeHeight(BiTree T)
{
    int hL, hR, Height;
    if (T == NULL)
    {  // 空树 高度为0
        return 0;
    }
    else
    {
        hL = treeHeight(T->lchild);  // 求左子树的高度
        hR = treeHeight(T->rchild);  // 求右子树的高度
        Height = ((hL > hR) ? hL : hR) + 1;  // 取高度较大者 加上根结点的高度
        return Height;
    }
}

// 求二叉树的结点数
int nodeCount(BiTree T)
{
    static int count = 0; // 叶子数

    if (T == NULL) { // 空树
        return (0);
    }
    else if (T->lchild != NULL || T->rchild != NULL) { // 有左孩子或有右孩子
        count++;
    }

    nodeCount(T->lchild);
    nodeCount(T->rchild);

    return count;
}

// 求二叉树的叶子数
int leafcount(BiTree T)
{
    static int count = 0; // 叶子数

    if (T == NULL) { // 空树
        return (0);
    }
    else if (T->lchild == NULL && T->rchild == NULL) { // 无左孩子且无右孩子
        count++;  
    }

    leafcount(T->lchild);
    leafcount(T->rchild);
        
    return count;
}

// 交换左右子树
void swap(BiTree T) {
    BiTree temp = 0;

    if (T != NULL) {
        temp = T->lchild;
        T->lchild = T->rchild;
        T->rchild = temp;

        swap(T->lchild);
        swap(T->rchild);        
    }
 }

int main() {

    BiTree T = 0;
    int num;

    cout << "1.  输入字符序列,建立二叉链表"         << endl;
    cout << "2.  先序遍历二叉树:递归算法"           << endl;
    cout << "3.  先序遍历二叉树:非递归算法"         << endl;
    cout << "4.  中序遍历二叉树:递归算法"           << endl;
    cout << "5.  中序遍历二叉树:非递归算法"         << endl;
    cout << "6.  后序遍历二叉树:递归算法"           << endl;
    cout << "7.  后序遍历二叉树:非递归算法"         << endl;
    cout << "8.  借助队列实现二叉树的层次遍历"       << endl;
    cout << "9.  求二叉树的高度"                     << endl;
    cout << "10. 求二叉树的结点数"                   << endl;
    cout << "11. 求二叉树的叶子数"                   << endl;
    cout << "12.  交换二叉树每个结点的左子树和右子树" << endl;
    cout << "13.  退出";
    cout << endl;

    while (true)
    {
        cout << "请输入您要选择的计算: " << endl;
        cin >> num;

        switch (num)
        {
            case 1: //调用递归建立二叉树算法
            {
                cout << "请输入二叉树各结点值, 例如:AB#D##C##" << endl;
                createNode(T);
                cout << endl;
            }break;

            case 2:
            {
                cout << "先序遍历二叉树-递归:";
                preOrder(T);
                cout << endl;
            }break;

            case 3:
            {
                cout << "先序遍历二叉树-非递归:";
                preOrderByStack(T);
                cout << endl;
            }break;

            case 4:
            {
                cout << "中序遍历二叉树-递归:";
                midOrder(T);
                cout << endl;
            }break;

            case 5:
            {
                cout << "中序遍历二叉树-非递归:";
                midOrderByStack(T);
                cout << endl;
            }break;

            case 6:
            {
                cout << "后序遍历二叉树-递归:";
                lastOrderByStack(T);
                cout << endl;
            }break;

            case 7:
            {
                cout << "后序遍历二叉树-非递归:";
                lastOrderByStack(T);
                cout << endl;
            }break;

            case 8:
            {
                cout << "层次遍历二叉树:";
                levelOrder(T);
                cout << endl;
            }break;

            case 9:
            {
                cout << "二叉树的高度为:";
                cout << treeHeight(T);
                cout << endl;
            }break;

            case 10:
            {
                cout << "二叉树的结点数为:";
                cout << nodeCount(T);
                cout << endl;
            }break;

            case 11:
            {
                cout << "二叉树的叶子数为:";
                cout << leafcount(T);
                cout << endl;
            }break;

            case 12:
            {
                cout << "交换二叉树每个结点的左子树和右子树:" << endl;
                swap(T);
                cout << "交换成功!您可继续输入选择查看交换后的遍历结果" << endl;
            }break;

            case 13:
            {
                cout << "退出成功!" << endl;
                system("pause");
                return 0;
            }break;

            default:
            {
                cout << "输入错误!请重新输入!" << endl;
            }
        }
    }

	system("pause");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1988563.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里云镜像站,提供了各种第三方镜像地址

阿里云提供了各项镜像缓存地址&#xff0c;对于很多国外服务的地址&#xff0c;通过阿里云缓存的地址去下载&#xff0c;速度会非常快。 如下&#xff0c;打开阿里云官方网站&#xff1a; 进入“镜像站”&#xff0c;如下图所示&#xff1a; 有我们常用的 npm、maven、操作系统…

武汉流星汇聚:互联网+跨境购物新风尚,消费者深度依赖跨境电商

在21世纪的数字时代&#xff0c;跨境电商平台以其独特的魅力&#xff0c;正逐步成为连接全球消费者与优质商品的桥梁。随着消费者对优质产品需求的日益增长、全球互联网使用量的不断扩大、跨境物流技术的飞速进步以及全球供应链能力的显著提升&#xff0c;跨境电商平台不仅为消…

uniapp——列表选择样式

案例 代码 <view class"list"><block v-for"(item,index) in 8" :key"index"><view class"item" click"choosePackage(item)" :class"{active:item current}"><view class"i_money&q…

【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro

看到这句话的时候证明&#xff1a;此刻你我都在努力 加油陌生人 前言 今天给大家带来一篇有关Java顺序表和链表的文章&#xff0c;顺序表和链表我之前的专栏也是写过的&#xff0c;是用C语言实现的&#xff0c;也是模仿实现了顺序表和链表里的方法了。 下面是传送门&#xff…

新一代AI技术的发展

人工智能技术正处于迈向全新阶段的关键转折点&#xff0c;从传统的NLP(自然语言处理)迅速迈向更开 放、更通用、多模态的AGI(通用人工智能),AGI的兴起为各行业带来了前所未有的机遇。AGI突破了传 统AI的局限&#xff0c;具备跨领域的广泛应用能力和自主学习能力&#xff0c;在自…

CTFHUB | web进阶 | PHP | Bypass disable_function | PHP-FPM

开启题目 查看源码&#xff0c;发现可以蚁剑连接 连接成功发现无任何发现&#xff0c;所以我们使用 Fastcgi/PHP-FPM 插件&#xff0c;配置如下 刷新目录发现插件上传了一个 php 文件&#xff0c;复制文件名拼接到后面再次连接 发现直接进入终端了&#xff0c;最后发现了 flag

MySQL数据库基础:增删查改

&#x1f48e;所属专栏&#xff1a; MySQL &#x1f48e;1. 常用数据类型 &#x1f48e;1.1 数值类型 数值类型可以指定无符号类型&#xff0c;默认为有符号类型&#xff0c;例如身高体重这种&#xff0c;只可能是正数的&#xff0c;可以指定为无符号 CREATE TABLE example (…

Linux PCI和PCIe总线

1 PCIe中断 - PCI/PCIe设备中断都是level触发&#xff0c;并且请求信号为低电平有效 - PCI总线一般只有INTA#到INTD#的4个中断引脚&#xff0c;所以PCI多功能设备的func一般不会超过4个&#xff0c;但是共享中断除外 2 IOMMU 2.1 ARM SMMU v2 Refer to my blog ARM SMMU v2. 2.…

糟糕界面集锦-控件篇 01

iarchitect 整理&#xff0c;bucher 译 在图形界面中&#xff0c;控件就是程序与用户之间沟通的桥梁&#xff0c;而这座桥梁的好坏则取决于如下两个方面&#xff1a; 控件是否符合需求控件之间是否风格一致 《Visual Basic Programmers Journal 101 Tech Tips for VB Develop…

网络工具(Netcat、iPerf)

目录 1. Netcat2. iPerf 1. Netcat Netcat 是一款简单的 Unix 工具&#xff0c;常用于测试 UDP 和 TCP 连接。 https://www.cnblogs.com/yywf/p/18154209 https://eternallybored.org/misc/netcat/ https://nmap.org/download.html 创建UDP监听端 nc -u -l localPort 创建UDP…

并行程序设计基础——Hello world

目录 一、Fortran 90 MPI实现 二、C MPI实现 三、MPI程序的一些惯例 四、小结 相信许多编程初学者的入门程序都是“Hello World”&#xff0c;我们同样来编写MPI的第一个程序“Hello World”。 一、Fortran 90 MPI实现 我们先给出代码&#xff0c;然后进行代码分析。 pro…

零基础入门汇编语言(第四版王爽)~第1章基础知识

文章目录 前言1.1 机器语言1.2 汇编语言的产生1.3 汇编语言的组成1.4 存储器1.5 指令和数据1.6 存储单元1.7 CPU对存储器的读写1.8 地址总线1.9 数据总线1.10 控制总线1.1~1.10小结检测点1.11.11 内存地址空间概述1.12 主板1.13接口卡1.14 各类存储器芯片1.15 内存地址空间 前言…

9.C基础_指针与数组

数组指针&#xff08;一维数组&#xff09; 数组指针就是" 数组的指针 "&#xff0c;它是一个指向数组首地址的指针变量。 1、数组名的含义 对于一维数组&#xff0c;数组名就是一个指针&#xff0c;指向数组的首地址。 基于如下代码进行分析&#xff1a; int a…

el-form-item,label在上方显示,输入框在下方展示

本来是两排展示去写&#xff0c;设计要求一排展示&#xff0c;label再上方&#xff0c;输入框、勾选框在下方&#xff1b;只能调整样式去修改&#xff1b;参考label-position这个属性 代码如下&#xff1a; <el-form ref"form" :model"formData" clas…

【好书推荐-第二十期】《程序员进阶之路:缓存、网络、内存与案例》:讲解计算机系统中的核心知识分享实际工作中的技术难题及解决方案

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公众号&#xff1a;洲与AI。 &#x1f388; 本文专栏&#xff1a;本文收录…

认识Creator热更新

Creator热更新 1、什么是热更新 当你下载一个游戏&#xff0c;比如王者荣耀&#xff0c;打开时发现提示有新的资源包要让你更新&#xff0c;那就是使用了热更新。 热更新主要是用于原生环境的andriod和ios&#xff0c;对于小游戏不用&#xff0c;小游戏是审核过后&#xff0c…

同声传译用什么软件?亲测好用的同传翻译器分享

巴黎奥运会的到来&#xff0c;让全球的目光再次聚焦于这座浪漫之都。作为国际盛事&#xff0c;语言沟通无疑成为连接各国运动员、观众与媒体的桥梁。 面对多语言环境的挑战&#xff0c;一款高效、准确的同声传译软件显得尤为重要。它不仅能即时传递赛场激情&#xff0c;还能让…

加密软件有什么功能

加密软件是一种用于保护数据安全的工具&#xff0c;它通过对数据进行加密处理&#xff0c;使得未经授权的用户无法访问或篡改这些数据。加密软件使用各种加密算法&#xff0c;如对称加密、非对称加密等&#xff0c;确保数据在传输和存储过程中的安全性。 一、加密软件的功能 数…

【leetcode】相同的树、另一棵树的子树、翻转二叉树(利用深度优先遍历)

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;数据结构、LeetCode专栏 &#x1f4da;本系…

【mars3d】LayerType 的arcgis_feature类型的图层配置聚合属性,达到聚合效果

相关api文档&#xff1a; Global - V3.7.23 - Mars3D API文档 Global - V3.7.23 - Mars3D API文档 ArcGisWfsLayer - V3.7.23 - Mars3D API文档 实现代码&#xff1a; export function onMounted(mapInstance) {map mapInstance // 记录首次创建的map// 添加参考三维模型co…