实验目的及要求:
1. 复习树的结构定义,二叉树在树结构定义基础上的限制;树及二叉树的相关名词,理解非线性结构与线性结构的明显区别,理解树与二叉树定义中体现的递归思想;
2. 深入理解二叉树的性质;
3. 理解并掌握完全二叉树的顺序存储、二叉树的二叉链表存储。
4. 掌握二叉链表存储结构下的二叉树的遍历(递归与非递归算法)及其最基础应用(求深度、求叶子结点数等)。
5. 掌握树、森林与二叉树的相互转换方法,掌握树与森林的遍历方法。
6. 理解树的带权路径长度概念、理解哈夫曼树的静态三叉链表存储结构,掌握建立哈夫曼树以及哈夫曼编码的方法。
实验内容:(任务一的1题,任务二、三都是选做)
任务一:二叉树的存储结构建立与二叉树遍历:试编写程序,完成以下问题:
- 【选做】从键盘读入字符(数字、字母或其他符号)建立一个深度不小于3的完全二叉树的顺序存储结构(一维数组),然后①输出按照二叉树结点层序编号的顺序输出二叉树所有结点,②输入一个字符查找该字符是否在完全二叉树中,如果不在则输出该字符不在二叉树中,如果在则输出该结点和数组下标以及该结点的双亲结点和数组下标,并且输出该结点的左孩子和右孩子结点情况(若有则输出左孩子或右孩子结点及其数组下标,若无则输出无左孩子或无右孩子结点);
- 从键盘读入字符(数字、字母或其他符号)建立一个深度不小于3的二叉树的二叉链表存储结构,然后①分别递归先序、中序和后序遍历二叉树并输出相应的遍历二叉树结点序列;②统计二叉树中结点总数;③求二叉树的深度;④统计二叉树的叶子节点数。
- 使用2中建立的二叉树二叉链表存储结构,然后①非递归中序遍历输出二叉树的结点序列;②非递归后序遍历输出二叉树的结点序列。
任务二:【选做】树、森林存储结构建立与树、森林的遍历.试编写程序,完成以下问题
- 从键盘读入字符(数字、字母或其他符号)建立一个深度不小于3层的树的孩子兄弟表存储结构,然后①分别递归先根、后根遍历该树并输出相应遍历树结点序列。
任务三:【选做】哈夫曼树与哈夫曼编码,试编写程序,完成以下问题。
- 从键盘读入不少于5个字母字符以及相应的权值,然后①以输入的字母字符以及相应的权值建立哈夫曼树的静态三叉链表存储结构;②输出该静态三叉链表;③若规定二叉树向左的分支为0,右为1,对字母字符进行哈夫曼编码并输出每个字符的哈夫曼编码。
程序代码:
任务一:本次代码为2个小问合在一起完成
#include <stdio.h>
#include<cstring>
#include<iostream>
#include<stack>
#include <malloc.h>
#include <stdlib.h>
#include<iomanip>
using namespace std;
typedef char DataType;
typedef struct node //定义二叉树
{
DataType data;
struct node *lchild,*rchild;
}TBinTree;
TBinTree* CreatBinTree(TBinTree *T) //构造二叉树
{
DataType ch;
ch=cin.get(); //输入二叉树的结点数值
if(ch=='#')
T=NULL;
else
{
T=(TBinTree *)malloc(sizeof(TBinTree));
//T = new TBinTree;
T->data=ch;
T->lchild=CreatBinTree(T->lchild);
T->rchild=CreatBinTree(T->rchild);
}
return T;
}
void PreOrderTraverse(TBinTree *T) // 先序遍历
{
if(T)
{
cout<<T->data;
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
void InOrderTraverse(TBinTree *T) //中序
{
if(T)
{
InOrderTraverse(T->lchild);
cout<<T->data;
InOrderTraverse(T->rchild);
}
}
void PostOrderTraverse(TBinTree* T)
{
if(T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
//printf("%c",T->data);
cout<<T->data;
}
}
void PreOrderWithoutRecursion(TBinTree *root){
//先序遍历的非递归实现
if (root == NULL)//如果根为空则结束
return;
TBinTree* p = root;
stack<TBinTree*> s;
while (!s.empty() || p)
{
while (p)
{
cout << setw(4) << p->data;
s.push(p);
p = p->lchild;
}
//当p为空时,说明根和左子树都遍历完了,该进入右子树了
if (!s.empty())
{
p = s.top();
s.pop();
p = p->rchild;
}
}
cout << endl;
}
void InOrderWithoutRecursion(TBinTree* root)
{
//空树
if (root == NULL)
return;
//树非空
TBinTree* p = root;
stack<TBinTree*> s;
while (!s.empty() || p)
{
while (p)
{
s.push(p);
p = p->lchild;
}
if (!s.empty())
{
p = s.top();
s.pop();
cout << setw(4) << p->data;
p = p->rchild;
}
}
}
//后序遍历非递归实现
void PostOrderWithoutRecursion(TBinTree* root)
{
if (root == NULL)
return;
stack<TBinTree*> s;
//pCur:当前访问节点,pLastVisit:上次访问节点
TBinTree* pCur, *pLastVisit;
pCur = root;
pLastVisit = NULL;
while (pCur)
{
s.push(pCur);
pCur = pCur->lchild;
}
while (!s.empty())
{
pCur = s.top();
s.pop();
if (pCur->rchild == NULL || pCur->rchild == pLastVisit)
{
cout << setw(4) << pCur->data;
pLastVisit = pCur;
}
else
{
//根节点再次入栈
s.push(pCur);
//进入右子树,且可肯定右子树一定不为空
pCur = pCur->rchild;
while (pCur)
{
s.push(pCur);
pCur = pCur->lchild;
}
}
}
cout << endl;
}
struct Queue {
TBinTree *P;
Queue *next;
};
struct LinkQueue {
Queue *front; //队头指针
Queue *rear; //队尾指针
};
void InitQueue(LinkQueue *Q, TBinTree *T) {
Q->front = new Queue;
Q->front->P = T;
Q->rear = new Queue;
Q->front->next = Q->rear;
Q->rear->P = NULL;
}
void EnQueue(LinkQueue *Q, TBinTree *e){
if(!e) return;
Q->rear->P = e;
Q->rear->next = new Queue;
Q->rear = Q->rear->next;
Q->rear->P = NULL;
}
void DeQueue(LinkQueue *Q) {
Queue *q = Q->front;
Q->front = Q->front->next;
delete q;
}
void LevelOrderTraverse(TBinTree *T)
{
if(!T) return;
LinkQueue *Q = new LinkQueue;
InitQueue(Q,T);
while(Q->front->P) {
cout<<Q->front->P->data;
EnQueue(Q,Q->front->P->lchild);
EnQueue(Q,Q->front->P->rchild);
DeQueue(Q);
}
}
int NodeCount(TBinTree *T){
if(T==NULL){
return 0;
}
else
return NodeCount(T->lchild)+NodeCount(T->rchild)+1;
}
int NodeCount_0Node(TBinTree *T){
if(T==NULL){
return 0;
}
else if(T->lchild==NULL&&T->rchild==NULL){
return 1;
}
else{
return NodeCount_0Node(T->lchild)+NodeCount_0Node(T->rchild);
}
}
void MaxNode(TBinTree *T,char arr[],int &i) // 先序遍历
{
if(T)
{
arr[i]=T->data;
i++;
MaxNode(T->lchild,arr,i);
MaxNode(T->rchild,arr,i);
}
}
int main(){
int max;
int min;
int i=0;
cout<<"请输入你的测试数据:"<<endl;
TBinTree *T =CreatBinTree(T);
char arr[20];
MaxNode(T,arr,i);
max = min = arr[0];
if(arr[0]==80){
cout<<"error";
exit(0);
}
for(int j=0;j<i;j++){
if(arr[j]>max){
max = arr[j];
}
if(arr[j]<min){
min = arr[j];
}
}
cout<<"最大值为:"<<max<<endl;
cout<<"最小值为:"<<min<<endl;
cout<<"非递归先序遍历为:";
PreOrderWithoutRecursion(T);
cout<<"非递归中序遍历为:" ;
InOrderWithoutRecursion(T);
cout<<"\n";
cout<<"非递归后序遍历为:" ;
PostOrderWithoutRecursion(T);
cout<<"\n";
int count = NodeCount(T);
cout<<"结点个数为:\t\t"<<count<<endl;
int count_0 = NodeCount_0Node(T);
cout<<endl;
cout<<"叶子结点个数为:\t"<<count_0<<endl;
cout<<"度为1的结点个数为:\t"<<count-2*count_0+1<<endl;
cout<<"度为2的结点个数为:\t"<<count_0-1<<endl;
cout<<endl;
cout<<"以下为递归遍历的方法遍历\n请输入您要哪种递归遍历的方法"<<endl ;
cout<<" 1:先序遍历:\n"
" 2:中序遍历:\n"
" 3:后序遍历:\n"
" 4:层序遍历:\n"
" 0:退出\n"
" 选择 :";
int n;
cin>>n;
switch(n) {
case 1: cout<<"先序遍历: "<< endl; PreOrderTraverse(T); break;
case 2: cout<<"中序遍历: "<< endl; InOrderTraverse(T); break;
case 3: cout<<"后序遍历: "<< endl; PostOrderTraverse(T); break;
case 4: cout<<"层序遍历: "<< endl; LevelOrderTraverse(T); break;
case 0:exit(0);
}
}
实验结果: