第六次作业 二叉树


这个作业属于哪个课程 https://edu.cnblogs.com/campus/qdu/DS2020
这个作业要求在哪里 https://edu.cnblogs.com/campus/qdu/DS2020/homework/11430
这个作业的目标 <①掌握二叉树的基本特性②掌握二叉树的先序、中序、后序的递归遍历算法③理解二叉树的先序、中序、后序的非递归遍历算法④通过求二叉树的深度、叶子结点数和层序遍历等算法,理解二叉树的基本特性>
学号 2018204167

一、实验目的

1、掌握二叉树的基本特性
2、掌握二叉树的先序、中序、后序的递归遍历算法
3、理解二叉树的先序、中序、后序的非递归遍历算法
4、通过求二叉树的深度、叶子结点数和层序遍历等算法,理解二叉树的基本特性

二、实验预习

说明以下概念

1、二叉树:

二叉树作为树形结构的一种,是每个节点最多有两个子树的树结构

2、递归遍历:

所谓遍历,是指沿着某条搜索路线,依次对树(或图)中每个节点均做一次访问,递归作为遍历的一种方法,是利用计算机的堆栈的概念,一般通过调用相同的函数来实现,函数中一般会设置终止的语句。

3、非递归遍历:

树的遍历若采用非递归的方法,就要采用栈去模拟实现。

4、层序遍历:

层序遍历:进行层序遍历时,对某一层的节点访问完后,再按照他们的访问次序对各个节点的左孩子和右孩子顺序访问,这样一层一层进行,先访问的节点其左右孩子也要先访问,这正好符合队列的操作特性。

三、实验内容和要求

1、阅读并运行下面程序,根据输入写出运行结果,并画出二叉树的形态。

#include<stdio.h>
#include<malloc.h>
#include<iostream>
#include<conio.h>
#define MAX 20
typedef struct BTNode{       /*节点结构声明*/
	char data ;               /*节点数据*/
	struct BTNode *lchild;
	struct BTNode *rchild ;  /*指针*/
}*BiTree;

void createBiTree(BiTree *t){ /* 先序遍历创建二叉树*/
	char s;
	BiTree q;
	printf("\nplease input data:(exit for #)");
	s=getche();
	if(s=='#'){*t=NULL; return;}
	q=(BiTree)malloc(sizeof(struct BTNode));
	if(q==NULL){printf("Memory alloc failure!"); exit(0);}
	q->data=s;
	*t=q;
	createBiTree(&q->lchild); /*递归建立左子树*/
	createBiTree(&q->rchild); /*递归建立右子树*/
}

void PreOrder(BiTree p){  /* 先序遍历二叉树*/
    if ( p!= NULL ) {
       	printf("%c", p->data);
       	PreOrder( p->lchild ) ;
       	PreOrder( p->rchild) ;
    }
}
void InOrder(BiTree p){  /* 中序遍历二叉树*/
    if( p!= NULL ) {
 	 InOrder( p->lchild ) ;
   	 printf("%c", p->data);
   	 InOrder( p->rchild) ;
    }
}
void PostOrder(BiTree p){  /* 后序遍历二叉树*/
   if ( p!= NULL ) {
    	PostOrder( p->lchild ) ;
       	PostOrder( p->rchild) ;
       	printf("%c", p->data);
    }
}
void Preorder_n(BiTree p){ /*先序遍历的非递归算法*/
    BiTree stack[MAX],q;
    int top=0,i;
    for(i=0;i<MAX;i++) stack[i]=NULL;/*初始化栈*/
    q=p;
    while(q!=NULL){
        printf("%c",q->data);
        if(q->rchild!=NULL) stack[top++]=q->rchild;
        if(q->lchild!=NULL) q=q->lchild;
        else
            if(top>0) q=stack[--top];
            else q=NULL;
    }
}
void release(BiTree t){ /*释放二叉树空间*/
  	if(t!=NULL){
    	release(t->lchild);
    	release(t->rchild);
    	free(t);
  	}
}
int main(){
    BiTree t=NULL;
    createBiTree(&t);
    printf("\n\nPreOrder the tree is:");
    PreOrder(t);
    printf("\n\nInOrder the tree is:");
    InOrder(t);
    printf("\n\nPostOrder the tree is:");
    PostOrder(t);
    printf("\n\n先序遍历序列(非递归):");
    Preorder_n(t);
    release(t);
    return 0;
}
运行程序
输入:

