二叉树和其他树

编译运行程序见:Github::Jasmine-up/Data-Structures-Algorithms-and-Applications/_23BinaryTree

定义

定义 11-1 一棵树 t是一个非空的有限元素集合,其中一个元素为根(root),其余的元素(如果有的话)组成t的子树(subtree)。

在画一棵树时,每个元素都代表一个节点。树根画在上面,其子树画在下面。在根与子树的根(如果有子树)之间有一条边。同样的,每一棵子树也是根在上,其子树在下。在一棵树中,一个元素节点及其孩子节点之间用边连接。树不能为空。

树的另一常用术语为级(level)。树根是 1级,其孩子(如果有)是 2 级,孩子的孩子是3 级,等等。

一棵树的高度(height)或深度depth)是树中级的个数

一个元素的度(degree of an element)是指其孩子的个数。叶节点的度为0。

一棵树的度(degree of a tree)是其元素的度的最大值

二叉树

定义

定义 11-2 一棵二叉树(binary treet有限元素集合可以为空)。当二叉树非空时,其中有一个元素称为根,余下的元素(如果有的话)被划分成两棵二叉树,分别称为t左子树和右子树。
二叉树和树的根本区别是:

  • 二叉树的每个元素都恰好有两棵子树(其中一个或两个可能为空)。而树的每个元素可有任意数量的子树。
  • 二叉树中,每个元素的子树都是有序的,也就是说,有左子树和右子树之分。而树的子树是无序的。

树和二叉树的另一个区别大概与定义有关,二叉可以为空,但树不能为空。有的作者放宽了对树的定义,允许树为空。
和树一样,二叉树也是根节点在顶部。二叉树左(右)子树中的元素画在根的左(右)下方。每个元素节点和其子节点之间用一条边相连。

在这里插入图片描述

二叉树特性

二叉树的特性

  • 特性 11-1 一棵二叉树有 n 个元素,n>0,它有 n-1 条边。

证明 二叉树的每个元素(除了根节点)有且只有一个父节点。在子节点与父节点间有且只有一条边,因此边数为n-1。

  • 特性 11-2 一棵二叉树的高度为hh>0,它最少有h个元素,最多有

    2

    h

    2^h

    2h-1 个元素。

证明 因为每一级最少有1个元素,因此元素的个数最少为h。每个元素最多有2个子节点,则第i层节点元素最多为

2

h

1

2^h-1

2h1 个,i>0。当 h=0 时,元素的总数为 0,也就是

2

0

1

2^0-1

201。当h>0 时,元素的总数不会超过

i

=

1

h

2

h

1

=

2

h

1

sum_{i=1}^h2^{h-1}=2^h-1

i=1h2h1=2h1

  • 特性 11-3 一棵二叉树有 n 个元素,n>0,它的高度最大为 n,最小高度为

    l

    o

    g

    2

    (

    n

    1

    )

    lceil log_2(n-1)rceil

    log2(n1)⌉

证明 因为每层至少有一个元素,因此高度不会超过n。由特性 11-2可以得知,高度为h 的二叉树最多有

2

h

1

2^h-1

2h1个元素。因为 n<

2

h

1

2^h-1

2h1,所以

h

>

l

o

g

2

(

n

+

1

)

h>log_2(n+1)

h>log2(n+1)。由于h是整数,所以

h

l

o

g

2

(

n

1

)

h geq lceil log_2(n-1)rceil

hlog2(n1)⌉

满二叉树

当高度为h的二叉树恰好有

2

h

1

2^h-1

2h1个元素时,称其为满二叉树(full binary tree如图11-6所示

在这里插入图片描述

完全二叉树

对高度为h的满二叉树的元素,从第一层到最后一层,在每一次中从左至右,顺序编号,从1到

2

h

1

2^h-1

2h1如图11-6所示)。假设从满二叉树中删除k个其编号

2

h

i

2^h-i

2hi元素,

1

i

k

<

2

h

1≤i≤k<2^h

1ik<2h,所得到的二叉树被称为完全二叉树(complete binary tree。满二叉树是完全二叉树的特例。

在这里插入图片描述

在完全二叉树中,一个元素与其孩子的编号有非常好的对应关系。

特性 11-4 设完全二叉树的一元素其编号为i,

1

<

i

<

n

1<i<n

1<i<n。有以下关系成立:
1)如果

i

=

1

i=1

i=1,则该元素为二叉树的根。若

i

>

1

i>1

i>1,则其父节点的编号为

i

/

2

lfloor i/2rfloor

i/2
2)如果

2

i

>

n

2i>n

2i>n,则该元素无左孩子。否则,其左孩子的编号为

2

i

2i

2i。左孩子一定是偶数。
3)如果

2

i

+

1

>

n

2i+1>n

2i+1>n,则该元素无右孩子。否则,其右孩子的编号为

2

i

+

1

2i+1

2i+1。右孩子一定是奇数

树的二叉树描述

当分布树t有节点超过两个孩子时,依然用二叉树来表示。此时,对每个节点x,可用其孩子节点的rightChild指针x的所有孩子链成一条链表x节点的leftChild指针指向该链表的第一个节点。x节点的rightChild指针来指向 x 的兄弟。图 11-15 是一棵树和其二叉树,其中实线表示指向左孩子的指针,虚线表示指向右孩子的指针

在这里插入图片描述

将森林转换为二叉树

(1)把每个树转换为二叉树。

(2)第一棵二叉树不动,从第二棵二叉树开始,依次把后一棵二叉树的根结点作为前一棵二叉树的根结点的右孩子,用线连接起来。当所有的二叉树连接起来后就得到了由森林转换来的二叉树。

二叉树的描述

数组描述

当缺少的元素数目多时,很浪费空间,因此不常用。

链表描述

二叉树最常用的表示方法是用指针。每个元素用一个节点表示,节点有两个指针域,分别称为leftChild和rightChild。除两个指针域之外,每个节点还有一个element域。

父节点的每一个指向孩子的指针表示一条边。因为 n个元素的二叉树仅有 n-1 条边,所以有2n-(n-1)=n+1个指针域没有值,它们被置为NULL。图 11-10 是二叉树的链表表示。

在这里插入图片描述

二叉树遍历

习题

二叉树的应用

设置信号放大器

在一个分布式网络中,资源从生产地送往其他地方。例如,汽油或天然气经过管道网络,从生产基地送到消费地。同样的,电力也是通过电网从发电厂输送到各消费点。可以用术语信号signal)来指称输送的资源(汽油、天然气、电力等)。当信号网络传输时,它在某一方面或某几个方面的性能可能会损失或衰减。例如,天然气管道中的气压会减少,电网上的电压会降低。另一方面,在信号传输中,噪声会增加。在信号信号源到消费点传输过程中,仅能容忍一定范围内的信号衰减。为了保证信号衰减不超过容忍值(tolerance),应在网络中至关重要位置上放置信号放大器(signal booster)。信号放大器可以增加信号的压强或电压使它与源点相同;可以增强信号,使信号与噪声之比与源点的相同。本节将设计一个算法,以计算信号放大器的放置地点。目标是,放大器的数目最少,同时保证信号衰减(与源点信号相关)不超过给定的容忍值。

为简化问题,假设分布网络是一树形结构,源点是树的根。树的每一个非根节点表示一个可以放置放大器的地点,某些节点同时也表示消费点。信号从一个节点流向其子节点。图11-12 是一树形分布网络。每条边上的数字是信号从父节点流到其子节点的信号衰减量。衰减量的单位假设可以附加。在图 11-12中,信号从节点p流到节点v的衰减量是5。从节点q到节点x的衰减量为3。如果把一个信号放大器放在节点r,那么虽然当信号从节点p到达节点r时,它的强度比在节点p时衰减了3个单位,但是,当它从节点r流出时,又恢复了它在源点p的强度。因此,信号到达节点v时,强度比在源点p时衰减了2个单位,到达节点z时,强度比在源点p时衰减了 4个单位。如果在节点r没有信号放大器,那么在节点 z 的信号将衰减 7个单位。

在这里插入图片描述

设 degradeFromParent(i)表示节点i与其父节点间的衰减量。因此,在图 11-12 中,degradeFromParent(s)=2,degradeFromParent(p)=0,degradeFromParent(r)=3。因为信号放大器只能放在树形分布网的节点上,所以节点i的degradeFromParent(i)如果大于容忍值,那么即使在节点i放置了信号放大器,信号的衰减量依然要超过容忍值。例如,若容忍值为2,则在图11-12的节点r上即使有信号放大器,信号的衰减量也不会小于或等于2。

在以节点i为根的子树中,从节点i到子树的每个叶子都有一个衰减量,我们把这些衰减量的最大者记为degradeToLeaf(i)。若i是叶节点,则degradeToLeaf(i)=0。在图11-12中,当iE(w,x,t,y,z)时,degradeToLeaf(i)=0。对于其他节点,degradeToLeaf(i)可以用下面的方程式来计算:

在这里插入图片描述

因此,degradeToLeaf(s)=3。在此公式中,要计算节点的degradeToLeaf值,就要先计算其子节点的degradeToLeaf值,因此必须对树进行遍历。先访问子节点再访问父节点。在访问一个节点时,同时计算它的degradeToLeaf值。这种遍历方法是对后序遍历的一种自然扩充,其树的度大于 2。

按照上述方法,在计算 degradeToLeaf过程中,遇到一节点i,它有一子节点j满足在这里插入图片描述

如果不在j节点放置放大器,那么从i节点到叶节点的信号衰减量将超过容忍值,即使在i节点处放置了放大器也是如此。例如在图 11-12 中,当计算degradeToLeaf(q)时,有

在这里插入图片描述

如果容忍值为 3,那么在 q 点或其祖先的任意一点放置放大器,都不能减少 q 与其后代间的衰减量。我们需要s点放一个放大器,这时degradeToLeaf(g)=3。

测试使用的是下面这棵树:测试时,输入的a的degradeToLeaf为0,degradeFromParent为1;输入的b的degradeToLeaf为0,degradeFromParent为2。

在这里插入图片描述

并查集

问题描述:有 n个元素从1 到 n编号。开始时,每一个元素在自己的类中然后执行系列findcombine操作。操作find(theElement)返回元素theElement所在类的唯一特征,而combine(a,b)把包含a和b的两个类合并

建模为树:任何一个集合 S 都可以描述为一棵具有

S

lvert S rvert

S个节点的树,一个节点代表一个元素。任何一个元素可以作为根元素;剩余元素的任何子集可以作为根元素的孩子;再剩余元素的任何子素集可以作为根元素的孙子,等等。

在这里插入图片描述

举例如图11-16,我们说,元素1、2、20、30 等属于以20为根的集合;元素 11、16、25、28 属于以16为根的集合;元素 15 属于以 15 为根的集合;元素 26 和 32 属于以 26 为根的集合

求解策略:并查集问题的求解策略是,把每一个集合表示为一棵树。在查找时,我们把根元素作为集合标志符。因此,find(3)的返回值是20(见图11-16);find(1)的返回值是20;find(26)的返回值是26。因为每一个集合都有唯一的根,所以当且仅当i和j属于同一个集合时,有find(i)=find(j)。为了确定元素theElement属于哪一个集合,我们从元素theElement 的节点开始,沿着节点到其父节点向上移动,直到根节点为止。

合并时,我们假设在调用语句unite(classA,classB)中,classA 和 classB分别是两个不同树集合的根(即classA classB)。为了把两个集合合并,我们让一棵树成为另一棵树的子树。例如,假设classA=16而classB=26(见图11-16),如果让 classA 成为 classB 的子树,那么结果如图11-17a所示;如果让classB成为classA的子树,那么结果如图 11-17b所示。

