二叉树结点染色问题 实验报告
实验报告二叉树

递归遍历右子树输出根结点数data}void postOrder1 (struct btnode *bt){概念栈,结点参数p,prebt入栈While(栈或p是不是为空){提取栈顶元素值if判定p是不是为空或是pre的根结点输出根结点数data栈顶元素出栈栈顶元素p赋给pre记录else if右结点非空将右结点压栈if左结点将左结点压栈}}void main(){struct btnode *root=NULL;root=createbt(root);preOrder(root); midOrder(root); postOrder(root);preOrder1(root); midOrder1(root); postOrder1(root);
实验报告:二叉树

实验报告:二叉树第一篇:实验报告:二叉树实验报告二叉树一实验目的1、进一步掌握指针变量,动态变量的含义;2、掌握二叉树的结构特性以及各种存储结构的特点及适用范围。
3、掌握用指针类型描述、访问和处理二叉树的运算。
4、熟悉各种存储结构的特征以及如何应用树结构解决具体问题。
二实验原理树形结构是一种应用十分广泛和重要的非线性数据结构,是一种以分支关系定义的层次结构。
在这种结构中,每个数据元素至多只有一个前驱,但可以有多个后继;数据元素之间的关系是一对多的层次关系。
树形结构主要用于描述客观世界中具有层次结构的数据关系,它在客观世界中大量存在。
遍历二叉树的实质是将非线性结构转为线性结构。
三使用仪器,材料计算机 2 Wndows xp 3 VC6.0四实验步骤【问题描述】建立一个二叉树,请分别按前序,中序和后序遍历该二叉树。
【基本要求】从键盘接受输入(按前序顺序),以二叉链表作为存储结构,建立二叉树(以前序来建立),并采用递归算法对其进行前序,中序和后序遍历,将结果输出。
【实现提示】按前序次序输入二叉树中结点的值(一个整数),0表示空树,叶子结点的特征是其左右孩子指针为空。
五实验过程原始记录基本数据结构描述; 2 函数间的调用关系;用类C语言描述各个子函数的算法;附录:源程序。
六试验结果分析将实验结果分析、实验中遇到的问题和解决问题的方法以及关于本实验项目的心得体会,写在实验报告上。
第二篇:数据结构-二叉树的遍历实验报告实验报告课程名:数据结构(C语言版)实验名:二叉树的遍历姓名:班级:学号:时间:2014.11.03一实验目的与要求1.掌握二叉树的存储方法2.掌握二叉树的三种遍历方法3.实现二叉树的三种遍历方法中的一种二实验内容• 接受用户输入一株二叉树• 输出这株二叉树的前根, 中根, 后根遍历中任意一种的顺序三实验结果与分析//*********************************************************** //头文件#include #include //*********************************************************** //宏定义#define OK 1 #define ERROR 0 #define OVERFLOW 0//*********************************************************** typedef struct BiTNode { //二叉树二叉链表存储结构char data;struct BiTNode *lChild,*rChild;}BiTNode,*BiTree;//******************************** *************************** int CreateBiTree(BiTree &T){ //按先序次序输入二叉中树结点的值,空格表示空树//构造二叉链表表示的二叉树T char ch;fflush(stdin);scanf(“%c”,&ch);if(ch==' ')T=NULL;else{ if(!(T=(BiTNode *)malloc(sizeof(BiTNode))))return(OVERFLOW);T->data=ch;Creat eBiTree(T->lChild);CreateBiTree(T->rChild);} return(OK);} //********************************************************* void PreOrderTraverse(BiTree T){ //采用二叉链表存储结构,先序遍历二叉树的递归算法if(T){ printf(“%c”,T->data);PreOrderTraverse(T->lChild);PreOrd erTraverse(T->rChild);} } /***********************************************************/ void InOrderTraverse(BiTree T){ //采用二叉链表存储结构,中序遍历二叉树的递归算法if(T){ InOrderTraverse(T->lChild);printf(“%c”,T->data);InOrderT raverse(T->rChild);} }//*********************************************************** void PostOrderTraverse(BiTree T){ //采用二叉链表存储结构,后序遍历二叉树的递归算法if(T){ PostOrderTraverse(T->lChild);PostOrderTraverse(T->rChild) ;printf(“%c”,T->data);} }//*********************************************************** void main(){ //主函数分别实现建立并输出先、中、后序遍历二叉树printf(“please input your tree follow the PreOrder:n”);BiTNode *Tree;CreateBiTree(Tree);printf(“n先序遍历二叉树:”);PreOrderTraverse(Tree);printf(“n中序遍历二叉树:”);InOrderTraverse(Tree);printf(“n后序遍历二叉树:”);PostOrderTraverse(Tree);}图1:二叉树的遍历运行结果第三篇:数据结构二叉树操作验证实验报告班级:计算机11-2 学号:40 姓名:朱报龙成绩:_________实验七二叉树操作验证一、实验目的⑴ 掌握二叉树的逻辑结构;⑵ 掌握二叉树的二叉链表存储结构;⑶ 掌握基于二叉链表存储的二叉树的遍历操作的实现。
数据结构二叉树前驱结点的实验报告

数据结构二叉树前驱结点的实验报告二叉树的前驱结点是指在中序遍历中,一个节点的前面那个节点,即左子树中最大的节点。
为了实现二叉树前驱结点的查找,我进行了如下实验。
首先,需要定义二叉树的数据结构。
在这个数据结构中,每个节点包含三个参数:值,左子节点和右子节点。
这个数据结构可以使用递归方式来定义。
接下来,需要定义查找前驱节点所需要的函数。
这个函数的参数是二叉树中的一个节点,函数的返回值是这个节点的前驱节点。
如果这个节点是二叉树中的根节点,那么它没有前驱节点,函数返回 null。
如果这个节点没有左子节点,那么前驱节点一定是它的某个祖先节点。
对于这种情况,可以向上递归,直到找到一个祖先节点,该祖先节点的右子节点是该节点或者该节点的某个祖先节点。
如果这个节点有左子节点,那么前驱节点一定是该节点的左子树中最右边的节点。
对于这种情况,可以向左递归,直到找到最右边的节点。
如果没有左子树,那么该节点的前驱节点就是null。
我实现了这个函数,并在一些测试用例上测试它的效果。
首先,我使用了一个简单的二叉树来进行测试。
这个二叉树包含了三个节点,根节点的值是2,左子节点的值是1,右子节点的值是3、我测试了根节点和右子节点的前驱节点,结果都是左子节点。
接下来,我测试了一个更复杂的二叉树,该二叉树包含了七个节点,是一个完整的二叉树。
我测试了二叉树中每一个节点的前驱节点,结果都是正确的。
通过这个实验,我学习了如何在二叉树中查找前驱节点。
这项技能在很多算法和数据结构中都有很多应用。
通过使用递归的方式,我可以在一些复杂的二叉树中轻松地查找前驱节点。
这种技能对于我今后的编程生涯非常重要,能够帮助我更高效地解决各种问题。
二叉树结点染色问题 实验报告

(一)需求和规格说明一棵二叉树可以按照如下规则表示成一个由0、1、2组成的字符序列,我们称之为“二叉树序列S”:例如,下图所表示的二叉树可以用二叉树序列S=21200110来表示。
任务是要对一棵二叉树的节点进行染色。
每个节点可以被染成红色、绿色或蓝色。
并且,一个节点与其子节点的颜色必须不同,如果该节点有两个子节点,那么这两个子节点的颜色也必须不相同。
给定一棵二叉树的二叉树序列,请求出这棵树中最多和最少有多少个点能够被染成绿色。
(二)设计分析过程:这是一道二叉树的染色问题,求染成绿色的最大最小情况,从本质上看,这是一道动态规划问题。
为了方便直观起见,代码开始时用先enum Color{nocolor = 0,green = 1,red = 2,blue = 3};定义了不同的颜色。
举个简单的例子,如下图所示:将整个二叉树划分成三个部分:根节点、左子树、右子树。
由于有约束条件,所以这三个部分存在着互相限制作用如下:1. 二叉树的根节点与左子树的根节点颜色不同;2.二叉树的根节点与右子树的根节点颜色不同;3.左子树根节点与右子树根节点颜色不同。
显然,上述的三个限制表示的是标号为1、2、3三个点之间的互相关系。
除此以外,左子树中的点与右子树中的点没有任何直接的限制关系!也就是说,如果我们事先确定了上述二叉树中标号为1、2、3的三个点的颜色,那么接下来,对左子树染色和对右子树染色将变成两个互不干扰的子问题,左子树最值与右子树最值不影响,可以分开求解。
【互不干扰,可以分开求解】如此一来,通过将三点染色,我们就可以把二叉树分成左右两个子树,整个问题被分解成两个较小规模的子问题。
算法设计:如图二所示,将二叉树划分成三部分,给标号为1、2、3三个点先染色后,将依次处理左子树,右子树。
在求解时,有以下2个问题:(1)染色的任意性标号为1、2、3的三个点的颜色并不一定固定依次是红、绿、蓝。
我们需要对所有染色情况进行枚举,并对每个染色情况进行左、右子树的分别处理。
[精品]【数据结构】二叉树实验报告
![[精品]【数据结构】二叉树实验报告](https://img.taocdn.com/s3/m/5d561ae96e1aff00bed5b9f3f90f76c661374c27.png)
[精品]【数据结构】二叉树实验报告二叉树实验报告一、实验目的:1.掌握二叉树的基本操作;2.理解二叉树的性质;3.熟悉二叉树的广度优先遍历和深度优先遍历算法。
二、实验原理:1.二叉树是一种树形结构,由n(n>=0)个节点组成;2.每个节点最多有两个子节点,称为左子节点和右子节点;3.二叉树的遍历分为四种方式:前序遍历、中序遍历、后序遍历和层次遍历。
三、实验环境:1.编程语言:C++;2.编译器:Dev-C++。
四、实验内容:1.定义二叉树节点结构体:struct BinaryTreeNode{int data; // 节点数据BinaryTreeNode *leftChild; // 左子节点指针BinaryTreeNode *rightChild; // 右子节点指针};2.初始化二叉树:queue<BinaryTreeNode *> q; // 使用队列存储节点q.push(root);int i = 1; // 创建子节点while (!q.empty() && i < length){BinaryTreeNode *node = q.front();q.pop();if (data[i] != -1) // 创建左子节点 {BinaryTreeNode *leftChild = new BinaryTreeNode;leftChild->data = data[i];leftChild->leftChild = nullptr;leftChild->rightChild = nullptr;node->leftChild = leftChild;q.push(leftChild);}i++;if (data[i] != -1) // 创建右子节点 {BinaryTreeNode *rightChild = new BinaryTreeNode;rightChild->data = data[i];rightChild->leftChild = nullptr;rightChild->rightChild = nullptr;node->rightChild = rightChild;q.push(rightChild);}i++;}return root;}3.前序遍历二叉树:五、实验结果:输入:int data[] = {1, 2, 3, 4, -1, -1, 5, 6, -1, -1, 7, 8};输出:前序遍历结果:1 2 4 5 3 6 7 8中序遍历结果:4 2 5 1 6 3 7 8后序遍历结果:4 5 2 6 8 7 3 1层次遍历结果:1 2 3 4 5 6 7 8通过本次实验,我深入理解了二叉树的性质和遍历方式,并掌握了二叉树的基本操作。
(完整word版)《二叉树基本操作实验报告》

《数据结构与数据库》实验报告实验题目二叉树的基本操作及运算学院:化学与材料科学学院专业班级:09级材料科学与工程系PB0920603姓名:李维谷学号:PB09206285邮箱:liwg@指导教师:贾伯琪实验时间:2010年10月17日一、需要分析问题描述:实现二叉树(包括二叉排序树)的建立,并实现先序、中序、后序和按层次遍历,计算叶子结点数、树的深度、树的宽度,求树的非空子孙结点个数、度为2的结点数目、度为2的结点数目,以及二叉树常用运算。
问题分析:二叉树树型结构是一类重要的非线性数据结构,对它的熟练掌握是学习数据结构的基本要求。
由于二叉树的定义本身就是一种递归定义,所以二叉树的一些基本操作也可采用递归调用的方法。
处理本问题,我觉得应该:1、建立二叉树;2、通过递归方法来遍历(先序、中序和后序)二叉树;3、通过队列应用来实现对二叉树的层次遍历;4、借用递归方法对二叉树进行一些基本操作,如:求叶子数、树的深度宽度等;5、运用广义表对二叉树进行广义表形式的打印。
算法规定:输入形式:为了方便操作,规定二叉树的元素类型都为字符型,允许各种字符类型的输入,没有元素的结点以空格输入表示,并且本实验是以先序顺序输入的。
输出形式:通过先序、中序和后序遍历的方法对树的各字符型元素进行遍历打印,再以广义表形式进行打印。
对二叉树的一些运算结果以整型输出。
程序功能:实现对二叉树的先序、中序和后序遍历,层次遍历。
计算叶子结点数、树的深度、树的宽度,求树的非空子孙结点个数、度为2的结点数目、度为2的结点数目。
对二叉树的某个元素进行查找,对二叉树的某个结点进行删除。
测试数据:输入一:ABC□□DE□G□□F□□□(以□表示空格),查找5,删除E预测结果:先序遍历ABCDEGF中序遍历CBEGDFA后序遍历CGEFDBA层次遍历ABCDEFG广义表打印A(B(C,D(E(,G),F)))叶子数3 深度5 宽度2 非空子孙数6 度为2的数目2 度为1的数目2查找5,成功,查找的元素为E删除E 后,以广义表形式打印A (B (C,D (,F )))输 入 二:ABD □□EH □□□CF □G □□□ (以□表示空格),查找10,删除B 预测结果:先序遍历 ABDEHCFG中序遍历 DBHEAGFC 后序遍历 DHEBGFCA层次遍历 ABCDEFHG广义表打印 A (B(D,E(H)),C(F(,G)))叶子数 3 深度 4 宽度 3 非空子孙数 7 度为2的数目 2 度为1的数目3 查找10,失败。
数据结构实验报告—二叉树

数据结构实验报告—二叉树数据结构实验报告—二叉树引言二叉树是一种常用的数据结构,它由节点和边构成,每个节点最多有两个子节点。
在本次实验中,我们将对二叉树的基本结构和基本操作进行实现和测试,并深入了解它的特性和应用。
实验目的1. 掌握二叉树的基本概念和特性2. 熟练掌握二叉树的基本操作,包括创建、遍历和查找等3. 了解二叉树在实际应用中的使用场景实验内容1. 二叉树的定义和存储结构:我们将首先学习二叉树的定义,并实现二叉树的存储结构,包括节点的定义和节点指针的表示方法。
2. 二叉树的创建和初始化:我们将实现二叉树的创建和初始化操作,以便后续操作和测试使用。
3. 二叉树的遍历:我们将实现二叉树的前序、中序和后序遍历算法,并测试其正确性和效率。
4. 二叉树的查找:我们将实现二叉树的查找操作,包括查找节点和查找最大值、最小值等。
5. 二叉树的应用:我们将探讨二叉树在实际应用中的使用场景,如哈夫曼编码、二叉搜索树等。
二叉树的定义和存储结构二叉树是一种特殊的树形结构,它的每个节点最多有两个子节点。
节点被表示为一个由数据和指向其左右子节点的指针组成的结构。
二叉树可以分为三类:满二叉树、完全二叉树和非完全二叉树。
二叉树可以用链式存储结构或顺序存储结构表示。
- 链式存储结构:采用节点定义和指针表示法,通过将节点起来形成一个树状结构来表示二叉树。
- 顺序存储结构:采用数组存储节点信息,通过计算节点在数组中的位置来进行访问和操作。
二叉树的创建和初始化二叉树的创建和初始化是二叉树操作中的基础部分。
我们可以通过手动输入或读取外部文件中的数据来创建二叉树。
对于链式存储结构,我们需要自定义节点和指针,并通过节点的方式来构建二叉树。
对于顺序存储结构,我们需要定义数组和索引,通过索引计算来定位节点的位置。
一般来说,初始化一个二叉树可以使用以下步骤:1. 创建树根节点,并赋初值。
2. 创建子节点,并到父节点。
3. 重复步骤2,直到创建完整个二叉树。
二叉树基本操作--实验报告

⼆叉树基本操作--实验报告实验三⼆叉树的基本操作学院:物理与电⼦学院班级:电信1105班姓名:刘岩学号:29⼀、实验⽬的1、熟悉⼆叉树的基本操作,掌握⼆叉树的实现以及实际应⽤。
3、加深对于⼆叉树的理解,逐步培养解决实际问题的编程能⼒。
⼆、实验环境1台WINDOWS环境的PC机,装有Visual C++ 。
三、实验内容1、问题描述现需要编写⼀套⼆叉树的操作函数,以便⽤户能够⽅便的利⽤这些函数来实现⾃⼰的应⽤。
其中操作函数包括:1>创建⼆叉树CreateBTNode(*b,*str):根据⼆叉树括号表⽰法的字符串*str⽣成对应的链式存储结构。
2>输出⼆叉树DispBTNode(*b):以括号表⽰法输出⼀棵⼆叉树。
3>查找结点FindNode(*b,x):在⼆叉树b中寻找data域值为x的结点,并返回指向该结点的指针。
4>求⾼度BTNodeDepth(*b):求⼆叉树b的⾼度。
若⼆叉树为空,则其⾼度为0;否则,其⾼度等于左⼦树与右⼦树中的最⼤⾼度加l。
5>求⼆叉树的结点个数NodesCount(BTNode *b)6>先序遍历的递归算法:void PreOrder(BTNode *b)7>中序遍历的递归算法:void InOrder(BTNode *b)8>后序遍历递归算法:void PostOrder(BTNode *b)9>层次遍历算法void LevelOrder(BTNode *b)2、基本要求实现以上9个函数。
主函数中实现以下功能:创建下图中的树b输出⼆叉树b找到’H’节点,输出其左右孩⼦值输出b的⾼度输出b的节点个数输出b的四种遍历顺序3、程序编写上图转化为⼆叉树括号表⽰法为A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))程序:#include <>#include <>#define MaxSize 100typedef char ElemType;typedef struct node{ElemType data; /*数据元素*/struct node *lchild; /*指向左孩⼦*/struct node *rchild; /*指向右孩⼦*/} BTNode;void CreateBTNode(BTNode *&b,char *str);//创建BTNode *FindNode(BTNode *b,ElemType x);//查找节点int BTNodeHeight(BTNode *b);//求⾼度void DispBTNode(BTNode *b);//输出int NodesCount(BTNode *b);//⼆叉树的结点个数void PreOrder(BTNode *b);//先序遍历递归void InOrder(BTNode *b);//中序遍历递归void PostOrder(BTNode *b);//后序遍历递归void LevelOrder(BTNode *b);//层次遍历//创建void CreateBTNode(BTNode *&b,char *str){BTNode *St[MaxSize],*p=NULL;int top=-1,k,j=0;char ch;b=NULL;ch=str[j];while(ch!='\0'){switch(ch){case '(':top++;St[top]=p;k=1;break;case ')':top--;break;case ',':k=2;break;default:p=(BTNode *)malloc(sizeof(BTNode)); p->data=ch;p->lchild=p->rchild=NULL;if(b==NULL)b=p;else{switch(k){case 1:St[top]->lchild=p;break;case 2:St[top]->rchild=p;break;}}}j++;ch=str[j];}}//输出void DispBTNode(BTNode *b){if(b!=NULL){printf("%c",b->data);if(b->lchild!=NULL||b->rchild!=NULL){printf("(");DispBTNode(b->lchild);if(b->rchild!=NULL)printf(",");DispBTNode(b->rchild);printf(")");}}}//查找节点BTNode *FindNode(BTNode *b,ElemType x){ BTNode *p;if(b==NULL)return b;else if(b->data==x)return b;else{p=FindNode(b->lchild,x);if(p!=NULL)return p;elsereturn FindNode(b->rchild,x);}}//求⾼度int BTNodeHeight(BTNode *b){int lchildh,rchildh;if(b==NULL)return (0);else{lchildh=BTNodeHeight(b->lchild);rchildh=BTNodeHeight(b->rchild);return(lchildh>rchildh)(lchildh+1):(rchildh+1);}}//⼆叉树的结点个数int NodesCount(BTNode *b){if(b==NULL)return 0;elsereturn NodesCount(b->lchild)+NodesCount(b->rchild)+1; }//先序遍历递归void PreOrder(BTNode *b){ if(b!=NULL){printf("%c",b->data); PreOrder(b->lchild); PreOrder(b->rchild);}}//中序遍历递归void InOrder(BTNode *b){if(b!=NULL){InOrder(b->lchild);printf("%c",b->data); InOrder(b->rchild);}}//后序遍历递归void PostOrder(BTNode *b){ if(b!=NULL){PostOrder(b->lchild); PostOrder(b->rchild);printf("%c",b->data);}}//层次遍历void LevelOrder(BTNode *b){ BTNode *p;BTNode *qu[MaxSize];int front,rear;front=rear=-1;rear++;qu[rear]=b;while(front!=rear){front=(front+1)%MaxSize;p=qu[front];printf("%c",p->data);if(p->lchild!=NULL){rear=(rear+1)%MaxSize;qu[rear]=p->lchild;}if(p->rchild!=NULL){rear=(rear+1)%MaxSize;qu[rear]=p->rchild;}}}void main(){BTNode *b,*p,*lp,*rp;char str[]="A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))";//根据树形图改写成的//⼆叉树括号表⽰法的字符串*str //char str[100];scanf("%s",&str);//⾃⾏输⼊括号表⽰的⼆叉树CreateBTNode(b,str); //创建树bprintf("\n");printf("输出⼆叉树:");//输出⼆叉树bDispBTNode(b);printf("\n");printf("'H'结点:");//找到'H'节点,输出其左右孩⼦值p=FindNode(b,'H');printf("\n");if (p!=NULL){printf("左孩⼦节点的值");printf("%c",p->lchild->data);printf("\n");printf("右孩⼦节点的值");printf("%c",p->rchild->data);printf("\n");//此处输出p的左右孩⼦节点的值}printf("\n");printf("⼆叉树b的深度:%d\n",BTNodeHeight(b));//输出b的⾼度printf("⼆叉树b的结点个数:%d\n",NodesCount(b));//输出b的节点个数printf("\n");printf(" 先序遍历序列:\n");//输出b的四种遍历顺序printf(" 算法:");PreOrder(b);printf("\n");printf(" 中序遍历序列:\n");printf(" 算法:");InOrder(b);printf("\n");printf(" 后序遍历序列:\n");printf(" 算法:");PostOrder(b);printf("\n");printf(" 层次遍历序列:\n");printf(" 算法:");LevelOrder(b); printf("\n");}四、实验⼼得与⼩结通过本次实验,我熟悉⼆叉树的基本知识内容,对课本的知识有了更加深刻的理解与掌握掌握。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(一)需求和规格说明一棵二叉树可以按照如下规则表示成一个由0、1、2组成的字符序列,我们称之为“二叉树序列S”:例如,下图所表示的二叉树可以用二叉树序列S=21200110来表示。
任务是要对一棵二叉树的节点进行染色。
每个节点可以被染成红色、绿色或蓝色。
并且,一个节点与其子节点的颜色必须不同,如果该节点有两个子节点,那么这两个子节点的颜色也必须不相同。
给定一棵二叉树的二叉树序列,请求出这棵树中最多和最少有多少个点能够被染成绿色。
(二)设计分析过程:这是一道二叉树的染色问题,求染成绿色的最大最小情况,从本质上看,这是一道动态规划问题。
为了方便直观起见,代码开始时用先enum Color{nocolor = 0,green = 1,red = 2,blue = 3};定义了不同的颜色。
举个简单的例子,如下图所示:将整个二叉树划分成三个部分:根节点、左子树、右子树。
由于有约束条件,所以这三个部分存在着互相限制作用如下:1. 二叉树的根节点与左子树的根节点颜色不同;2.二叉树的根节点与右子树的根节点颜色不同;3.左子树根节点与右子树根节点颜色不同。
显然,上述的三个限制表示的是标号为1、2、3三个点之间的互相关系。
除此以外,左子树中的点与右子树中的点没有任何直接的限制关系!也就是说,如果我们事先确定了上述二叉树中标号为1、2、3的三个点的颜色,那么接下来,对左子树染色和对右子树染色将变成两个互不干扰的子问题,左子树最值与右子树最值不影响,可以分开求解。
【互不干扰,可以分开求解】如此一来,通过将三点染色,我们就可以把二叉树分成左右两个子树,整个问题被分解成两个较小规模的子问题。
算法设计:如图二所示,将二叉树划分成三部分,给标号为1、2、3三个点先染色后,将依次处理左子树,右子树。
在求解时,有以下2个问题:(1)染色的任意性标号为1、2、3的三个点的颜色并不一定固定依次是红、绿、蓝。
我们需要对所有染色情况进行枚举,并对每个染色情况进行左、右子树的分别处理。
同样,当根节点只有一个子节点时,我们也要枚举此时的染色方案。
(2)根节点的颜色已确定由于2号点已经染色,所以,在递归处理左子树时,问题就转化成“根节点颜色已确定,求满足约束条件的最多(最小)染色方案”。
这个转化后的子问题与原问题略有差异:原问题中根节点可以任意染色,而转化后的子问题中根节点的颜色是固定的。
为了便于递归调用相同的处理操作,我们必须保证所有问题的条件与求解目标的统一!于是,有必要将原问题稍做修改:事先求出整个二叉树根节点为红色、绿色或蓝色情况下问题的解(这就与子问题是同一类型了),然后取这三个解中的最大(或最小)值,即得到原问题的解。
分析至此,我们已经得出了解决问题的大致方法:将原问题转化成“根节点颜色确定,求染色最值方案”;枚举根节点的左节点与右节点(如果存在)的颜色,同时满足约束条件;对每种染色方案,递归处理求左、右两子树。
给二叉树上所有节点标号,从1~N;用son记录二叉树的构造关系, Son(i,0)和Son(i,1)分别表示编号是i的节点,其左右两个子节点的编号(如果不存在,则用-1表示)。
例如在上图中,我们有Son(1,0)=2,Son(1,1)=3。
用F(i,j)表示一个子问题一个子问题可以由两个参数来描述:根节点编号i,根节点颜色j。
F(i , j)表示:以编号是i、颜色是j的节点为根节点的子树,在满足约束条件的情况下染色,绿色节点最多(最少)有多少个。
按照先前所设计的算法,可以大致得出如下式:0 i == -1F(i,j) = F(son(i,0), j1)+F (son(i,1),j2) i<>-1 j<>green F(son(i,0),j1)+ F(son(i,1),j2+1 i<>-1 j == green根据我们的分析,算法会有重复操作,多次计算F(i,j)的值。
那么,我们不妨造一个表将F(i,j)保存起来,这样就能有效避免重复计算了。
类型成员名描述结构体名成员类别node 属性int ChildNum 存储当前结点拥有的孩子值,Color color 存储当前结点的颜色类名成员类别类型成员名描述employee 属性int length S的长度node的动态数组tree 存储tree的结点方法TREE() 构建treevoid Preorder(inti) 以第i结点为根结点进行先序遍历int Son(int i ,boolright)返回第i个结点的孩子,第二个参数表示返回是左孩子还是右孩子,若没有,返回-1int GreenMax() 求最多有多少个绿色结点并返回int GreenMin() 求最少有多少个绿色结点并返回int Max(inti,Color j,intmermory[]) 求以第i个结点在颜色j下为根结点时最多有多少个绿色结点并返回int Min(inti,Color j,intmermory[]) 求以第i个结点在颜色j下为根结点时最少有多少个绿色结点并返回时间复杂度从一棵树的根结点开始,依次求解结点的子树最多/少有多少的结点可以染成绿色,若树有n个结点,那么复杂度为O(n)。
(三)用户手册用户通过修改TREE.TRE文本文档中二叉序列S来构造不同的二叉树,-1表示S结束。
运行第一行表示读入的s的值。
第二行先序遍历来验证生成的树是否正确之后给出结果:绿色结点最多有多少个:绿色结点最少有多少个:(四)调试及测试运行实例:附录 源程序#include <iostream>#include"tree.h"using namespace std;int main(){Tree Tree;cout << endl << "先序遍历:" << endl;tree.preorder(tree.root);cout << endl;cout << "绿色结点最多有:";cout << tree.GreenMax() << endl;cout << "绿色结点最少有:";cout << tree.GreenMin() << endl;return 0;}tree.henum Color{nocolor = 0,green = 1,red = 2,blue = 3};struct node{int ChildNum;Color color;};class TREE{public:int length;node *tree = new node[length * 2 + 2];TREE();void preorder(int i); //先序遍历int son(int i, bool rigth);int GreenMax();int GreenMin();int Max(int i, Color j,int memory[]);int Min(int i, Color j,int memory[]);};tree.cpp#include <fstream>#include<iostream>#include"tree.h"using namespace std;TREE::TREE(){ifstream s;s.open("TREE.TRE"); //通过打开“TREE.TRE”文件来构造一个树if (!s){cout << "打开文件错误!";exit(0);}int ChildNum;int length = 0;node *tree = new node[length * 2 + 1];s >> ChildNum;cout << "读入的S=";while (ChildNum != -1){cout << ChildNum;length++;switch (ChildNum){case'0':tree[length].ChildNum = 0;tree[length * 2].ChildNum = -1; //-1表示该结点为空tree[length * 2 + 1].ChildNum = -1;break;case'1':tree[length].ChildNum = 1;tree[length * 2 + 1].ChildNum = -1;break;case '2':tree[length].ChildNum = 2;break;}s >> ChildNum;}}int TREE::son(int i, bool rigth){if (rigth){if (tree[i * 2 + 1].ChildNum == -1)return -1;else return i * 2 + 1;}else{if (tree[2 * i].ChildNum == -1)return -1;else return i * 2;}}int TREE::GreenMax(){int * temp = new int [3 * length + 1]; //temp来记录以及求过的结点,避免重复运算for (int i = 1; i < 3 * length + 1; i++)temp[i] = -1;int a = Max(1, green,temp);int b = Max(1, red,temp);int c = Max(1, blue,temp);return a >(b = b > c ? b : c) ? a : b;}int TREE::Max(int i, Color j,int memory[]){int t = 3 * (i - 1) + j;if (memory[t] == -1){if (i = -1)memory[t] = 0;else{if (j != green)memory[t] = Max(son(i, 0), Color((j + 1) % 3), memory) + Max(son(i, 1), Color((j + 1) % 3), memory);else memory[t] = Max(son(i, 0), Color((j + 1) % 3), memory) + Max(son(i, 1), Color((j + 1) % 3), memory) + 1;}}return memory[t];}int TREE::GreenMin(){int * temp = new int [3 * length + 1]; /for (int i = 1; i < 3 * length + 1; i++)temp[i] = -1;int a = Min(1, green,temp);int b = Min(1, red,temp);int c = Min(1, blue,temp);return a <(b = b < c ? b : c) ? a : b;}int TREE::Min(int i, Color j,int memory[])int t = 3 * (i - 1) + j;if (memory[t] == -1){if (i = -1)memory[t] = 0;else{if (j != green)memory[t] = Min(son(i, 0), Color((j + 1) % 3), memory) + Min(son(i, 1), Color((j + 1) % 3), memory);else memory[t] = Min(son(i, 0), Color((j + 1) % 3), memory) + Min(son(i, 1), Color((j + 1) % 3), memory) + 1;}}return memory[t];}void TREE::preorder(int i){if (i > 0 && i < 2 * length + 1){cout << tree[i].ChildNum << " ";preorder(i * 2);preorder(i * 2 + 1);}}。