ABC##DE#G##F###

运行结果:

二叉树形态:

2、在上题中补充求二叉树中求结点总数算法(提示:可在某种遍历过程中统计遍历的结点数),并在主函数中补充相应的调用验证正确性。

算法代码:
#include<stdio.h>
#include<malloc.h>
#include<iostream>
#include<conio.h>
#define MAX 20
typedef struct BTNode{       /*节点结构声明*/
	char data ;               /*节点数据*/
	struct BTNode *lchild;
	struct BTNode *rchild ;  /*指针*/
}*BiTree;

void createBiTree(BiTree *t){ /* 先序遍历创建二叉树*/
	char s;
	BiTree q;
	printf("\nplease input data:(exit for #)");
	s=getche();
	if(s=='#'){*t=NULL; return;}
	q=(BiTree)malloc(sizeof(struct BTNode));
	if(q==NULL){printf("Memory alloc failure!"); exit(0);}
	q->data=s;
	*t=q;
	createBiTree(&q->lchild); /*递归建立左子树*/
	createBiTree(&q->rchild); /*递归建立右子树*/
}

void PreOrder(BiTree p){  /* 先序遍历二叉树*/
    if ( p!= NULL ) {
       	printf("%c", p->data);
       	PreOrder( p->lchild ) ;
       	PreOrder( p->rchild) ;
    }
}
void InOrder(BiTree p){  /* 中序遍历二叉树*/
    if( p!= NULL ) {
 	 InOrder( p->lchild ) ;
   	 printf("%c", p->data);
   	 InOrder( p->rchild) ;
    }
}
void PostOrder(BiTree p){  /* 后序遍历二叉树*/
   if ( p!= NULL ) {
    	PostOrder( p->lchild ) ;
       	PostOrder( p->rchild) ;
       	printf("%c", p->data);
    }
}
void Preorder_n(BiTree p){ /*先序遍历的非递归算法*/
    BiTree stack[MAX],q;
    int top=0,i;
    for(i=0;i<MAX;i++) stack[i]=NULL;/*初始化栈*/
    q=p;
    while(q!=NULL){
        printf("%c",q->data);
        if(q->rchild!=NULL) stack[top++]=q->rchild;
        if(q->lchild!=NULL) q=q->lchild;
        else
            if(top>0) q=stack[--top];
            else q=NULL;
    }
}
void release(BiTree t){ /*释放二叉树空间*/
  	if(t!=NULL){
    	release(t->lchild);
    	release(t->rchild);
    	free(t);
  	}
}
int PreOrder_num(BiTree p) {
	int j=0;
	BiTree stack[MAX],q;
	int top=0,i;
	for(i=0; i<MAX; i++) stack[i]=NULL; /*初始化栈*/
	q=p;
	while(q!=NULL) {
		j++;
		if(q->rchild!=NULL) stack[top++]=q->rchild;
		if(q->lchild!=NULL) q=q->lchild;
		else
			if(top>0) q=stack[--top];
			else q=NULL;
	}
    return j;
}
int main(){
    BiTree t=NULL;
    createBiTree(&t);
    printf("\n\nPreOrder the tree is:");
    PreOrder(t);
    printf("\n\nInOrder the tree is:");
    InOrder(t);
    printf("\n\nPostOrder the tree is:");
    PostOrder(t);
    printf("\n\n先序遍历序列(非递归):");
    Preorder_n(t);
    printf("\n\n结点总数:");
    printf("%d",PreOrder_num(t));
    release(t);
    return 0;
}
运行结果:

3、在上题中补充求二叉树中求叶子结点总数算法(提示:可在某种遍历过程中统计遍历的叶子结点数),并在主函数中补充相应的调用验证正确性。

