mirror of
https://github.com/kangjianwei/Data-Structure.git
synced 2026-08-18 01:10:14 +08:00
💡 <06 树和二叉树>习题代码
This commit is contained in:
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# 包含公共库
|
||||
include_directories(${CMAKE_SOURCE_DIR}/Status)
|
||||
|
||||
# 生成可执行文件
|
||||
add_executable(06.35 06.35.c)
|
||||
# 链接公共库
|
||||
target_link_libraries(06.35 Scanf_lib)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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.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})
|
||||
@@ -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 @@
|
||||
先序序列→ABD^^E^^C^^
|
||||
@@ -0,0 +1 @@
|
||||
先序序列→FGH^^I^^J^^
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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})
|
||||
@@ -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,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;
|
||||
}
|
||||
@@ -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^^^
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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})
|
||||
@@ -0,0 +1 @@
|
||||
先序序列→ABDG^^^EH^^I^^CF^J^^^
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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})
|
||||
@@ -0,0 +1 @@
|
||||
先序序列→ABDG^^^EH^^I^^CF^J^^^
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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})
|
||||
@@ -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^^^
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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})
|
||||
@@ -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,9 @@
|
||||
^AL
|
||||
ABL
|
||||
ACR
|
||||
BDL
|
||||
CEL
|
||||
CFR
|
||||
DGR
|
||||
FHL
|
||||
^^L
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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.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})
|
||||
@@ -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 @@
|
||||
先序序列→*/*+a^^b^^-c^^d^^e^^-g^^h^^
|
||||
@@ -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
Reference in New Issue
Block a user