區間染色_浮水法_洛谷_P3740貼海報
這個作業屬於哪個課程 | https://edu.cnblogs.com/campus/qdu/DS2020 | |
---|---|---|
這個作業要求在哪裡 | https://edu.cnblogs.com/campus/qdu/DS2020/homework/11430 | |
這個作業的目標 | 掌握二叉樹 | |
學號 | 2018204186 |
一、實驗目的
1、掌握二叉樹的基本特性
2、掌握二叉樹的先序、中序、後序的遞迴遍歷演算法
3、理解二叉樹的先序、中序、後序的非遞迴遍歷演算法
4、通過求二叉樹的深度、葉子結點數和層序遍歷等演算法,理解二叉樹的基本特性
二、實驗預習
說明以下概念
1、二叉樹:在電腦科學中,樹是一種重要的非線性資料結構,直觀的看,它是資料元素按分支關係組織起來的結構。二叉樹是每個節點最多有兩個子樹的有序樹,通常子樹的根被稱作“左子樹”和“右子樹”。
2、遞迴遍歷:遍歷:所謂遍歷(Traversal),是指沿著某條搜尋路線,依次對樹(或圖)中每個節點均做一次訪問。訪問結點所做的操作依賴於具體的應用問題, 具體的訪問操作可能是檢查節點的值、更新節點的值等。不同的遍歷方式,其訪問節點的順序是不一樣的。遍歷是二叉樹上最重要的運算之一,是二叉樹上進行其它運算之基礎。當然遍歷的概念也適合於多元素集合的情況。
遞迴:程式呼叫自身的程式設計技巧稱為遞迴。
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 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);
}
}
執行結果:
選做實驗:(程式碼可另附紙)
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、補充二叉樹中序、後序非遞迴演算法。
/*二叉樹的遍歷* 2011.8.25*/
#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;
}```
四、實驗小結
五、評語