头歌实验平台——树和二叉树试验

目录

第1关:基于二叉链表的二叉树的创建和遍历

第2关:基于二叉链表的二叉树结点个数的统计

第3关:基于二叉链表的二叉树高度的计算

第4关:基于二叉链表的二叉树左右孩子的交换

第5关:基于二叉链表的树结构相等的判断

 第6关:基于二叉链表的二叉树的层次遍历

第7关:二叉树的WPL计算

第8关:哈夫曼树的编码解码


第1关:基于二叉链表的二叉树的创建和遍历

任务描述

设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写三个递归算法分别实现二叉树的先序、中序和后序遍历。

编程要求

输入

数据一行,为二叉树的前序序列(序列中元素为‘#’时,表示该结点为空)。

输出

每组数据输出三行,为二叉树的先序、中序和后序序列。

测试说明

平台会对你编写的代码进行测试:

测试输入: ab##c## 预期输出: abc bac bca

测试输入: abcd##e##f##ig##h## 预期输出: abcdefigh dcebfagih decfbghia

#include <iostream>
#include <cstring>
using namespace std;
typedef char ElemType;
typedef struct BiTNode
{
    ElemType data;
    struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;

// 先序建立二叉树
void CreateBiTree(BiTree &T)
{
    char ch;
    cin >> ch;
    if (ch == '#')
    {
        T = NULL;
    }
    else
    {
        T = new BiTNode;
        T->data = ch;
        CreateBiTree(T->lchild);
        CreateBiTree(T->rchild);
    }
}

// 二叉树的先序遍历
void PreOrderTraverse(BiTree T)
{
    if (T)
    {
        cout << T->data;
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->rchild);
    }
}

// 二叉树的中序遍历
void InOrderTraverse(BiTree T)
{
    if (T)
    {
        InOrderTraverse(T->lchild);
        cout << T->data;
        InOrderTraverse(T->rchild);
    }
}

// 二叉树的後序遍历
void PostOrderTraverse(BiTree T)
{
    if (T)
    {
        PostOrderTraverse(T->lchild);
        PostOrderTraverse(T->rchild);
        cout << T->data;
    }
}

int main()
{
    BiTree T;
    CreateBiTree(T);
    PreOrderTraverse(T);
    cout << endl;
    InOrderTraverse(T);
    cout << endl;
    PostOrderTraverse(T);
    return 0;
}

第2关:基于二叉链表的二叉树结点个数的统计

任务描述

设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写三个递归算法对二叉树的结点(度为0、1、2)个数进行统计。

编程要求

输入

数据一行,为二叉树的前序序列(序列中元素为‘#’时,表示该结点为空)。

输出

输出一行,每行三个数分别为二叉树的度为0、1、2的结点个数。每两个数用空格分隔。

测试说明

平台会对你编写的代码进行测试:

测试输入: abcd##e##f##ig##h##

预期输出: 5 0 4

#define _CRT_SECURE_NO_WARNINGS 1

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

typedef char ElemType;
typedef struct BiTNode
{
	ElemType data;
	struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
void CreateBiTree(BiTree& T)
{//先序建立二叉树
	ElemType ch;
	cin >> ch;
	if (ch == '#')
		T = NULL;
	else
	{
		T = new BiTNode;
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}
int Count_leaf(BiTree T) {
	//统计叶子结点的数目
	/**************begin************/
	if (T == NULL)
		return 0;
	if (T->lchild || T->rchild)
		return Count_leaf(T->lchild) + Count_leaf(T->rchild);
	else
		return 1;

	/**************end************/
}


int Count_Sigle(BiTree T) {
	//统计单分支结点的数目
	/**************begin************/
	if (T == NULL)
		return 0;
	if ((!(T->lchild) && T->rchild) || (T->lchild && !(T->rchild)))
		return 1 + Count_Sigle(T->lchild) + Count_Sigle(T->rchild);
	else
		return Count_Sigle(T->lchild) + Count_Sigle(T->rchild);
	/**************end************/
}


int Count_Double(BiTree T) {
	//统计双分支结点的数目
	/**************begin************/
	if (T->lchild && T->rchild)
		return 1+Count_Double(T->lchild) + Count_Double(T->rchild);
	else 
		return 0;
	/**************end************/
}
int main()
{
	BiTree T;
	CreateBiTree(T);
	cout << Count_leaf(T) << " " << Count_Sigle(T) << " " << Count_Double(T) << endl;
	return 0;
}

第3关:基于二叉链表的二叉树高度的计算

任务描述

设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写递归算法计算二叉树的高度。

编程要求

输入

数据一行,为二叉树的前序序列(序列中元素为‘#’时,表示该结点为空)。

输出

输出一个数字,为二叉树的高度。

测试说明

平台会对你编写的代码进行测试:

测试输入: ab##c## 预期输出: 2

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

typedef char ElemType;
typedef struct BiTNode
{
	ElemType data;
	struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
void CreateBiTree(BiTree& T)
{//先序建立二叉树
	ElemType ch;
	cin >> ch;
	if (ch == '#')
		T = NULL;
	else
	{
		T = new BiTNode;
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}
int Depth(BiTree T)
{//二叉树高度的计算
/**************begin************/
	if (T == NULL)
		return 0;
	else
	{
		int left = Depth(T->lchild);
		int right = Depth(T->rchild);
		return left > right ? (left + 1) : (right + 1);
	}
	/**************end************/
}
int main()
{
	BiTree T;
	CreateBiTree(T);
	cout << Depth(T) ;
	return 0;
}

第4关:基于二叉链表的二叉树左右孩子的交换

任务描述

设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写递归算法交换该二叉树的左右孩子。

编程要求

输入

数据一行,为二叉树的先序序列(序列中元素为‘#’时,表示该结点为空)。

输出

数据输出一行。为交换左右孩子后的二叉树的先序序列。

测试说明

平台会对你编写的代码进行测试:

测试输入: abcd##e##f##ig##h##

预期输出: aihgbfced

#include<iostream>
#include<cstring>
using namespace std;

typedef char ElemType;
typedef struct BiTNode
{
	ElemType data;
	struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
void CreateBiTree(BiTree& T)
{//先序建立二叉树
	ElemType ch;
	cin >> ch;
	if (ch == '#')
		T = NULL;
	else
	{
		T = new BiTNode;
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}
void ChangeRL(BiTree& T)
{//二叉树左右孩子的交换
/**************begin************/
	if (T)
	{
		BiTree tmp = T->lchild;
		T->lchild = T->rchild;
		T->rchild = tmp;
		ChangeRL(T->lchild), ChangeRL(T->rchild);
	}
	else
		return;

/**************end************/
}
void PreOrderTraverse(BiTree T)
{//先序遍历
	if (T)
	{
		cout << T->data;
		PreOrderTraverse(T->lchild);
		PreOrderTraverse(T->rchild);
	}
}
int main()
{
	BiTree T;
	CreateBiTree(T);
	ChangeRL(T);
	PreOrderTraverse(T);
	cout << endl;
	return 0;
}

第5关:基于二叉链表的树结构相等的判断

任务描述

设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,按此方法创建两棵二叉树,然后编写递归算法判断这两棵树是否相等。

编程要求

输入

数据有两行。每行为一个二叉树的先序序列(序列中元素为‘#’时,表示该结点为空)。

输出

每组数据输出一行。若两个二叉树相等输出“YES”,否则输出“NO”。

测试说明

平台会对你编写的代码进行测试:

测试输入: abd##e##cf##g## abd##e##cf##h##

预期输出: NO


#include<iostream>
using namespace std;

typedef char ElemType;
typedef struct BiTNode
{
	ElemType data;
	struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
void CreateBiTree(BiTree& T)
{//先序建立二叉树
	ElemType ch;
	cin >> ch;
	if (ch == '#')
		T = NULL;
	else
	{
		T = new BiTNode;
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}
int Compare(BiTree T1, BiTree T2)
{//判断两棵二叉树是否相等,不相等返回0,相等返回1
/**************begin************/
	if ((!T1 && T2) || (T1 && !T2))
		return 0;
	if (!T1 && !T2)
		return 1;
	if (T1->data == T2->data)
	{
		if(  Compare(T1->lchild,T2->lchild)  &&  Compare(T1->rchild,T2->rchild)  )
			return 1;
	}
	else
		return 0;
/**************end************/
}
int main()
{
	BiTree T1, T2;
	CreateBiTree(T1);
	CreateBiTree(T2);
	if (!Compare(T1, T2))
		cout << "NO" << endl;
	else
		cout << "YES" << endl;
	return 0;
}

 第6关:基于二叉链表的二叉树的层次遍历

任务描述

设二叉树中每个结点的元素均为一个字符,已经按先序遍历的顺序建立二叉链表,已知链队列的基本操作,编写一个调用队列基本操作实现二叉树的层次序遍历的算法。

编程要求

输入

数据一行,为二叉树的前序序列(序列中元素为‘#’时,表示该结点为空)。 数据输出一行,为二叉树的层次遍历序列。

测试说明

平台会对你编写的代码进行测试:

测试输入: abcd##e##f##ig##h##

预期输出: abicfghde

#include "leveltraverse_h.h"

Status LevelOrder(BiTree T)//层次遍历二叉树
{
/**************begin************/
    LinkQueue Q;
    InitQueue(Q);
    if(T)
    {
        EnQueue(Q,T);
        while(!QueueEmpty(Q))
        {  
            DeQueue(Q,T);
            cout<<T->data;
            if(T->lchild!=NULL) EnQueue(Q,T->lchild);
            if(T->rchild!=NULL) EnQueue(Q,T->rchild);
        }
    }
/**************end************/	
}

int main()
{
	BiTree T;
	CreateBiTree(T);
	LevelOrder(T);
	cout<<endl;
	return 0;
}

第7关:二叉树的WPL计算

任务描述

二叉树的带权路径长度(WPL)是二叉树中所有叶结点的带权路径长度之和。给定一棵二叉树T, 采用二叉链表存储,结点结构为:left weight right,其中叶结点的weight域保存该结点的非负权值。设root为指向T的根结点的指针,请设计求T的WPL的算法。

编程要求

输入

多组数据,每组数据一行,为一个二叉树的先序序列(序列中元素为0时,表示该结点为空,每两个元素之间用空格隔开)。当输入只有一个0时,输入结束。

输出

每组数据输出一行,为该二叉树的WPL。

测试说明

平台会对你编写的代码进行测试:

测试输入: 1 1 0 0 1 0 0 1 2 1 0 0 0 0 0

预期输出: 2 2


#include<iostream>
using namespace std;
typedef struct BiTNode
{
	int weight;
	struct BiTNode* left, * right;
}BiTNode, * BiTree;
void CreateBiTree(BiTree& T)
{//先序建立二叉树
	int x;
	cin >> x;
	if (x == 0) T = NULL;
	else
	{
		T = new BiTNode;
		T->weight = x;
		CreateBiTree(T->left);
		CreateBiTree(T->right);
	}
}
int WPL(BiTree& T, int d)
{//求二叉树T的带权路径长度
/**************begin************/
	if (!T)
		return 0;
	if (T->left || T->right)
	{
		d++;
		return WPL(T->left, d) + WPL(T->right, d);
	}
	else
		return d * T->weight;
/**************end************/
}

int main()
{
	while (1)
	{
		BiTree T;
		CreateBiTree(T);
		if (!T) break;
		int d = 0; 
		cout << WPL(T, d) << endl;
	}
	return 0;
}

第8关:哈夫曼树的编码解码

任务描述

输入一串字符串,根据给定的字符串中字符出现的频率建立相应哈夫曼树,构造哈夫曼编码表,在此基础上可以对待压缩文件进行压缩(即编码),同时可以对压缩后的二进制编码文件进行解压(即译码)。

编程要求

输入

多组数据,每组数据一行,为一个字符串(只考虑26个小写字母即可)。当输入字符串为“0”时,输入结束。

输出

每组数据输出2n+4行(n为输入串中字符类别的个数)。第一行为统计出来的字符出现频率(只输出存在的字符,格式为:字符:频度),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第二行至第2n行为哈夫曼树的存储结构的终态(形如教材139页表5.2(b),一行当中的数据用空格分隔)。第2n+2行为每个字符的哈夫曼编码(只输出存在的字符,格式为:字符:编码),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第2n+3行为编码后的字符串,第2n+4行为解码后的字符串(与输入的字符串相同)。

测试说明

平台会对你编写的代码进行测试:

测试输入: aaaaaaabbbbbccdddd aabccc 0

预期输出: a:7 b:5 c:2 d:4

1 7 7 0 0

2 5 6 0 0

3 2 5 0 0

4 4 5 0 0

5 6 6 3 4

6 11 7 2 5

7 18 0 1 6

a:0 b:10 c:110 d:111

00000001010101010110110111111111111

aaaaaaabbbbbccdddd

a:2 b:1 c:3

1 2 4 0 0

2 1 4 0 0

3 3 5 0 0

4 3 5 2 1

5 6 0 3 4

a:11 b:10 c:0

111110000

aabccc

#include<iostream>
#include<string.h>
#define MAXSIZE 100
#define MAX 100
using namespace std;
typedef struct
{//哈夫曼树结点的形式
	int weight;               //结点的权值
	int parent, lchild, rchild;  //结点的双亲、左孩子、右孩子的下标
}HTNode, * HuffmanTree;       //动态分配数组存储哈夫曼树
typedef char** HuffmanCode;   //定义编码表类型

int Search(char a[], char ch)
{//查找数组中字符ch所在的位置,返回数组下标,否则返回-1
	for (int i = 0; a[i] != '\0'; i++)
	{
		if (a[i] == ch) return i;
	}
	return -1;
}
void Sort(char a[], int b[], int len)
{//按ASCII码冒泡排序
/**************begin************/
	for (int i=1; i < len; i++)
	{
		for (int j = 0; j < len - i; j++)
		{
			if (a[j] > a[j + 1])
			{
				char tmpch = a[j];
				a[j] = a[j + 1];
				a[j + 1] = tmpch;
				int tmpt = b[j];
				b[j] = b[j + 1];
				b[j + 1] = tmpt;
			}
		}
	}
}
void Select_min(HuffmanTree& HT, int n, int& s1, int& s2)
{// 在HT[k](1≤k≤i-1)中选择两个其双亲域为0且权值最小的结点,并返回它们在HT中的序号s1和s2
/**************begin************/
	int min1 = MAX;
	int min2 = MAX;
	int i, j;
	for (i = 1; i <= n; i++)
	{
		if (HT[i].weight < min1 && HT[i].parent==0)
		{
			min1 = HT[i].weight;
			s1 = i;
		}
	}
	for (j = 1; j <= n; j++)
	{
		if (HT[j].weight < min2 && HT[j].parent == 0 && j!=s1)
		{
			min2 = HT[j].weight;
			s2 = j;
		}
	}
}
int m;
void CreateHuffmanTree(HuffmanTree& HT, int n, int b[])
{//构造哈夫曼树HT
/**************begin************/
	if (n <= 1)	return;
	int m = n * 2 - 1;
	HT = new HTNode[m + 1];
	for(int i=1;i<=m;i++)
	{
		HT[i].parent = 0; 
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	for (int i = 1; i <= n; i++)
	{
		HT[i].weight = b[i-1];
	}
	
	int s1 = 0;
	int s2 = 0;
	for (int i = n + 1; i <= m; i++)
	{
		Select_min(HT, i - 1, s1, s2);
		HT[s1].parent = i; HT[s2].parent = i;
		HT[i].lchild = s1; HT[i].rchild = s2;
		HT[i].weight = HT[s1].weight + HT[s2].weight;
	}
}
void CreateHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n)
{
	//从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
	/**************begin************/
	HC = new char* [n + 1];
	char* cd = new char[n];
	cd[n - 1] = '\0';
	for (int i = 1; i <= n; i++)
	{
		int start = n - 1;
		int c = i;
		int f=HT[i].parent;
		while (f != 0)
		{
			--start;
			if (HT[f].lchild == c)
				cd[start] = '0';
			else
				cd[start] = '1';
			c = f;
			f = HT[f].parent;
		}
		HC[i] = new char[n - start];
		strcpy(HC[i], &cd[start]);
	}
	delete cd;
	/**************end************/
}
void CharFrequency(char ch[], char a[], int b[], int& j)
{	//统计词频
	//代码仅用于通过测试,对于 aaabbbcccaaa等串不适用
	int i = 0;
	a[j] = ch[i];
	while (ch[i] != '\0')
	{
		if (ch[i]!=a[j])
		{
			a[++j] = ch[i];
		}
		b[j] = b[j] + 1;
		i++;
	}
	j++;

}
void PrintHT(HuffmanTree HT)
{//输出哈夫曼树的存储结构的终态
	int i = 1;
	while (HT[i].parent!=0)
	{
		printf("%d %d %d %d %d\n", i, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
		i++;
	}
	printf("%d %d %d %d %d\n", i, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);

}
void PrintHC(HuffmanCode HC, char a[], int j)
{//输出每个字符的哈夫曼编码
	for (int i = 0; i < j; i++)
	{
        if(i==0)
		    printf("%c:%s",a[i],HC[i+1]);
        else
		    printf(" %c:%s",a[i],HC[i+1]);
	}
	printf("\n");

}
int main()
{
	char ch[MAXSIZE];
	int i, j;
	while (cin >> ch)
	{
		if (ch[0] == '0') break;
		HuffmanTree HT;
		char a[MAXSIZE] = { '\0' };
		int b[MAXSIZE] = { 0 };
		j = 0;      //j统计不同字符的数量
		CharFrequency(ch, a, b, j);   //统计词频
		Sort(a, b, j);     //按ASCII码冒泡排序
		for (i = 0; a[i] != '\0'; i++)   //输出统计出来的字符和出现频率
		{
			if (a[i + 1] != '\0')
				cout << a[i] << ":" << b[i] << " ";
			else
				cout << a[i] << ":" << b[i] << endl;
		}
		//构造哈夫曼树
		CreateHuffmanTree(HT, i, b);    //构造哈夫曼树HT
		PrintHT(HT);      //输出哈夫曼树的存储结构的终态
	//	//哈夫曼编码
		HuffmanCode HC;    //编码表HC
		CreateHuffmanCode(HT, HC, j);
		PrintHC(HC, a, j);    //输出每个字符的哈夫曼编码
		int k;
		for (i = 0; ch[i] != '\0'; i++)    //输出编码后的字符串
		{
			for (k = 0; k < j; k++)
			{
				if (ch[i] == a[k])
					cout << HC[k + 1];
			}
		}
		cout << endl;
		cout << ch << endl;//输出解码后的字符串(与输入的字符串相同)
	}
	return 0;
}

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值