算法代码:
int LeafNodes(BiTree p) {
	int num1=0 ,num2=0;
	if(p==NULL)
	return 0;
	else if(p->lchild==NULL&&p->rchild==NULL)
	return 1;
	else{ 
		num1=LeafNodes(p->lchild) ;
		num2=LeafNodes(p->rchild) ;
 		return (num1+num2);
    }
} 
int main(){
    BiTree t=NULL;
    createBiTree(&t);
    printf("\n\nPreOrder the tree is:");
    PreOrder(t);
    printf("\n\nInOrder the tree is:");
    InOrder(t);
    printf("\n\nPostOrder the tree is:");
    PostOrder(t);
    printf("\n\n先序遍历序列(非递归):");
    Preorder_n(t);
    printf("\n\n结点总数:");
	printf("%d",PreOrder_num(t));
    printf("\n\n叶结点总数:"); 
    printf("%d",LeafNodes(t));   
    release(t);
    return 0;
}
运行结果:

4、在上题中补充求二叉树深度算法,并在主函数中补充相应的调用验证正确性。

算法代码:
int BTNodeDepth(BiTree p) {
	int lchilddep,rchilddep;
	if(p==NULL)
		return 0;
	else {
		lchilddep=BTNodeDepth(p->lchild);
		rchilddep=BTNodeDepth(p->rchild);
		return(lchilddep>rchilddep)?(lchilddep+1):(rchilddep+1);
	}
}
int main(){
    BiTree t=NULL;
    createBiTree(&t);
    printf("\n\nPreOrder the tree is:");
    PreOrder(t);
    printf("\n\nInOrder the tree is:");
    InOrder(t);
    printf("\n\nPostOrder the tree is:");
    PostOrder(t);
    printf("\n\n先序遍历序列(非递归):");
    Preorder_n(t);
    printf("\n\n结点总数:");
    printf("%d",PreOrder_num(t));
    printf("\n\n树的深度:");
    printf("%d",BTNodeDepth(t));    
    release(t);
    return 0;
}
运行结果:

选做实验:(代码可另附纸)

4、补充二叉树层次遍历算法。(提示:利用队列实现)

#include<stdio.h>
#include<stdlib.h>
 
typedef char EType;
 
struct BinaryTreeNode//定义节点
{  
    EType data;  
    struct BinaryTreeNode *LChild;  
    struct BinaryTreeNode *RChild;  
};  
typedef BinaryTreeNode BinaryTree; 
 
typedef struct QType  
{  
    BinaryTreeNode *ptr;
}QType; 
 
typedef struct Queue
{
	QType *element;//循环线性队列,0号空间不使用(为了区分队满与队空),注意这不是链式队列
	int front;
	int rear;
	int MaxSize;
}Queue;
 
void CreatBiTree(BinaryTreeNode **BT);
bool IsEmpty(Queue &Q);
bool IsFull(Queue &Q);
bool GetFront(Queue &Q,QType &result);
bool EnQueue(Queue &Q,QType &x);
bool DeQueue(Queue &Q,QType &result);
void LevelOrder_LtoR_UtoD(BinaryTreeNode *BT);
void LevelOrder_RtoL_UtoD(BinaryTreeNode *BT);
 
int main()
{
	BinaryTreeNode *BT = NULL;
	CreatBiTree(&BT);
	printf("从上至下,从左至右遍历二叉树输出为:");
	LevelOrder_LtoR_UtoD(BT);
	printf("\n");
	printf("从上至下,从右至左遍历二叉树输出为:");
	LevelOrder_RtoL_UtoD(BT);
	printf("\n");
	return 0;
}
 
void CreatQueue(Queue &Q,int MaxQueueSize)
{
	Q.MaxSize = MaxQueueSize;
	Q.element = new QType[Q.MaxSize+1];
	Q.front = 0;
	Q.rear = 0;
}
 
bool IsEmpty(Queue &Q)
{
	if(Q.front == Q.rear)
		return true;
	return false;
}
 
bool IsFull(Queue &Q)
{
	if(Q.front == (Q.rear+1)%(Q.MaxSize+1))
		return true;
	return false;
}
 
bool GetFront(Queue &Q,QType &result)
{
	if(IsEmpty(Q))
		return false;
	result = Q.element[(Q.front+1)%(Q.MaxSize+1)];
	return true;
}
 
bool EnQueue(Queue &Q,QType &x)//进队操作:rear向后移
{
	if(IsFull(Q))
		return false;
	Q.rear = (Q.rear+1)%(Q.MaxSize+1);
	Q.element[Q.rear] = x;
	return true;
}
 
