目录
- 第1关:括号表示法创建二叉树
- 任务描述
- 相关知识
- 编程要求
- 测试说明
- 完整代码
- 第2关:先序序列创建二叉树
- 任务描述
- 相关知识
- ==二叉树的前序遍历==
- ==如何创建一颗二叉树==
- ==伪代码如下:==
- ==二叉树的中序遍历==
- 编程要求
- 测试说明
- 完整代码
- 第3关:计算二叉树的深度和节点个数
- 任务描述
- 相关知识
- 二叉树深度概念
- 编程要求
- 测试说明
- 完整代码
- 第4关:二叉树前序遍历递归和非递归算法
- 任务描述
- 相关知识
- 递归法
- ==递归伪代码==
- 二叉树左右子树性质
- 编程要求
- 测试说明
- 完整代码
- 第5关:二叉树中序遍历递归和非递归算法
- 任务描述
- 相关知识
- ==递归法==
- ==二叉树左右子树性质==
- 编程要求
- 测试说明
- 完整代码
- 第6关:层次遍历二叉树
- 任务描述
- 相关知识
- ==队列基本操作==
- ==二叉树层次遍历==
- 编程要求
- 测试说明
- 完整代码
- 第7关:由前序和中序遍历序列构造二叉树
- 任务描述
- 相关知识
- 编程要求
- 测试说明
- 完整代码
- 第8关:由中序序列和后序序列构造二叉树
- 任务描述
- 相关知识
- 编程要求
- 测试说明
- 完整代码
- 第9关:二叉树的顺序存储及基本操作
- 任务描述
- 相关知识
- 二叉树的递归定义:
- ==二叉树与度为2的树的区别:==
- ==二叉树的性质==
- 性质1 非空二叉树上叶结点数等于双分支结点数加1。即n0=n2+1。
- 性质2 非空二叉树上第i层上至多有 2
- 性质3 高度为h的二叉树至多有2
- 满二叉树特性:
- ==完全二叉树:==
- 性质4 对完全二叉树中编号为i的结点(1≤i≤n,n≥1,n为结点数)有:
- ==二叉树的遍历==
- 1.先序遍历
- 2.中序遍历
- 3.后序遍历
- 4. 层次遍历
- ==二叉树也可以采用两种存储方式:顺序存储结构和链式存储结构。==
- 二叉树的顺序存储结构
- 编程要求
- 测试说明
- 完整代码
温馨提示:题目有点多,博客左右侧以及文章开头都有目录,用好目录链接,快速到达~
第1关:括号表示法创建二叉树
任务描述
本关任务:给出一棵二叉树的括号表示法,本题要求实现3个函数,根据给出的括号表示法创建该二叉树并输出。输出时,也按二叉树的括号表示法输出。然后再求出二叉树高度并输出。
相关知识
二叉树的括号表示法如图所示:
上面5棵二叉树中,从左至右,每棵二叉树的括号表示法依次为:A,A(B,C),A(B(D),C),A(B(,D),C(E)),A(B(D,E),C(F,G))。
编程要求
代码窗口中给出了二叉树类型定义文件binary_tree.h和实现文件binary_tree.cpp。您的任务是根据提示,在右侧编辑器补充代码,完成给定的3个函数。函数声明如下:
// 利用二叉树的括号表示法创建二叉树root
// 参数:二叉树的根结点指针root。
// 参数:二叉树的括号表示法字符串s。
void CreateTree(BTNode* &root, ElemType* s);
//以嵌套括号表示法输出一棵树
void DispTree(BTNode* root);
// 求二叉树的高度
// 参数:二叉树根节点root
int getHeight(BTNode* root);
测试说明
平台会对你编写的代码进行测试:
输入样例1:
A(B(D),C)
(对应二叉树如下)
输出样例1:
A(B(D),C)
3
输入样例2:
A(B(,D),C(E))
(对应二叉树如下)
输出样例2:
A(B(,D),C(E))
3
开始你的任务吧,祝你成功!
完整代码
#include "binary_tree.h"//根据嵌套括号表示法的字符串生成链式存储的二叉树
void CreateTree(BTNode* &root, char str[]) {/*请在BEGIN和END之间实现你的代码*//*****BEGIN*****/BTNode* St[60], * p; root = NULL;int top = -1, k, i = 0; //栈顶指针char ch = str[i];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 (root == NULL) root = p; else{k == 1 ? St[top]->lchild = p : St[top]->rchild = p;}}ch = str[++i];}/******END******/
}//以嵌套括号表示法输出一棵二叉树
void DispTree(BTNode* root) {/*请在BEGIN和END之间实现你的代码*//*****BEGIN*****/if (root != NULL){printf("%c", root->data);if (root->lchild != NULL || root->rchild != NULL){printf("(");DispTree(root->lchild);if (root->rchild != NULL)printf(",");DispTree(root->rchild);printf(")");}}/******END******/
}// 求二叉树的高度
// 参数:二叉树根节点root
int getHeight(BTNode* root)
{/*请在BEGIN和END之间实现你的代码*//*****BEGIN*****/int lchildh, rchildh;if (root == NULL) return 0;else{lchildh = getHeight(root->lchild);rchildh = getHeight(root->rchild);return (lchildh > rchildh) ? (lchildh + 1) : (rchildh + 1);}/******END******/
}
//
// binary_tree.h#ifndef __BTNODE_H
#define __BTNODE_H#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>using namespace std;typedef char ElemType;typedef struct BTNode {ElemType data; // 树节点元素BTNode* lchild; // 左子树指针BTNode* rchild; // 右子树指针BTNode() { // 树节点初始化lchild = NULL;rchild = NULL;}BTNode(ElemType item) { // 用元素初始化树节点data = item;lchild = NULL;rchild = NULL;}~BTNode() { // 释放树节点内存lchild = NULL;rchild = NULL;}
} BTNode;//创建新结点的工具函数
BTNode* getNewNode(ElemType e);// 利用二叉树的括号表示法创建二叉树root
// 参数:二叉树的根结点指针root。
// 参数:二叉树的括号表示法字符串s。
void CreateTree(BTNode* &root, ElemType* s);//以嵌套括号表示法输出一棵树
void DispTree(BTNode* root);// 求二叉树的高度
// 参数:二叉树根节点root
int getHeight(BTNode* root);#endif /* __BTNODE_H */
第2关:先序序列创建二叉树
任务描述
本关任务:利用先序遍历创建二叉树,并给出相应二叉树的中序遍历结果。
相关知识
为了完成本关任务,你需要掌握:1.二叉树的前序遍历,2.如何创建一颗二叉树,3.二叉树的中序遍历。
二叉树的前序遍历
前序遍历preorder traversal是指按照先根节点,再左节点,最后右节点的次序访问二叉树中所有的节点,使得每个节点被访问且仅被访问一次。
例:图1表示一个二叉树,前序遍历的顺序如节点上面数字所示,结果为ABCDEF。
如何创建一颗二叉树
本关基于二叉链表存储定义了树节点数据结构:
struct BiTreeNode {char data; // 树节点元素BiTreeNode* left; // 左子树指针BiTreeNode* right; // 右子树指针
};
利用先序遍历创建二叉树,我们需要知道先序遍历的叶子节点,通过增加符合#表示叶子节点的子节点,则图1的先序遍历为:ABC##D##EF###。
- 根据先序遍历的过程,首先创建根节点,然后使用递归的方法创建左子树节点,直到遇到符号#,表示到了叶子节点,回溯父节点并创建右子树节点。
伪代码如下:
BiTreeNode* CreatBiTree(char* s, int &i, int len)
{root = new BiTreeNode(s[i++]); //创建根节点root->left = CreatBiTree(s, i, len); //递归创建左子树root->right = CreatBiTree(s, i, len); //递归创建右子树return root;
}
二叉树的中序遍历
中序遍历inorder traversal是指按照先左节点,再根节点,最后右节点的次序访问二叉树中所有的节点,使得每个节点被访问且仅被访问一次。
例:图2表示一个二叉树,中序遍历的顺序如节点上面数字所示,结果为CBDAFE。
编程要求
本关的编程任务是补全右侧代码片段CreatBiTree和InOrder中Begin至End中间的代码,具体要求如下:
- 在CreatBiTree中,利用先序遍历创建二叉树,并返回二叉树根节点指针。
- 在InOrder中,完成二叉树的中序遍历,并输出遍历结果,中间没有空格,末尾不换行。
测试说明
平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。
以下是平台的测试样例:
测试输入:ABC##D##EF###
预期输出:CBDAFE
测试输入:ABCD###E#F##G##
预期输出:DCBEFAG
开始你的任务吧,祝你成功!
完整代码
//
// binary_tree.cpp#include "binary_tree.h"//创建新结点的工具函数
BTNode* getNewNode(char e)
{BTNode* p = (BTNode*)malloc(sizeof(BTNode));p->data = e;p->lchild = p->rchild = NULL;return p;
}BTNode* CreateTree(char* s, int &i, int len)
// 利用先序遍历创建二叉树
// 参数:先序遍历字符串s,字符串初始下标i=0,字符串长度len。
// 返回:二叉树
{// 请在这里补充代码,完成本关任务/********** Begin *********/if(s[i]=='#' || i>len){i++;return NULL;}BTNode* BTP = getNewNode(s[i++]);BTP->lchild = CreateTree(s,i,len);BTP->rchild = CreateTree(s,i,len);return BTP;/********** End **********/
}// 二叉树的中序遍历
// 参数:二叉树根节点root
// 输出:中间没有空格,末尾不换行。
void InOrder(BTNode* root)
{// 请在这里补充代码,完成本关任务/********** Begin *********/if(root==NULL){return;}InOrder(root->lchild);printf("%c",root->data);InOrder(root->rchild);/********** End **********/
}
//
// binary_tree.h#ifndef __BTNODE_H
#define __BTNODE_H#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;typedef struct BTNode {char data; // 树节点元素BTNode* lchild; // 左子树指针BTNode* rchild; // 右子树指针BTNode() { // 树节点初始化lchild = NULL;rchild = NULL;}BTNode(char item) { // 用元素初始化树节点data = item;lchild = NULL;rchild = NULL;}~BTNode() { // 释放树节点内存lchild = NULL;rchild = NULL;}
} BTNode;//创建新结点的工具函数
BTNode* getNewNode(char e);BTNode* CreateTree(char* s, int &i, int len);
// 利用先序遍历创建二叉树
// 参数:先序遍历字符串s,字符串初始下标i=0,字符串长度len。
// 返回:二叉树void InOrder(BTNode* root);
// 二叉树的中序遍历
// 参数:二叉树根节点root
// 输出:二叉树的中序遍历,中间没有空格,末尾不换行。#endif /* __BTNODE_H */
第3关:计算二叉树的深度和节点个数
任务描述
本关任务:给定一棵二叉树,计算该二叉树的深度、总节点个数和叶子节点个数。
相关知识
为了完成本关任务,你需要掌握:1.二叉树深度概念,2.二叉树节点,3.二叉树叶子节点概念。
二叉树深度概念
二叉树的深度指的是二叉树中最大的结点层数。例如:图1所示的二叉树最大的节点层数为3,所以该二叉树深度为3。
-
二叉树节点
二叉树的节点包含一个数据元素及两个指向子树的分支,例如:图1所示的二叉树的总节点个数为6。 -
二叉树叶子节点概念
叶子节点是度为0的节点,二叉树节点的度为子树的个数。例如:图1所示的二叉树叶子节点为C,D和F,个数为3。
编程要求
本关的编程任务是补全右侧代码片段GetTreeDepth、GetNodeNumber和GetLeafNodeNumber中Begin至End中间的代码,具体要求如下:
- 在GetTreeDepth中计算该二叉树的深度,返回深度值。
- 在GetNodeNumber中计算该二叉树的总的节点个数,返回节点个数。
- 在GetLeafNodeNumber中计算该二叉树的叶子节点个数,返回叶子节点个数。
测试说明
平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。
以下是平台的测试样例:
测试输入:ABC##D##EF###
预期输出:
3
6
3
测试输入:ABCD###E#F##G##
预期输出:
4
7
3
开始你的任务吧,祝你成功!
完整代码
//
// binary_tree.cpp#include "binary_tree.h"//创建新结点的工具函数
BTNode* getNewNode(char e)
{BTNode* p = (BTNode*)malloc(sizeof(BTNode));p->data = e;p->lchild = p->rchild = NULL;return p;
}// 计算该二叉树的深度
// 参数:二叉树根节点root
// 返回:二叉树的深度
int GetTreeDepth(BTNode* root)
{// 请在这里补充代码,完成本关任务/********** Begin *********/if(!root)return 0;if(!root->lchild && !root->rchild)return 1;int deep=0;int deepl = GetTreeDepth(root->lchild);if(deep<deepl)deep=deepl;int deepr = GetTreeDepth(root->rchild);if(deep<deepr)deep=deepr;return deep+1;/********** End **********/
}// 计算该二叉树的总节点个数
// 参数:二叉树根节点root
// 返回:二叉树的总节点个数
int GetNodeNumber(BTNode* root)
{// 请在这里补充代码,完成本关任务/********** Begin *********/if (root == NULL)return 0;elsereturn GetNodeNumber(root->lchild) + GetNodeNumber(root->rchild) +1;/********** End **********/
}// 计算该二叉树的叶子节点个数
// 参数:二叉树根节点root
// 返回:二叉树的叶子节点个数
int GetLeafNodeNumber(BTNode* root)
{// 请在这里补充代码,完成本关任务/********** Begin *********/if(!root)return 0;if(!root->lchild && !root->rchild) return 1;int leaf = GetLeafNodeNumber(root->lchild);leaf += GetLeafNodeNumber(root->rchild);return leaf;/********** End **********/
}
//
// binary_tree.h#ifndef binary_tree_h
#define binary_tree_h#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;typedef struct BTNode {char data; // 树节点元素BTNode* lchild; // 左子树指针BTNode* rchild; // 右子树指针BTNode() { // 树节点初始化lchild = NULL;rchild = NULL;}BTNode(char item) { // 用元素初始化树节点data = item;lchild = NULL;rchild = NULL;}~BTNode() { // 释放树节点内存lchild = NULL;rchild = NULL;}
} BTNode;//创建新结点的工具函数
BTNode* getNewNode(char e);// 利用先序遍历创建二叉树
// 参数:先序遍历字符串s,字符串初始下标i=0,字符串长度len。
// 返回:二叉树
BTNode* CreateTree(char* s, int &i, int len);// 计算该二叉树的深度
// 参数:二叉树根节点root
// 返回:二叉树的深度
int GetTreeDepth(BTNode* root);// 计算该二叉树的总节点个数
// 参数:二叉树根节点root
// 返回:二叉树的总节点个数
int GetNodeNumber(BTNode* root);// 计算该二叉树的叶子节点个数
// 参数:二叉树根节点root
// 返回:二叉树的叶子节点个数
int GetLeafNodeNumber(BTNode* root);#endif /* binary_tree_h */
第4关:二叉树前序遍历递归和非递归算法
任务描述
本关任务:给定一棵二叉树,使用递归和非递归的方法实现二叉树的先(前)序遍历结果。
相关知识
为了完成本关任务,你需要掌握:1.递归算法,2.二叉树左右子树性质,3.二叉树先序遍历。
递归法
递归算法recursion algorithm在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。其核心是将原始问题转化为子问题。
例如:计算n阶乘的程序在数学上可以定义为:
递归伪代码
则递归算法求n阶乘的伪代码为:
int fact(int n){if(n == 0)return 1;elsereturn n * fact(n - 1);
}
二叉树左右子树性质
二叉树的每个节点最多只有两个分支,通常分支被称作左子树和右子树,并且二叉树的分支具有左右次序,不能颠倒。图1是一棵二叉树。
编程要求
本关的编程任务是补全右侧代码片段PreOrder和PreOrder_iter中Begin至End中间的代码,具体要求如下:
- 在PreOrder中使用递归算法实现二叉树先序遍历递归算法并输出结果,中间没有空格,末尾不换行。
- 在PreOrder_iter中实现二叉树的先序遍历非递归算法并输出结果,中间没有空格,末尾不换行。
测试说明
平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。
以下是平台的测试样例:
测试输入:ABC##D##EF###
预期输出:
AEFBDC
AEFBDC
测试输入:ABCD###E#F##G##
预期输出:
AGBEFCD
AGBEFCD
开始你的任务吧,祝你成功!
完整代码
//
// binary_tree.cpp#include "binary_tree.h"// 二叉树的前序遍历
// 参数:二叉树根节点root
// 输出:二叉树的前序遍历,中间没有空格,末尾不换行。
void PreOrder(BTNode* root)
{// 请在这里补充代码,完成本关任务/********** Begin *********/if(root!=NULL){printf("%c",root->data);PreOrder(root->lchild);PreOrder(root->rchild);}/********** End **********/
}// 二叉树的前序遍历非递归算法
// 参数:二叉树根节点root
// 输出:二叉树的前序遍历,中间没有空格,末尾不换行。
void PreOrder_iter(BTNode* root)
{// 请在这里补充代码,完成本关任务/********** Begin *********/BTNode *St[100000],*p;int top=-1;if(root!=NULL){top++;St[top]=root;while(top>-1){p=St[top];top--;printf("%c",p->data);if(p->rchild!=NULL){top++;St[top]=p->rchild;}if(p->lchild!=NULL){top++;St[top]=p->lchild;}}printf("\n");}/********** End **********/
}
//
// binary_tree.h#ifndef binary_tree_h
#define binary_tree_h#include <bits/stdc++.h>using namespace std;typedef struct BTNode {char data; // 树节点元素BTNode* lchild; // 左子树指针BTNode* rchild; // 右子树指针BTNode() { // 树节点初始化lchild = NULL;rchild = NULL;}BTNode(char item) { // 用元素初始化树节点data = item;lchild = NULL;rchild = NULL;}~BTNode() { // 释放树节点内存lchild = NULL;rchild = NULL;}
} BTNode;//创建新结点的工具函数
BTNode* getNewNode(char e);// 利用先序遍历创建二叉树
// 参数:先序遍历字符串s,字符串初始下标i=0,字符串长度len。
// 返回:二叉树
BTNode* CreateTree(char* s, int &i, int len);// 二叉树的前序遍历
// 参数:二叉树根节点root
// 输出:二叉树的前序遍历,中间没有空格,末尾不换行。
void PreOrder(BTNode* root);// 二叉树的前序遍历非递归算法
// 参数:二叉树根节点root
// 输出:二叉树的前序遍历,中间没有空格,末尾不换行。
void PreOrder_iter(BTNode* root);#endif /* binary_tree_h */
第5关:二叉树中序遍历递归和非递归算法
任务描述
本关任务:给定一棵二叉树,使用递归和非递归的方法实现二叉树的中序遍历结果。
相关知识
为了完成本关任务,你需要掌握:1.递归算法,2.二叉树左右子树性质,3.二叉树中序遍历。
递归法
递归算法recursion algorithm在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。其核心是将原始问题转化为子问题。
例如:计算n阶乘的程序在数学上可以定义为:
则递归算法求n阶乘的伪代码为:
int fact(int n){if(n == 0)return 1;elsereturn n * fact(n - 1);
}
二叉树左右子树性质
二叉树的每个节点最多只有两个分支,通常分支被称作左子树和右子树,并且二叉树的分支具有左右次序,不能颠倒。图1是一棵二叉树。
编程要求
本关的编程任务是补全右侧代码片段InOrder和InOrder_iter中Begin至End中间的代码,具体要求如下:
- 在InOrder中使用递归算法实现二叉树中序遍历递归算法并输出结果,中间没有空格,末尾不换行。
- 在InOrder_iter中实现二叉树的中序遍历非递归算法并输出结果,中间没有空格,末尾不换行。
测试说明
平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。
以下是平台的测试样例:
测试输入:ABC##D##EF###
预期输出:
CBDAFE
CBDAFE
测试输入:ABCD###E#F##G##
预期输出:
DCBEFAG
DCBEFAG
开始你的任务吧,祝你成功!
完整代码
//
// binary_tree.cpp#include "binary_tree.h"// 二叉树的中序遍历
// 参数:二叉树根节点root
// 输出:二叉树的中序遍历,中间没有空格,末尾不换行。
void InOrder(BTNode* root)
{// 请在这里补充代码,完成本关任务/********** Begin *********/if(root!=NULL){InOrder(root->lchild);printf("%c",root->data);InOrder(root->rchild);}/********** End **********/
}// 二叉树的中序遍历非递归算法
// 参数:二叉树根节点root
// 输出:二叉树的中序遍历,中间没有空格,末尾不换行。
void InOrder_iter(BTNode* root)
{// 请在这里补充代码,完成本关任务/********** Begin *********/BTNode *St[100000],*p;int top=-1;if(root!=NULL){p=root;while(top>-1||p!=NULL){while(p!=NULL){top++;St[top]=p;p=p->lchild;}if(top>-1){p=St[top];top--;printf("%c",p->data);p=p->rchild;}}printf("\n");}/********** End **********/
}
//
// binary_tree.h#ifndef binary_tree_h
#define binary_tree_h#include <bits/stdc++.h>using namespace std;typedef struct BTNode {char data; // 树节点元素BTNode* lchild; // 左子树指针BTNode* rchild; // 右子树指针BTNode() { // 树节点初始化lchild = NULL;rchild = NULL;}BTNode(char item) { // 用元素初始化树节点data = item;lchild = NULL;rchild = NULL;}~BTNode() { // 释放树节点内存lchild = NULL;rchild = NULL;}
} BTNode;//创建新结点的工具函数
BTNode* getNewNode(char e);// 利用先序遍历创建二叉树
// 参数:先序遍历字符串s,字符串初始下标i=0,字符串长度len。
// 返回:二叉树
BTNode* CreateTree(char* s, int &i, int len);// 二叉树的前序遍历
// 参数:二叉树根节点root
// 输出:二叉树的中序遍历,中间没有空格,末尾不换行。
void InOrder(BTNode* root);// 二叉树的中序遍历非递归算法
// 参数:二叉树根节点root
// 输出:二叉树的中序遍历,中间没有空格,末尾不换行。
void InOrder_iter(BTNode* root);#endif /* binary_tree_h */
第6关:层次遍历二叉树
任务描述
本关任务:给定一棵二叉树,借助队列实现层次遍历二叉树。
相关知识
为了完成本关任务,你需要掌握:1.队列基本操作,2.二叉树层次遍历。
队列基本操作
本关卡提供C++ STL模板队列queue的相关操作和功能。
- 使用实例如下:
queue<int> q; // 创建队列对象
q.push(3); // 元素入队列
q.push(4);
cout<<q.size()<<endl; //打印队列元素个数
while(!q.empty()) {cout<<q.front()<<endl; // 打印队首元素q.pop(); // 移除队首元素
}
二叉树层次遍历
层次遍历要求先访问离根节点最近的层的节点,然后依次访问下一层的节点。例如:图1的层次遍历顺序为节点上的数字,结果为:ABECDF。
编程要求
本关的编程任务是补全右侧代码片段LevelOrder中Begin至End中间的代码,具体要求如下:
- 在LevelOrder中实现二叉树的层次遍历并输出结果,中间没有空格,末尾不换行。
测试说明
平台将自动编译补全后的代码,并生成若干组测试数据,接着根据程序的输出判断程序是否正确。
以下是平台的测试样例:
测试输入:ABC##D##EF###
预期输出:ABECDF
测试输入:ABCD###E#F##G##
预期输出:ABGCEDF
开始你的任务吧,祝你成功!
完整代码
//
// binary_tree.cpp#include "binary_tree.h"// 二叉树的层次遍历(队列实现)
// 参数:二叉树根节点root
// 输出:二叉树的层次遍历,中间没有空格,末尾不换行。
void LevelOrder(BTNode* root)
{// 请在这里补充代码,完成本关任务/********** Begin *********/queue<BTNode*> que;que.push(root);while(!que.empty()){int size=que.size();for(int i=1;i<=size;i++){BTNode* p=que.front();que.pop();cout << p->data;if(p->lchild)que.push(p->lchild);if(p->rchild)que.push(p->rchild);}}/********** End **********/
}
//
// binary_tree.h#ifndef binary_tree_h
#define binary_tree_h#include <bits/stdc++.h>using namespace std;typedef struct BTNode {char data; // 树节点元素BTNode* lchild; // 左子树指针BTNode* rchild; // 右子树指针BTNode() { // 树节点初始化lchild = NULL;rchild = NULL;}BTNode(char item) { // 用元素初始化树节点data = item;lchild = NULL;rchild = NULL;}~BTNode() { // 释放树节点内存lchild = NULL;rchild = NULL;}
} BTNode;//创建新结点的工具函数
BTNode* getNewNode(char e);// 利用先序遍历创建二叉树
// 参数:先序遍历字符串s,字符串初始下标i=0,字符串长度len。
// 返回:二叉树
BTNode* CreateTree(char* s, int &i, int len);// 二叉树的层次遍历(队列实现)
// 参数:二叉树根节点root
// 输出:二叉树的层次遍历,中间没有空格,末尾不换行。
void LevelOrder(BTNode* root);#endif /* binary_tree_h */
第7关:由前序和中序遍历序列构造二叉树
任务描述
本关任务要求采用前序遍历序列和中序遍历序列构造二叉树。
相关知识
给定一棵二叉树的前序遍历序列和中序遍历序列可以构造出这棵二叉树。例如前序序列是ABDECFG,中序序列是DBEAFCG,那么这颗二叉树的结构如图1所示。
树结点结构定义为:
struct BTNode{char data;struct BTNode* lchild;struct BTNode* rchild;
};
编程要求
本关任务是实现ConstructTree.cpp里的TNode* InPreToTree(char *pa, char *ia, int p1, int p2, int i1, int i2)。
该函数的功能是由前序遍历序列和中序遍历序列构造二叉树
前序序列为pa[p1:p2]
中序序列为ia[i1:i2]
返回所构造的二叉树的根指针
提示1:这是一个递归函数,在主程序中调用:
InPreToTree(pa,ia,0,n-1,0,n-1),其中n是序列长度。
提示2:由于在DeleteTree()中是使用delete删除一个树结点,所以在InPreToTree()需要使用new来申请结点空间。
//ConstructTree.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include binary_tree.h"
/*
InPreToTree(): 由前序遍历序列和中序遍历序列构造二叉树
前序序列为pa[p1:p2]
中序序列为ia[i1:i2]
返回所构造的二叉树的根指针
*/
TNode* InPreToTree(char *pa, char *ia, int p1, int p2, int i1, int i2)
{//在begin和end之间添加你的代码/********* begin **********//********* end ************/
}
void PrintPostTravel(BTNode* t)
{if(t==NULL) return;if(t->lchild) PrintPostTravel(t->lchild);if(t->rchild) PrintPostTravel(t->rchild);printf("%c", t->data);
}
void DeleteTree(BTNode* t)
{if(t==NULL) return;if(t->lchild) DeleteTree(t->lchild);if(t->rchild) DeleteTree(t->rchild);delete t;
}
测试说明
本关的测试过程如下:
平台编译step7/Main.cpp;
平台运行该可执行文件,并以标准输入方式提供测试输入;
平台获取该可执行文件的输出,然后将其与预期输出对比,如果一致则测试通过;否则测试失败。
输入格式:
输入前序序列
输入中序序列
输出格式:
输出后序序列
以下是平台对step7/Main.cpp的测试样例:
样例输入
ABDECFG
DBEAFCG
样例输出
Post Travel Result:DEBFGCA
开始你的任务吧,祝你成功!
完整代码
/*作答区文件*/
///
#include "binary_tree.h"
//**InPreToTree(): 由前序遍历序列和中序遍历序列构造二叉树前序序列为pa[p1:p2]中序序列为ia[i1:i2]返回所构造的二叉树的根指针
*/
BTNode* InPreToTree(char *pa, char *ia, int p1, int p2, int i1, int i2)
{/*请在BEGIN和END之间实现你的代码*//*****BEGIN*****/BTNode *root=new BTNode;root->data=pa[p1];root->lchild=NULL;root->rchild=NULL;if(pa[p1]==pa[p2])return root;int a=i1;while(ia[a]!=root->data&&a<=i2)a++;if(ia[a]!=root->data)exit(0);int leftlen=a-i1; if(leftlen>0)root->lchild=InPreToTree(pa,ia,p1+1,p1+leftlen,i1,a-1);int rightlen=i2-a;if(rightlen>0)root->rchild=InPreToTree(pa,ia,p2-rightlen+1,p2,a+1,i2);return root;/******END******/
}
//
// binary_tree.h 头文件#ifndef binary_tree_h
#define binary_tree_h#include <bits/stdc++.h>using namespace std;typedef struct BTNode {char data; // 树节点元素BTNode* lchild; // 左子树指针BTNode* rchild; // 右子树指针BTNode() { // 树节点初始化lchild = NULL;rchild = NULL;}BTNode(char item) { // 用元素初始化树节点data = item;lchild = NULL;rchild = NULL;}~BTNode() { // 释放树节点内存lchild = NULL;rchild = NULL;}
} BTNode;/**InPreToTree(): 由前序遍历序列和中序遍历序列构造二叉树前序序列为pa[p1:p2]中序序列为ia[i1:i2]返回所构造的二叉树的根指针
*/
BTNode* InPreToTree(char *pa, char *ia, int p1, int p2, int i1, int i2);#endif /* binary_tree_h */
第8关:由中序序列和后序序列构造二叉树
任务描述
本关任务要求采用中序遍历序列和后序遍历序列构造二叉树。
相关知识
给定一棵二叉树的中序遍历序列和后序遍历序列可以构造出这棵二叉树。例如后序序列是DEBFGCA,中序序列是DBEAFCG,那么这颗二叉树的结构如图1所示。
树结点结构定义为:
struct BTNode{char data;struct BTNode* lchild;struct BTNode* rchild;
};
编程要求
本关任务是实现ConstructTree.cpp里的BTNode* InPostToTree(char *post, char *in, int n)。
该函数的功能是由后序遍历序列和中序遍历序列构造二叉树
后序序列为post[0:n-1]
中序序列为in[0:n-1]
返回所构造的二叉树的根指针
提示1:这是一个递归函数,在主程序中调用:
InPostToTree(post,in,n),其中n是序列长度。
提示2:由于在DeleteTree()中是使用delete删除一个树结点,所以在InPostToTree()需要使用new来申请结点空间。
//ConstructTree.cpp
#include "binary_tree.h"
/**InPostToTree(): 由后序遍历序列和中序遍历序列构造二叉树后序序列为post[0:n-1]中序序列为in[0:n-1]返回所构造的二叉树的根指针
*/
BTNode* InPostToTree(char *post, char *in, int n);
{//在begin和end之间添加你的代码/********* begin **********//********* end ************/
}
void PrintPreTravel(BTNode* t)
{printf("%c", t->data);if(t==NULL) return;if(t->lchild) PrintPreTravel(t->lchild);if(t->rchild) PrintPreTravel(t->rchild);
}
void DeleteTree(BTNode* t)
{if(t==NULL) return;if(t->lchild) DeleteTree(t->lchild);if(t->rchild) DeleteTree(t->rchild);delete t;
}
测试说明
本关的测试过程如下:
平台编译step8/Main.cpp;
平台运行该可执行文件,并以标准输入方式提供测试输入;
平台获取该可执行文件的输出,然后将其与预期输出对比,如果一致则测试通过;否则测试失败。
输入格式:
输入后序序列
输入中序序列
输出格式:
输出前序序列
以下是平台对step8/Main.cpp的测试样例:
样例输入
DEBFGCA
DBEAFCG
样例输出
Pre Travel Result:ABDECFG
开始你的任务吧,祝你成功!
完整代码
/*step8/ConstructTree.cpp 作答区文件*/
///
#include "binary_tree.h"
//**InPostToTree(): 由后序遍历序列和中序遍历序列构造二叉树后序序列为post[0:n-1]中序序列为in[0:n-1]返回所构造的二叉树的根指针
*/
BTNode* InPostToTree(char *post, char *in, int n)
{/*请在BEGIN和END之间实现你的代码*//*****BEGIN*****/BTNode *s;char r,*p;int k;if (n<=0) return NULL;r=*(post+n-1);s=(BTNode *)malloc(sizeof(BTNode));s->data=r;for (p=in; p<in+n; p++)if (*p==r)break;k=p-in;s->lchild=InPostToTree(post,in,k);s->rchild=InPostToTree(post+k,p+1,n-k-1);return s;/******END******/
}
//
// binary_tree.h 头文件#ifndef binary_tree_h
#define binary_tree_h#include <bits/stdc++.h>using namespace std;typedef struct BTNode {char data; // 树节点元素BTNode* lchild; // 左子树指针BTNode* rchild; // 右子树指针BTNode() { // 树节点初始化lchild = NULL;rchild = NULL;}BTNode(char item) { // 用元素初始化树节点data = item;lchild = NULL;rchild = NULL;}~BTNode() { // 释放树节点内存lchild = NULL;rchild = NULL;}
} BTNode;/**InPostToTree(): 由后序遍历序列和中序遍历序列构造二叉树后序序列为post[0:n-1]中序序列为in[0:n-1]返回所构造的二叉树的根指针
*/
BTNode* InPostToTree(char *post, char *in, int n);#endif /* binary_tree_h */
第9关:二叉树的顺序存储及基本操作
任务描述
本关任务:以顺序结构存储二叉树,编写前序、中序、后序及层次顺序遍历二叉树的算法,并计算二叉树深度、所有结点总数。
相关知识
二叉树的定义
二叉树的递归定义:
- 二叉树或者是一棵空树。
- 或者是一棵由一个根结点和两棵互不相交的分别称做根结点的左子树和右子树所组成的非空树,左子树和右子树又同样都是一棵二叉树。
二叉树的逻辑示意图
二叉树与度为2的树的区别:
度为2的树至少有3个结点,而二叉树的结点数可以为0。
度为2的树不区分子树的次序,而二叉树中的每个结点最多有两个孩子结点,且必须要区分左右子树,即使在结点只有一棵子树的情况下也要明确指出该子树是左子树还是右子树。
二叉树的5种形态:
二叉树的五种形态
二叉树的性质
性质1 非空二叉树上叶结点数等于双分支结点数加1。即n0=n2+1。
约定:二叉树上叶结点数为n0,单分支结点数为n1,双分支结点数为n2,
性质2 非空二叉树上第i层上至多有 2
i−1
个结点,这里应有i≥1。
性质3 高度为h的二叉树至多有2
h
−1个结点(h≥1)。
满二叉树:在一棵二叉树中,当第i层的结点数为2
i−1
个时,则称此层的结点数是满的,当一棵二叉树中的每一层都满时,且叶子结点在同一层上,则称此树为满二叉树。
满二叉树特性:
-
除叶子结点以外的其他结点的度皆为2。
-
高度为h的满二叉树中的结点数为2
h
−1个。 -
层序编号:从根结点为1开始,按照层次从小到大、同一层从左到右的次序顺序编号。可以对满二叉树的结点进行连续编号。
满二叉树编号
完全二叉树:
完全二叉树:在一棵二叉树中,除最后一层外,若其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干个结点,则称此树为完全二叉树。
完全二叉树特性:
-
完全二叉树中至多只有最下边两层结点的度数小于2。
-
高度为h的完全二叉树若按层序编号,它与高度为h的满二叉树中结点的编号一一对应。
如下图所示的一棵完全二叉树,它与等高度的满二叉树相比,在最后一层的右边缺少了3个结点。
完全二叉树编号
性质4 对完全二叉树中编号为i的结点(1≤i≤n,n≥1,n为结点数)有:
(1)若 i⩽└ n/2 ┘,即2i≤n,则编号为i的结点为分支结点,否则为叶子结点。
(2)若n为奇数,则每个分支结点都既有左孩子结点,也有右孩子结点; 若n为偶数,则编号最大的分支结点只有左孩子结点,没有右孩子结点,其余分支结点都有左、右孩子结点。
(3)若编号为i的结点有左孩子结点,则左孩子结点的编号为2i;若编号为i的结点有右孩子结点,则右孩子结点的编号为(2i+1)。
(4)除树根结点外,若一个结点的编号为i,则它的双亲结点的编号为 └ i/2 ┘,也就是说,当i为偶数时,其双亲结点的编号为 i/2,它是双亲结点的左孩子结点,当i为奇数时,其双亲结点的编号为 (i−1)/2 ,它是双亲结点的右孩子结点。
二叉树的遍历
二叉树的遍历是指按一定的次序访问树中的所有结点,使每个结点恰好被访问一次。其中遍历次序保证了二叉树上每个结点均被访问一次且仅有一次。
二叉树常用的遍历有先序(根)遍历、中序(根)遍历、后序(根)遍历和层次遍历。
所谓先序、中序、后序,区别在于访问根结点的顺序。
1.先序遍历
若二叉树非空,则:
① 访问根结点;
② 先序遍历左子树;
③ 先序遍历右子树。
先序遍历序列的特点:其第一个元素值为二叉树中根结点值。
2.中序遍历
若二叉树非空,则:
① 中序遍历左子树;
② 访问根结点;
③ 中序遍历右子树。
中序遍历序列的特点:若已知二叉树的根结点值,以该值为界,将中序遍历序列分为两部分,前半部分为左子树的中序遍历序列,后半部分为右子树的中序遍历序列。
3.后序遍历
若二叉树非空,则:
① 后序遍历左子树;
② 后序遍历右子树;
③ 访问根结点。
后序遍历序列的特点:最后一个元素值为二叉树中根结点值。
4. 层次遍历
层次遍历是从根结点出发,按照从上向下,同一层从左向右的次序访问所有的结点。采用层次遍历得到的访问结点序列称为层次遍历序列。
层次遍历序列的特点:其第一个元素值为二叉树中根结点值。
例:图1表示一个二叉树
前序遍历:ABCDEF
中序遍历:CBDAFE
后序遍历:CDBFEA
层次遍历:ABECDF
二叉树也可以采用两种存储方式:顺序存储结构和链式存储结构。
二叉树的顺序存储结构
顺序存储一棵二叉树时,就是用一组连续的存储单元存放二叉树中的结点。
由二叉树的性质4可知,对于完全二叉树(或满二叉树),树中结点层序编号可以唯一地反映出结点之间的逻辑关系,所以可以用一维数组按从上到下、从左到右的顺序存储树中所有结点值,通过数组元素的下标关系反映完全二叉树或满二叉树中结点之间的逻辑关系。
一棵完全二叉树的顺序存储结构:
完全二叉树及其相应的顺序存储结构
一般的二叉树的顺序存储结构:
一般二叉树及其相应的顺序存储结构
二叉树顺序存储结构的类型定义如下:
typedef ElemType SqBinTree[MaxSize];
其中,ElemType为二叉树中结点的数据值类型,MaxSize为顺序表的最大长度。为了方便运算,通常将下标为0的位置空着,值为#的结点为空结点。
完全二叉树或满二叉树采用顺序存储结构比较合适,既能够最大可能地节省存储空间,又可以利用数组元素的下标确定结点在二叉树中的位置以及结点之间的关系。
对于一般二叉树,如果它接近于完全二叉树形态,需要增加的空结点个数不多,也可适合采用顺序存储结构。
如果需要增加很多空结点才能将一棵二叉树改造成为一棵完全二叉树,采用顺序存储结构会造成空间的大量浪费,这时不宜用顺序存储结构。例如:
编程要求
根据提示,在右侧编辑器补充代码。具体要求如下:
InitBiTree(SqBiTree &T)//构造空二叉树T。CreateBiTree(SqBiTree &T)//按层序次序输入二叉树中结点的值(字符型或整型), 构造顺序存储的二叉树TBiTreeEmpty(SqBiTree T)//判断二叉树T是否为空二叉树,若是则返回TRUE,否则FALSEBiTreeDepth(SqBiTree T)//返回二叉树T的深度PreOrderTraverse(SqBiTree T,void(*Visit)(TElemType))//先序遍历二叉树T,对每个结点调用函数Visit一次且仅一次InOrderTraverse(SqBiTree T,void(*Visit)(TElemType))//中序遍历二叉树T,对每个结点调用函数Visit一次且仅一次PostOrderTraverse(SqBiTree T,void(*Visit)(TElemType))//后序遍历二叉树T,对每个结点调用函数Visit一次且仅一次 LevelOrderTraverse(SqBiTree T,void(*Visit)(TElemType)) // 层序遍历二叉树
测试说明
平台会对你编写的代码进行测试:
测试输入:ABCDEF###G##H
预期输出:
按先序遍历的结果为:ABDEGCFH
按中序遍历的结果为:DBGEAFHC
按后序遍历的结果为:DGEBHFCA
按层序遍历的遍历结果为:ABCDEFGH
该二叉树的高度为:4
开始你的任务吧,祝你成功!
完整代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>#define OK 1
#define ERROR 0#define MAX_TREE_SIZE 100typedef char TElemType ;typedef TElemType SqBiTree[MAX_TREE_SIZE];TElemType Nil='#';void input(TElemType &x) // 函数变量
{scanf("%c",&x);
}void visit(TElemType x) // 函数变量
{printf("%c",x);
}void InitBiTree(SqBiTree &T)
{ // 构造空二叉树T。因为T是数组名,故不需要&int i;for(i=0;i<MAX_TREE_SIZE;i++)T[i]=Nil; // 初值为空(Nil在主程中定义)
}void CreateBiTree(SqBiTree &T)
{ // 按层序次序输入二叉树中结点的值(字符型或整型), 构造顺序存储的二叉树T/********** Begin **********/ int i=1;scanf("%s",T+1);while(T[i] != '\0')i++;T[i]='#';/********** End **********/
}int BiTreeEmpty(SqBiTree T)
{ // 初始条件:二叉树T存在。操作结果:若T为空二叉树,则返回TRUE,否则FALSEif(T[1]==Nil) // 根结点为空,则树空return 1;elsereturn 0;
}int BiTreeDepth(SqBiTree T)
{ // 初始条件:二叉树T存在。操作结果:返回T的深度/********** Begin **********/ int i=MAX_TREE_SIZE-1,j;while(T[i]=='#')i--;j=i;int dep=0;do{dep++;j=j/2;}while(j>=1);return dep;/********** End **********/
}
void PreTraverse(SqBiTree T,int e)
{ // PreOrderTraverse()调用/********** Begin **********/ if(T[e] != '#'){visit(T[e]);PreTraverse(T,2*e);PreTraverse(T,2*e+1);} /********** End **********/
}
void PreOrderTraverse(SqBiTree T,void(*Visit)(TElemType))
{ // 初始条件:二叉树存在,Visit是对结点操作的应用函数// 操作结果:先序遍历T,对每个结点调用函数Visit一次且仅一次if(!BiTreeEmpty(T)) // 树不空PreTraverse(T,1);printf("\n");
}void InTraverse(SqBiTree T,int e)
{ // InOrderTraverse()调用/********** Begin **********/ if(T[e] != '#'){InTraverse(T,2*e);visit(T[e]);InTraverse(T,2*e+1);} /********** End **********/
}void InOrderTraverse(SqBiTree T,void(*Visit)(TElemType))
{ // 初始条件:二叉树存在,Visit是对结点操作的应用函数// 操作结果:中序遍历T,对每个结点调用函数Visit一次且仅一次if(!BiTreeEmpty(T)) // 树不空InTraverse(T,1);printf("\n");
}void PostTraverse(SqBiTree T,int e)
{ // PostOrderTraverse()调用/********** Begin **********/ if(T[e] != '#'){PostTraverse(T,2*e);PostTraverse(T,2*e+1);visit(T[e]);}/********** End **********/
}void PostOrderTraverse(SqBiTree T,void(*Visit)(TElemType))
{ // 初始条件:二叉树T存在,Visit是对结点操作的应用函数// 操作结果:后序遍历T,对每个结点调用函数Visit一次且仅一次if(!BiTreeEmpty(T)) // 树不空PostTraverse(T,1);printf("\n");
}void LevelOrderTraverse(SqBiTree T,void(*Visit)(TElemType))
{ // 层序遍历二叉树/********** Begin **********/ int dep=BiTreeDepth(T);int tree_max=pow(dep,2)-1;for(int i=1;i<tree_max;i++){if(T[i]=='#')continue;visit(T[i]);}printf("\n");/********** End **********/
}int main()
{TElemType e;SqBiTree Bt,s;InitBiTree(Bt);CreateBiTree(Bt); printf("按先序遍历的结果为:");PreOrderTraverse(Bt,visit);printf("按中序遍历的结果为:");InOrderTraverse(Bt,visit);printf("按后序遍历的结果为:");PostOrderTraverse(Bt,visit);printf("按层序遍历的遍历结果为:");LevelOrderTraverse(Bt,visit); printf("该二叉树的高度为:%d\n",BiTreeDepth(Bt) );return 0;
}