1、上机名称
实现二叉树的创建和图形化遍历
2、上机要求
- 用三叉链表储存一个二叉树
- 对二叉树进行图形化遍历(前中后层)
3、上机环境
Microsoft visual studio 2022 Windows11 64位操作系统
EasyX插件库装载,参见:easyx官网、安装教程
4、程序清单
4.1 Mytree.h头文件
头文件引入、宏定义、三叉链表节点、绘图所用的位置信息
#pragma once
#pragma warning (disable:4996)
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<math.h>
#include<graphics.h>
#include <conio.h>
#define ConsoleX 640 //控制台宽
#define ConsoleY 960 //控制台高
#define offset 3 //绘图偏移量
#define rx 30 //打印字符长
#define ry 40 //打印字符宽
//有数据修改能传引用传引用(能传指针传指针),可以解决99%的问题。
#define maxsize 50 //假设容器里面最大不会超过50个数据
typedef int Level;
typedef char Data; //数据元素用字符型抽象
typedef struct POS{
int x;
int y;
}Pos;
typedef struct TNode {
int id; //标识创建顺序的ID
Data data; //数据元素
Level level; //节点的层数标记
Pos pos; //通过freshposx freshposy分配的位置信息,需要先分配level
struct TNode* parent; //双亲节点
struct TNode* lcd; //左子树
struct TNode* rcd; //右子树
}Tnode, * pTnode; //一个三叉链表节点
//两个小定义用起来舒服点
typedef Tnode TreeData;
typedef pTnode pTreeData;
创建一个容器,初始化树使用、遍历使用
//容器的创建
typedef struct Vector { //一个多功能容器,需要装的是树的节点指针
pTreeData data[maxsize];
int length;
}vector;
void init_vector(vector& v); //初始化
void push_back(vector& v,pTnode tree); //尾插法
void push_front(vector& v, pTnode tree); //头插法
Tnode pop_back(vector& v); //尾部取元素
Tnode pop_front(vector& v); //头部取元素
int getlen(vector v); //长度信息
二叉树基本操作,与基本实验相同,实现中略有不同。
//二叉树操作
vector TreeCreate(/*pTnode* parent,*/pTnode& tree);//创建二叉树 同时返回容器装好每个节点的位置,便于输出
void TreeOutput(vector v); //输出二叉树 我采用的是按照创建序号索引进行输出,打印所有具体信息
int gethigh(pTnode tree); //返回二叉树高度采用递归策略
void First_Order_View(vector v); //先序遍历二叉树,由于创建时采用先序法创建,所以ID顺序即为先序遍历顺序
void Second_Order_View(pTnode tree);//中序遍历二叉树,采用递归策略。
void Third_Order_View(pTnode tree); //后序遍历二叉树,采用递归策略。
void Level_Order_View(pTnode tree); //层序遍历,需要用到队列,拿上面的容器当队列。
void TreeDestory(vector& v); //可以通过遍历销毁树,也通过对容器的操作销毁树,我采取后一种方法,因为容器也需要销毁。
freshlevel:在树建立之后,分配树的层级信息,由树根开始从1向大分配,需要传入树的总高度,失败返回0
freshposx:在层级信息完善后,分配树的x坐标信息。
freshpoxy:在层级信息完善后,分配树的y坐标信息。
makestatus:上三者的综合调用,需要将create调用形成的vector传入,调用此函数来完成位置信息的更新即可。
//绘图信息配置
int freshlevel(int treehigh,pTnode tree);
int freshposx(pTnode tree);
int freshposy(int treehigh,pTnode tree);
void makestatus(vector treeinfo);
绘图操作,包括输出数据节点和输出节点的连线
//绘图操作
void putdata(pTnode tree);
void putlink(pTnode tree);
4.2 Mytree.cpp实现文件
两个全局变量,用法已给出注释
#include "Mytree.h"
int ID = 0; //用于统计创建树的有效大小,标记ID
vector TreeInfo = {}; //创建形成的链表,通过线性存储方式储存树节点位置
容器功能的实现,与基本实验无区别
//容器功能实现
void init_vector(vector& v){
v.length = 0;
for (int i = 0; i < maxsize; i++) {
v.data[i] = NULL;
}
}
void push_back(vector& v, pTnode tree){
v.data[v.length] = tree;
v.length++;
}
void push_front(vector& v, pTnode tree){
for (int i = v.length; i > 0; i--) {
v.data[i] = v.data[i - 1];
}
v.data[0] = tree;
v.length++;
}
Tnode pop_back(vector& v)
{
if (v.length > 0) {
v.length--;
return *v.data[v.length];
}
else exit(-1);
}
Tnode pop_front(vector& v){
if (v.length > 0) {
Tnode ret = *v.data[0];
for (int i = 0; i < v.length - 1; i++) {
v.data[i] = v.data[i + 1];
}
v.length--;
return ret;
}
else exit(-1);
}
int getlen(vector v)
{
return v.length;
}
树的相关代码实现,主要改动在于创建时考虑父节点的创建、遍历时输出图形的逻辑、暂停
//树的功能操作
vector TreeCreate(/*pTnode* parent,*/pTnode& tree){
Data data; //用具接受存储数据输入
char key; //用于接收用户提示信息输入
//初始化tree
tree = (pTnode)malloc(sizeof(TNode));
/*tree->parent = *parent;*/
tree->lcd = NULL;
tree->rcd = NULL;
tree->id = ++ID;
printf("请输入存储到 ID为%d树 的字符>>",tree->id);
scanf("%c", &data); getchar();
tree->data = data;
push_back(TreeInfo,tree);
left: //讨论是否创建子树
printf("是否对ID为%d的树创建左子树?(Y/N)>>",tree->id);
scanf("%c", &key); getchar();
if (key == 'Y' || key == 'y') {//如果创建左子树
TreeCreate(/*&tree,*/tree->lcd);
tree->lcd->parent = tree;
}
else if (key == 'N' || key == 'n') {//如果不创建左子树
tree->lcd = (pTnode)malloc(sizeof(TNode));
tree->lcd->data = '#'; //存入占位符
tree->lcd->lcd = NULL;
tree->lcd->rcd = NULL;
tree->lcd->id = -1;
}
else goto left;
right:
printf("是否对ID为%d的树创建右子树?(Y/N)>>",tree->id);
scanf("%c", &key); getchar();
if (key == 'Y' || key == 'y') {//如果创建右子树
TreeCreate(/*&tree,*/tree->rcd);
tree->rcd->parent = tree;
}
else if (key == 'N' || key == 'n') {//如果不创建右子树
tree->rcd = (pTnode)malloc(sizeof(TNode));
tree->rcd->data = '#'; //存入占位符
tree->rcd->lcd = NULL;
tree->rcd->rcd = NULL;
tree->rcd->id = -1;
}
else goto right;
return TreeInfo;
}
void TreeOutput(vector v){
for (int i = 0; i < v.length; i++) {
printf("节点ID为 %d的树的信息: ", v.data[i]->id);
printf("数据:%c ", v.data[i]->data);
if (v.data[i]->parent == NULL) printf("此节点是树根 ");
else printf("双亲结点ID:%d ", v.data[i]->parent->id);
if (v.data[i]->lcd->data == '#')printf("没有左子树 ");
else { printf("左子树ID:%d,对应值为%c ", v.data[i]->lcd->id, v.data[i]->lcd->data); }
if (v.data[i]->rcd->data == '#')printf("没有右子树 ");
else { printf("右子树ID:%d,对应值为%c ", v.data[i]->rcd->id, v.data[i]->rcd->data); }
printf("\n");
}
}
int gethigh(pTnode tree){
int hl, hr;
if (tree->data != '#') {
hl = gethigh(tree->lcd);
hr = gethigh(tree->rcd);
return hl > hr ? hl + 1 : hr + 1;
}
else return 0; //如果不存在,返回0
}
void First_Order_View(vector v){
for (int i = 0; i < v.length; i++) {
printf("%c ", v.data[i]->data);
putlink(v.data[i]);
FlushBatchDraw();
system("pause");
putdata(v.data[i]);
FlushBatchDraw();
system("pause");
}
}
void Second_Order_View(pTnode tree){
if (tree->data != '#') {
Second_Order_View(tree->lcd);
printf("%c ", tree->data);
putdata(tree);
FlushBatchDraw();
system("pause");
Second_Order_View(tree->rcd);
putlink(tree);
FlushBatchDraw();
system("pause");
}
else return;
}
void Third_Order_View(pTnode tree){
if (tree->data != '#') {
Third_Order_View(tree->lcd);
Third_Order_View(tree->rcd);
printf("%c ", tree->data);
putdata(tree);
FlushBatchDraw();
system("pause");
putlink(tree);
FlushBatchDraw();
system("pause");
}
else return;
}
void Level_Order_View(pTnode tree){
vector v = {};
init_vector(v);
push_back(v, tree);
while (v.length) {
Tnode out = pop_front(v);//取出队头元素
if (out.lcd->data != '#') push_back(v, out.lcd);//如果有左子树,左子树进队列
if (out.rcd->data != '#') push_back(v, out.rcd);//如果有右子树,右子树进队列
printf("%c ", out.data);
putlink(&out);
FlushBatchDraw();
system("pause");
putdata(&out);
FlushBatchDraw();
system("pause");
}
}
void TreeDestory(vector& v){
for (int i = 0; i < maxsize; i++) {
free(v.data[i]); //v.data里面装的是指向树节点的指针,释放v.data就是释放树
}
//free(v.data); //不需要重复释放了
v.length = 0;
printf("\n内存释放完毕...");
}
位置信息配置与图形绘制
void TreeDestory(vector& v){
for (int i = 0; i < maxsize; i++) {
free(v.data[i]); //v.data里面装的是指向树节点的指针,释放v.data就是释放树
}
//free(v.data); //不需要重复释放了
v.length = 0;
printf("\n内存释放完毕...");
}
int freshlevel(int treehigh, pTnode tree){
int high = 0;
if (tree->parent != NULL) high = tree->parent->level + 1;
else high = 1;
tree->level = high;
printf("%c at level %d ,", tree->data, tree->level);
return high;
}
int freshposx(pTnode tree){
pTnode parent = tree->parent;
int dx = ConsoleX / pow(2, tree->level - 1) / 2;
if (parent != NULL) {
if (parent->lcd == tree) tree->pos.x = parent->pos.x - dx;
else if (parent->rcd == tree)tree->pos.x = parent->pos.x + dx;
else {
printf("结构有误!");
exit(-4);
}
}
else tree->pos.x = dx;
printf("%c x %d ,", tree->data, tree->pos.x);
return tree->pos.x;
}
int freshposy(int treehigh,pTnode tree) {
int dy = ConsoleY / treehigh;
int ret = dy * (tree->level-1);
tree->pos.y = ret;
printf("%c x %d ,", tree->data, tree->pos.y);
return ret;
}
void makestatus(vector treeinfo){
int treehight = gethigh(treeinfo.data[0]);
for (int i = 0; i < treeinfo.length; i++) {
freshlevel(treehight, treeinfo.data[i]);
}
for (int i = 0; i < treeinfo.length; i++) {
freshposx(treeinfo.data[i]);
freshposy(treehight, treeinfo.data[i]);
}
}
void putdata(pTnode tree){
if (tree->data != '#') {
setlinecolor(GREEN);
rectangle(tree->pos.x - offset, tree->pos.y - offset, tree->pos.x + rx + offset, tree->pos.y + ry + offset);
settextcolor(GREEN);
settextstyle(40, 0, L"宋体");
outtextxy(tree->pos.x, tree->pos.y, tree->data);
printf("put %d %d %c\n", tree->pos.x, tree->pos.y, tree->data);
}
else return;
}
void putlink(pTnode tree){
if (tree->data!='#' && tree->parent != NULL) {
setlinecolor(BLUE);
setlinestyle(PS_DASH,3);
line(tree->parent->pos.x + (rx + offset) / 2, tree->parent->pos.y + ry + offset, tree->pos.x + (rx + offset) / 2, tree->pos.y - offset);
}
else return;
}
4.3 main.cpp源文件
#include"MyTree.h"
int main() {
pTnode tree = NULL;
vector treeinfo = TreeCreate(tree);
tree->parent = NULL;
TreeOutput(treeinfo);
int treehight = gethigh(tree);
printf("树的高度为%d\n", treehight);
makestatus(treeinfo);
initgraph(ConsoleX, ConsoleY, EX_SHOWCONSOLE);
setbkcolor(WHITE);
cleardevice();
BeginBatchDraw();
printf("先序遍历:\n");
First_Order_View(treeinfo);
cleardevice();
printf("\n中序遍历:\n");
Second_Order_View(tree);
cleardevice();
printf("\n后序遍历:\n");
Third_Order_View(tree);
cleardevice();
printf("\n层序遍历:\n");
Level_Order_View(tree);
cleardevice();
outtextxy(0, 0, L"thanks for your using");
EndBatchDraw();
getchar();
}
输入输出
输入样例:
A
y
B
y
D
n
n
y
E
y
H
n
n
y
I
n
n
y
C
y
F
n
n
y
G
y
J
n
n
n
输出样例: