A : 二叉树基础
题目描述
创建二叉树类。二叉树的存储结构使用链表。提供操作:前序遍历、中序遍历、后序遍历、层次遍历、计算二叉树结点数目、计算二叉树高度,其中前序遍历要求以递归方式实现,中序遍历、后序遍历要求以非递归方式实现。
输入输出格式
输入格式
第一行为一个数字 n (10<=n<=100000),表示有这棵树有 n 个节点,编号为 1~n。
之后 n 行每行两个数字,第 i 行的两个数字 a、b 表示编号为 i 的节点的左孩子节点为 a,右孩子节点为 b,-1 表示该位置没有节点。
保证数据有效,根节点为 1。
输出格式
第一行,n 个数字,表示该树的前序遍历。
第二行,n 个数字,表示该树的中序遍历。
第三行,n 个数字,表示该树的后序遍历。
第四行,n 个数字,表示该树的层次遍历。
第五行,n 个数字,第 i 个数字表示以 i 节点为根的子树的节点数目。
第六行,n 个数字,第 i 个数字表示以 i 节点为根的子树的高度。
数据结构与算法描述
现需要构造一个树的节点结构体,包括节点的数字,左右孩子。构造二叉树链表类,私有成员为根节点,节点的指针数组,树的节点个数。构造函数中要用new给初始化根节点,并分配空间。给指针数组分配空间,并把根节点传到数组里。
struct binaryTreeNode {//树节点
int element;
binaryTreeNode* leftchild;
binaryTreeNode* rightchild;
binaryTreeNode(int a){
element=a;
leftchild=rightchild=NULL;
}
};
输入函数:参数有结点序号,左右孩子的输入,利用结点的指针数组依次将存进数组的树节点提取出来,不为-1则说明孩子存在,则将其存在数组对应的位置。再主函数中依次将n个节点传入函数。
void input(int i,int a,int b){//输入函数
binaryTreeNode* x=treenode[i];
if(a!=-1){
x->leftchild=new binaryTreeNode(a);//初始化该孩子
treenode[a]=x->leftchild;//将孩子传给对应位置的指针数组
}
if(b!=-1){
x->rightchild=new binaryTreeNode(b);
treenode[b]=x->rightchild;
}
}
前序遍历:利用递归,每次先输出根节点的数,再依次递归左子树、右子树。
void preOrder(binaryTreeNode *t) {//前序遍历
if (t != NULL) {
cout << t->element << " ";
preOrder(t->leftchild);
preOrder(t->rightchild);
}
}
void outputpreOrder(){//前序遍历输出
preOrder(root);
cout << endl;
}
中序遍历:利用栈先进后出的性质。从根开始压入栈中,依次寻找左子树并依次压入栈中。等到没有左子树了,将栈顶输出,再转向右子树,如果右子树存在,再判断右子树是否有左子树,再次循环。
void inOrder(){//中序遍历
arrayStack<binaryTreeNode*> s(treesize);//声明一个treesize大小的栈
binaryTreeNode* t;
t=root;
while(t!=NULL || !s.empty()){
while(t!=NULL){
s.push(t);//不为空压入栈中
t=t->leftchild;//看是否有左子树
}
//此时t的左子树或没有,或者已经输出了
t=s.top();
s.pop();
cout<<t->element<<" ";//将栈顶输出
t=t->rightchild;
}
}
后序遍历:前序遍历的顺序是根左右,后序遍历的顺序是左右根,将前序遍历的左右反过来,就变成了根右左,借助栈倒过来就变成了左右根和后序遍历的顺序一样了。前序遍历需要一个栈,存后序遍历倒过来的数也要一个栈。将原前序遍历输出的位置改为进入后序遍历的栈压入,依次找是否存在右子树(原前序遍历为左子树),当没有时将栈顶元素弹出,并判断其是否有左子树(原前序遍历是右子树)。依次压入栈后,因为栈是后进先出,使得根右左倒着输出,为后序遍历的左右根。
void postOrder(){//后序遍历
arrayStack<binaryTreeNode*> s1(treesize);//前序遍历需要用的栈
arrayStack<binaryTreeNode*> s2(treesize);//存后序遍历
binaryTreeNode* t=root;
while(t!=NULL || !s1.empty()){
while(t!=NULL){
s2.push(t);//中间的根节点放到后序的栈里
s1.push(t);
t=t->rightchild;
}
//此时t的左(后序改为右)子树或没有,或者已经输出了
t=s1.top();
s1.pop();
t=t->leftchild;//查看已经输出的节点是否有右(后序改为左)子树
}
while(!s2.empty()){//利用栈后进先出,输出后序遍历
binaryTreeNode* a=s2.top();
cout<<a->element<<" ";
s2.pop();
}
}
层次遍历:利用队列先进先出,将跟压入队列中。在循环中先去除队列的第一个,并输出、删除,然后依次判断左右子树是否有,如果有则压入队列中,直到队列为空循环结束。
void linkedBinaryTree::levelOrder() {//层次遍历
queue<binaryTreeNode*> q(treesize);//声明一个 treesize大小的队列,利用队列先进先出
binaryTreeNode* t;
q.push(root);//将根压入队列中
while (!q.empty()) {
t = q.front();
cout << t->element << " ";
q.pop();
//先判断左,再判断右
if (t->leftchild != NULL) {
q.push(t->leftchild);
}
if (t->rightchild != NULL) {
q.push(t->rightchild);
}
}
cout << endl;
}
计算以i为根节点的子树的节点个数:利用递归当i为NULL时返回0,依次用nl,nr接收左右子树的节点数,返回值为左右子树节点数求和并加1,原左右子树节点数本身也要加一。
int linkedBinaryTree::number(binaryTreeNode* t){
if (t == NULL) return 0;
int nl = number(t->leftchild);//左子树节点数
int nr = number(t->rightchild);//右子树节点数
return (nl++)+(nr++)+1;//左右节点数求和并加上t节点,原节点数本身加一(递归返回的过程)
}
输出节点个数:类似层次遍历,用一个数组,数组对应的位置就是以对应节点为根时子树的节点个数。再层次遍历时依次调用上一个函数,将返回值存入数组中。最后将数组输出。
void linkedBinaryTree::outputnumber(){
queue<binaryTreeNode*> q(treesize);//队列类层次遍历
binaryTreeNode* t;
int b[treesize + 1];//以各节点为根的节点数
q.push(root);
while (!q.empty()) {//层次遍历
t = q.front();
b[t->element]=number(t);//将节点数,存在对应节点的数组位置上
q.pop();
if (t->leftchild != NULL) {
q.push(t->leftchild);
}
if (t->rightchild != NULL) {
q.push(t->rightchild);
}
}
for(int i=1;i<=treesize;i++){
cout<<b[i]<<" ";
}
cout<<endl;
}
计算以i为根节点的子树的高:利用递归,用hl,hr分别接受递归产生的左右子树的高,判断hl,hr哪个大,大的加一就为要返回的高,本身也要加一。
int linkedBinaryTree::height(binaryTreeNode* t) {
if (t == NULL) return 0;
int hl = height(t->leftchild);//左子树的高
int hr = height(t->rightchild);//右子树的高
if (hl > hr)return ++hl;//将较大的加一(加上t本身)作为高,原高本身加一(递归返回的过程)
else return ++hr;
}
输出个节点的高:与输出系节点个数相同。致死将数组改为存高度。
void linkedBinaryTree::outputheight() {
queue<binaryTreeNode*> q(treesize);//队列,类层次遍历
binaryTreeNode* t;
int b[treesize + 1];//各节点高度
q.push(root);
while (!q.empty()) {//层次遍历
t = q.front();
b[t->element]=height(t);//将高度存到数组的对应位置
q.pop();
if (t->leftchild != NULL) {
q.push(t->leftchild);
}
if (t->rightchild != NULL) {
q.push(t->rightchild);
}
}
for(int i=1;i<=treesize;i++){
cout<<b[i]<<" ";
}
cout<<endl;
}
测试结果
完整代码(含注释)
#include<iostream>
using namespace std;
template<class T>
class queue {
private:
int queuefront;//第一个数前一个位置的索引
int queueback;//最后一个数的索引
int arraylength;//队列长度
T* queue0;
public:
queue(int l) {
arraylength = l;
queue0 = new T[arraylength];
queuefront = queueback = 0;
}
~queue() { delete[] queue0; }
bool empty()const { return queuefront==queueback; }//是否为空
int qsize()const { return queueback - queuefront; }//列表大小
T& front() { return queue0[queuefront]; }//第一个位置
void pop() {//删除
queuefront++;
}
void push(T& theelement) {//插入
queue0[queueback] = theelement;
queueback++;
}
};
template<class T>
class arrayStack {
private:
int stackTop;//栈顶
int arrayLength;//栈的容量
T* stack;//元素数组
public:
arrayStack(int al=2000) {
arrayLength = al;
stack = new T[al];
stackTop = -1;//栈为空
}
~arrayStack() { delete[] stack; }
bool empty()const { return stackTop == -1; }//判断是否为空
int Stacksize()const { return stackTop + 1; }//元素个数
T& top() { return stack[stackTop]; }//返回栈顶元素
void pop() {//删除栈顶元素
stack[stackTop] = 0;
stackTop--;
}
void push(const T& theElement) {//在栈顶后加入元素
++stackTop;
stack[stackTop] = theElement;
}
};
struct binaryTreeNode {//树节点
int element;
binaryTreeNode* leftchild;
binaryTreeNode* rightchild;
binaryTreeNode(int a){
element=a;
leftchild=rightchild=NULL;
}
};
class linkedBinaryTree {//二叉树链表
private:
binaryTreeNode* root;//根节点
binaryTreeNode** treenode;//节点的指针数组
int treesize;//树的节点个数
public:
linkedBinaryTree(int t) {
root = new binaryTreeNode(1);//初始化根节点
treesize = t;
treenode=new binaryTreeNode*[treesize+1];//给指针数组分配空间
treenode[1]=root;
}
bool empty()const { return treesize == 0; }
void input(int i,int a,int b){//输入函数
binaryTreeNode* x=treenode[i];
if(a!=-1){
x->leftchild=new binaryTreeNode(a);//初始化该孩子
treenode[a]=x->leftchild;//将孩子传给对应位置的指针数组
}
if(b!=-1){
x->rightchild=new binaryTreeNode(b);
treenode[b]=x->rightchild;
}
}
void preOrder(binaryTreeNode *t) {//前序遍历
if (t != NULL) {
cout << t->element << " ";
preOrder(t->leftchild);
preOrder(t->rightchild);
}
}
void outputpreOrder(){//前序遍历输出
preOrder(root);
cout << endl;
}
void inOrder(){//中序遍历
arrayStack<binaryTreeNode*> s(treesize);//声明一个treesize大小的栈
binaryTreeNode* t;
t=root;
while(t!=NULL || !s.empty()){
while(t!=NULL){
s.push(t);//不为空压入栈中
t=t->leftchild;//看是否有左子树
}
//此时t的左子树或没有,或者已经输出了
t=s.top();
s.pop();
cout<<t->element<<" ";//将栈顶输出
t=t->rightchild;
}
}
void postOrder(){//后序遍历
arrayStack<binaryTreeNode*> s1(treesize);//前序遍历需要用的栈
arrayStack<binaryTreeNode*> s2(treesize);//存后序遍历
binaryTreeNode* t=root;
while(t!=NULL || !s1.empty()){
while(t!=NULL){
s2.push(t);//中间的根节点放到后序的栈里
s1.push(t);
t=t->rightchild;
}
//此时t的左(后序改为右)子树或没有,或者已经输出了
t=s1.top();
s1.pop();
t=t->leftchild;//查看已经输出的节点是否有右(后序改为左)子树
}
while(!s2.empty()){//利用栈后进先出,输出后序遍历
binaryTreeNode* a=s2.top();
cout<<a->element<<" ";
s2.pop();
}
}
void levelOrder();
int number(binaryTreeNode* t);
void outputnumber();
int height(binaryTreeNode* t);
void outputheight();
};
void linkedBinaryTree::levelOrder() {//层次遍历
queue<binaryTreeNode*> q(treesize);//声明一个 treesize大小的队列,利用队列先进先出
binaryTreeNode* t;
q.push(root);//将根压入队列中
while (!q.empty()) {
t = q.front();
cout << t->element << " ";
q.pop();
//先判断左,再判断右
if (t->leftchild != NULL) {
q.push(t->leftchild);
}
if (t->rightchild != NULL) {
q.push(t->rightchild);
}
}
cout << endl;
}
int linkedBinaryTree::number(binaryTreeNode* t){
if (t == NULL) return 0;
int nl = number(t->leftchild);//左子树节点数
int nr = number(t->rightchild);//右子树节点数
return (nl++)+(nr++)+1;//左右节点数求和并加上t节点,原节点数本身加一(递归返回的过程)
}
void linkedBinaryTree::outputnumber(){
queue<binaryTreeNode*> q(treesize);//队列类层次遍历
binaryTreeNode* t;
int b[treesize + 1];//以各节点为根的节点数
q.push(root);
while (!q.empty()) {//层次遍历
t = q.front();
b[t->element]=number(t);//将节点数,存在对应节点的数组位置上
q.pop();
if (t->leftchild != NULL) {
q.push(t->leftchild);
}
if (t->rightchild != NULL) {
q.push(t->rightchild);
}
}
for(int i=1;i<=treesize;i++){
cout<<b[i]<<" ";
}
cout<<endl;
}
int linkedBinaryTree::height(binaryTreeNode* t) {
if (t == NULL) return 0;
int hl = height(t->leftchild);//左子树的高
int hr = height(t->rightchild);//右子树的高
if (hl > hr)return ++hl;//将较大的加一(加上t本身)作为高,原高本身加一(递归返回的过程)
else return ++hr;
}
void linkedBinaryTree::outputheight() {
queue<binaryTreeNode*> q(treesize);//队列,类层次遍历
binaryTreeNode* t;
int b[treesize + 1];//各节点高度
q.push(root);
while (!q.empty()) {//层次遍历
t = q.front();
b[t->element]=height(t);//将高度存到数组的对应位置
q.pop();
if (t->leftchild != NULL) {
q.push(t->leftchild);
}
if (t->rightchild != NULL) {
q.push(t->rightchild);
}
}
for(int i=1;i<=treesize;i++){
cout<<b[i]<<" ";
}
cout<<endl;
}
int main(){
int n;
cin>>n;
linkedBinaryTree tree(n);
for(int i=1;i<=n;i++){
int a,b;
cin>>a>>b;
tree.input(i,a,b);
}
tree.outputpreOrder();
tree.inOrder();
cout<<endl;//原函数没回车
tree.postOrder();
cout<<endl;
tree.levelOrder();
tree.outputnumber();
tree.outputheight();
return 0;
}
B : 二叉树遍历
题目描述
接收二叉树前序序列和中序序列(各元素各不相同),输出该二叉树的后序序列。
输入输出格式
输入格式
输入有三行:
第一行为数字 n。
第二行有 n 个数字,表示二叉树的前序遍历。
第三行有 n 个数字,表示二叉树的中序遍历。
输出格式
输出一行,表示该二叉树的后序遍历序列。
数据结构与算法描述
前序遍历先输出根,中序遍历为左根右,可以利用中序遍历分开左右子树。在递归函数中找到根在中序遍历的位置,然后分别进行左子树,右子树递归,后面输出根的数。递归函数的参数有,前序的数组,中序的数组,前序数组的起始位置,后序数组的起始位置,各子树数组的长度。
测试结果
完整代码(含注释)
#include<iostream>
using namespace std;
void postOrder(int* preOrder,int* inOrder,int prestart,int instart,int length){//前序的数组,中序的数组,前序数组的起始位置,后序数组的起始位置,各子树数组的长度
int i=0;
while(preOrder[prestart]!=inOrder[instart+i]){//找到中序数组中,根节点的位置,i为左右子树的分界线
i++;
}
if(i>0){
postOrder(preOrder,inOrder,prestart+1,instart,i);//左子树
}
if(length-i-1>0){
postOrder(preOrder,inOrder,prestart+i+1,instart+i+1,length-i-1);//右子树
}
cout<<preOrder[prestart]<<" ";
}
int main(){
int n;
cin>>n;
int preOrder[n];
for(int i=0;i<n;i++){
cin>>preOrder[i];
}
int inOrder[n];
for(int i=0;i<n;i++){
cin>>inOrder[i];
}
postOrder(preOrder,inOrder,0,0,n);
return 0;
}
如能打赏,不胜感激[叩谢]。