第六次作業 二叉樹


這個作業屬於哪個課程 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