bool DeQueue(Queue &Q,QType &result)//出队操作:front向后移
{
	if(IsEmpty(Q))
		return false;
	Q.front = (Q.front+1)%(Q.MaxSize+1);
	result = Q.element[Q.front];
	return true;
}
 
void CreatBiTree(BinaryTreeNode **BT)//以前序遍历方法输入节点的data,构造一棵二叉树
{  
    EType tem;  
      
    scanf("%c",&tem);  
    if(' ' == tem)  
    {  
        *BT = NULL;  
    }  
    else  
    {  
        *BT = new BinaryTreeNode;  
        (*BT)->data = tem;  
        CreatBiTree(&(*BT)->LChild);//递归
        CreatBiTree(&(*BT)->RChild);  
    }  
}  
 
void LevelOrder_LtoR_UtoD(BinaryTreeNode *BT)
{
	Queue Q;
	QType temp;
	BinaryTreeNode *p;
	int MaxQueueSize = 50;
	CreatQueue(Q,MaxQueueSize);
	p = BT;
	temp.ptr = p;
	EnQueue(Q,temp);//先将根节点进队
	while(p)//二叉树为空就直接结束
	{
		if(!DeQueue(Q,temp))//节点出队,当队空时,出队操作返回false,程序return
			return;//这是这个循环的出口,如果一个二叉树不为空,最终都是在这里跳出循环
		p = temp.ptr;
		printf("%c\t",p->data);
 
		if(p->LChild)//若该节点的左孩子存在,则将其进队
		{
			temp.ptr = p->LChild;
			EnQueue(Q,temp);
		}
        if(p->RChild)//若该节点的右孩子存在,则将其进队
		{
			temp.ptr = p->RChild;
			EnQueue(Q,temp);
		}
	}
}
 
void LevelOrder_RtoL_UtoD(BinaryTreeNode *BT)
{
    Queue Q;
	QType temp;
	BinaryTreeNode *p;
	int MaxQueueSize = 50;
	CreatQueue(Q,MaxQueueSize);
	p = BT;
	temp.ptr = p;
	EnQueue(Q,temp);
	while(p)
	{
		if(!DeQueue(Q,temp))
			return;
		p = temp.ptr;
		printf("%c\t",p->data);
 
		if(p->RChild)
		{
			temp.ptr = p->RChild;
			EnQueue(Q,temp);
		}
		if(p->LChild)
		{
			temp.ptr = p->LChild;
			EnQueue(Q,temp);
		}
	}
}

5、补充二叉树中序、后序非递归算法。


#include <iostream>
#include<string.h>
#include<stack>
#include<stdlib.h>
using namespace std;

typedef struct node
{
    char data;
    struct node *lchild,*rchild;
}BinTree;

typedef struct node1
{
    BinTree *btnode;
    bool isFirst;
}BTNode;


void creatBinTree(char *s,BinTree *&root)  //创建二叉树,s为形如A(B,C(D,E))形式的字符串
{
    int i;
    bool isRight=false;
    stack<BinTree*> s1;          //存放结点
    stack<char> s2;              //存放分隔符
    BinTree *p,*temp;
    root->data=s[0];
    root->lchild=NULL;
    root->rchild=NULL;
    s1.push(root);
    i=1;
    while(i<strlen(s))
    {
        if(s[i]=='(')
        {
            s2.push(s[i]);
            isRight=false;
        }
        else if(s[i]==',')
        {
            isRight=true;
        }
        else if(s[i]==')')
        {
            s1.pop();
            s2.pop();
        }
        else if(isalpha(s[i]))
        {
            p=(BinTree *)malloc(sizeof(BinTree));
            p->data=s[i];
            p->lchild=NULL;
            p->rchild=NULL;
            temp=s1.top();
            if(isRight==true)
            {
                temp->rchild=p;
                cout<<temp->data<<"的右孩子是"<<s[i]<<endl;
            }
            else
            {
                temp->lchild=p;
                cout<<temp->data<<"的左孩子是"<<s[i]<<endl;
            }
            if(s[i+1]=='(')
                s1.push(p);
        }
        i++;
    }
}

