💡 <06 树和二叉树>习题代码

This commit is contained in:
康建伟
2019-12-08 00:25:05 +08:00
parent d4d1919971
commit 164d4f881c
606 changed files with 47407 additions and 0 deletions
@@ -0,0 +1,102 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
/* 元素最大数量 */
#define MAX 100
/*
* 根据左/右孩子列表,判断u是否为v的子孙
*/
Status Algo_6_33(int L[MAX + 1], int R[MAX + 1], int u, int v);
/*
* 根据双亲结点列表,判断u是否为v的子孙
*/
Status Algo_6_34(int T[MAX + 1], int u, int v);
int main(int argc, char* argv[]) {
int T[MAX + 1] = {0, 0, 1, 1, 2, 2, 3, 5, 5, 6}; // 0号单元弃用
int L[MAX + 1] = {0, 2, 4, 6, 0, 7, 0, 0, 0, 0};
int R[MAX + 1] = {0, 3, 5, 0, 0, 8, 9, 0, 0, 0};
int u, v;
printf("作为示例,建立如下的树:\n");
printf(" → 1 2 3 4 5 6 7 8 9\n"); // 序号
printf("T[n]→ 0 1 1 2 2 3 5 5 6\n"); // 双亲结点列表
printf("L[n]→ 2 4 6 0 7 0 0 0 0\n"); // 左孩子列表
printf("R[n]→ 3 5 0 0 8 9 0 0 0\n"); // 右孩子列表
printf("\n");
printf("请输入需要验证的子孙及祖先...\n\n");
printf("子孙(1~9) u = ");
scanf("%d", &u);
printf("祖先(1~9) v = ");
scanf("%d", &v);
printf("\n");
printf("███题 6.33 验证...███\n");
{
if(Algo_6_33(L, R, u, v) == TRUE) {
printf("u=%d 是 v=%d 的子孙!\n", u, v);
} else {
printf("u=%d 不是 v=%d 的子孙!!\n", u, v);
}
printf("\n");
}
printf("███题 6.34 验证...███\n");
{
if(Algo_6_34(T, u, v) == TRUE) {
printf("u=%d 是 v=%d 的子孙!\n", u, v);
} else {
printf("u=%d 不是 v=%d 的子孙!!\n", u, v);
}
printf("\n");
}
return 0;
}
/*
* 根据左/右孩子列表,判断u是否为v的子孙
*/
Status Algo_6_33(int L[MAX + 1], int R[MAX + 1], int u, int v) {
// 如果u是v的孩子
if(L[v] == u || R[v] == u) {
return TRUE;
} else {
// 如果存在左孩子,向左搜索
if(L[v]!=0 && Algo_6_33(L, R, u, L[v])==TRUE) {
return TRUE;
}
// 如果存在右孩子,向左搜索
if(R[v]!=0 && Algo_6_33(L, R, u, R[v])==TRUE) {
return TRUE;
}
}
return FALSE;
}
/*
* 根据双亲结点列表,判断u是否为v的子孙
*/
Status Algo_6_34(int T[MAX + 1], int u, int v) {
// 如果u的双亲是v
if(T[u] == v) {
return TRUE;
} else {
if(T[u] != 0 && Algo_6_34(T, T[u], v) == TRUE) {
return TRUE;
}
}
return FALSE;
}
@@ -0,0 +1,7 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(06.33-06.34 06.33-06.34.c)
# 链接公共库
target_link_libraries(06.33-06.34 Scanf_lib)
+45
View File
@@ -0,0 +1,45 @@
#include <stdio.h>
/* 结点数量 */
#define N 15
/*
* 求符合题意的整数值
*/
int Algo_6_35(char* BiTree, int i);
int main(int argc, char* argv[]) {
// 顺序存储的二叉树(结点从0号单元开始存储)
char BiTree[N] = {'A', 'B', 'C', 'D', 'E', 'F', '\0', 'G', '\0', 'H', 'I', '\0', 'J', '\0', '\0'};
int i, j;
printf("作为示例,建立二叉树的顺序存储结构(^代表空字符,即此处没有结点信息):ABCDEF^G^HI^J^^");
printf("\n");
printf("请输入结点索引(0~%d)", N);
scanf("%d", &i);
printf("\n");
j = Algo_6_35(BiTree, i);
if(j != -1) {
printf("结点 %d 对应的十进制整数为 %d 。\n", i, j);
} else {
printf("此处结点不存在!\n");
}
return 0;
}
/*
* 求符合题意的整数值
*/
int Algo_6_35(char* BiTree, int i) {
if(BiTree[i] == '\0') {
return -1; // 此处不存在结点
}
return i + 1;
}
+7
View File
@@ -0,0 +1,7 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(06.35 06.35.c)
# 链接公共库
target_link_libraries(06.35 Scanf_lib)
+63
View File
@@ -0,0 +1,63 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#include "BiTree.h" //**▲06 树和二叉树**//
/*
* 判断两棵二叉树是否相似
*/
Status Algo_6_36(BiTree B1, BiTree B2);
int main(int argc, char* argv[]) {
BiTree B1, B2, B3;
printf("创建二叉树 B1 ...\n");
CreateBiTree(&B1, "TestData_B1.txt");
PrintGraph(B1);
printf("\n");
printf("创建二叉树 B2 ...\n");
CreateBiTree(&B2, "TestData_B2.txt");
PrintGraph(B2);
printf("\n");
printf("创建二叉树 B3 ...\n");
CreateBiTree(&B3, "TestData_B3.txt");
PrintGraph(B3);
printf("\n");
if(Algo_6_36(B1, B2) == TRUE) {
printf("B1与B2相似!\n");
} else {
printf("B1与B2不相似!!\n");
}
if(Algo_6_36(B2, B3) == TRUE) {
printf("B2与B3相似!\n");
} else {
printf("B2与B3不相似!!\n");
}
return 0;
}
/*
* 判断两棵二叉树是否相似
*/
Status Algo_6_36(BiTree B1, BiTree B2) {
// 都为空树
if(BiTreeEmpty(B1) && BiTreeEmpty(B2)) {
return TRUE;
} else {
// 都不为空树
if(!BiTreeEmpty(B1) && !BiTreeEmpty(B2)) {
// 判断左右子树
if(Algo_6_36(B1->lchild, B2->lchild) && Algo_6_36(B1->rchild, B2->rchild)) {
return TRUE;
}
}
}
return FALSE;
}
+178
View File
@@ -0,0 +1,178 @@
/*=============================
* 二叉树的二叉链表存储结构
*
* 包含算法: 6.1、6.2、6.3、6.4
=============================*/
#include "BiTree.h"
#include "LinkQueue.h" //**▲03 栈和队列**//
/*
* ████████ 算法6.4 ████████
*
* 创建
*
* 按照预设的定义来创建二叉树。
* 这里约定使用【先序序列】来创建二叉树。
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateBiTree(BiTree* T, char* path) {
FILE* fp;
int readFromConsole; // 是否从控制台读取数据
// 如果没有文件路径信息,则从控制台读取输入
readFromConsole = path == NULL || strcmp(path, "") == 0;
if(readFromConsole) {
printf("请输入二叉树的先序序列,如果没有子结点,使用^代替:");
CreateTree(T, NULL);
} else {
// 打开文件,准备读取测试数据
fp = fopen(path, "r");
if(fp == NULL) {
return ERROR;
}
CreateTree(T, fp);
fclose(fp);
}
return OK;
}
/*
* 判空
*
* 判断二叉树是否为空树。
*/
Status BiTreeEmpty(BiTree T) {
return T == NULL ? TRUE : FALSE;
}
/*
* 树深
*
* 返回二叉树的深度(层数)。
*/
int BiTreeDepth(BiTree T) {
int LD, RD;
if(T == NULL) {
return 0; // 空树深度为0
} else {
LD = BiTreeDepth(T->lchild); // 求左子树深度
RD = BiTreeDepth(T->rchild); // 求右子树深度
return (LD >= RD ? LD : RD) + 1;
}
}
/*━━━━━━━━━━━━━━━━━━━━━━ 仅限内部使用的函数 ━━━━━━━━━━━━━━━━━━━━━━*/
// 创建二叉树的内部函数
static void CreateTree(BiTree* T, FILE* fp) {
char ch;
// 读取当前结点的值
if(fp == NULL) {
scanf("%c", &ch);
} else {
ReadData(fp, "%c", &ch);
}
if(ch == '^') {
*T = NULL;
} else {
// 生成根结点
*T = (BiTree) malloc(sizeof(BiTNode));
if(!(*T)) {
exit(OVERFLOW);
}
(*T)->data = ch;
CreateTree(&((*T)->lchild), fp); // 创建左子树
CreateTree(&((*T)->rchild), fp); // 创建右子树
}
}
/*━━━━━━━━━━━━━━━━━━━━━━ 图形化输出 ━━━━━━━━━━━━━━━━━━━━━━*/
// 以图形化形式输出当前结构,仅限内部测试使用
void PrintGraph(BiTree T) {
int level, width;
int i, j, k, w;
int begin;
int distance;
TElemType** tmp;
LinkQueue Q;
BiTree e;
// 遇到空树则无需继续计算
if(BiTreeEmpty(T)) {
printf("\n");
return;
}
level = BiTreeDepth(T); // (完全)二叉树结构高度
width = (int)pow(2, level)-1; // (完全)二叉树结构宽度
// 动态创建行
tmp = (TElemType**)malloc(level* sizeof(TElemType*));
// 动态创建列
for(i = 0; i < level; i++) {
tmp[i] = (TElemType*)malloc(width* sizeof(TElemType));
// 初始化内存值为空字符
memset(tmp[i], '\0', width);
}
// 借助队列实现层序遍历
InitQueue(&Q);
EnQueue(&Q, T);
// 遍历树中所有元素,将其安排到二维数组tmp中合适的位置
for(i = 0; i < level; i++) {
w = (int) pow(2, i); // 二叉树当前层的宽度
distance = width / w; // 二叉树当前层的元素间隔
begin = width / (int) pow(2, i + 1); // 二叉树当前层首个元素之前的空格数
for(k = 0; k < w; k++) {
DeQueue(&Q, &e);
if(e == NULL) {
EnQueue(&Q, NULL);
EnQueue(&Q, NULL);
} else {
j = begin + k * (1 + distance);
tmp[i][j] = e->data;
// 左孩子入队
EnQueue(&Q, e->lchild);
// 右孩子入队
EnQueue(&Q, e->rchild);
}
}
}
for(i = 0; i < level; i++) {
for(j = 0; j < width; j++) {
if(tmp[i][j] != '\0') {
printf("%c", tmp[i][j]);
} else {
printf(" ");
}
}
printf("\n");
}
}
+76
View File
@@ -0,0 +1,76 @@
/*=============================
* 二叉树的二叉链表存储结构
*
* 包含算法: 6.1、6.2、6.3、6.4
=============================*/
#ifndef BITREE_H
#define BITREE_H
#include <stdio.h>
#include <stdlib.h> // 提供 malloc、free 原型
#include <string.h> // 提供 memset、strcmp 原型
#include <math.h> // 提供 pow 原型
#include "Status.h" //**▲01 绪论**//
/* 二叉树元素类型定义,这里假设其元素类型为char */
typedef char TElemType;
/* 二叉树结点定义 */
typedef struct BiTNode {
TElemType data; // 结点元素
struct BiTNode* lchild; // 左孩子指针
struct BiTNode* rchild; // 右孩子指针
} BiTNode;
/* 指向二叉树结点的指针 */
typedef BiTNode* BiTree;
/*
* ████████ 算法6.4 ████████
*
* 创建
*
* 按照预设的定义来创建二叉树。
* 这里约定使用【先序序列】来创建二叉树。
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateBiTree(BiTree* T, char* path);
/*
* 判空
*
* 判断二叉树是否为空树。
*/
Status BiTreeEmpty(BiTree T);
/*
* 树深
*
* 返回二叉树的深度(层数)。
*/
int BiTreeDepth(BiTree T);
/*━━━━━━━━━━━━━━━━━━━━━━ 仅限内部使用的函数 ━━━━━━━━━━━━━━━━━━━━━━*/
// 创建二叉树的内部函数
static void CreateTree(BiTree* T, FILE* fp);
/*━━━━━━━━━━━━━━━━━━━━━━ 图形化输出 ━━━━━━━━━━━━━━━━━━━━━━*/
// 以图形化形式输出当前结构,仅限内部测试使用
void PrintGraph(BiTree T);
#endif
+12
View File
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(06.36 LinkQueue.h LinkQueue.c BiTree.h BiTree.c 06.36.c)
# 链接公共库
target_link_libraries(06.36 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+102
View File
@@ -0,0 +1,102 @@
/*=========================
* 队列的链式存储结构(链队)
==========================*/
#ifndef LINKQUEUE_C
#define LINKQUEUE_C
#include "LinkQueue.h" //**▲03 栈和队列**//
/*
* 初始化
*
* 构造一个空的链队。
* 初始化成功则返回OK,否则返回ERROR。
*
*【注】
* 这里的队列带有头结点
*/
Status InitQueue(LinkQueue* Q) {
if(Q == NULL) {
return ERROR;
}
(*Q).front = (*Q).rear = (QueuePtr) malloc(sizeof(QNode));
if(!(*Q).front) {
exit(OVERFLOW);
}
(*Q).front->next = NULL;
return OK;
}
/*
* 判空
*
* 判断链队中是否包含有效数据。
*
* 返回值:
* TRUE : 链队为空
* FALSE: 链队不为空
*/
Status QueueEmpty(LinkQueue Q) {
if(Q.front == Q.rear) {
return TRUE;
} else {
return FALSE;
}
}
/*
* 入队
*
* 将元素e添加到队列尾部。
*/
Status EnQueue(LinkQueue* Q, QElemType e) {
QueuePtr p;
if(Q == NULL || (*Q).front == NULL) {
return ERROR;
}
p = (QueuePtr) malloc(sizeof(QNode));
if(!p) {
exit(OVERFLOW);
}
p->data = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear = p;
return OK;
}
/*
* 出队
*
* 移除队列头部的元素,将其存储到e中。
*/
Status DeQueue(LinkQueue* Q, QElemType* e) {
QueuePtr p;
if(Q == NULL || (*Q).front == NULL || (*Q).front == (*Q).rear) {
return ERROR;
}
p = (*Q).front->next;
*e = p->data;
(*Q).front->next = p->next;
if((*Q).rear == p) {
(*Q).rear = (*Q).front;
}
free(p);
return OK;
}
#endif
+65
View File
@@ -0,0 +1,65 @@
/*=========================
* 队列的链式存储结构(链队)
==========================*/
#ifndef LINKQUEUE_H
#define LINKQUEUE_H
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
#include "BiTree.h" //**▲06 树和二叉树**//
/* 链队元素类型定义 */
typedef BiTree QElemType;
// 队列元素结构
typedef struct QNode {
QElemType data;
struct QNode* next;
} QNode, * QueuePtr;
// 队列结构
typedef struct {
QueuePtr front; // 队头指针
QueuePtr rear; // 队尾指针
} LinkQueue; // 队列的链式存储表示
/*
* 初始化
*
* 构造一个空的链队。
* 初始化成功则返回OK,否则返回ERROR。
*
*【注】
* 这里的队列带有头结点
*/
Status InitQueue(LinkQueue* Q);
/*
* 判空
*
* 判断链队中是否包含有效数据。
*
* 返回值:
* TRUE : 链队为空
* FALSE: 链队不为空
*/
Status QueueEmpty(LinkQueue Q);
/*
* 入队
*
* 将元素e添加到队列尾部。
*/
Status EnQueue(LinkQueue* Q, QElemType e);
/*
* 出队
*
* 移除队列头部的元素,将其存储到e中。
*/
Status DeQueue(LinkQueue* Q, QElemType* e);
#endif
+1
View File
@@ -0,0 +1 @@
先序序列→ABD^^E^^C^^
+1
View File
@@ -0,0 +1 @@
先序序列→FGH^^I^^J^^
+1
View File
@@ -0,0 +1 @@
先序序列→KLM^^N^^OP^^^
@@ -0,0 +1,133 @@
#include <stdio.h>
#include "Status.h" //**01 绪论**//
#include "SqStack.h" //**03 栈和队列**//
#include "BiTree.h" //**06 树和二叉树**//
/*
* 先序遍历的非递归形式
*/
Status Algo_6_37(BiTree T);
/*
* 后序遍历的非递归形式
*/
Status Algo_6_38(BiTree T);
int main(int argc, char* argv[]) {
BiTree T;
printf("创建二叉树 T ...\n");
CreateBiTree(&T, "TestData.txt");
PrintGraph(T);
printf("\n");
printf("███题 6.37 验证...███\n");
{
printf("二叉树先序遍历序列为:");
Algo_6_37(T);
printf("\n");
}
printf("███题 6.38 验证...███\n");
{
printf("二叉树后序遍历序列为:");
Algo_6_38(T);
printf("\n");
}
return 0;
}
/*
* 先序遍历的非递归形式
*/
Status Algo_6_37(BiTree T) {
SqStack S;
SElemType e;
if(BiTreeEmpty(T)) {
printf("\n");
return ERROR;
}
InitStack(&S);
Push(&S, T);
while(!StackEmpty(S)) {
GetTop(S, &e);
printf("%c ", e->data);
if(e->lchild) {
Push(&S, e->lchild);
} else {
while(!StackEmpty(S)) {
Pop(&S, &e);
if(e->rchild) {
Push(&S, e->rchild);
break;
}
}
}
}
printf("\n");
return OK;
}
/*
* 后序遍历的非递归形式
*/
Status Algo_6_38(BiTree T) {
SqStack S;
BiTree p;
SElemType e;
int StackMark[100] = {0}; // 标记栈,设置各结点访问标记(初始化为0)
int k;
if(BiTreeEmpty(T)) {
printf("\n");
return ERROR;
}
InitStack(&S);
p = T;
k = -1;
while(TRUE) {
while(p) {
Push(&S, p);
k++;
StackMark[k] = 1; // 设置第一次访问的标记
p = p->lchild;
}
// p为空但栈不为空
while(!p && !StackEmpty(S)) {
GetTop(S, &p);
// 已访问过一次,当前是第二次访问
if(StackMark[k] == 1) {
StackMark[k] = 2;
p = p->rchild;
// 已访问过两次,当前是第三次访问
} else {
printf("%c ", p->data);
Pop(&S, &e);
StackMark[k] = 0;
k--;
p = NULL;
}
}
if(StackEmpty(S)) {
break;
}
}
printf("\n");
return OK;
}
+178
View File
@@ -0,0 +1,178 @@
/*=============================
* 二叉树的二叉链表存储结构
*
* 包含算法: 6.1、6.2、6.3、6.4
=============================*/
#include "BiTree.h"
#include "LinkQueue.h" //**▲03 栈和队列**//
/*
* ████████ 算法6.4 ████████
*
* 创建
*
* 按照预设的定义来创建二叉树。
* 这里约定使用【先序序列】来创建二叉树。
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateBiTree(BiTree* T, char* path) {
FILE* fp;
int readFromConsole; // 是否从控制台读取数据
// 如果没有文件路径信息,则从控制台读取输入
readFromConsole = path == NULL || strcmp(path, "") == 0;
if(readFromConsole) {
printf("请输入二叉树的先序序列,如果没有子结点,使用^代替:");
CreateTree(T, NULL);
} else {
// 打开文件,准备读取测试数据
fp = fopen(path, "r");
if(fp == NULL) {
return ERROR;
}
CreateTree(T, fp);
fclose(fp);
}
return OK;
}
/*
* 判空
*
* 判断二叉树是否为空树。
*/
Status BiTreeEmpty(BiTree T) {
return T == NULL ? TRUE : FALSE;
}
/*
* 树深
*
* 返回二叉树的深度(层数)。
*/
int BiTreeDepth(BiTree T) {
int LD, RD;
if(T == NULL) {
return 0; // 空树深度为0
} else {
LD = BiTreeDepth(T->lchild); // 求左子树深度
RD = BiTreeDepth(T->rchild); // 求右子树深度
return (LD >= RD ? LD : RD) + 1;
}
}
/*━━━━━━━━━━━━━━━━━━━━━━ 仅限内部使用的函数 ━━━━━━━━━━━━━━━━━━━━━━*/
// 创建二叉树的内部函数
static void CreateTree(BiTree* T, FILE* fp) {
char ch;
// 读取当前结点的值
if(fp == NULL) {
scanf("%c", &ch);
} else {
ReadData(fp, "%c", &ch);
}
if(ch == '^') {
*T = NULL;
} else {
// 生成根结点
*T = (BiTree) malloc(sizeof(BiTNode));
if(!(*T)) {
exit(OVERFLOW);
}
(*T)->data = ch;
CreateTree(&((*T)->lchild), fp); // 创建左子树
CreateTree(&((*T)->rchild), fp); // 创建右子树
}
}
/*━━━━━━━━━━━━━━━━━━━━━━ 图形化输出 ━━━━━━━━━━━━━━━━━━━━━━*/
// 以图形化形式输出当前结构,仅限内部测试使用
void PrintGraph(BiTree T) {
int level, width;
int i, j, k, w;
int begin;
int distance;
TElemType** tmp;
LinkQueue Q;
BiTree e;
// 遇到空树则无需继续计算
if(BiTreeEmpty(T)) {
printf("\n");
return;
}
level = BiTreeDepth(T); // (完全)二叉树结构高度
width = (int)pow(2, level)-1; // (完全)二叉树结构宽度
// 动态创建行
tmp = (TElemType**)malloc(level* sizeof(TElemType*));
// 动态创建列
for(i = 0; i < level; i++) {
tmp[i] = (TElemType*)malloc(width* sizeof(TElemType));
// 初始化内存值为空字符
memset(tmp[i], '\0', width);
}
// 借助队列实现层序遍历
InitQueue(&Q);
EnQueue(&Q, T);
// 遍历树中所有元素,将其安排到二维数组tmp中合适的位置
for(i = 0; i < level; i++) {
w = (int) pow(2, i); // 二叉树当前层的宽度
distance = width / w; // 二叉树当前层的元素间隔
begin = width / (int) pow(2, i + 1); // 二叉树当前层首个元素之前的空格数
for(k = 0; k < w; k++) {
DeQueue(&Q, &e);
if(e == NULL) {
EnQueue(&Q, NULL);
EnQueue(&Q, NULL);
} else {
j = begin + k * (1 + distance);
tmp[i][j] = e->data;
// 左孩子入队
EnQueue(&Q, e->lchild);
// 右孩子入队
EnQueue(&Q, e->rchild);
}
}
}
for(i = 0; i < level; i++) {
for(j = 0; j < width; j++) {
if(tmp[i][j] != '\0') {
printf("%c", tmp[i][j]);
} else {
printf(" ");
}
}
printf("\n");
}
}
+76
View File
@@ -0,0 +1,76 @@
/*=============================
* 二叉树的二叉链表存储结构
*
* 包含算法: 6.1、6.2、6.3、6.4
=============================*/
#ifndef BITREE_H
#define BITREE_H
#include <stdio.h>
#include <stdlib.h> // 提供 malloc、free 原型
#include <string.h> // 提供 memset、strcmp 原型
#include <math.h> // 提供 pow 原型
#include "Status.h" //**▲01 绪论**//
/* 二叉树元素类型定义,这里假设其元素类型为char */
typedef char TElemType;
/* 二叉树结点定义 */
typedef struct BiTNode {
TElemType data; // 结点元素
struct BiTNode* lchild; // 左孩子指针
struct BiTNode* rchild; // 右孩子指针
} BiTNode;
/* 指向二叉树结点的指针 */
typedef BiTNode* BiTree;
/*
* ████████ 算法6.4 ████████
*
* 创建
*
* 按照预设的定义来创建二叉树。
* 这里约定使用【先序序列】来创建二叉树。
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateBiTree(BiTree* T, char* path);
/*
* 判空
*
* 判断二叉树是否为空树。
*/
Status BiTreeEmpty(BiTree T);
/*
* 树深
*
* 返回二叉树的深度(层数)。
*/
int BiTreeDepth(BiTree T);
/*━━━━━━━━━━━━━━━━━━━━━━ 仅限内部使用的函数 ━━━━━━━━━━━━━━━━━━━━━━*/
// 创建二叉树的内部函数
static void CreateTree(BiTree* T, FILE* fp);
/*━━━━━━━━━━━━━━━━━━━━━━ 图形化输出 ━━━━━━━━━━━━━━━━━━━━━━*/
// 以图形化形式输出当前结构,仅限内部测试使用
void PrintGraph(BiTree T);
#endif
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(06.37-06.38 SqStack.h SqStack.c LinkQueue.h LinkQueue.c BiTree.h BiTree.c 06.37-06.38.c)
# 链接公共库
target_link_libraries(06.37-06.38 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+102
View File
@@ -0,0 +1,102 @@
/*=========================
* 队列的链式存储结构(链队)
==========================*/
#ifndef LINKQUEUE_C
#define LINKQUEUE_C
#include "LinkQueue.h" //**▲03 栈和队列**//
/*
* 初始化
*
* 构造一个空的链队。
* 初始化成功则返回OK,否则返回ERROR。
*
*【注】
* 这里的队列带有头结点
*/
Status InitQueue(LinkQueue* Q) {
if(Q == NULL) {
return ERROR;
}
(*Q).front = (*Q).rear = (QueuePtr) malloc(sizeof(QNode));
if(!(*Q).front) {
exit(OVERFLOW);
}
(*Q).front->next = NULL;
return OK;
}
/*
* 判空
*
* 判断链队中是否包含有效数据。
*
* 返回值:
* TRUE : 链队为空
* FALSE: 链队不为空
*/
Status QueueEmpty(LinkQueue Q) {
if(Q.front == Q.rear) {
return TRUE;
} else {
return FALSE;
}
}
/*
* 入队
*
* 将元素e添加到队列尾部。
*/
Status EnQueue(LinkQueue* Q, QElemType e) {
QueuePtr p;
if(Q == NULL || (*Q).front == NULL) {
return ERROR;
}
p = (QueuePtr) malloc(sizeof(QNode));
if(!p) {
exit(OVERFLOW);
}
p->data = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear = p;
return OK;
}
/*
* 出队
*
* 移除队列头部的元素,将其存储到e中。
*/
Status DeQueue(LinkQueue* Q, QElemType* e) {
QueuePtr p;
if(Q == NULL || (*Q).front == NULL || (*Q).front == (*Q).rear) {
return ERROR;
}
p = (*Q).front->next;
*e = p->data;
(*Q).front->next = p->next;
if((*Q).rear == p) {
(*Q).rear = (*Q).front;
}
free(p);
return OK;
}
#endif
@@ -0,0 +1,65 @@
/*=========================
* 队列的链式存储结构(链队)
==========================*/
#ifndef LINKQUEUE_H
#define LINKQUEUE_H
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
#include "BiTree.h" //**▲06 树和二叉树**//
/* 链队元素类型定义 */
typedef BiTree QElemType;
// 队列元素结构
typedef struct QNode {
QElemType data;
struct QNode* next;
} QNode, * QueuePtr;
// 队列结构
typedef struct {
QueuePtr front; // 队头指针
QueuePtr rear; // 队尾指针
} LinkQueue; // 队列的链式存储表示
/*
* 初始化
*
* 构造一个空的链队。
* 初始化成功则返回OK,否则返回ERROR。
*
*【注】
* 这里的队列带有头结点
*/
Status InitQueue(LinkQueue* Q);
/*
* 判空
*
* 判断链队中是否包含有效数据。
*
* 返回值:
* TRUE : 链队为空
* FALSE: 链队不为空
*/
Status QueueEmpty(LinkQueue Q);
/*
* 入队
*
* 将元素e添加到队列尾部。
*/
Status EnQueue(LinkQueue* Q, QElemType e);
/*
* 出队
*
* 移除队列头部的元素,将其存储到e中。
*/
Status DeQueue(LinkQueue* Q, QElemType* e);
#endif
+106
View File
@@ -0,0 +1,106 @@
/*=========================
* 栈的顺序存储结构(顺序栈)
==========================*/
#include "SqStack.h" //**▲03 栈和队列**//
/*
* 初始化
*
* 构造一个空栈。初始化成功则返回OK,否则返回ERROR。
*/
Status InitStack(SqStack* S) {
if(S == NULL) {
return ERROR;
}
(*S).base = (SElemType*) malloc(STACK_INIT_SIZE * sizeof(SElemType));
if((*S).base == NULL) {
exit(OVERFLOW);
}
(*S).top = (*S).base;
(*S).stacksize = STACK_INIT_SIZE;
return OK;
}
/*
* 判空
*
* 判断顺序栈中是否包含有效数据。
*
* 返回值:
* TRUE : 顺序栈为空
* FALSE: 顺序栈不为空
*/
Status StackEmpty(SqStack S) {
if(S.top == S.base) {
return TRUE;
} else {
return FALSE;
}
}
/*
* 取值
*
* 返回栈顶元素,并用e接收。
*/
Status GetTop(SqStack S, SElemType* e) {
if(S.base == NULL || S.top == S.base) {
return 0;
}
// 不会改变栈中元素
*e = *(S.top - 1);
return OK;
}
/*
* 入栈
*
* 将元素e压入到栈顶。
*/
Status Push(SqStack* S, SElemType e) {
if(S == NULL || (*S).base == NULL) {
return ERROR;
}
// 栈满时,追加存储空间
if((*S).top - (*S).base >= (*S).stacksize) {
(*S).base = (SElemType*) realloc((*S).base, ((*S).stacksize + STACKINCREMENT) * sizeof(SElemType));
if((*S).base == NULL) {
exit(OVERFLOW); // 存储分配失败
}
(*S).top = (*S).base + (*S).stacksize;
(*S).stacksize += STACKINCREMENT;
}
// 进栈先赋值,栈顶指针再自增
*(S->top++) = e;
return OK;
}
/*
* 出栈
*
* 将栈顶元素弹出,并用e接收。
*/
Status Pop(SqStack* S, SElemType* e) {
if(S == NULL || (*S).base == NULL) {
return ERROR;
}
if((*S).top == (*S).base) {
return ERROR;
}
// 出栈栈顶指针先递减,再赋值
*e = *(--(*S).top);
return OK;
}
+67
View File
@@ -0,0 +1,67 @@
/*=========================
* 栈的顺序存储结构(顺序栈)
==========================*/
#ifndef SQSTACK_H
#define SQSTACK_H
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
#include "BiTree.h" //**▲06 树和二叉树**//
/* 宏定义 */
#define STACK_INIT_SIZE 100 // 顺序栈存储空间的初始分配量
#define STACKINCREMENT 10 // 顺序栈存储空间的分配增量
/* 顺序栈元素类型定义 */
typedef BiTree SElemType;
// 顺序栈元素结构
typedef struct {
SElemType* base; // 栈底指针
SElemType* top; // 栈顶指针
int stacksize; // 当前已分配的存储空间,以元素为单位
} SqStack;
/*
* 初始化
*
* 构造一个空栈。初始化成功则返回OK,否则返回ERROR。
*/
Status InitStack(SqStack* S);
/*
* 判空
*
* 判断顺序栈中是否包含有效数据。
*
* 返回值:
* TRUE : 顺序栈为空
* FALSE: 顺序栈不为空
*/
Status StackEmpty(SqStack S);
/*
* 取值
*
* 返回栈顶元素,并用e接收。
*/
Status GetTop(SqStack S, SElemType* e);
/*
* 入栈
*
* 将元素e压入到栈顶。
*/
Status Push(SqStack* S, SElemType e);
/*
* 出栈
*
* 将栈顶元素弹出,并用e接收。
*/
Status Pop(SqStack* S, SElemType* e);
#endif
@@ -0,0 +1 @@
先序序列→ABDG^^^EH^^I^^CF^J^^^
+153
View File
@@ -0,0 +1,153 @@
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
/* 二叉树元素类型,这里设置为字符 */
typedef char TElemType;
/* 二叉树的结点定义 */
typedef struct BiTNode {
TElemType data; // 结点元素
struct BiTNode* lchild; // 左孩子指针
struct BiTNode* rchild; // 右孩子指针
struct BiTNode* parent;
int mark;
} BiTNode;
/* 指向二叉树结点的指针 */
typedef BiTNode* BiTree;
/*
* 后序遍历的递推形式
*/
void Algo_6_39(BiTree T);
// 构造二叉树(先序序列)
Status CreateBiTree(BiTree* T, char* path);
// 构造二叉树的内部实现,p用来追踪子树根结点
void CreateTree(BiTree* T, BiTree p, FILE* fp);
// 以图形化形式输出当前二叉树
void PrintGraph(BiTree T);
int main(int argc, char* argv[]) {
BiTree T;
printf("创建二叉树 T ...\n");
CreateBiTree(&T, NULL);
PrintGraph(T);
printf("二叉树后序遍历序列为:");
Algo_6_39(T);
return 0;
}
/*
* 后序遍历的递推形式
*/
void Algo_6_39(BiTree T) {
BiTree p = T;
while(p != NULL) {
// mark==0:还未访问,则先向左访问
if(p->mark == 0) {
p->mark = 1;
if(p->lchild != NULL) {
p = p->lchild;
}
// mark==1:左侧已访问,则再向右访问
} else if(p->mark == 1) {
p->mark = 2;
if(p->rchild != NULL) {
p = p->rchild;
}
// mark==2:左右都访问完了,则打印根结点
} else {
printf("%c ", p->data);
p->mark = 0; // 标记重置
p = p->parent;
}
}
printf("\n");
}
// 构造二叉树(先序序列)
Status CreateBiTree(BiTree* T, char* path) {
FILE* fp;
fp = fopen("TestData.txt", "r");
CreateTree(T, NULL, fp);
fclose(fp);
return OK;
}
// 构造二叉树的内部实现,p用来追踪子树根结点
void CreateTree(BiTree* T, BiTree p, FILE* fp) {
char ch;
ReadData(fp, "%c", &ch);
if(ch == '^') {
*T = NULL;
} else {
*T = (BiTree) malloc(sizeof(BiTNode));
if(!(*T)) {
exit(OVERFLOW);
}
(*T)->data = ch;
(*T)->parent = p;
(*T)->mark = 0;
CreateTree(&(*T)->lchild, *T, fp);
CreateTree(&(*T)->rchild, *T, fp);
}
}
// 以图形化形式输出当前二叉树
void PrintGraph(BiTree T) {
BiTree p = T;
int i = 1;
while(p != NULL) {
// mark==0:还未访问,则先向左访问
if(p->mark == 0) {
printf("%c ", p->data);
i++;
p->mark = 1;
if(p->lchild != NULL) {
p = p->lchild;
} else {
printf("^\n");
i--;
}
// mark==1:左侧已访问,则再向右访问
} else if(p->mark == 1) {
p->mark = 2;
i++;
if(p->rchild != NULL) {
printf("%*c", 2 * (i - 1), ' ');
p = p->rchild;
} else {
printf("%*c^\n", 2 * (i - 1), ' ');
i--;
}
// mark==2:左右都访问完了,则打印根结点
} else {
p->mark = 0; // 标记重置
p = p->parent;
i--;
}
}
printf("\n");
}
+12
View File
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(06.39 06.39.c)
# 链接公共库
target_link_libraries(06.39 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+1
View File
@@ -0,0 +1 @@
先序序列→ABDG^^^EH^^I^^CF^J^^^
+169
View File
@@ -0,0 +1,169 @@
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
/* 二叉树元素类型,这里设置为字符 */
typedef char TElemType;
/* 二叉树的结点定义 */
typedef struct BiTNode {
TElemType data; // 结点元素
struct BiTNode* lchild; // 左孩子指针
struct BiTNode* rchild; // 右孩子指针
struct BiTNode* parent;
} BiTNode;
/* 指向二叉树结点的指针 */
typedef BiTNode* BiTree;
/*
* 中序遍历的递推形式
*
*【注】
* 遍历的关键是分辨当前结点第几次被访问。
*/
void Algo_6_40(BiTree T);
// 构造二叉树(先序序列)
Status CreateBiTree(BiTree* T, char* path);
// 构造二叉树的内部实现,p用来追踪子树根结点
void CreateTree(BiTree* T, BiTree p, FILE* fp);
// 以图形化形式输出当前二叉树
void PrintGraph(BiTree T);
int main(int argc, char* argv[]) {
BiTree T;
printf("创建二叉树 T ...\n");
CreateBiTree(&T, NULL);
PrintGraph(T);
printf("二叉树中序遍历序列为:");
Algo_6_40(T);
return 0;
}
/*
* 中序遍历的递推形式
*
*【注】
* 遍历的关键是分辨当前结点第几次被访问。
*/
void Algo_6_40(BiTree T) {
BiTree p = T;
while(p != NULL) {
// 第一次访问结点,向左访问
if(p->lchild != NULL) {
p = p->lchild;
} else {
// 从左子树返回的结点第二次被访问,要输出
printf("%c ", p->data);
// 若当前结点属于右分支,返回到父结点后要跳过父结点
while(p->rchild == NULL) {
// 从右子树返回的结点第三次被访问,不输出
while(p->parent != NULL && p->parent->rchild == p) {
p = p->parent;
}
if(p->parent != NULL) {
// 若当前结点属于左分支,返回到父结点后要访问父结点
if(p->parent->lchild == p) {
p = p->parent;
printf("%c ", p->data); // 同样返回自左子树
}
} else {
printf("\n");
// 从右子树返回到根结点时,遍历完成
return;
}
}
p = p->rchild;
}
}
}
// 构造二叉树(先序序列)
Status CreateBiTree(BiTree* T, char* path) {
FILE* fp;
fp = fopen("TestData.txt", "r");
CreateTree(T, NULL, fp);
fclose(fp);
return OK;
}
// 构造二叉树的内部实现,p用来追踪子树根结点
void CreateTree(BiTree* T, BiTree p, FILE* fp) {
char ch;
ReadData(fp, "%c", &ch);
if(ch == '^') {
*T = NULL;
} else {
*T = (BiTree) malloc(sizeof(BiTNode));
if(!(*T)) {
exit(OVERFLOW);
}
(*T)->data = ch;
(*T)->parent = p;
CreateTree(&(*T)->lchild, *T, fp);
CreateTree(&(*T)->rchild, *T, fp);
}
}
// 以图形化形式输出当前二叉树
void PrintGraph(BiTree T) {
BiTree p = T;
int i = 1;
while(p != NULL) {
// 从左子树返回的结点第二次被访问,要输出
printf("%c ", p->data);
i++;
// 第一次访问结点,向左访问
if(p->lchild != NULL) {
p = p->lchild;
} else {
printf("^\n");
// 若当前结点属于右分支,返回到父结点后要跳过父结点
while(p->rchild == NULL) {
printf("%*c^\n", 2 * (i - 1), ' ');
i--;
// 从右子树返回的结点第三次被访问,不输出
while(p->parent != NULL && p->parent->rchild == p) {
p = p->parent;
i--;
}
if(p->parent != NULL) {
// 若当前结点属于左分支,返回到父结点后要访问父结点
if(p->parent->lchild == p) {
p = p->parent;
}
} else {
printf("\n");
// 从右子树返回到根结点时,遍历完成
return;
}
}
printf("%*c", 2 * (i - 1), ' ');
p = p->rchild;
}
}
}
+12
View File
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(06.40 06.40.c)
# 链接公共库
target_link_libraries(06.40 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+1
View File
@@ -0,0 +1 @@
先序序列→ABDG^^^EH^^I^^CF^J^^^
File diff suppressed because it is too large Load Diff
+220
View File
@@ -0,0 +1,220 @@
/*=============================
* 二叉树的二叉链表存储结构
*
* 包含算法: 6.1、6.2、6.3、6.4
=============================*/
#include "BiTree.h"
#include "LinkQueue.h" //**▲03 栈和队列**//
/*
* 初始化
*
* 构造空二叉树。
*/
Status InitBiTree(BiTree* T) {
if(T == NULL) {
return ERROR;
}
*T = NULL;
return OK;
}
/*
* 置空
*
* 清理二叉树中的数据,使其成为空树。
*/
Status ClearBiTree(BiTree* T) {
if(T == NULL) {
return ERROR;
}
// 在*T不为空时进行递归清理
if(*T) {
if((*T)->lchild!=NULL) {
ClearBiTree(&((*T)->lchild));
}
if((*T)->rchild!=NULL) {
ClearBiTree(&((*T)->rchild));
}
free(*T);
*T = NULL;
}
return OK;
}
/*
* ████████ 算法6.4 ████████
*
* 创建
*
* 按照预设的定义来创建二叉树。
* 这里约定使用【先序序列】来创建二叉树。
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateBiTree(BiTree* T, char* path) {
FILE* fp;
int readFromConsole; // 是否从控制台读取数据
// 如果没有文件路径信息,则从控制台读取输入
readFromConsole = path == NULL || strcmp(path, "") == 0;
if(readFromConsole) {
printf("请输入二叉树的先序序列,如果没有子结点,使用^代替:");
CreateTree(T, NULL);
} else {
// 打开文件,准备读取测试数据
fp = fopen(path, "r");
if(fp == NULL) {
return ERROR;
}
CreateTree(T, fp);
fclose(fp);
}
return OK;
}
/*
* 判空
*
* 判断二叉树是否为空树。
*/
Status BiTreeEmpty(BiTree T) {
return T == NULL ? TRUE : FALSE;
}
/*
* 树深
*
* 返回二叉树的深度(层数)。
*/
int BiTreeDepth(BiTree T) {
int LD, RD;
if(T == NULL) {
return 0; // 空树深度为0
} else {
LD = BiTreeDepth(T->lchild); // 求左子树深度
RD = BiTreeDepth(T->rchild); // 求右子树深度
return (LD >= RD ? LD : RD) + 1;
}
}
/*━━━━━━━━━━━━━━━━━━━━━━ 仅限内部使用的函数 ━━━━━━━━━━━━━━━━━━━━━━*/
// 创建二叉树的内部函数
static void CreateTree(BiTree* T, FILE* fp) {
char ch;
// 读取当前结点的值
if(fp == NULL) {
scanf("%c", &ch);
} else {
ReadData(fp, "%c", &ch);
}
if(ch == '^') {
*T = NULL;
} else {
// 生成根结点
*T = (BiTree) malloc(sizeof(BiTNode));
if(!(*T)) {
exit(OVERFLOW);
}
(*T)->data = ch;
CreateTree(&((*T)->lchild), fp); // 创建左子树
CreateTree(&((*T)->rchild), fp); // 创建右子树
}
}
/*━━━━━━━━━━━━━━━━━━━━━━ 图形化输出 ━━━━━━━━━━━━━━━━━━━━━━*/
// 以图形化形式输出当前结构,仅限内部测试使用
void PrintGraph(BiTree T) {
int level, width;
int i, j, k, w;
int begin;
int distance;
TElemType** tmp;
LinkQueue Q;
BiTree e;
// 遇到空树则无需继续计算
if(BiTreeEmpty(T)) {
printf("\n");
return;
}
level = BiTreeDepth(T); // (完全)二叉树结构高度
width = (int)pow(2, level)-1; // (完全)二叉树结构宽度
// 动态创建行
tmp = (TElemType**)malloc(level* sizeof(TElemType*));
// 动态创建列
for(i = 0; i < level; i++) {
tmp[i] = (TElemType*)malloc(width* sizeof(TElemType));
// 初始化内存值为空字符
memset(tmp[i], '\0', width);
}
// 借助队列实现层序遍历
InitQueue(&Q);
EnQueue(&Q, T);
// 遍历树中所有元素,将其安排到二维数组tmp中合适的位置
for(i = 0; i < level; i++) {
w = (int) pow(2, i); // 二叉树当前层的宽度
distance = width / w; // 二叉树当前层的元素间隔
begin = width / (int) pow(2, i + 1); // 二叉树当前层首个元素之前的空格数
for(k = 0; k < w; k++) {
DeQueue(&Q, &e);
if(e == NULL) {
EnQueue(&Q, NULL);
EnQueue(&Q, NULL);
} else {
j = begin + k * (1 + distance);
tmp[i][j] = e->data;
// 左孩子入队
EnQueue(&Q, e->lchild);
// 右孩子入队
EnQueue(&Q, e->rchild);
}
}
}
for(i = 0; i < level; i++) {
for(j = 0; j < width; j++) {
if(tmp[i][j] != '\0') {
printf("%c", tmp[i][j]);
} else {
printf(" ");
}
}
printf("\n");
}
}
+90
View File
@@ -0,0 +1,90 @@
/*=============================
* 二叉树的二叉链表存储结构
*
* 包含算法: 6.1、6.2、6.3、6.4
=============================*/
#ifndef BITREE_H
#define BITREE_H
#include <stdio.h>
#include <stdlib.h> // 提供 malloc、free 原型
#include <string.h> // 提供 memset、strcmp 原型
#include <math.h> // 提供 pow 原型
#include "Status.h" //**▲01 绪论**//
/* 二叉树元素类型定义,这里假设其元素类型为char */
typedef char TElemType;
/* 二叉树结点定义 */
typedef struct BiTNode {
TElemType data; // 结点元素
struct BiTNode* lchild; // 左孩子指针
struct BiTNode* rchild; // 右孩子指针
} BiTNode;
/* 指向二叉树结点的指针 */
typedef BiTNode* BiTree;
/*
* 初始化
*
* 构造空二叉树。
*/
Status InitBiTree(BiTree* T);
/*
* 置空
*
* 清理二叉树中的数据,使其成为空树。
*/
Status ClearBiTree(BiTree* T);
/*
* ████████ 算法6.4 ████████
*
* 创建
*
* 按照预设的定义来创建二叉树。
* 这里约定使用【先序序列】来创建二叉树。
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateBiTree(BiTree* T, char* path);
/*
* 判空
*
* 判断二叉树是否为空树。
*/
Status BiTreeEmpty(BiTree T);
/*
* 树深
*
* 返回二叉树的深度(层数)。
*/
int BiTreeDepth(BiTree T);
/*━━━━━━━━━━━━━━━━━━━━━━ 仅限内部使用的函数 ━━━━━━━━━━━━━━━━━━━━━━*/
// 创建二叉树的内部函数
static void CreateTree(BiTree* T, FILE* fp);
/*━━━━━━━━━━━━━━━━━━━━━━ 图形化输出 ━━━━━━━━━━━━━━━━━━━━━━*/
// 以图形化形式输出当前结构,仅限内部测试使用
void PrintGraph(BiTree T);
#endif
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(06.41-06.49 LinkQueue.h LinkQueue.c BiTree.h BiTree.c 06.41-06.49.c)
# 链接公共库
target_link_libraries(06.41-06.49 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+102
View File
@@ -0,0 +1,102 @@
/*=========================
* 队列的链式存储结构(链队)
==========================*/
#ifndef LINKQUEUE_C
#define LINKQUEUE_C
#include "LinkQueue.h" //**▲03 栈和队列**//
/*
* 初始化
*
* 构造一个空的链队。
* 初始化成功则返回OK,否则返回ERROR。
*
*【注】
* 这里的队列带有头结点
*/
Status InitQueue(LinkQueue* Q) {
if(Q == NULL) {
return ERROR;
}
(*Q).front = (*Q).rear = (QueuePtr) malloc(sizeof(QNode));
if(!(*Q).front) {
exit(OVERFLOW);
}
(*Q).front->next = NULL;
return OK;
}
/*
* 判空
*
* 判断链队中是否包含有效数据。
*
* 返回值:
* TRUE : 链队为空
* FALSE: 链队不为空
*/
Status QueueEmpty(LinkQueue Q) {
if(Q.front == Q.rear) {
return TRUE;
} else {
return FALSE;
}
}
/*
* 入队
*
* 将元素e添加到队列尾部。
*/
Status EnQueue(LinkQueue* Q, QElemType e) {
QueuePtr p;
if(Q == NULL || (*Q).front == NULL) {
return ERROR;
}
p = (QueuePtr) malloc(sizeof(QNode));
if(!p) {
exit(OVERFLOW);
}
p->data = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear = p;
return OK;
}
/*
* 出队
*
* 移除队列头部的元素,将其存储到e中。
*/
Status DeQueue(LinkQueue* Q, QElemType* e) {
QueuePtr p;
if(Q == NULL || (*Q).front == NULL || (*Q).front == (*Q).rear) {
return ERROR;
}
p = (*Q).front->next;
*e = p->data;
(*Q).front->next = p->next;
if((*Q).rear == p) {
(*Q).rear = (*Q).front;
}
free(p);
return OK;
}
#endif
@@ -0,0 +1,65 @@
/*=========================
* 队列的链式存储结构(链队)
==========================*/
#ifndef LINKQUEUE_H
#define LINKQUEUE_H
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
#include "BiTree.h" //**▲06 树和二叉树**//
/* 链队元素类型定义 */
typedef BiTree QElemType;
// 队列元素结构
typedef struct QNode {
QElemType data;
struct QNode* next;
} QNode, * QueuePtr;
// 队列结构
typedef struct {
QueuePtr front; // 队头指针
QueuePtr rear; // 队尾指针
} LinkQueue; // 队列的链式存储表示
/*
* 初始化
*
* 构造一个空的链队。
* 初始化成功则返回OK,否则返回ERROR。
*
*【注】
* 这里的队列带有头结点
*/
Status InitQueue(LinkQueue* Q);
/*
* 判空
*
* 判断链队中是否包含有效数据。
*
* 返回值:
* TRUE : 链队为空
* FALSE: 链队不为空
*/
Status QueueEmpty(LinkQueue Q);
/*
* 入队
*
* 将元素e添加到队列尾部。
*/
Status EnQueue(LinkQueue* Q, QElemType e);
/*
* 出队
*
* 移除队列头部的元素,将其存储到e中。
*/
Status DeQueue(LinkQueue* Q, QElemType* e);
#endif
@@ -0,0 +1 @@
先序序列→ABDG^^^EH^^I^^CF^J^^^
+83
View File
@@ -0,0 +1,83 @@
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
#include "BiTree.h" //**▲06 树和二叉树**//
#define MAX_TREE_SIZE 1024 // 二叉树元素数量最大值
/*
* 读取预定格式的结点信息,按层序创建二叉树。
*/
Status Algo_6_50(BiTree* T, FILE* fp);
int main(int argc, char* argv[]) {
BiTree T;
FILE* fp;
printf("创建二叉树(层序序列)...\n");
fp = fopen("TestData.txt", "r");
Algo_6_50(&T, fp);
fclose(fp);
printf("\n");
printf("二叉树T为:\n");
PrintGraph(T);
return 0;
}
/*
* 读取预定格式的结点信息,按层序创建二叉树。
*/
Status Algo_6_50(BiTree* T, FILE* fp) {
char s[4];
BiTree tmp[MAX_TREE_SIZE]; // 按层序存储遇到的每个结点的指针
int m, n;
BiTree p;
m = n = 0;
*T= NULL;
while(TRUE) {
ReadData(fp, "%s", s);
printf("%s\n", s);
// 退出标志
if(s[1] == '^') {
return OK;
}
p = (BiTree) malloc(sizeof(BiTNode));
if(p==NULL) {
exit(OVERFLOW);
}
p->data = s[1];
p->lchild = p->rchild = NULL;
// 根结点
if(s[0] == '^') {
*T = p;
tmp[n++] = p;
} else {
// 寻找子树结点
while(m<n && tmp[m]->data != s[0]) {
m++;
}
if(m>=n) {
return ERROR;
}
if(s[2] == 'L') {
tmp[m]->lchild = p;
} else {
tmp[m]->rchild = p;
}
}
tmp[n++] = p;
}
}
+121
View File
@@ -0,0 +1,121 @@
/*=============================
* 二叉树的二叉链表存储结构
*
* 包含算法: 6.1、6.2、6.3、6.4
=============================*/
#include "BiTree.h"
#include "LinkQueue.h" //**▲03 栈和队列**//
/*
* 初始化
*
* 构造空二叉树。
*/
Status InitBiTree(BiTree* T) {
if(T == NULL) {
return ERROR;
}
*T = NULL;
return OK;
}
/*
* 判空
*
* 判断二叉树是否为空树。
*/
Status BiTreeEmpty(BiTree T) {
return T == NULL ? TRUE : FALSE;
}
/*
* 树深
*
* 返回二叉树的深度(层数)。
*/
int BiTreeDepth(BiTree T) {
int LD, RD;
if(T == NULL) {
return 0; // 空树深度为0
} else {
LD = BiTreeDepth(T->lchild); // 求左子树深度
RD = BiTreeDepth(T->rchild); // 求右子树深度
return (LD >= RD ? LD : RD) + 1;
}
}
// 以图形化形式输出当前结构,仅限内部测试使用
void PrintGraph(BiTree T) {
int level, width;
int i, j, k, w;
int begin;
int distance;
TElemType** tmp;
LinkQueue Q;
BiTree e;
// 遇到空树则无需继续计算
if(BiTreeEmpty(T)) {
printf("\n");
return;
}
level = BiTreeDepth(T); // (完全)二叉树结构高度
width = (int)pow(2, level)-1; // (完全)二叉树结构宽度
// 动态创建行
tmp = (TElemType**)malloc(level* sizeof(TElemType*));
// 动态创建列
for(i = 0; i < level; i++) {
tmp[i] = (TElemType*)malloc(width* sizeof(TElemType));
// 初始化内存值为空字符
memset(tmp[i], '\0', width);
}
// 借助队列实现层序遍历
InitQueue(&Q);
EnQueue(&Q, T);
// 遍历树中所有元素,将其安排到二维数组tmp中合适的位置
for(i = 0; i < level; i++) {
w = (int) pow(2, i); // 二叉树当前层的宽度
distance = width / w; // 二叉树当前层的元素间隔
begin = width / (int) pow(2, i + 1); // 二叉树当前层首个元素之前的空格数
for(k = 0; k < w; k++) {
DeQueue(&Q, &e);
if(e == NULL) {
EnQueue(&Q, NULL);
EnQueue(&Q, NULL);
} else {
j = begin + k * (1 + distance);
tmp[i][j] = e->data;
// 左孩子入队
EnQueue(&Q, e->lchild);
// 右孩子入队
EnQueue(&Q, e->rchild);
}
}
}
for(i = 0; i < level; i++) {
for(j = 0; j < width; j++) {
if(tmp[i][j] != '\0') {
printf("%c", tmp[i][j]);
} else {
printf(" ");
}
}
printf("\n");
}
}
+54
View File
@@ -0,0 +1,54 @@
/*=============================
* 二叉树的二叉链表存储结构
*
* 包含算法: 6.1、6.2、6.3、6.4
=============================*/
#ifndef BITREE_H
#define BITREE_H
#include <stdio.h>
#include <stdlib.h> // 提供 malloc、free 原型
#include <string.h> // 提供 memset、strcmp 原型
#include <math.h> // 提供 pow 原型
#include "Status.h" //**▲01 绪论**//
/* 二叉树元素类型定义,这里假设其元素类型为char */
typedef char TElemType;
/* 二叉树结点定义 */
typedef struct BiTNode {
TElemType data; // 结点元素
struct BiTNode* lchild; // 左孩子指针
struct BiTNode* rchild; // 右孩子指针
} BiTNode;
/* 指向二叉树结点的指针 */
typedef BiTNode* BiTree;
/*
* 初始化
*
* 构造空二叉树。
*/
Status InitBiTree(BiTree* T);
/*
* 判空
*
* 判断二叉树是否为空树。
*/
Status BiTreeEmpty(BiTree T);
/*
* 树深
*
* 返回二叉树的深度(层数)。
*/
int BiTreeDepth(BiTree T);
// 以图形化形式输出当前结构,仅限内部测试使用
void PrintGraph(BiTree T);
#endif
+12
View File
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(06.50 LinkQueue.h LinkQueue.c BiTree.h BiTree.c 06.50.c)
# 链接公共库
target_link_libraries(06.50 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+102
View File
@@ -0,0 +1,102 @@
/*=========================
* 队列的链式存储结构(链队)
==========================*/
#ifndef LINKQUEUE_C
#define LINKQUEUE_C
#include "LinkQueue.h" //**▲03 栈和队列**//
/*
* 初始化
*
* 构造一个空的链队。
* 初始化成功则返回OK,否则返回ERROR。
*
*【注】
* 这里的队列带有头结点
*/
Status InitQueue(LinkQueue* Q) {
if(Q == NULL) {
return ERROR;
}
(*Q).front = (*Q).rear = (QueuePtr) malloc(sizeof(QNode));
if(!(*Q).front) {
exit(OVERFLOW);
}
(*Q).front->next = NULL;
return OK;
}
/*
* 判空
*
* 判断链队中是否包含有效数据。
*
* 返回值:
* TRUE : 链队为空
* FALSE: 链队不为空
*/
Status QueueEmpty(LinkQueue Q) {
if(Q.front == Q.rear) {
return TRUE;
} else {
return FALSE;
}
}
/*
* 入队
*
* 将元素e添加到队列尾部。
*/
Status EnQueue(LinkQueue* Q, QElemType e) {
QueuePtr p;
if(Q == NULL || (*Q).front == NULL) {
return ERROR;
}
p = (QueuePtr) malloc(sizeof(QNode));
if(!p) {
exit(OVERFLOW);
}
p->data = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear = p;
return OK;
}
/*
* 出队
*
* 移除队列头部的元素,将其存储到e中。
*/
Status DeQueue(LinkQueue* Q, QElemType* e) {
QueuePtr p;
if(Q == NULL || (*Q).front == NULL || (*Q).front == (*Q).rear) {
return ERROR;
}
p = (*Q).front->next;
*e = p->data;
(*Q).front->next = p->next;
if((*Q).rear == p) {
(*Q).rear = (*Q).front;
}
free(p);
return OK;
}
#endif
+65
View File
@@ -0,0 +1,65 @@
/*=========================
* 队列的链式存储结构(链队)
==========================*/
#ifndef LINKQUEUE_H
#define LINKQUEUE_H
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
#include "BiTree.h" //**▲06 树和二叉树**//
/* 链队元素类型定义 */
typedef BiTree QElemType;
// 队列元素结构
typedef struct QNode {
QElemType data;
struct QNode* next;
} QNode, * QueuePtr;
// 队列结构
typedef struct {
QueuePtr front; // 队头指针
QueuePtr rear; // 队尾指针
} LinkQueue; // 队列的链式存储表示
/*
* 初始化
*
* 构造一个空的链队。
* 初始化成功则返回OK,否则返回ERROR。
*
*【注】
* 这里的队列带有头结点
*/
Status InitQueue(LinkQueue* Q);
/*
* 判空
*
* 判断链队中是否包含有效数据。
*
* 返回值:
* TRUE : 链队为空
* FALSE: 链队不为空
*/
Status QueueEmpty(LinkQueue Q);
/*
* 入队
*
* 将元素e添加到队列尾部。
*/
Status EnQueue(LinkQueue* Q, QElemType e);
/*
* 出队
*
* 移除队列头部的元素,将其存储到e中。
*/
Status DeQueue(LinkQueue* Q, QElemType* e);
#endif
+9
View File
@@ -0,0 +1,9 @@
^AL
ABL
ACR
BDL
CEL
CFR
DGR
FHL
^^L
+90
View File
@@ -0,0 +1,90 @@
#include <stdio.h>
#include "Status.h" //**▲01 绪论**//
#include "BiTree.h" //**▲06 树和二叉树**//
/*
* 输出算术表达式构成的二叉树(中序遍历)
*/
void Algo_6_51(BiTree T);
// 判断字符c是否为操作符
Status IsOperator(char c);
// 判断两个操作符的优先级
Status Priority(char a, char b);
int main(int argc, char* argv[]) {
BiTree T;
printf("创建二叉树(先序序列)T...\n");
InitBiTree(&T);
CreateBiTree(&T, "TestData.txt");
PrintGraph(T);
printf("\n");
printf("输出算术表达式:");
Algo_6_51(T);
printf("\n");
return 0;
}
/*
* 输出算术表达式构成的二叉树(中序遍历)
*/
void Algo_6_51(BiTree T) {
if(T == NULL) {
return;
}
if(T->lchild != NULL) {
// 当前结点的左孩子是操作符且优先级低于当前结点
if(IsOperator(T->lchild->data) && Priority(T->lchild->data, T->data) < 0) {
printf("(");
Algo_6_51(T->lchild);
printf(")");
} else {
Algo_6_51(T->lchild);
}
}
printf("%c", T->data);
if(T->rchild != NULL) {
// 当前结点的右孩子是操作符且优先级低于当前结点
if(IsOperator(T->rchild->data) && Priority(T->rchild->data, T->data) < 0) {
printf("(");
Algo_6_51(T->rchild);
printf(")");
} else {
Algo_6_51(T->rchild);
}
}
}
// 判断字符c是否为操作符
Status IsOperator(char c) {
if(c == '+' || c == '-' || c == '*' || c == '/') {
return TRUE;
} else {
return ERROR;
}
}
// 判断两个操作符的优先级
Status Priority(char a, char b) {
// a的优先级低
if((a == '+' || a == '-') && (b == '*' || b == '/')) {
return -1;
// a的优先级高
} else if((a == '*' || a == '/') && (b == '+' || b == '-')) {
return 1;
// 优先级相同
} else {
return 0;
}
}
+220
View File
@@ -0,0 +1,220 @@
/*=============================
* 二叉树的二叉链表存储结构
*
* 包含算法: 6.1、6.2、6.3、6.4
=============================*/
#include "BiTree.h"
#include "LinkQueue.h" //**▲03 栈和队列**//
/*
* 初始化
*
* 构造空二叉树。
*/
Status InitBiTree(BiTree* T) {
if(T == NULL) {
return ERROR;
}
*T = NULL;
return OK;
}
/*
* 置空
*
* 清理二叉树中的数据,使其成为空树。
*/
Status ClearBiTree(BiTree* T) {
if(T == NULL) {
return ERROR;
}
// 在*T不为空时进行递归清理
if(*T) {
if((*T)->lchild!=NULL) {
ClearBiTree(&((*T)->lchild));
}
if((*T)->rchild!=NULL) {
ClearBiTree(&((*T)->rchild));
}
free(*T);
*T = NULL;
}
return OK;
}
/*
* ████████ 算法6.4 ████████
*
* 创建
*
* 按照预设的定义来创建二叉树。
* 这里约定使用【先序序列】来创建二叉树。
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateBiTree(BiTree* T, char* path) {
FILE* fp;
int readFromConsole; // 是否从控制台读取数据
// 如果没有文件路径信息,则从控制台读取输入
readFromConsole = path == NULL || strcmp(path, "") == 0;
if(readFromConsole) {
printf("请输入二叉树的先序序列,如果没有子结点,使用^代替:");
CreateTree(T, NULL);
} else {
// 打开文件,准备读取测试数据
fp = fopen(path, "r");
if(fp == NULL) {
return ERROR;
}
CreateTree(T, fp);
fclose(fp);
}
return OK;
}
/*
* 判空
*
* 判断二叉树是否为空树。
*/
Status BiTreeEmpty(BiTree T) {
return T == NULL ? TRUE : FALSE;
}
/*
* 树深
*
* 返回二叉树的深度(层数)。
*/
int BiTreeDepth(BiTree T) {
int LD, RD;
if(T == NULL) {
return 0; // 空树深度为0
} else {
LD = BiTreeDepth(T->lchild); // 求左子树深度
RD = BiTreeDepth(T->rchild); // 求右子树深度
return (LD >= RD ? LD : RD) + 1;
}
}
/*━━━━━━━━━━━━━━━━━━━━━━ 仅限内部使用的函数 ━━━━━━━━━━━━━━━━━━━━━━*/
// 创建二叉树的内部函数
static void CreateTree(BiTree* T, FILE* fp) {
char ch;
// 读取当前结点的值
if(fp == NULL) {
scanf("%c", &ch);
} else {
ReadData(fp, "%c", &ch);
}
if(ch == '^') {
*T = NULL;
} else {
// 生成根结点
*T = (BiTree) malloc(sizeof(BiTNode));
if(!(*T)) {
exit(OVERFLOW);
}
(*T)->data = ch;
CreateTree(&((*T)->lchild), fp); // 创建左子树
CreateTree(&((*T)->rchild), fp); // 创建右子树
}
}
/*━━━━━━━━━━━━━━━━━━━━━━ 图形化输出 ━━━━━━━━━━━━━━━━━━━━━━*/
// 以图形化形式输出当前结构,仅限内部测试使用
void PrintGraph(BiTree T) {
int level, width;
int i, j, k, w;
int begin;
int distance;
TElemType** tmp;
LinkQueue Q;
BiTree e;
// 遇到空树则无需继续计算
if(BiTreeEmpty(T)) {
printf("\n");
return;
}
level = BiTreeDepth(T); // (完全)二叉树结构高度
width = (int)pow(2, level)-1; // (完全)二叉树结构宽度
// 动态创建行
tmp = (TElemType**)malloc(level* sizeof(TElemType*));
// 动态创建列
for(i = 0; i < level; i++) {
tmp[i] = (TElemType*)malloc(width* sizeof(TElemType));
// 初始化内存值为空字符
memset(tmp[i], '\0', width);
}
// 借助队列实现层序遍历
InitQueue(&Q);
EnQueue(&Q, T);
// 遍历树中所有元素,将其安排到二维数组tmp中合适的位置
for(i = 0; i < level; i++) {
w = (int) pow(2, i); // 二叉树当前层的宽度
distance = width / w; // 二叉树当前层的元素间隔
begin = width / (int) pow(2, i + 1); // 二叉树当前层首个元素之前的空格数
for(k = 0; k < w; k++) {
DeQueue(&Q, &e);
if(e == NULL) {
EnQueue(&Q, NULL);
EnQueue(&Q, NULL);
} else {
j = begin + k * (1 + distance);
tmp[i][j] = e->data;
// 左孩子入队
EnQueue(&Q, e->lchild);
// 右孩子入队
EnQueue(&Q, e->rchild);
}
}
}
for(i = 0; i < level; i++) {
for(j = 0; j < width; j++) {
if(tmp[i][j] != '\0') {
printf("%c", tmp[i][j]);
} else {
printf(" ");
}
}
printf("\n");
}
}
+90
View File
@@ -0,0 +1,90 @@
/*=============================
* 二叉树的二叉链表存储结构
*
* 包含算法: 6.1、6.2、6.3、6.4
=============================*/
#ifndef BITREE_H
#define BITREE_H
#include <stdio.h>
#include <stdlib.h> // 提供 malloc、free 原型
#include <string.h> // 提供 memset、strcmp 原型
#include <math.h> // 提供 pow 原型
#include "Status.h" //**▲01 绪论**//
/* 二叉树元素类型定义,这里假设其元素类型为char */
typedef char TElemType;
/* 二叉树结点定义 */
typedef struct BiTNode {
TElemType data; // 结点元素
struct BiTNode* lchild; // 左孩子指针
struct BiTNode* rchild; // 右孩子指针
} BiTNode;
/* 指向二叉树结点的指针 */
typedef BiTNode* BiTree;
/*
* 初始化
*
* 构造空二叉树。
*/
Status InitBiTree(BiTree* T);
/*
* 置空
*
* 清理二叉树中的数据,使其成为空树。
*/
Status ClearBiTree(BiTree* T);
/*
* ████████ 算法6.4 ████████
*
* 创建
*
* 按照预设的定义来创建二叉树。
* 这里约定使用【先序序列】来创建二叉树。
*
*
*【备注】
*
* 教材中默认从控制台读取数据。
* 这里为了方便测试,避免每次运行都手动输入数据,
* 因而允许选择从预设的文件path中读取测试数据。
*
* 如果需要从控制台读取数据,则path为NULL或者为空串,
* 如果需要从文件中读取数据,则需要在path中填写文件名信息。
*/
Status CreateBiTree(BiTree* T, char* path);
/*
* 判空
*
* 判断二叉树是否为空树。
*/
Status BiTreeEmpty(BiTree T);
/*
* 树深
*
* 返回二叉树的深度(层数)。
*/
int BiTreeDepth(BiTree T);
/*━━━━━━━━━━━━━━━━━━━━━━ 仅限内部使用的函数 ━━━━━━━━━━━━━━━━━━━━━━*/
// 创建二叉树的内部函数
static void CreateTree(BiTree* T, FILE* fp);
/*━━━━━━━━━━━━━━━━━━━━━━ 图形化输出 ━━━━━━━━━━━━━━━━━━━━━━*/
// 以图形化形式输出当前结构,仅限内部测试使用
void PrintGraph(BiTree T);
#endif
+12
View File
@@ -0,0 +1,12 @@
# 包含公共库
include_directories(${CMAKE_SOURCE_DIR}/Status)
# 生成可执行文件
add_executable(06.51 LinkQueue.h LinkQueue.c BiTree.h BiTree.c 06.51.c)
# 链接公共库
target_link_libraries(06.51 Scanf_lib)
# 记录要拷贝到*.exe目录下的资源文件
file(GLOB TestData TestData*.txt)
# 将资源文件拷贝到*.exe目录下,不然无法加载
file(COPY ${TestData} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+102
View File
@@ -0,0 +1,102 @@
/*=========================
* 队列的链式存储结构(链队)
==========================*/
#ifndef LINKQUEUE_C
#define LINKQUEUE_C
#include "LinkQueue.h" //**▲03 栈和队列**//
/*
* 初始化
*
* 构造一个空的链队。
* 初始化成功则返回OK,否则返回ERROR。
*
*【注】
* 这里的队列带有头结点
*/
Status InitQueue(LinkQueue* Q) {
if(Q == NULL) {
return ERROR;
}
(*Q).front = (*Q).rear = (QueuePtr) malloc(sizeof(QNode));
if(!(*Q).front) {
exit(OVERFLOW);
}
(*Q).front->next = NULL;
return OK;
}
/*
* 判空
*
* 判断链队中是否包含有效数据。
*
* 返回值:
* TRUE : 链队为空
* FALSE: 链队不为空
*/
Status QueueEmpty(LinkQueue Q) {
if(Q.front == Q.rear) {
return TRUE;
} else {
return FALSE;
}
}
/*
* 入队
*
* 将元素e添加到队列尾部。
*/
Status EnQueue(LinkQueue* Q, QElemType e) {
QueuePtr p;
if(Q == NULL || (*Q).front == NULL) {
return ERROR;
}
p = (QueuePtr) malloc(sizeof(QNode));
if(!p) {
exit(OVERFLOW);
}
p->data = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear = p;
return OK;
}
/*
* 出队
*
* 移除队列头部的元素,将其存储到e中。
*/
Status DeQueue(LinkQueue* Q, QElemType* e) {
QueuePtr p;
if(Q == NULL || (*Q).front == NULL || (*Q).front == (*Q).rear) {
return ERROR;
}
p = (*Q).front->next;
*e = p->data;
(*Q).front->next = p->next;
if((*Q).rear == p) {
(*Q).rear = (*Q).front;
}
free(p);
return OK;
}
#endif
+65
View File
@@ -0,0 +1,65 @@
/*=========================
* 队列的链式存储结构(链队)
==========================*/
#ifndef LINKQUEUE_H
#define LINKQUEUE_H
#include <stdio.h>
#include <stdlib.h> // 提供malloc、realloc、free、exit原型
#include "Status.h" //**▲01 绪论**//
#include "BiTree.h" //**▲06 树和二叉树**//
/* 链队元素类型定义 */
typedef BiTree QElemType;
// 队列元素结构
typedef struct QNode {
QElemType data;
struct QNode* next;
} QNode, * QueuePtr;
// 队列结构
typedef struct {
QueuePtr front; // 队头指针
QueuePtr rear; // 队尾指针
} LinkQueue; // 队列的链式存储表示
/*
* 初始化
*
* 构造一个空的链队。
* 初始化成功则返回OK,否则返回ERROR。
*
*【注】
* 这里的队列带有头结点
*/
Status InitQueue(LinkQueue* Q);
/*
* 判空
*
* 判断链队中是否包含有效数据。
*
* 返回值:
* TRUE : 链队为空
* FALSE: 链队不为空
*/
Status QueueEmpty(LinkQueue Q);
/*
* 入队
*
* 将元素e添加到队列尾部。
*/
Status EnQueue(LinkQueue* Q, QElemType e);
/*
* 出队
*
* 移除队列头部的元素,将其存储到e中。
*/
Status DeQueue(LinkQueue* Q, QElemType* e);
#endif
+1
View File
@@ -0,0 +1 @@
先序序列→*/*+a^^b^^-c^^d^^e^^-g^^h^^
+90
View File
@@ -0,0 +1,90 @@
#include <stdio.h>
#include <math.h> // 提供pow、log原型
#include "BiTree.h" //**▲06 树和二叉树**//
#define MAX_TREE_SIZE 1024 // 二叉树元素数量最大值
/*
* 计算二叉树的繁茂度:宽度x高度
* 注:宽度为各层结点数的最大值
*/
int Algo_6_52(BiTree T);
int main(int argc, char* argv[]) {
BiTree T;
printf("创建二叉树(先序序列)T...\n");
InitBiTree(&T);
CreateBiTree(&T, "TestData.txt");
PrintGraph(T);
printf("\n");
printf("树的繁茂度为: %d", Algo_6_52(T));
printf("\n");
return 0;
}
/*
* 计算二叉树的繁茂度:宽度x高度
* 注:宽度为各层结点数的最大值
*/
int Algo_6_52(BiTree T) {
int lux; // 繁茂度
int col, width; // 各层宽度和最大宽度
int row, high; // 当前结点所在层数和最大高度
BiTree queue[MAX_TREE_SIZE]; // 树指针数组,模拟队列
int level[MAX_TREE_SIZE]; // 记录当前结点在第几层
BiTree p;
int m, n;
if(T==NULL) {
return 0;
}
width = high = 0;
m = n = 0;
col = 1;
queue[n] = T;
level[n] = 1;
n++;
while(m<n){
p = queue[m];
row = level[m]; // 当前结点所在的层
m++;
// 进入新的一层
if(row>high) {
high = row;
col = 1; // 换行时要重置列数
} else {
col++;
}
if(col>width) {
width = col;
}
if(p->lchild!=NULL) {
queue[n] = p->lchild;
level[n] = row+1;
n++;
}
if(p->rchild!=NULL) {
queue[n] = p->rchild;
level[n] = row+1;
n++;
}
}
lux = width * high;
return lux;
}

Some files were not shown because too many files have changed in this diff Show More