在这里插入图片描述

C++实现:查集问题的求解策略模拟指针的一个极好的应用这里需要树的链表描述,其中每个节点必须有一个parent域,但不必有孩子域。还需要直接访问节点。为找到含有元素10的集合,先要找到元素10的节点,然后沿着节点的parent指针找到根节点。如果n个节点的索引号从1到n(n是元素个数),且节点e表示元素e,那么很容易实现直接访问。每个parent域给出父节点的索引,因此parent域为整数类型
图11-18就是采用这种方法来表示图 11-16的。节点内的数字是其parent域的值,节点外的数字是该节点的索引索引同时也是该节点所表示的元素。根节点的 parent 域被置为 0。因为没有索引是 0 的节点,所以 parent为0 表示不指向任何节点(即为空链)。

在这里插入图片描述

性能分析构造函数时间性能是O(numberOfElements);查找函数find的时间性能是O(h),其中h是树的高度。合并函数unite的时间性能是O(1)。假设一个系列操作要执行u次合并和f次查找,一个系列操作的时间为O(fu)

每次合并前都要执行两次查找(这些查找决定了要合并的树的根),此处可以优化,因为查找比较费时间,如果每次合并都查找的话就很占用时间。

合并函数的性能改进:在对根为 i和根为j的树进行合并操作时,利用重量规则或高度规则,可以提高并查集算法的性能。

**定义 11-3[重量规则]**若根为i的树的节点数少于根为 j的树的节点数,则将j作为i 的父节点。否则,将i作为j的父节点。
**定义 11-4[高度规则]**若根为 i 的树的高度小于根为j 的树的高度,则将j 作为 i 的父节点,否则,将i作为j的父节点。

使用重量队则的测试见代码:_28binaryTreeChains.cpp

**引理 11-1[重量规则引理]**假设从单元素集合出发,用重量规则进行合并操作。若以此方式构建一棵具有 p 个节点的树 t,则 t 的高度最多为

l

o

g

2

p

+

1

lfloor log_2prfloor+1

log2p+1

使用重量规则,合并和查找序列的代价(不包括初始化时间)为O(u+flogu) =O(flogu)(因为我们假定f>u)。

查找函数的性能改进:缩短从元素e到根的查找路径。这个方法利用了路径压缩(path compression过程,这个过程实现至少有3种不同的途径–路径紧缩(path compaction)、路径分割(path splitting)和路径对折(path halving)。

路径紧缩中,从待查节点到根节点的路径上,所有节点的parent 指针都被改为指向根节点。以图 11-20 为例,当执行查找操作find(10)时,从10到根的路径有节点10、15和3。把这些节点的parent域改为 2,就得到图 11-21(节点 3 的指针本来就指向 2,因此其 parent域不必修改。但是为简化起见,程序还是对路径上的每个节点都进行了修改)。

在这里插入图片描述

在这里插入图片描述

路径紧缩代码

在这里插入图片描述

在路径分割中,从e节点到根节点的路径上,除根节点和其子节点之外,每个节点的parent指针都被改为指向各自的祖父。在图11-20中,路径分割从节点13开始,结果得到图11-22 的树。在路径分割时,只考虑从e到根节点的一条路径就够了。
在路径对折中,从e节点到根节点的路径上,除根节点和其子节点之外,每隔一个节点,其parent指针都被改为指向各自的祖父。在路径对折中,指针改变的个数仅为路径分割中的一半。同样,在路径对折中只考虑从e到根的一条路径就够了。在图11-20中,路径对折从节点13开始,结果得到图11-23的树。

在这里插入图片描述

仿真测试

main.cpp

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月13日17点38分
Last Version:			V1.0
Descriptions:			main()函数,控制运行所有的测试函数
*/
#include "_28binaryTreeChains.h"

int main()
{
    binaryTreeChainsTest();
    treeExpressionsTest();
    treeApplicationTest();
    return 0;
}

_28binaryTreeChains.h

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月27日09点44分
Last Version:			V1.0
Descriptions:			用链表表示的二叉树.h
笔记:
	1.静态函数指针初始化格式void (*binaryTreeChains<E>::visit)(binaryTreeNode<E>*) = 0;
	2.不能单独专门化成员模板函数,只能针对整个类专门化。
	3.在模板函数中可以使用typeid()区别对待特定数据类型。
本程序注意事项:
	1.所有关于前缀、后缀、中缀表达式的全部使用了char类型代表元素,char类型数组存储整个表达式
*/
#pragma once
#ifndef _BINARYTREECHAINS_H_
#define _BINARYTREECHAINS_H_
#include <iostream>
#include <vector>
#include <cstring>
#include <stack>
#include <queue>
#include "_1myExceptions.h"
#include "_28binaryTreeNode.h"
#include "_28binaryTree.h"
#include "_28booster.h"
#include "_28treeUnionFindNode.h"
using namespace std;
/*二叉树基础测试函数*/
void binaryTreeChainsTest();
/*二叉树树表达式测试函数*/
void treeExpressionsTest();
/*二叉树应用的测试函数*/
void treeApplicationTest();

template<class E>
class binaryTreeChains : public binaryTree<binaryTreeNode<E>>
{
public:
    /*二叉树的基础成员函数*/
    /*构造函数函数*/
    binaryTreeChains() {
        root = nullptr; treeSize = 0;
    }
    /*练习44:编写类linkedBinaryTree的一个复制构造函数。测试代码。*/
    /* 计算时间复杂性。复制构造函数*/
    binaryTreeChains(binaryTreeChains<E>&amp; m) {
        root = treeCreateTree(m.root);
    }
    /*练习题33和练习题35*/
    /*构造函数---先序和中序遍历或后序和中序创建二叉树*/
    /*flag == false时,是先序和中序遍历构建二叉树;flag == true时,是后序和中序构建二叉树*/
    binaryTreeChains(E preOrPostOrder[], E inOrder[],int length,bool flag)
    {
        if(flag == false)
            root = preInCreateTree(preOrPostOrder, inOrder, length);
        else
            root = postInCreateTree(preOrPostOrder, inOrder, length);
    }
    /*构造函数---前缀或后缀或中缀表达式创建二叉树*/
    /*
    练习37:当flag = 1时,前缀表达式创建二叉树
    当flag = 2时,中缀表达式创建二叉树
    练习36:当flag = 3时,后缀表达式创建二叉树
    */
    binaryTreeChains(E expression[], int length,int flag)
    {
        switch (flag)
        {
            case 1:
                root = preExprCreateTree(expression, length);
                break;
            case 2:
                root = inExprCreateTree(expression, length);
                break;
            case 3:
                root = postExprCreateTree(expression, length);
                break;
        }
    }
    /*析构函数*/
    ~binaryTreeChains() { erase(); }
    /*当树为空时,返回true;否则,返回false*/
    bool empty() const { return treeSize == 0; }
    /*返回元素个数*/
    int size() const { return treeSize; }
    /*前序遍历二叉树,使用函数指针的目的是是的本函数可以实现多种目的*/
    void preOrder(void(*theVisit)(binaryTreeNode<E>*))
    {
        visit = theVisit;
        /*是因为递归,所以才要这样的*/
        preOrder(root);/*这里调用的是成员函数,preOrder()*/
    }
    /*前序遍历---输出endl*/
    void preOrderOutput() { preOrder(output); cout << endl; }
    /*前序遍历---不使用递归而使用迭代函数*/
    vector<E> iterativePreOrder();

    /*中序遍历二叉树,使用函数指针的目的是是的本函数可以实现多种目的*/
    void inOrder(void(*theVisit)(binaryTreeNode<E>*))
    {
        visit = theVisit;
        /*是因为递归,所以才要这样的*/
        inOrder(root);/*这里调用的是静态成员函数inOrder()*/
    }
    /*中序遍历---输出endl*/
    void inOrderOutput() { inOrder(output); cout << endl; }
    /*中序遍历---不使用递归而使用迭代函数*/
    vector<E> iterativeInOrder();

    /*后续遍历二叉树,使用函数指针的目的是是的本函数可以实现多种目的*/
    void postOrder(void(*theVisit)(binaryTreeNode<E>*))
    {
        visit = theVisit;
        /*是因为递归,所以才要这样的*/
        postOrder(root);/*这里调用的是静态成员函数inOrder()*/
    }
    /*后序遍历---输出endl*/
    void postOrderOutput() { postOrder(output); cout << endl; }
    /*后序遍历---不使用递归而使用迭代函数*/
    vector<E> iterativePostOrder();

    /*层次遍历二叉树*/
    void levelOrder(void (*theVisit)(binaryTreeNode<E>*));
    /*层次遍历---输出endl*/
    void levelOrderOutput() { levelOrder(output); cout << endl; }

    /*清空二叉树 这里必须使用后序遍历 不然会出错*/
    void erase()
    {
        postOrder(dispose);
        root = nullptr;
        treeSize = 0;
    }
    /*输入时为了将root根节点传递给createBiTree()函数*/
    void input(void)
    {
        createBiTree(root);
    }
    /*是一个手动创建二叉树的函数,使用本函数得手动设置各节点之间的关系,见信号放大器应用的使用*/
    /*将左数和右数合并为一个树(也就是this树)*/
    void makeTree(const E&amp; element, binaryTreeChains<E>&amp;, binaryTreeChains<E>&amp;);
    /*练习45:比较二叉树*this和二叉树m*/
    bool compare(binaryTreeChains<E>&amp; m)
    {
        return compareTree(root, m.root);
    }
    /*练习46:交换每一个结点的左右子树*/
    void swapTrees()
    {
        swapTrees(root);
    }
    /*练习27:计算二叉树高度*/
    int height() const { return height(root); }
    /*练习47:计算二叉树的最大高度差*/
    int maxHeightDifference()
    {
        return maxHeightDifference(root);
    }
    /*练习29:计算二叉树在那一层具有最多的结点---返回值为结点最多的层*/
    int layerMaxNumOfNode();
    /*计算二叉树在在哪一层具有最多的结点--返回值为结点最多的层的结点数量*/
    int maxNumOfNodeInLayer();


    /*二叉树表达式的成员函数*/
    /*计算树的表达式的值*/
    int compulateTree()
    {
        return compulateTree(root);
    }
private:
    /*二叉树基础私有成员*/
    binaryTreeNode<E>* root;//指向根的指针
    int treeSize;//树的结点个数
    static void (*visit)(binaryTreeNode<E>*);//是一个函数指针,返回值为void 函数参数为binaryTreeNode<E>*
    static void preOrder(binaryTreeNode<E>* t);
    static void inOrder(binaryTreeNode<E>* t);
    static void postOrder(binaryTreeNode<E>* t);
    static void dispose(binaryTreeNode<E>* t) { delete t; }
    static void output(binaryTreeNode<E>* t) { cout << t->element << " "; }
    /*创建二叉树---递归---作为私有成员只能被成员函数调用*/
    void createBiTree(binaryTreeNode<E>*& tree);
    /*复制构造函数调用的函数*/
    binaryTreeNode<E>* treeCreateTree(binaryTreeNode<E>*& node);
    /*私有成员函数---用于比较二叉树compare()*/
    bool compareTree(binaryTreeNode<E>* thisNode, binaryTreeNode<E>* xNode);
    /*私有成员函数---交换树的每个结点的左右子树---递归*/
    void swapTrees(binaryTreeNode<E>*& node);
    /*私有成员函数---计算二叉树高度---返回根为node的树的高度*/
    int height(binaryTreeNode<E>* node) const;
    /*私有成员函数---计算结点node的左右子树高度的差值*/
    int heightDifference(binaryTreeNode<E>* node) const;
    /*私有成员函数---计算二叉树的最大高度差---返回值为二叉树的最大高度差*/
    int maxHeightDifference(binaryTreeNode<E>* node) const;
    binaryTreeNode<E>* preInCreateTree(E preOrder[], E inOrder[], int size);
    binaryTreeNode<E>* postInCreateTree(E postOrder[], E inOrder[], int size);


    /*二叉树表达式的私有成员*/
    /*计算树的表达式的值*/
    /*本程序所有关于前缀、中缀、后缀表达式的处理全部是char类型,并且只能进行个位数的计算*/
    int compulateTree(binaryTreeNode<E>* node) const;
    binaryTreeNode<E>* preExprCreateTree(E expression[], int length);
    binaryTreeNode<E>* inExprCreateTree(E expression[], int length);
    binaryTreeNode<E>* postExprCreateTree(E expression[], int length);
};
/*私有静态成员初始化*/
/*这里静态函数指针成员的初始化,不初始化会引发LINK错误*/
template<class E>
void (*binaryTreeChains<E>::visit)(binaryTreeNode<E>*) = 0;      // visit function

/*非成员函数*/
/*返回元素data在数组中的位置,找到则返回该元素的位置,未找到则返回-1*/
template<class E>
int findRootLoc(E list[], E data, int length);
/*练习38:将后缀表达式转换为完全括号化的中缀表达式 完全括号化的中缀表达式如((a)+(b))*/
/*参数说明:postExpr是后缀表达式数组的指针,inExpr用于存储生成的前缀表达式,length是后缀表达式的长度*/
void postExprToIn(char postExpr[], string& inExpr, int length);
/*获取操作符的优先级,不包括栈外左括号的优先级,因为遇到栈外左括号,直接入栈就行*/
int getPriority(char op);
/*将中缀表达式转换为后缀表达式*/
/*参数说明:inExpr为指向中缀表达式的指针,postExpr为指向生成的后序表达式的指针,length表示中缀表达式的长度*/
void inExprToPost(char inExpr[], char postExpr[], int length);
/*练习41:将中缀表达式转换为前缀表达式---从后往前归入前缀表达式*/
/*参数说明:inExpr为指向中缀表达式的指针,preExpr为指向生成的后序表达式数组的指针,inLength表示中缀表达式的长度,preLength表示前缀表达式的长度*/
void inExprToPre(char inExpr[], char preExpr[], int inLength, int preLength);
/*练习39:将前缀表达式转换为带括号的中缀表达式 如((a+b)+(c*d))*/
/*参数说明:postExpr是后缀表达式数组的指针,inExpr用于存储生成的前缀表达式,length是后缀表达式的长度*/
void preExprToIn(char preExpr[], string& inExpr, int length);

/*计算表达式的值*/
/*前缀表达式计算表达式的值*/
/*参数说明:preExpr表示指向前缀表达式数组的指针,length表示前缀表达式的长度;返回值为计算的结果*/
int preCalculate(char preExpr[], int length);
/*中缀表达式计算表达式的值*/
/*参数说明:inExpr表示指向中缀表达式数组的指针,length表示中缀表达式的长度;返回值为计算的结果*/
int inCalculate(char inExpr[], int length);
/*练习43:后缀表达式计算表达式的值*/
/*参数说明:postExpr表示指向后缀表达式数组的指针,length表示后缀表达式的长度;返回值为计算的结果*/
int postCalculate(char postExpr[], int length);

/*二叉树的应用*/
/*设置信号放大器*/
void placeBoosters(binaryTreeNode<booster>* x);
/*并查集*/
void initialize(int numberOfElements);
int find(int theElement);
void unite(int rootA, int rootB);

/*二叉树的普通成员函数*/
/*前序遍历 递归*/
template<class E>
void binaryTreeChains<E>::preOrder(binaryTreeNode<E>* t)
{
    if (t != nullptr)
    {
        visit(t);/*访问树根*/
        preOrder(t->leftChild);/*前序遍历左子树*/
        preOrder(t->rightChild);/*前序遍历右子树*/
    }
}
/*前序遍历---不使用递归而使用迭代函数*/
template<class E>
vector<E> binaryTreeChains<E>::iterativePreOrder()
{
    binaryTreeNode<E>* currentNode = root;
    stack<binaryTreeNode<E>*> st;
    vector<E> result;

    /*写法1---前序中序后序遍历非递归统一版*/
    /*首先将父节点入栈*/
    if (currentNode != nullptr)
        st.push(currentNode);
    while (!st.empty())
    {
        currentNode = st.top();
        st.pop();
        /*如果遇到nullptr,则输出当前栈顶元素*/
        if (currentNode == nullptr)
        {
            result.push_back(st.top()->element);
            st.pop();
        }
            /*如果没有遇到nullptr,则按照右左中的顺序入栈结点,最后入栈nullptr*/
        else
        {
            if (currentNode->rightChild != nullptr)
                st.push(currentNode->rightChild);
            if (currentNode->leftChild != nullptr)
                st.push(currentNode->leftChild);
            st.push(currentNode);
            /*每次都在已遍历的根节点后入栈nullptr*/
            st.push(nullptr);
        }
    }

    ///*写法2*/
    ///*当结点为nullptr并且栈为空时结束循环*/
    //while (currentNode != nullptr || !st.empty())
    //{
    //	/*先将左边的左边的元素入栈*/
    //	while (currentNode != nullptr)
    //	{
    //		st.push(currentNode);
    //		result.push_back(currentNode->element);
    //		currentNode = currentNode->leftChild;
    //	}
    //	/*然后一个一个遍历左边的元素,并将该元素存储vector中*/
    //	currentNode = st.top();
    //	st.pop();
    //	currentNode = currentNode->rightChild;
    //}
    return result;
}

/*中序遍历 递归*/
template<class E>
void binaryTreeChains<E>::inOrder(binaryTreeNode<E>* t)
{
    if (t != nullptr)
    {
        inOrder(t->leftChild);/*中序遍历左子树*/
        visit(t);/*访问树根*/
        inOrder(t->rightChild);/*中序遍历右子树*/
    }
}
/*中序遍历---不使用递归而使用迭代函数*/
template<class E>
vector<E> binaryTreeChains<E>::iterativeInOrder()
{
    binaryTreeNode<E>* currentNode = root;
    stack<binaryTreeNode<E>*> st;
    vector<E> result;
    /*写法1---前序中序后序遍历非递归统一版*/
    /*首先将父节点入栈*/
    if (currentNode != nullptr)
        st.push(currentNode);
    while (!st.empty())
    {
        currentNode = st.top();
        st.pop();
        /*如果遇到nullptr,则输出当前栈顶元素*/
        if (currentNode == nullptr)
        {
            result.push_back(st.top()->element);
            st.pop();
        }
            /*如果没有遇到nullptr,则按照右左中的顺序入栈结点,最后入栈nullptr*/
        else
        {
            if (currentNode->rightChild != nullptr)
                st.push(currentNode->rightChild);
            st.push(currentNode);
            /*每次都在已遍历的根节点后入栈nullptr*/
            st.push(nullptr);
            if (currentNode->leftChild != nullptr)
                st.push(currentNode->leftChild);
        }
    }
    /*写法2*/
    ///*当结点为nullptr并且栈为空时结束循环*/
    //while (currentNode != nullptr || !st.empty())
    //{
    //	/*先将左边的左边的元素入栈*/
    //	while (currentNode != nullptr)
    //	{
    //		st.push(currentNode);
    //		currentNode = currentNode->leftChild;
    //	}
    //	/*然后一个一个遍历左边的元素,并将该元素存储vector中*/
    //	currentNode = st.top();
    //	st.pop();
    //	result.push_back(currentNode->element);
    //	currentNode = currentNode->rightChild;
    //}
    return result;
}

/*后序遍历 递归*/
template<class E>
void binaryTreeChains<E>::postOrder(binaryTreeNode<E>* t)
{
    if (t != nullptr)
    {
        postOrder(t->leftChild);/*后序遍历左子树*/
        postOrder(t->rightChild);/*后序遍历右子树*/
        visit(t);/*访问树根*/
    }
}
/*后序遍历---不使用递归而使用迭代函数*/
template<class E>
vector<E> binaryTreeChains<E>::iterativePostOrder()
{
    binaryTreeNode<E>* currentNode = root;
    stack<binaryTreeNode<E>*> st;
    vector<E> result;
    /*前序中序后序遍历非递归统一版*/
    /*首先将父节点入栈*/
    if (currentNode != nullptr)
        st.push(currentNode);
    while (!st.empty())
    {
        currentNode = st.top();
        st.pop();
        /*如果遇到nullptr,则输出当前栈顶元素*/
        if (currentNode == nullptr)
        {
            result.push_back(st.top()->element);
            st.pop();
        }
            /*如果没有遇到nullptr,则按照右左中的顺序入栈结点,最后入栈nullptr*/
        else
        {
            st.push(currentNode);
            /*每次都在已遍历的根节点后入栈nullptr*/
            st.push(nullptr);
            if (currentNode->rightChild != nullptr)
                st.push(currentNode->rightChild);
            if (currentNode->leftChild != nullptr)
                st.push(currentNode->leftChild);
        }
    }
    return result;
}

/*层次遍历二叉树 非递归*/
template<class E>
void binaryTreeChains<E>::levelOrder(void (*theVisit)(binaryTreeNode<E>*))
{
    visit = theVisit;
    binaryTreeNode<E>* temp;
    queue<binaryTreeNode<E>*> que;
    que.push(root);
    while (!que.empty())
    {
        temp = que.front();
        que.pop();
        visit(temp);
        if (temp->leftChild != nullptr)
            que.push(temp->leftChild);
        if (temp->rightChild != nullptr)
            que.push(temp->rightChild);
    }
}
/*创建二叉树---递归---模板实现*/
template<class E>
void binaryTreeChains<E>::createBiTree(binaryTreeNode<E>*& tree)
{
    E data;
    cout << "Please enter the tree element:";
    while (!(cin >> data))
    {
        cin.clear();//清空标志位
        while (cin.get() != 'n')//删除无效输入
            continue;
        cout << "Please enter the tree element:";
    }
    cin.get();
    /*针对char类型的特例*/
    if (typeid(data) == typeid(char)) {
        if (data == '#')
            tree = nullptr;
        else {
            treeSize++;
            tree = new binaryTreeNode<E>(data);
            createBiTree(tree->leftChild);
            createBiTree(tree->rightChild);
        }
        /*关于二叉树对于设置信号放大器的应用我新定义了成员函数maketree()生成二叉树
            这里报错:C2228“.degradeFromParent”的左边必须有类/结构/联合
            我实在是不知道怎么改
        */
        //else if (typeid(data) == typeid(booster))
        //	if (data.degradeFromParent == 999)
        //		tree = nullptr;
        //	else
        //	{
        //		treeSize++;
        //		tree = new binaryTreeNode<E>(data);
        //		createBiTree(tree->leftChild);
        //		createBiTree(tree->rightChild);
        //	}
    }
    else/*针对其他类型*/{
        if (data == 999)
            tree = nullptr;//当遇到999时,令树的根节点为nullptr,从而结束该分支的递归
        else
        {
            treeSize++;
            tree = new binaryTreeNode<E>(data);
            createBiTree(tree->leftChild);
            createBiTree(tree->rightChild);
        }
    }
}
/*是一个手动创建二叉树的函数,使用本函数得手动设置各节点之间的关系,见信号放大器应用的使用*/
/*将左树和右树合并为一个树*/
template<class E>
void binaryTreeChains<E>::makeTree(const E& element, binaryTreeChains<E>& left, binaryTreeChains<E>& right)
{// Combine left, right, and element to make new tree.
    // left, right, and this must be different trees.
    // create combined tree
    root = new binaryTreeNode<E>(element, left.root, right.root);
    treeSize = left.treeSize + right.treeSize + 1;

    // deny access from trees left and right
    left.root = right.root = NULL;
    left.treeSize = right.treeSize = 0;
}

/*练习24:根据二叉树创建二叉树---用于复制构造函数*/
template<class E>
binaryTreeNode<E>* binaryTreeChains<E>::treeCreateTree(binaryTreeNode<E>*& node)
{
    binaryTreeNode<E>* head = nullptr;
    if (node != nullptr)
    {
        treeSize++;
//        cout << "node->element = " << node->element << endl;
        head = new binaryTreeNode<E>(node->element);
        head->leftChild = treeCreateTree(node->leftChild);
        head->rightChild = treeCreateTree(node->rightChild);
    }
    return head;
}

/*练习45:私有成员函数---用于比较二叉树compare()*/
template<class E>
bool binaryTreeChains<E>::compareTree(binaryTreeNode<E>* thisNode, binaryTreeNode<E>* xNode)
{
    /*两个结点都为空时,二叉树相等*/
    if (thisNode == nullptr && xNode == nullptr)
        return true;
    /*一个结点为空,一个结点非空,则二叉树不相等*/
    if ((thisNode == nullptr && xNode != nullptr) || (thisNode != nullptr && xNode == nullptr))
        return false;
    /*两个结点的元素不等,则二叉树不相等*/
    if (thisNode->element != xNode->element)
        return false;
    else/*两个结点相等,则比较彼此的左子树和右子树*/
        return compareTree(thisNode->leftChild, xNode->leftChild) && compareTree(thisNode->rightChild, xNode->rightChild);
}

/*练习46:私有成员函数---交换树的每个结点的左右子树---递归*/
template<class E>
void binaryTreeChains<E>::swapTrees(binaryTreeNode<E>*& node)
{
    if (node != nullptr)
    {
        swapTrees(node->leftChild);
        swapTrees(node->rightChild);
        binaryTreeNode<E>* temp = node->leftChild;
        node->leftChild = node->rightChild;
        node->rightChild = temp;
    }
}

/*练习27:私有成员函数---计算二叉树高度---返回根为node的树的高度*/
template<class E>
int binaryTreeChains<E>::height(binaryTreeNode<E>* node) const
{
    if (node == nullptr)
        return 0;
    int hl = height(node->leftChild);
    int hr = height(node ->rightChild);
    if (hl > hr)
        return ++hl;
    else
        return ++hr;
}

/*私有成员函数---计算结点node的左右子树高度的差值*/
template<class E>
int binaryTreeChains<E>::heightDifference(binaryTreeNode<E>* node) const
{
    if (node == nullptr)
        return 0;
    int lh = height(node->leftChild);
    int rh = height(node->rightChild);
//    cout << node->element << ":" << lh << endl;
//    cout << node->element << ":" << rh << endl;

    if (lh > rh)
        return lh - rh;
    else
        return rh - lh;
}

/*练习47:私有成员函数---计算二叉树的最大高度差---返回值为二叉树的最大高度差*/
template<class E>
int binaryTreeChains<E>::maxHeightDifference(binaryTreeNode<E>* node) const
{
    if (node == nullptr)
        return 0;
    int height = heightDifference(node);//当前结点的左右子树的高度差
    int hl = maxHeightDifference(node->leftChild);//当前结点的左子树的左右子树的高度差
    int hr = maxHeightDifference(node->rightChild);//当前结点的右子树的左右子树的高度差

    if (height >= hl && height >= hr)
        return height;
    else if (hl >= height && hl >= hr)
        return hl;
    else if (hr >= height && hr >= hl)
        return hr;
}

/*练习29:计算二叉树在那一层具有最多的结点---返回值为结点最多的层*/
/*当二叉树为空时,返回0*/
template<class E>
int binaryTreeChains<E>::layerMaxNumOfNode()
{
    if (root == nullptr)
        return 0;
    int num = 0;//累加每层的结点数
    int layer = 0;//记录当前的层数
    int maxNum = 0;//存储结点最多的层的结点个数
    int maxLayer = 0;//存储结点最多的层的层数
    binaryTreeNode<E>* lastNode = root;//存储上一层最后一个结点的元素位置
    binaryTreeNode<E>* nextNode = nullptr;//存储当前层最后一个结点的元素位置
    binaryTreeNode<E>* currentNode;
    queue<binaryTreeNode<E>*> que;
    que.push(root);
    while (!que.empty())
    {
        currentNode = que.front();
        que.pop();
        num++;
        if (currentNode->leftChild != nullptr)
        {
            que.push(currentNode->leftChild);
            nextNode = currentNode->leftChild;
        }
        if (currentNode->rightChild != nullptr)
        {
            que.push(currentNode->rightChild);
            nextNode = currentNode->rightChild;
        }
        if (currentNode == lastNode)
        {
            layer++;//刚刚处理完第几层
            lastNode = nextNode;
            nextNode = nullptr;
            if (num > maxNum)
            {
                maxNum = num;
                maxLayer = layer;
            }
            num = 0;
        }
    }
    return maxLayer;
}

/*计算二叉树在在哪一层具有最多的结点--返回值为结点最多的层的结点数量*/
/*当二叉树为空时,返回0*/
template<class E>
int binaryTreeChains<E>::maxNumOfNodeInLayer()
{
    if (root == nullptr)
        return 0;
    int num = 0;//累加每层的结点数
    int layer = 0;//记录当前的层数
    int maxNum = 0;//存储结点最多的层的结点个数
    int maxLayer = 0;//存储结点最多的层的层数
    binaryTreeNode<E>* lastNode = root;//存储上一层最后一个结点的元素位置
    binaryTreeNode<E>* nextNode = nullptr;//存储当前层最后一个结点的元素位置
    binaryTreeNode<E>* currentNode = nullptr;
    queue<binaryTreeNode<E>*> que;
    que.push(root);
    while (!que.empty())
    {
        currentNode = que.front();
        que.pop();
        num++;
        if (currentNode->leftChild != nullptr)
        {
            que.push(currentNode->leftChild);
            nextNode = currentNode->leftChild;
        }
        if (currentNode->rightChild != nullptr)
        {
            que.push(currentNode->rightChild);
            nextNode = currentNode->rightChild;
        }
        if (currentNode == lastNode)
        {
            layer++;//刚刚处理完第几层
            lastNode = nextNode;
            nextNode = nullptr;
            if (num > maxNum)
            {
                maxNum = num;
                maxLayer = layer;
            }
            num = 0;
        }
    }
    return maxNum;
}

/*使用前序和中序遍历构建二叉树*/
/*关键点在于找到根节点在中序中的位置,该位置之前为该根的左子树,该位置之后为该根的右子树*/
template<class E>
binaryTreeNode<E>* binaryTreeChains<E>::preInCreateTree(E preOrder[], E inOrder[], int size)
{
    /*如果没有左右子树,则返回nullptr*/
    if (size == 0)
        return nullptr;
    binaryTreeNode<E>*  rootData = new binaryTreeNode<E>(preOrder[0]);
    /*找到根节点的位置,中序中该位置左侧就是该根节点的左子树,该位置右侧就是该根节点的右子树*/
    int rootLoc = findRootLoc<E>(inOrder, preOrder[0] ,size);
    /*创建左子树和右子树*/
    rootData->leftChild = preInCreateTree(preOrder + 1, inOrder, rootLoc);
    rootData->rightChild = preInCreateTree(preOrder + 1 + rootLoc, inOrder + rootLoc + 1, size - 1 - rootLoc);
    return rootData;
}
/*使用后序和中序遍历构建二叉树*/
/*关键点在于找到根节点在中序中的位置,该位置之前为该根的左子树,该位置之后为该根的右子树*/
template<class E>
binaryTreeNode<E>* binaryTreeChains<E>::postInCreateTree(E postOrder[], E inOrder[], int size)
{
    /*如果没有左右子树,则返回nullptr*/
    if (size == 0)
        return nullptr;
    binaryTreeNode<E>* rootData = new binaryTreeNode<E>(postOrder[size-1]);
    /*找到根节点的位置,中序中该位置左侧就是该根节点的左子树,该位置右侧就是该根节点的右子树*/
    int rootLoc = findRootLoc<E>(inOrder, postOrder[size-1], size);
    /*创建左子树和右子树*/
    rootData->leftChild = postInCreateTree(postOrder, inOrder, rootLoc);
    rootData->rightChild = postInCreateTree(postOrder + rootLoc, inOrder + rootLoc + 1, size - 1 - rootLoc);
    return rootData;
}


/*二叉树表达式的成员函数*/
/*计算树的表达式的值*/
/*用字符串记录表达式*/
/*这个函数需要使用char类型的树,其他类型的二叉树不满足要求*/
template<class E>
int binaryTreeChains<E>::compulateTree(binaryTreeNode<E>* node) const
{
    if (node == nullptr)
        return 0;
    if (node->leftChild == nullptr && node->rightChild == nullptr) //左右子树都是nullptr时,说明它是叶子节点,而叶子结点就是数而非符号
        return node->element - '0';//就返回叶子结点
    int a = compulateTree(node->leftChild);//先计算左子树
    int b = compulateTree(node->rightChild);//再计算右子树
    switch (node->element)//当前结点不是叶子节点时,说明他是符号结点
    {
        case '+':
            return a + b;
        case '-':
            return a - b;
        case '*':
            return a * b;
        case '/':
            if (b != 0)
                return a / b;
            else
                throw illegalParameterValue("除数不能为0!");
    }
}

/*使用全部是二元操作符的前缀表达式创建二叉树*/
/*从尾元素开始遍历表达式的元素*/
/*如果是数据,则生成binaryTreeNode并入栈*/
/*如果不是数据,则生成binaryTreeNode,从栈中弹出两个数据形成其子树,第一个弹出的是其左子树,第二个弹出的是其右子树;然后再将当前结点入栈*/
template<class E>
binaryTreeNode<E>* binaryTreeChains<E>::preExprCreateTree(E expression[],int length)
{
    stack<binaryTreeNode<E>*> st;//用于存储已经处理数据生成的binaryTreeNode
    binaryTreeNode<E>* temp = nullptr;
    for (int i = length-1; i >= 0; i--)
    {
        /*如果是数据,则生成二叉树结点入栈*/
        if (expression[i] >= '0' && expression[i] <= '9')
        {
            temp = new binaryTreeNode<E>(expression[i]);
            st.push(temp);
        }
        else
        {
            temp = new binaryTreeNode<E>(expression[i]);
            temp->leftChild = st.top();
            st.pop();
            temp->rightChild = st.top();
            st.pop();
            st.push(temp);
        }
    }
    return temp;
}

/*使用全部是二元操作符的中缀表达式(包含括号以表明优先级)创建二叉树*/
/*如果是数据,则生成binaryTreeNode并入数据栈*/
/*
操作符处理规则:
	如果当前操作符优先级大于操作符栈的顶部元素,直接入操作符栈
	如果当前操作符优先级小于或等于操作符栈的顶部元素,先将顶部元素出操作符栈再将当前操作符入操作符栈
	当前操作符为左括号时直接入栈
	当前操作符为右括号时,让栈顶到左括号为止的操作符出操作符栈,括号不出现在后缀表达式中
出操作符栈时:生成当前符号的binaryTreeNode,其右子树为数据栈的栈顶元素,数据栈顶元素出栈,其左子树为数据栈当前的栈顶元素,数据栈顶元素出栈;
			  当前符号binaryTreeNode入数据栈。
*/
/*获取操作符优先级的getPriority()函数是一个非成员函数*/
template<class E>
binaryTreeNode<E>* binaryTreeChains<E>::inExprCreateTree(E expression[], int length)
{
    stack<binaryTreeNode<E>*> st;//用于存储已经处理的数据生成的binaryTreeNode
    stack<E> opStack;
    binaryTreeNode<E>* temp = nullptr;
    E data;
    for (int i = 0; i < length; i++)
    {
        data = expression[i];
        /*如果是数据,则生成二叉树结点入栈*/
        if (data >= '0' && data <= '9')
        {
            temp = new binaryTreeNode<E>(data);
            st.push(temp);
        }
        else
        {
            if (opStack.empty())
                opStack.push(data);
            else
                switch (data)
                {
                    case '(':opStack.push(data); break;//当遇到左括号时,直接将其入栈
                    case ')'://当遇到右括号时,让栈顶到左括号的操作符出栈
                        while (opStack.top() != '(')
                        {
                            temp = new binaryTreeNode<E>(opStack.top());
                            opStack.pop();
                            temp->rightChild = st.top();
                            st.pop();
                            temp->leftChild = st.top();
                            st.pop();
                            st.push(temp);
                        }
                        opStack.pop();//让(出栈
                        break;
                        /*当遇到+ - * /时,当其优先级大于栈顶元素时,入栈;否则,先将栈顶元素出栈,再将当前元素入栈*/
                    case '+':
                    case '-':
                    case '*':
                    case '/':
                        if (getPriority(data) > getPriority(opStack.top()))
                            opStack.push(data);
                        else
                        {
                            temp = new binaryTreeNode<E>(opStack.top());
                            opStack.pop();
                            temp->rightChild = st.top();
                            st.pop();
                            temp->leftChild = st.top();
                            st.pop();
                            st.push(temp);
                        }
                        break;
                    default:break;
                }
            /*当检查到中缀表达式的最后一个元素且栈非空时,将栈中的元素全部输出到后缀表达式*/
            if (!opStack.empty() && i == length - 1)
                while (!opStack.empty())
                {
                    temp = new binaryTreeNode<E>(opStack.top());
                    opStack.pop();
                    temp->rightChild = st.top();
                    st.pop();
                    temp->leftChild = st.top();
                    st.pop();
                    st.push(temp);
                }
        }
    }
    return temp;
}

/*使用全部是二元操作符的后缀表达式创建二叉树*/
/*从首元素开始遍历表达式的元素*/
/*如果是数据,则生成binaryTreeNode并入栈*/
/*如果不是数据,则生成binaryTreeNode,从栈中弹出两个数据形成其子树,第一个弹出的是其右子树,第二个弹出的是其左子树;然后再将当前结点入栈*/
template<class E>
binaryTreeNode<E>* binaryTreeChains<E>::postExprCreateTree(E expression[], int length)
{
    stack<binaryTreeNode<E>*> st;//用于存储已经处理的数据生成的binaryTreeNode
    binaryTreeNode<E>* temp = nullptr;
    for (int i = 0; i < length; i++)
    {
        /*如果是数据,则生成二叉树结点入栈*/
        if (expression[i] >= '0' && expression[i] <= '9')
        {
            temp = new binaryTreeNode<E>(expression[i]);
            st.push(temp);
        }
        else
        {
            temp = new binaryTreeNode<E>(expression[i]);
            temp->rightChild = st.top();
            st.pop();
            temp->leftChild = st.top();
            st.pop();
            st.push(temp);
        }
    }
    return temp;
}

#endif

_28binaryTreeChains.cpp

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月27日09点44分
Last Version:			V1.0
Descriptions:			用链表表示的二叉树.cpp
笔记:
	1.静态函数指针初始化格式:void (*binaryTreeChains<E>::visit)(binaryTreeNode<E>*) = 0;
	2.不能单独专门化成员模板函数,只能针对整个类专门化。
	3.在模板函数中可以使用typeid()区别对待特定数据类型。
本程序注意事项:
	1.所有关于前缀、后缀、中缀表达式的全部使用了char类型代表元素,char类型数组存储整个表达式
*/
#include "_2myFunctions.h"
#include "_28binaryTreeChains.h"
/*二叉树应用的全局变量*/
/*设置信号放大器*/
int tolerance = 3;//设置容忍值为3
/*并查集*/
treeUnionFindNode* node;

void binaryTreeChainsTest()
{
    cout << endl << "******************************binaryTreeChainsTest()函数开始**********************************" << endl;
    cout << endl << "测试成员函数*******************************************" << endl;
    cout << "输入****************************" << endl;
    cout << "默认构造函数********************" << endl;
    binaryTreeChains<int> a;
    a.input();
    cout << "a.preOrderOutput() = ";
    a.preOrderOutput();
    cout << "复制构造函数********************" << endl;
    binaryTreeChains<int> b(a);
    cout << "b.preOrderOutput() = ";
    b.preOrderOutput();
    cout << "前序中序构造函数****************" << endl;
    int preOrder[] = { 1, 2, 4, 5, 3,7, 6 };
    int inOrder[] = { 4, 2, 5, 1, 7, 3,6 };
    binaryTreeChains<int>e(preOrder, inOrder, 7,false);
    cout << "e.preOrderOutput() = ";
    e.preOrderOutput();
    cout << "e.inOrderOutput() = ";
    e.inOrderOutput();
    cout << "e.postOrderOutput() = ";
    e.postOrderOutput();
    cout << "后序中序构造函数****************" << endl;
    int postOrder[] = { 4,5,2,7,6,3,1 };
    binaryTreeChains<int>f(postOrder, inOrder, 7,true);
    cout << "f.preOrderOutput() = ";
    f.preOrderOutput();
    cout << "f.inOrderOutput() = ";
    f.inOrderOutput();
    cout << "f.postOrderOutput() = ";
    f.postOrderOutput();
    cout << "输出****************************" << endl;
    cout << "前序输出************************" << endl;
    cout << "a.preOrderOutput() = ";
    a.preOrderOutput();
    cout << "b.preOrderOutput() = ";
    b.preOrderOutput();
    //迭代函数遍历
    cout << "a.iterativePreOrder() = ";
    vector<int> result = a.iterativePreOrder();
    vector<int>::iterator ite;
    ite = result.begin();
    for (; ite != result.end(); ite++) {
        cout << *ite << " ";
    }
    cout << endl;
    cout << "中序输出************************" << endl;
    //递归遍历
    cout << "a.inOrderOutput() = ";
    a.inOrderOutput();
    cout << "b.inOrderOutput() = ";
    b.inOrderOutput();
    //迭代函数遍历
    cout << "a.iterativeInOrder() = ";
    result = a.iterativeInOrder();
    ite = result.begin();
    for (; ite != result.end(); ite++) {
    	cout << *ite << " ";
    }
    cout << endl;
    cout << "后序输出************************" << endl;
    cout << "a.postOrderOutput() = ";
    a.postOrderOutput();
    cout << "b.postOrderOutput() = ";
    b.postOrderOutput();
    //迭代函数遍历
    cout << "a.iterativePostOrder() = ";
    result = a.iterativePostOrder();
    ite = result.begin();
    for (; ite != result.end(); ite++) {
    	cout << *ite << " ";
    }
    cout << endl;
    cout << "层序输出************************" << endl;
    cout << "a.levelOrderOutput() = ";
    a.levelOrderOutput();
    cout << "b.levelOrderOutput() = ";
    b.levelOrderOutput();
    cout << endl;
    cout << "empty()*************************" << endl;
    cout << "a.empty() = " << a.empty() << endl;
    cout << "b.empty() = " << b.empty() << endl;
    cout << "size()**************************" << endl;
    cout << "a.size() = " << a.size() << endl;
    cout << "b.size() = " << b.size() << endl;
    cout << "compare()***********************" << endl;
    cout << "a.compare(b) = " << a.compare(b) << endl;
    binaryTreeChains<int> c;
    c.input();
    cout << "a.compare(c) = " << a.compare(c) << endl;
    cout << "swapTrees()*********************" << endl;
    cout << "a.preOrderOutput() = ";
    a.preOrderOutput();
    a.swapTrees();
    cout << "a.preOrderOutput() = ";
    a.preOrderOutput();
    cout << "height()************************" << endl;
    cout << "a.height() = " << a.height() << endl;
    cout << "maxHeightDifference()***********" << endl;
    cout << "a.maxHeightDifference() = " << a.maxHeightDifference() << endl;
    cout << "layerMaxNumOfNode()*************" << endl;
    cout << "a.layerMaxNumOfNode() = " << a.layerMaxNumOfNode() << endl;
    cout << "maxNumOfNodeInLayer()***********" << endl;
    cout << "a.maxNumOfNodeInLayer() = " << a.maxNumOfNodeInLayer() << endl;

    cout << "******************************binaryTreeChainsTest()函数结束**********************************" << endl;


}

void treeExpressionsTest()
{
    cout << endl << "*******************************treeExpressionTest()函数开始***********************************" << endl;
    cout << endl << "二叉树表达式测试***************************************" << endl;
    /*使用前缀表达式创建二叉树*/
    cout << "前缀表达式构造函数**************" << endl;
    char preExpression[] = { '/','+','-','1','2','+','3','4','*','+','5','6','*','7','8'};
    binaryTreeChains<char>g(preExpression, 15, 1);
    cout << "g.preOrderOutput() = ";
    g.preOrderOutput();
    cout << "g.inOrderOutput() = ";
    g.inOrderOutput();
    cout << "g.postOrderOutput() = ";
    g.postOrderOutput();
    /*使用中缀表达式创建二叉树*/
    cout << "中缀表达式构造函数**************" << endl;
    char inExpression[] = { '(','(','1','-','2',')','+','(','3','+','4',')',')','/','(','(','5','+','6',')','*','(','7','*','8',')',')' };
    /*这里的长度11是包含括号的长度*/
    binaryTreeChains<char>i(inExpression, 27, 2);
    cout << "i.preOrderOutput() = ";
    i.preOrderOutput();
    cout << "i.inOrderOutput() = ";
    i.inOrderOutput();
    cout << "i.postOrderOutput() = ";
    i.postOrderOutput();
    /*使用后缀表达式创建二叉树*/
    cout << "后缀表达式构造函数**************" << endl;
    char postExpression[] = { '1','2','-','3','4','+','+','5','6','+','7','8','*','*','/'};
    binaryTreeChains<char>h(postExpression, 15, 3);
    cout << "h.preOrderOutput() = ";
    h.preOrderOutput();
    cout << "h.inOrderOutput() = ";
    h.inOrderOutput();
    cout << "h.postOrderOutput() = ";
    h.postOrderOutput();
    /*计算树表达式的值*/
    cout << "计算树表达式的值****************" << endl;
    cout << "compulateTree()*****************" << endl;
    binaryTreeChains<char> d;
    d.input();
    cout << "d.preOrderOutput() = ";
    d.preOrderOutput();
    cout << "d.compulateTree() = " << d.compulateTree() << endl;
    /*将后缀表达式转换为中缀表达式*/
    cout << "将后缀表达式转换为中缀表达式****" << endl;
    cout << "postExprToIn()******************" << endl;
    char postExpr1[9] = { '1','2','3','+','4','*','5','-','+' };
    string inExpr1;
    postExprToIn(postExpr1, inExpr1, 9);
    cout << "postExpr1[9] = ";
    traverse1dArray<char>(postExpr1, 9);
    cout << "inExpr1 = " << inExpr1 << endl;
    /*将前缀表达式转换为中缀表达式*/
    cout << "将前缀表达式转换为中缀表达式****" << endl;
    cout << "preExprToIn()*******************" << endl;
    char preExpr1[9] = { '+','1','-','*','+','2','3','4','5' };
    string inExpr2;
    preExprToIn(preExpr1, inExpr2, 9);
    cout << "preExpr1[9] = ";
    traverse1dArray<char>(preExpr1, 9);
    cout << "inExpr1 = " << inExpr2 << endl;
    /*将中缀表达式转换为后缀表达式,需要注意的是,一定要使用括号标出优先级*/
    cout << "将中缀表达式转换为后缀表达式****" << endl;
    cout << "inExprToPost()******************" << endl;
    char inExpr[25] = { '(','(','-','1',')','+','(','2','+','3',')',')','/','(','(','+','4',')','*','(','5','*','6',')',')' };
    char postExpr[13];//这里的长度13是后缀表达式的长度
    inExprToPost(inExpr, postExpr, 25);//这里的长度25是带有括号的中缀表达式的长度
    cout << "inExpr[25] = ";
    traverse1dArray<char>(inExpr, 25);
    cout << "postExpr[13] = ";
    traverse1dArray<char>(postExpr, 13);
    cout << "将中缀表达式转换为前缀表达式****" << endl;
    /*将中缀表达式转换为前缀表达式,需要注意的是,一定要使用括号标出优先级*/
    cout << "inExprToPre()******************" << endl;
    char preExpr[13];//这里的长度13是前缀表达式的长度
    inExprToPre(inExpr, preExpr, 25,13);//这里的长度25是带有括号的中缀表达式的长度
    cout << "inExpr[25] = ";
    traverse1dArray<char>(inExpr, 25);
    cout << "preExpr[13] = ";
    traverse1dArray<char>(preExpr, 13);

    /*计算表达式的值*/
    /*计算前缀表达式的值*/
    cout << "计算前缀表达式的值**************" << endl;
    cout << "preCalculate()******************" << endl;
    char preExpr2[9] = { '+','1','-','*','+','2','3','4','5' };
    int result = preCalculate(preExpr2, 9);
    cout << "result = " << result << endl;
    /*计算中缀表达式的值*/
    cout << "计算中缀表达式的值**************" << endl;
    cout << "inCalculate()******************" << endl;
    char inExpr3[17] = {'(','1','+','(','(','(','2','+','3',')','*','4',')','-','5',')',')'};
    result = inCalculate(inExpr3, 17);
    cout << "result = " << result << endl;
    char inExpr4[27] = { '(','(','5','-','2',')','+','(','3','+','4',')',')','/','(' ,'(','1','+','1',')','*','(','1','*','1',')',')' };
    result = inCalculate(inExpr4, 27);
    cout << "result = " << result << endl;
    /*练习43:计算后缀表达式的值*/
    cout << "计算后缀表达式的值**************" << endl;
    cout << "postCalculate()*****************" << endl;
    char postExpr2[9] = { '1','2','3','+','4','*','5','-','+' };
    result = postCalculate(postExpr2, 9);
    cout << "result = " << result << endl;
    cout << "*******************************treeExpressionTest()函数结束***********************************" << endl;
}

void treeApplicationTest()
{
    cout << endl << "******************************treeApplicationTest()函数开始***********************************" << endl;
    cout << endl << "二叉树应用测试*****************************************" << endl;
    cout << "设置信号放大器******************" << endl;
    booster a, b;
    /*输入*/
    cin >> a;// 这里输入0和1
    cin >> b;// 这里输入0和2
    binaryTreeChains<booster> t, u, v, w, x, y;
    u.makeTree(a, x, x);
    v.makeTree(b, u, x);
    u.makeTree(a, x, x);
    w.makeTree(a, u, x);
    b.degradeFromParent = 3;
    u.makeTree(b, v, w);
    v.makeTree(a, x, x);
    b.degradeFromParent = 3;
    w.makeTree(b, x, x);
    y.makeTree(a, v, w);
    w.makeTree(a, x, x);
    t.makeTree(b, y, w);
    b.degradeFromParent = 0;
    v.makeTree(b, t, u);
    v.postOrder(placeBoosters);
    v.postOrderOutput();
    v.preOrderOutput();
    v.inOrderOutput();
    cout << "并查集**************************" << endl;
    initialize(10);
    unite(1, 2);
    unite(3, 4);
    unite(1, 3);
    cout << "find(1) = " << find(1) << " find(2) = " << find(2) << endl;
    cout << "find(3) = " << find(3) << " find(4) = " << find(4) << endl;
    cout << "find(5) = " << find(5) << " find(6) = " << find(6) << endl;
    cout << "******************************treeApplicationTest()函数结束***********************************" << endl;
}

/*非成员函数*/
/*返回元素data在数组中的位置,找到则返回该元素的位置,未找到则返回-1*/
template<class E>
int findRootLoc(E list[], E data, int length)
{
    for (int i = 0; i < length; i++)
    {
        if (list[i] == data)
            return i;
    }
    return -1;
}
/*获取优先级---inExprToPost中使用*/
int getPriority(char op)
{
    switch (op)
    {
        case '+':return 1;
        case '-':return 1;
        case '*':return 2;
        case '/':return 2;
        case'(':return 0;
        case ')':return 0;//右括号的优先级是0
        default:break;
    }
}
/*练习38:将后缀表达式转换为完全括号化的中缀表达式 完全括号化的中缀表达式如((a)+(b))*/
/*参数说明:postExpr是后缀表达式数组的指针,inExpr用于存储生成的前缀表达式,length是后缀表达式的长度*/
void postExprToIn(char postExpr[], string& inExpr, int length)
{
    inExpr.clear();
    stack<string> st;/*用于存储中间结果*/
    string a, b, c;
    char data;
    for (int i = 0; i < length; i++)
    {
        data = postExpr[i];
        /*当遇到数字时,直接入栈*/
        if (data >= '0' && data <= '9')
            st.push({ data,'' });
        else
        {
            /*每执行一次计算就添加括号,每个数据都加括号实在不需要,看起来很冗余*/
            b = st.top() + '';
            st.pop();
            a = st.top() + '';
            st.pop();
            c = '(' + a + data + b + ')';
            st.push(c);
        }
    }
    if (st.size() == 1)
        inExpr = st.top();
    else
        inExpr = "后缀表达式非法,转换失败!";
}
/*练习40:将中缀表达式转换为后缀表达式*/
/*条件:必须要包含括号---用于区分优先级*/
/*操作数处理规则:因为操作数的顺序在中缀、前缀、后缀表达式中是一样的,所以在从中缀向前缀或后缀转换时,仅需要从左到右扫描中缀表达式*/
/*
操作符处理规则:
	如果当前操作符优先级大于操作符栈的顶部元素,直接入栈
	如果当前操作符优先级小于或等于操作符栈的顶部元素,先将顶部元素出栈再将当前操作符入栈
	当前操作符为左括号时直接入栈
	当前操作符为右括号时,让栈顶到左括号为止的操作符出栈,括号不出现在后缀表达式中
*/
/*把扫描到的操作数直接输出,而遇到的操作符保留在栈中,根据操作符和左括号的优先级来确定输出*/
/*+-的优先级为1,*和/的优先级为2,栈外左括号的优先级为3,栈内左括号的优先级为0*/
/*返回后缀表达式---使用postExpr[]数组返回*/
/*参数说明:inExpr为指向中缀表达式的指针,postExpr为指向生成的后序表达式的指针,length表示中缀表达式的长度*/
void inExprToPost(char inExpr[], char postExpr[], int length)
{
    int postLoc = 0;//记录后缀表达式的当前位置
    char data = 0;//记录读取的前缀表达式的元素
    stack<char> opStack;//用于存储中间过程的符号
    /*顺序访问中缀表达式*/
    for (int i = 0; i < length; i++)
    {
        data = inExpr[i];
        /*当遇到数字时,直接将其存储到后缀表达式中*/
        if (data >= '0' && data <= '9')
        {
            postExpr[postLoc] = data;
            postLoc++;//后缀表达式存储一个值,当前位置+1
        }
        else/*当遇到的是符号时*/
        {
            if (opStack.empty())
                opStack.push(data);
            else
                switch (data)
                {
                    case '(':opStack.push('('); break;//当遇到左括号时,直接将其入栈
                    case ')'://当遇到右括号时,让栈顶到左括号的操作符出栈
                        while (opStack.top() != '(')
                        {
                            postExpr[postLoc] = opStack.top();
                            postLoc++;
                            opStack.pop();
                        }
                        opStack.pop();//让(出栈
                        break;
                        /*当遇到+ - * /时,当其优先级大于栈顶元素时,入栈;否则,先将栈顶元素出栈,再将当前元素入栈*/
                    case '+':
                    case '-':
                    case '*':
                    case '/':
                        if (getPriority(data) > getPriority(opStack.top()))
                            opStack.push(data);
                        else
                        {
                            postExpr[postLoc] = opStack.top();
                            postLoc++;
                            opStack.pop();
                            opStack.push(data);
                        }
                        break;
                    default:break;
                }
            /*当检查到中缀表达式的最后一个元素且栈非空时,将栈中的元素全部输出到后缀表达式*/
            if (!opStack.empty() && i == length - 1)
                while (!opStack.empty())
                {
                    postExpr[postLoc] = opStack.top();
                    postLoc++;
                    opStack.pop();
                }
        }
    }
}
/*练习41:将中缀表达式转换为前缀表达式---从后往前归入前缀表达式*/
/*
首先设定一个操作符栈,从右到左顺序扫描整个中缀表达式,如果是操作数,则直接归入前缀表达式;
如果是操作符:
	1.如果是右括号,则直接将其入栈;
	2.如果是左括号,则将操作符栈中的操作符依次弹栈,归入前缀表达式,直至遇到右括号,将右括号弹栈,处理结束;
	3.如果是其他操作符,如果栈顶操作符优先级大于当前操作符的优先级,则弹栈,并归入前缀表达式,
	直至栈顶操作符优先级小于等于当前操作符优先级,这时将当前操作符压栈。
*/
/*参数说明:inExpr为指向中缀表达式的指针,preExpr为指向生成的后序表达式数组的指针,inLength表示中缀表达式的长度,preLength表示前缀表达式的长度*/
void inExprToPre(char inExpr[], char preExpr[], int inLength, int preLength)
{
    int postLoc = preLength - 1;//记录前缀表达式的当前位置
    char data = 0;//记录读取的中缀表达式的元素
    stack<char> opStack;//用于存储中间过程的符号
    /*顺序访问中缀表达式*/
    for (int i = inLength - 1; i >= 0; i--)
    {
        data = inExpr[i];
        /*当遇到数字时,直接将其存储到前缀表达式中*/
        if (data >= '0' && data <= '9')
        {
            preExpr[postLoc] = data;
            postLoc--;//前缀表达式存储一个值,当前位置-1
        }
        else/*当遇到的是符号时*/
        {
            /*当操作符栈为空时,直接将当前操作符入栈*/
            if (opStack.empty())
                opStack.push(data);
            else
                switch (data)
                {
                    case ')':opStack.push(')'); break;//当遇到右括号时,直接将其入栈
                    case '('://当遇到左括号时,让栈顶到右括号的操作符出栈
                        while (opStack.top() != ')')
                        {
                            preExpr[postLoc] = opStack.top();
                            postLoc--;
                            opStack.pop();
                        }
                        opStack.pop();//让')'出栈
                        break;
                        /*当遇到+ - * /时,当栈顶元素优先级大于当前操作符优先级时,入栈;
                        否则,将栈顶元素出栈,出栈直到当前操作符优先级大于栈顶元素优先级,最后将当前元素入栈*/
                    case '+':
                    case '-':
                    case '*':
                    case '/':
                        while (getPriority(opStack.top()) > getPriority(data))/*栈顶元素操作符优先级大于当前操作符优先级,就出栈*/
                        {
                            preExpr[postLoc] = opStack.top();
                            postLoc--;
                            opStack.pop();
                        }
                        opStack.push(data);/*直到上述条件不成立,就入栈*/
                        break;
                    default:break;
                }
            /*当检查到中缀表达式的最后一个元素且栈非空时,将栈中的元素全部输出到前缀表达式*/
            if (!opStack.empty() && i == 0)
                while (!opStack.empty())
                {
                    preExpr[postLoc] = opStack.top();
                    postLoc--;
                    opStack.pop();
                }
        }
    }
}

/*练习39:将前缀表达式转换为带括号的中缀表达式 如((a+b)+(c*d))*/
/*参数说明:postExpr是后缀表达式数组的指针,inExpr用于存储生成的前缀表达式,length是后缀表达式的长度*/
void preExprToIn(char preExpr[], string& inExpr, int length)
{
    inExpr.clear();
    stack<string> st;/*用于存储中间结果*/
    string a, b, c;
    char data;
    for (int i = length-1; i >= 0; i--)
    {
        data = preExpr[i];
        /*当遇到数字时,直接入栈*/
        if (data >= '0' && data <= '9')
            st.push({ data,'' });
        else
        {
            /*每执行一次计算就添加括号,每个数据都加括号实在不需要,看起来很冗余*/
            a = st.top() + '';
            st.pop();
            b = st.top() + '';
            st.pop();
            c = '(' + a + data + b + ')';
            st.push(c);
        }
    }
    if (st.size() == 1)
        inExpr = st.top();
    else
        inExpr = "后缀表达式非法,转换失败!";
}

/*计算表达式的值*/
/*前缀表达式计算表达式的值*/
/*参数说明:preExpr表示指向前缀表达式数组的指针,length表示前缀表达式的长度;返回值为计算的结果*/
int preCalculate(char preExpr[], int length)
{
    stack<int> st;/*用于存储中间结果*/
    char data;
    int a, b;
    for (int i = length - 1; i >= 0; i--)
    {
        data = preExpr[i];
        /*当遇到数字时,直接入栈*/
        if (data >= '0' && data <= '9')
            st.push(data-'0');
        else
        {
            switch (data)//当前结点不是叶子节点时,说明他是符号结点
            {
                case '+':
                    a = st.top();
                    st.pop();
                    b = st.top();
                    st.pop();
                    st.push(a + b);
                    break;
                case '-':
                    a = st.top();
                    st.pop();
                    b = st.top();
                    st.pop();
                    st.push(a - b);
                    break;
                case '*':
                    a = st.top();
                    st.pop();
                    b = st.top();
                    st.pop();
                    st.push(a * b);
                    break;
                case '/':
                    a = st.top();
                    st.pop();
                    b = st.top();
                    st.pop();
                    if (b != 0)
                        st.push(a / b);
                    else
                        throw illegalParameterValue("除数不能为0!");
                    break;
                default:break;
            }
        }
    }
    if (st.size() == 1)
        return st.top();
    else
        cout << "前缀表达式非法,计算失败!" << endl;
    return 0;
}
/*针对不同的操作符,执行不同的运算*/
/*参数说明:op即为操作符,a是左操作数,b是右操作数;返回值为运算的结果*/
int calculate(char op, int a, int b)
{
    switch (op)
    {
        case '+':return a + b;
        case '-':return a - b;
        case '*':return a * b;
        case '/':
            if (b == 0)
                throw illegalParameterValue("除数不能为0!");
            else
                return a / b;
    }
}
/*中缀表达式计算表达式的值*/
/*参数说明:inExpr表示指向中缀表达式数组的指针,length表示中缀表达式的长度;返回值为计算的结果*/
int inCalculate(char inExpr[], int length)
{
    stack<int> st;/*用于存储中间结果*/
    stack<char> opStack;/*用于存储操作符*/
    char data;
    int a, b;
    for (int i = 0; i < length; i++)
    {
        data = inExpr[i];
        /*如果是数据,则生成二叉树结点入栈*/
        if (data >= '0' && data <= '9')
            st.push(data - '0');
        else
        {
            if (opStack.empty())
                opStack.push(data);
            else
                switch (data)
                {
                    case '(':opStack.push(data); break;//当遇到左括号时,直接将其入栈
                    case ')'://当遇到右括号时,让栈顶到左括号的操作符出栈
                        while (opStack.top() != '(')
                        {
                            /*获取数据*/
                            b = st.top();
                            st.pop();
                            a = st.top();
                            st.pop();
                            /*获取符号*/
                            data = opStack.top();
                            opStack.pop();
                            /*计算结果并入栈*/
                            st.push(calculate(data, a, b));
                        }
                        opStack.pop();//让(出栈
                        break;
                        /*当遇到+ - * /时,当其优先级大于栈顶元素时,入栈;否则,先将栈顶元素出栈,再将当前元素入栈*/
                    case '+':
                    case '-':
                    case '*':
                    case '/':
                        if (getPriority(data) > getPriority(opStack.top()))
                            opStack.push(data);
                        else
                        {
                            b = st.top();
                            st.pop();
                            a = st.top();
                            st.pop();
                            st.push(calculate(data, a, b));
                        }
                        break;
                    default:break;
                }
        }
        /*当检查到中缀表达式的最后一个元素且栈非空时,将操作符栈中的元素弹出并计算运算的值*/
        if (!opStack.empty() && i == length - 1)
            while (!opStack.empty())
            {
                /*获取数据*/
                b = st.top();
                st.pop();
                a = st.top();
                st.pop();
                /*获取符号*/
                data = opStack.top();
                opStack.pop();
                /*计算结果并入栈*/
                st.push(calculate(data, a, b));
            }
    }
    return st.top();
}
/*练习43:后缀表达式计算表达式的值*/
/*参数说明:postExpr表示指向后缀表达式数组的指针,length表示后缀表达式的长度;返回值为计算的结果*/
int postCalculate(char postExpr[], int length)
{
    stack<int> st;/*用于存储中间结果*/
    char data;
    int a, b;
    for (int i = 0; i < length; i++)
    {
        data = postExpr[i];
        /*当遇到数字时,直接入栈*/
        if (data >= '0' && data <= '9')
            st.push(data - '0');
        else
        {
            switch (data)//当前结点不是叶子节点时,说明他是符号结点
            {
                case '+':
                    b = st.top();
                    st.pop();
                    a = st.top();
                    st.pop();
                    st.push(a + b);
                    break;
                case '-':
                    b = st.top();
                    st.pop();
                    a = st.top();
                    st.pop();
                    st.push(a - b);
                    break;
                case '*':
                    b = st.top();
                    st.pop();
                    a = st.top();
                    st.pop();
                    st.push(a * b);
                    break;
                case '/':
                    b = st.top();
                    st.pop();
                    a = st.top();
                    st.pop();
                    if (b != 0)
                        st.push(a / b);
                    else
                        throw illegalParameterValue("除数不能为0!");
                    break;
                default:break;
            }
        }
    }
    if (st.size() == 1)
        return st.top();
    else
        cout << "后缀表达式非法,计算失败!" << endl;
    return 0;
}

/*二叉树的应用---设置信号放大器*/
void placeBoosters(binaryTreeNode<booster>* x)
{//计算节点x的衰减值,如果衰减值超过容忍值,则放置放大器
    x->element.degradeToLeaf = 0;  //初始化节点x的 到叶子节点的衰减值为0
    //计算x的左子树的衰减值,根据需求放置放大器

    //为什么在设置左右子树到叶子的衰减值时方法不一样,原因是在设置左子树时没有管其右子树到叶子的衰减值是否更大;
    //但是呢每个根节点都有左子树和右子树,该根节点到叶子的衰减值设置为左右子树的最大衰减值;因此在设置右子树时
    //就必须考虑左子树到叶子的衰减是否大于右子树
    binaryTreeNode<booster>* y = x->leftChild;
    if (y != nullptr)
    {//如果x的左子树为空,则不管
        //计算x到叶子节点的衰减值
        int degradation = y->element.degradeToLeaf + y->element.degradeFromParent;
        //如果衰减值大于容忍值
        if (degradation > tolerance)
        {//则在x的左子树放置放大器
            y->element.boosterHere = true;
            x->element.degradeToLeaf = y->element.degradeFromParent;
        }
        else  //不需要放大器
            x->element.degradeToLeaf = degradation;//将x到叶子节点的衰减值设置为degradation
    }

    //计算节点x的衰减值,如果衰减值超过容忍值,则放置放大器
    y = x->rightChild;
    if (y != nullptr)
    {	//当x的右子树不为空时
        int degradation = y->element.degradeToLeaf + y->element.degradeFromParent;
        if (degradation > tolerance)
        {//在x的右子树放置放大器
            y->element.boosterHere = true;
            degradation = y->element.degradeFromParent;
        }
        if (x->element.degradeToLeaf < degradation)
            x->element.degradeToLeaf = degradation;
    }
}

/*二叉树的应用---并查集*/
void initialize(int numberOfElements)
{//初始化numberOfElements个树,每个树都是一个元素
    node = new treeUnionFindNode[numberOfElements + 1];
}

int find(int theElement)
{
    //返回元素theElement所在树的根
    while (!node[theElement].root)//只要节点的root不为true,就一直找他的父节点
        theElement = node[theElement].parent;  // move up one level
    return theElement;
}
/*rootA和rootB是索引*/
void unite(int rootA, int rootB)
{
    //使用重量规则,合并其根不同的树
    //重量大的作为根节点
    if (node[rootA].parent < node[rootB].parent)
    {
        node[rootB].parent += node[rootA].parent;
        node[rootA].parent = rootB;
        node[rootA].root = false;
    }
    else
    {
        node[rootA].parent += node[rootB].parent;
        node[rootB].parent = rootA;
        node[rootB].root = false;
    }
}

_28binaryTreeNode.h

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月27日09点44分
Last Version:			V1.0
Descriptions:			二叉树的结点结构体
*/
#pragma once
#ifndef _BINARYTREENODE_H_
#define _BINARYTREENODE_H_
template<class T>
struct binaryTreeNode
{
    T element;
    binaryTreeNode<T>* leftChild,//左子树
    *rightChild;//右子树
    /*默认构造函数*/
    binaryTreeNode() { leftChild = rightChild = nullptr; }
    /*只初始化element*/
    binaryTreeNode(T melement)
    {
        element = melement;
        leftChild = rightChild = nullptr;
    }
    /*三个元素都初始化*/
    binaryTreeNode(T melement, binaryTreeNode<T>* mleftChild, binaryTreeNode<T>* mrightChild)
    {
        element = melement;
        leftChild = mleftChild;
        rightChild = mrightChild;
    }
};

#endif

_28binaryTree.h

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月27日09点43分
Last Version:			V1.0
Descriptions:			二叉树的抽象类
*/
#pragma once
#ifndef _BINARYTREE_H_
#define _BINARYTREE_H_
template<class T>
class binaryTree
{
public:
    virtual ~binaryTree() {}
    virtual bool empty() const = 0;
    virtual int size() const = 0;
    virtual void preOrder(void (*)(T*)) = 0;
    virtual void inOrder(void (*)(T*)) = 0;
    virtual void postOrder(void (*)(T*)) = 0;
    virtual void levelOrder(void (*)(T*)) = 0;
};
#endif

_28booster.h

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年9月17日10点47分
Last Version:			V1.0
Descriptions:			二叉树的应用 设置信号放大器 节点结构体
*/
#pragma once
#ifndef _BOOSTER_H_
#define _BOOSTER_H_
#include <iostream>
using namespace std;

struct booster
{
    int degradeToLeaf,           //到叶子结点的衰减
    degradeFromParent;       //父节点到该节点的衰减
    bool boosterHere;            //是否在此节点放置放大器
    /*重载<<操作符*/
    friend ostream& operator<<(ostream& out, booster& m)
    {
        out << m.boosterHere << ' ' << m.degradeToLeaf << ' ' << m.degradeFromParent << ' ';
        return out;
    }
    /*重载>>操作符*/
    friend istream& operator>>(istream& in, booster& m)
    {
        cout << "Please enter the degradeToLeaf:";
        while (!(in >> m.degradeToLeaf))
        {
            in.clear();//清空标志位
            while (in.get() != 'n')//删除无效的输入
                continue;
            cout << "Please enter the degradeToLeaf:";
        }
        cout << "Please enter the degradeFromParent:";
        while (!(in >> m.degradeFromParent))
        {
            in.clear();//清空标志位
            while (in.get() != 'n')//删除无效的输入
                continue;
            cout << "Please enter the degradeFromParent:";
        }
        m.boosterHere = 0;
        return in;
    }
};
#endif

_28treeUnionFindNode.h

#pragma once
#ifndef _TREEUNIONFINDNODE_H_
#define _TREEUNIONFINDNODE_H_
/*
注意事项:
1.当且仅当一个节点是当前根节点时,他的root域为true;
2.每个根节点的parent域用来记录该树的节点总数

规则
1.重量规则
    若根为i的树的节点数少于根为j的树的节点数,则将j作为i的父节点;否则,将i作为j的父节点。
2.高度规则
    若根为i的树的高度小于根为j的树的高度,则将j作为i的父节点;否则,将i作为j的父节点。
*/
struct treeUnionFindNode
{
    int parent;  // if true then tree weight
    // otherwise pointer to parent in tree
    bool root;   // true iff root

    treeUnionFindNode()
    {
        parent = 1; root = true;
    }
};
#endif

_1myExceptions.h

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月13日17点38分
Last Version:			V1.0
Descriptions:			综合各种异常
*/
#pragma once
#ifndef _MYEXCEPTIONS_H_
#define _MYEXCEPTIONS_H_
#include <string>
#include<iostream>

using namespace std;

// illegal parameter value
class illegalParameterValue
{
public:
    illegalParameterValue(string theMessage = "Illegal parameter value")
    {message = theMessage;}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// illegal input data
class illegalInputData
{
public:
    illegalInputData(string theMessage = "Illegal data input")
    {message = theMessage;}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// illegal index
class illegalIndex
{
public:
    illegalIndex(string theMessage = "Illegal index")
    {message = theMessage;}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// matrix index out of bounds
class matrixIndexOutOfBounds
{
public:
    matrixIndexOutOfBounds
            (string theMessage = "Matrix index out of bounds")
    {message = theMessage;}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// matrix size mismatch
class matrixSizeMismatch
{
public:
    matrixSizeMismatch(string theMessage =
    "The size of the two matrics doesn't match")
    {message = theMessage;}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// stack is empty
class stackEmpty
{
public:
    stackEmpty(string theMessage =
    "Invalid operation on empty stack")
    {message = theMessage;}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// queue is empty
class queueEmpty
{
public:
    queueEmpty(string theMessage =
    "Invalid operation on empty queue")
    {message = theMessage;}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// hash table is full
class hashTableFull
{
public:
    hashTableFull(string theMessage =
    "The hash table is full")
    {message = theMessage;}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// edge weight undefined
class undefinedEdgeWeight
{
public:
    undefinedEdgeWeight(string theMessage =
    "No edge weights defined")
    {message = theMessage;}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};

// method undefined
class undefinedMethod
{
public:
    undefinedMethod(string theMessage =
    "This method is undefined")
    {message = theMessage;}
    void outputMessage() {cout << message << endl;}
private:
    string message;
};
#endif

_2myFunctions.h

/*
Project name :			allAlgorithmsTest
Last modified Date:		2022年8月13日17点38分
Last Version:			V1.0
Descriptions:			综合各种非成员函数
*/
#pragma once
#ifndef _MYFUNCTIONS_H_
#define _MYFUNCTIONS_H_
#include<iostream>
#include "_1myExceptions.h"
#include<cmath>
#include <exception>
using std::min;
using std::endl;
using std::cout;
using std::bad_alloc;
/*交换两数据*/
template<class V>
void Swap(V& a, V& b)
{
    V temp = a;
    a = b;
    b = temp;
}
/*
作用:将数组的长度加倍
输入:指针a指向需要改变长度的数组,oldLength表示数组原来的长度,newLength表示需要改变的新长度
结果:将数组扩容/缩容 为newLength
*/
template<class T>
void changeLength(T*& a, int oldLength, int newLength)
{
    if (newLength < 0)
        throw illegalParameterValue("new length must be >= 0");
    T* temp = new T[newLength];
    int number = min(oldLength, newLength);
    copy(a, a + number, temp);
    delete[] a;
    a = temp;
}
/*遍历一维数组*/
template<class T>
void traverse1dArray(T* x, int length)
{
    for (int i = 0; i < length; i++)
        cout << x[i] << " ";
    cout << endl;
}
/*创建二维数组*/
template <class T>
bool make2dArray(T**& x, int numberOfRows, int numberOfColumns)
{
    try {
        //行指针
        x = new T * [numberOfRows];
        //为每一行分配内存
        for (int i = 0; i < numberOfRows; i++)
            x[i] = new int[numberOfColumns];
        return true;
    }
    catch (bad_alloc) { return false; }
}

/*遍历二维数组*/
template<class T>
void traverse2dArray(T**& x, int numberOfRows, int numberOfColumns)
{
    for (int i = 0; i < numberOfRows; i++)
    {
        for (int j = 0; j < numberOfColumns; j++)
        {
            cout.width(4);
            cout << x[i][j] << "  ";
        }
        cout << endl;
    }
}
#endif

运行结果

******************************binaryTreeChainsTest()函数开始**********************************

测试成员函数*******************************************
输入****************************
默认构造函数********************
Please enter the tree element:1
Please enter the tree element:2
Please enter the tree element:999 
Please enter the tree element:999
Please enter the tree element:3
Please enter the tree element:999
Please enter the tree element:999
a.preOrderOutput() = 1 2 3 
复制构造函数********************
b.preOrderOutput() = 1 2 3 
前序中序构造函数****************
e.preOrderOutput() = 1 2 4 5 3 7 6 
e.inOrderOutput() = 4 2 5 1 7 3 6 
e.postOrderOutput() = 4 5 2 7 6 3 1 
后序中序构造函数****************
f.preOrderOutput() = 1 2 4 5 3 7 6
f.inOrderOutput() = 4 2 5 1 7 3 6
f.postOrderOutput() = 4 5 2 7 6 3 1
输出****************************
前序输出************************
a.preOrderOutput() = 1 2 3
b.preOrderOutput() = 1 2 3
a.iterativePreOrder() = 1 2 3
中序输出************************
a.inOrderOutput() = 2 1 3
b.inOrderOutput() = 2 1 3
a.iterativeInOrder() = 2 1 3
后序输出************************
a.postOrderOutput() = 2 3 1
b.postOrderOutput() = 2 3 1
a.iterativePostOrder() = 2 3 1
层序输出************************
a.levelOrderOutput() = 1 2 3
b.levelOrderOutput() = 1 2 3

empty()*************************
a.empty() = 0
b.empty() = 0
size()**************************
a.size() = 3
b.size() = 3
compare()***********************
a.compare(b) = 1
Please enter the tree element:66
Please enter the tree element:88
Please enter the tree element:999
Please enter the tree element:999
Please enter the tree element:99
Please enter the tree element:999
Please enter the tree element:999
a.compare(c) = 0
swapTrees()*********************
a.preOrderOutput() = 1 2 3
a.preOrderOutput() = 1 3 2
height()************************
a.height() = 2
maxHeightDifference()***********
a.maxHeightDifference() = 0
layerMaxNumOfNode()*************
a.layerMaxNumOfNode() = 2
maxNumOfNodeInLayer()***********
a.maxNumOfNodeInLayer() = 2
******************************binaryTreeChainsTest()函数结束**********************************

*******************************treeExpressionTest()函数开始***********************************

二叉树表达式测试***************************************
前缀表达式构造函数**************
g.preOrderOutput() = / + - 1 2 + 3 4 * + 5 6 * 7 8
g.inOrderOutput() = 1 - 2 + 3 + 4 / 5 + 6 * 7 * 8
g.postOrderOutput() = 1 2 - 3 4 + + 5 6 + 7 8 * * /
中缀表达式构造函数**************
i.preOrderOutput() = / + - 1 2 + 3 4 * + 5 6 * 7 8
i.inOrderOutput() = 1 - 2 + 3 + 4 / 5 + 6 * 7 * 8
i.postOrderOutput() = 1 2 - 3 4 + + 5 6 + 7 8 * * /
后缀表达式构造函数**************
h.preOrderOutput() = / + - 1 2 + 3 4 * + 5 6 * 7 8
h.inOrderOutput() = 1 - 2 + 3 + 4 / 5 + 6 * 7 * 8
h.postOrderOutput() = 1 2 - 3 4 + + 5 6 + 7 8 * * /
计算树表达式的值****************
compulateTree()*****************
Please enter the tree element:+
Please enter the tree element:2
Please enter the tree element:#
Please enter the tree element:#
Please enter the tree element:3
Please enter the tree element:#
Please enter the tree element:#
d.preOrderOutput() = + 2 3
d.compulateTree() = 5
将后缀表达式转换为中缀表达式****
postExprToIn()******************
postExpr1[9] = 1 2 3 + 4 * 5 - +
inExpr1 = (1+(((2+3)*4)-5))
将前缀表达式转换为中缀表达式****
preExprToIn()*******************
preExpr1[9] = + 1 - * + 2 3 4 5
inExpr1 = (1+(((2+3)*4)-5))
将中缀表达式转换为后缀表达式****
inExprToPost()******************
inExpr[25] = ( ( - 1 ) + ( 2 + 3 ) ) / ( ( + 4 ) * ( 5 * 6 ) )
postExpr[13] = 1 - 2 3 + + 4 + 5 6 * * /
将中缀表达式转换为前缀表达式****
inExprToPre()******************
result = 16
result = 5
计算后缀表达式的值**************
postCalculate()*****************
result = 16
*******************************treeExpressionTest()函数结束***********************************

******************************treeApplicationTest()函数开始***********************************

二叉树应用测试*****************************************
设置信号放大器******************
Please enter the degradeToLeaf:0
Please enter the degradeFromParent:1
Please enter the degradeToLeaf:0
Please enter the degradeFromParent:2
0 0 1  0 0 3  1 3 1  0 0 1  1 1 3  0 0 1  0 1 2  0 0 1  0 1 1  1 3 3  0 3 0  
0 3 0  1 1 3  1 3 1  0 0 1  0 0 3  0 0 1  1 3 3  0 1 2  0 0 1  0 1 1  0 0 1  
0 0 1  1 3 1  0 0 3  1 1 3  0 0 1  0 3 0  0 0 1  0 1 2  1 3 3  0 0 1  0 1 1  
并查集**************************
find(1) = 1 find(2) = 1
find(3) = 1 find(4) = 1
find(5) = 5 find(6) = 6
******************************treeApplicationTest()函数结束***********************************

Process finished with exit code 0

原文地址:https://blog.csdn.net/weixin_44410704/article/details/134632272

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_6639.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注