第六次作业:二叉树

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

实验三 二叉树

一、实验目的

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

二、实验预习

说明以下概念
1、二叉树:二叉树是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树,且有左右之分。二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个结点。
2、递归遍历:由于二叉树所具有的递归性质,一棵非空的二叉树可以看作是由根节点、左子树和右子树3部分构成,因为若能依次遍历这3部分的信息,也就遍历了整个二叉树。按照左子树的遍历在右子树的遍历之前进行的约定,根访问根节点位置的不同,可以得到二叉的前序、中序、后序3种遍历方法。
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、在上题中补充求二叉树中求结点总数算法(提示:可在某种遍历过程中统计遍历的结点数),并在主函数中补充相应的调用验证正确性。
算法代码:

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; 
}

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

int LeafNodes(BiTree p){
     int num1,num2;
     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);
      }
}

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);
 }
}

5、主程序补充代码(全部调用):

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节点数为%d",PreOrder_num(t));
	printf("\n子叶数为%d",LeafNodes(t));
	printf("\n深度为%d",BTNodeDepth(t));
	release(t);
	return 0;
}

输出结果:

选做实验:
补充二叉树层次遍历算法(提示:利用队列实现):(摘自网络)

#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);
		}
	}
}

补充二叉树中序、后序非递归算法:(摘自网络)

#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;
}

四、实验小结

通过本次实验对树以及二叉树的性质和算法有了初步的认识,但是部分更加深层次的东西仍有待掌握,继续加油!

posted @ 2020-11-07 11:43  宋端  阅读(497)  评论(0编辑  收藏  举报