void display(BinTree *root)        //显示树形结构
{
    if(root!=NULL)
    {
        cout<<root->data;
        if(root->lchild!=NULL)
        {
            cout<<'(';
            display(root->lchild);
        }
        if(root->rchild!=NULL)
        {
            cout<<',';
            display(root->rchild);
            cout<<')';
        }
    }
}

void preOrder1(BinTree *root)     //递归前序遍历
{
    if(root!=NULL)
    {
        cout<<root->data<<" ";
        preOrder1(root->lchild);
        preOrder1(root->rchild);
    }
}

void inOrder1(BinTree *root)      //递归中序遍历
{
    if(root!=NULL)
    {
        inOrder1(root->lchild);
        cout<<root->data<<" ";
        inOrder1(root->rchild);
    }
}

void postOrder1(BinTree *root)    //递归后序遍历
{
    if(root!=NULL)
    {
        postOrder1(root->lchild);
        postOrder1(root->rchild);
        cout<<root->data<<" ";
    }
}

void preOrder2(BinTree *root)     //非递归前序遍历
{
    stack<BinTree*> s;
    BinTree *p=root;
    while(p!=NULL||!s.empty())
    {
        while(p!=NULL)
        {
            cout<<p->data<<" ";
            s.push(p);
            p=p->lchild;
        }
        if(!s.empty())
        {
            p=s.top();
            s.pop();
            p=p->rchild;
        }
    }
}

void inOrder2(BinTree *root)      //非递归中序遍历
{
    stack<BinTree*> s;
    BinTree *p=root;
    while(p!=NULL||!s.empty())
    {
        while(p!=NULL)
        {
            s.push(p);
            p=p->lchild;
        }
        if(!s.empty())
        {
            p=s.top();
            cout<<p->data<<" ";
            s.pop();
            p=p->rchild;
        }
    }
}

void postOrder2(BinTree *root)    //非递归后序遍历
{
    stack<BTNode*> s;
    BinTree *p=root;
    BTNode *temp;
    while(p!=NULL||!s.empty())
    {
        while(p!=NULL)              //沿左子树一直往下搜索,直至出现没有左子树的结点
         {
            BTNode *btn=(BTNode *)malloc(sizeof(BTNode));
            btn->btnode=p;
            btn->isFirst=true;
            s.push(btn);
            p=p->lchild;
        }
        if(!s.empty())
        {
            temp=s.top();
            s.pop();
            if(temp->isFirst==true)     //表示是第一次出现在栈顶
             {
                temp->isFirst=false;
                s.push(temp);
                p=temp->btnode->rchild;
            }
            else                        //第二次出现在栈顶
             {
                cout<<temp->btnode->data<<" ";
                p=NULL;
            }
        }
    }
}

void postOrder3(BinTree *root)     //非递归后序遍历
{
    stack<BinTree*> s;
    BinTree *cur;                      //当前结点
    BinTree *pre=NULL;                 //前一次访问的结点
    s.push(root);
    while(!s.empty())
    {
        cur=s.top();
        if((cur->lchild==NULL&&cur->rchild==NULL)||
           (pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))
        {
            cout<<cur->data<<" ";  //如果当前结点没有孩子结点或者孩子节点都已被访问过
              s.pop();
            pre=cur;
        }
        else
        {
            if(cur->rchild!=NULL)
                s.push(cur->rchild);
            if(cur->lchild!=NULL)
                s.push(cur->lchild);
        }
    }
}


int main(int argc, char *argv[])
{
    char s[100];
    while(scanf("%s",s)==1)
    {
        BinTree *root=(BinTree *)malloc(sizeof(BinTree));
        creatBinTree(s,root);
        display(root);
        cout<<endl;
        preOrder2(root);
        cout<<endl;
        inOrder2(root);
        cout<<endl;
        postOrder2(root);
        cout<<endl;
        postOrder3(root);
        cout<<endl;
    }
    return 0;
}

四、实验小结

在这次实验中,进一步学习到了二叉树的先序、中序、后序的递归遍历算法及非递归遍历算法,通过求二叉树的深度、叶子结点数和层序遍历等算法,进一步理解了二叉树的基本特性。

五、评语


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM