将教材目录生成为普通树结构的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <direct.h>
#define MAX_CHILDREN 12 // 每个节点最多11个子节点
// 树节点结构体
typedef struct TreeNode {
int id;
char longid[50]; //作为主码
char name[100];
int pageStart;
int pageEnd;
int level;
struct TreeNode* parent;
struct TreeNode* children[MAX_CHILDREN]; // 子节点数组
} TreeNode;
// 树结构
typedef struct {
TreeNode* root;
} ChapterTree;
void PrintTreeStructure(ChapterTree* tree) {
// 如果树的根节点为空,直接返回
if (!tree->root) return;
// 定义一个队列,用于层次遍历树结构,最多存储2000个节点
TreeNode* queue[2000];
// 初始化
int front = 0, rear = 0;
// 将根节点入队
queue[rear++] = tree->root;
// 当队列不为空时,循环遍历
while (front < rear) {
// 取队列头节点
TreeNode* current = queue[front++];
// 如果当前节点有子节点,则打印当前节点的信息
if (current->children[0] != NULL) {
printf("节点%d [%s] 的子节点: ", current->id, current->longid);
// 如果使用name会输出乱码,因为无法识别中文字体,所以使用longid(主码)作为输出对象
}
// 遍历所有子节点位置(包括NULL)
for (int i = 0; i < MAX_CHILDREN; i++) {
// 如果子节点为空,跳出循环
if (current->children[i] == NULL) {
break;
} else {
printf("[%d]%d ", i, current->children[i]->id); // 打印子节点的索引和id
queue[rear++] = current->children[i]; // 将子节点入队
}
}
// 如果当前节点有子节点,则换行
if (current->children[0] != NULL) {
printf("\n");
}
}
}
// 查找指定ID的节点
TreeNode* FindNodeById(ChapterTree* tree, int targetId) {
// 如果树为空,直接返回NULL
if (!tree->root) return NULL;
// 创建一个队列用于广度优先搜索,最大容量为2000
TreeNode* queue[2000];
int front = 0, rear = 0;
// 将根节点入队
queue[rear++] = tree->root;
// 当队列不为空时继续搜索
while (front < rear) {
// 取出队列头部的节点
TreeNode* current = queue[front++];
// 如果当前节点的ID等于目标ID,返回该节点
if (current->id == targetId) return current;
// 遍历当前节点的所有子节点
for (int i = 0; i < MAX_CHILDREN; i++) {
// 如果子节点存在,将其入队
if (current->children[i]) {
queue[rear++] = current->children[i];
}
}
}
// 如果遍历完整棵树仍未找到,返回NULL
return NULL;
}
// 从文件加载章节树
void LoadFile(const char* filename, ChapterTree* tree) {
// 创建虚拟根节点
tree->root = (TreeNode*)calloc(1, sizeof(TreeNode));
strcpy(tree->root->longid, "0");
strcpy(tree->root->name, "Root");
tree->root->id = 0;
tree->root->parent = NULL;
tree->root->level = 0;
// 打开文件
FILE* file = fopen(filename, "r");
if (!file) {
// 如果文件打开失败,释放根节点并返回
perror("无法打开文件");
free(tree->root);
tree->root = NULL;
return;
}
char line[256];
// 逐行读取文件内容
while (fgets(line, sizeof(line), file)) {
// 去掉行尾的换行符
line[strcspn(line, "\n")] = 0;
// 解析字段,以制表符为分隔符(我的理解是类似于python的解包,将元组中的的值进行写入)
char* token = strtok(line, "\t");
char longid[50] = "";
strncpy(longid, token, 49);
token = strtok(NULL, "\t");
char name[100] = "";
strncpy(name, token, 99);
token = strtok(NULL, "\t");
int pageStart = token ? atoi(token) : 0;
token = strtok(NULL, "\t");
int pageEnd = token ? atoi(token) : 0;
token = strtok(NULL, "\t");
int id = token ? atoi(token) : 0;
token = strtok(NULL, "\t");
int parentId = token ? atoi(token) : 0;
// 创建新节点,并赋值
TreeNode* newNode = (TreeNode*)calloc(1, sizeof(TreeNode));
strncpy(newNode->name, name, 99);
newNode->pageStart = pageStart;
newNode->pageEnd = pageEnd;
newNode->id = id;
strncpy(newNode->longid, longid, 49);
newNode->level = 0;
// 查找父节点,如果parentId为0,则父节点为根节点
TreeNode* parent = (parentId == 0) ? tree->root : FindNodeById(tree, parentId);
if (parent) {
// 寻找父节点的第一个空子节点位置
int insertPos = -1;
for (int i = 0; i < MAX_CHILDREN; i++) {
if (!parent->children[i]) {
insertPos = i;
break;
}
}
// 如果找到空位置,将新节点插入
if (insertPos != -1) {
parent->children[insertPos] = newNode;
newNode->parent = parent;
newNode->level = parent->level + 1;
} else {
// 如果父节点已满,打印错误信息并释放新节点
printf("错误:父节点%d已达最大子节点数,无法插入%d\n", parentId, id);
free(newNode);
}
} else {
// 如果未找到父节点,打印错误信息并释放新节点
printf("未找到父节点%d,节点%d未被插入\n", parentId, id);
free(newNode);
}
}
// 关闭文件
fclose(file);
}
// 写入txt文件函数
void WriteToFile(const char* filename, ChapterTree* tree) {
if (!tree->root) return;
FILE* file = fopen(filename, "w");
if (!file) {
perror("无法打开文件");
return;
}
TreeNode* queue[2000];
int front = 0, rear = 0;
queue[rear++] = tree->root;
while (front < rear) {
TreeNode* current = queue[front++];
// 写入当前节点信息
fprintf(file, "节点%d [%s] 的子节点: ", current->id, current->longid);
// 遍历所有子节点位置(包括NULL)
for (int i = 0; i < MAX_CHILDREN; i++) {
if (current->children[i]==NULL) {
break;
} else {
fprintf(file, "[%d]%d ", i, current->children[i]->id);
queue[rear++] = current->children[i];
}
}
fprintf(file, "\n");
}
fclose(file);
}
int main() {
ChapterTree tree = {NULL};
// 加载文件
//LoadFile("目录1.txt", &tree);
LoadFile("目录(优化).txt", &tree); //将在章节名按*+章节号命名,不会有汉字错误
// 输出树结构
printf("树结构(节点ID [子节点位置]子节点ID):\n");
PrintTreeStructure(&tree);
// 写入文件
WriteToFile("树结构.txt", &tree);
getchar();
return 0;
}
结果:
同时生成了新文件,成功!
输出的优化后目录的结果为:
节点0 [0] 的子节点: [0]1 [1]16 [2]37 [3]57 [4]69 [5]82 [6]92 [7]105 [8]136 [9]159 [10]174 [11]189
节点1 [*1] 的子节点: [0]2 [1]8 [2]9
节点16 [*2] 的子节点: [0]17 [1]18 [2]19 [3]20 [4]25 [5]32 [6]33
节点37 [*3] 的子节点: [0]38 [1]43 [2]46 [3]53
节点57 [*4] 的子节点: [0]58 [1]62 [2]63 [3]64
节点69 [*5] 的子节点: [0]70 [1]74 [2]77 [3]78
节点82 [*6] 的子节点: [0]83 [1]84 [2]85 [3]86 [4]87 [5]88
节点92 [*7] 的子节点: [0]93 [1]96 [2]99
节点105 [*8] 的子节点: [0]106 [1]111 [2]115 [3]118 [4]123 [5]128 [6]132 [7]133 [8]134
节点136 [*9] 的子节点: [0]137 [1]140 [2]143 [3]146 [4]149 [5]153 [6]156 [7]157
节点159 [*10] 的子节点: [0]160 [1]161 [2]164 [3]167 [4]170 [5]171 [6]172
节点174 [*11] 的子节点: [0]175 [1]176 [2]180 [3]183
节点189 [bibiliography] 的子节点:
节点2 [1.1] 的子节点: [0]3 [1]4 [2]5 [3]6 [4]7
节点8 [1.2] 的子节点:
节点9 [1.3] 的子节点: [0]10 [1]11 [2]12 [3]13 [4]14
节点17 [2.1] 的子节点:
节点18 [2.1.1] 的子节点:
节点19 [2.1.2] 的子节点:
节点20 [2.2] 的子节点: [0]21 [1]22 [2]23 [3]24
节点25 [2.3] 的子节点: [0]26 [1]27 [2]28 [3]29 [4]30 [5]31
节点32 [2.4] 的子节点:
节点33 [2.5] 的子节点: [0]34 [1]35
节点38 [3.1] 的子节点: [0]39 [1]40 [2]41 [3]42
节点43 [3.2] 的子节点: [0]44 [1]45
节点46 [3.3] 的子节点: [0]47 [1]48 [2]49 [3]50 [4]51 [5]52
节点53 [3.4] 的子节点: [0]54 [1]55
节点58 [4.1] 的子节点: [0]59 [1]60 [2]61
节点62 [4.2] 的子节点:
节点63 [4.3] 的子节点:
节点64 [4.4] 的子节点: [0]65 [1]66 [2]67
节点70 [5.1] 的子节点: [0]71 [1]72 [2]73
节点74 [5.2] 的子节点: [0]75 [1]76
节点77 [5.3] 的子节点: [0]79 [1]80
节点78 [5.4] 的子节点:
节点83 [6.1] 的子节点:
节点84 [6.2] 的子节点:
节点85 [6.3] 的子节点:
节点86 [6.4] 的子节点:
节点87 [6.5] 的子节点:
节点88 [6.6] 的子节点: [0]89 [1]90
节点93 [7.1] 的子节点: [0]94 [1]95
节点96 [7.2] 的子节点: [0]97 [1]98
节点99 [7.3] 的子节点: [0]100 [1]101 [2]102 [3]103
节点106 [8.1] 的子节点: [0]107 [1]108 [2]109 [3]110
节点111 [8.2] 的子节点: [0]112 [1]113 [2]114
节点115 [8.3] 的子节点: [0]116 [1]117
节点118 [8.4] 的子节点: [0]119 [1]120 [2]121 [3]122
节点123 [8.5] 的子节点: [0]124 [1]125 [2]126 [3]127
节点128 [8.6] 的子节点: [0]129 [1]130 [2]131
节点132 [8.7] 的子节点:
节点133 [8.8] 的子节点:
节点134 [8.9] 的子节点:
节点137 [9.1] 的子节点: [0]138 [1]139
节点140 [9.2] 的子节点: [0]141 [1]142
节点143 [9.3] 的子节点: [0]144 [1]145
节点146 [9.4] 的子节点: [0]147 [1]148
节点149 [9.5] 的子节点: [0]150 [1]151 [2]152
节点153 [9.6] 的子节点: [0]154 [1]155
节点156 [9.7] 的子节点:
节点157 [9.8] 的子节点:
节点160 [10.1] 的子节点:
节点161 [10.2] 的子节点: [0]162 [1]163
节点164 [10.3] 的子节点: [0]165 [1]166
节点167 [10.4] 的子节点: [0]168 [1]169
节点170 [10.5] 的子节点:
节点171 [10.6] 的子节点:
节点172 [10.7] 的子节点:
节点175 [11.1] 的子节点:
节点176 [11.2] 的子节点: [0]177 [1]178 [2]179
节点180 [11.3] 的子节点: [0]181 [1]182
节点183 [11.4] 的子节点: [0]184 [1]185 [2]186 [3]187
节点3 [1.1.1] 的子节点:
节点4 [1.1.2] 的子节点:
节点5 [1.1.3] 的子节点:
节点6 [1.1.4] 的子节点:
节点7 [1.1.5] 的子节点:
节点10 [1.3.1] 的子节点:
节点11 [1.3.2] 的子节点:
节点12 [1.3.3] 的子节点:
节点13 [1.3.4] 的子节点:
节点14 [1.3.5] 的子节点:
节点21 [2.2.1] 的子节点:
节点22 [2.2.2] 的子节点:
节点23 [2.2.3] 的子节点:
节点24 [2.2.4] 的子节点:
节点26 [2.3.1] 的子节点:
节点27 [2.3.2] 的子节点:
节点28 [2.3.3] 的子节点:
节点29 [2.3.4] 的子节点:
节点30 [2.3.5] 的子节点:
节点31 [2.3.6] 的子节点:
节点34 [2.5.1] 的子节点:
节点35 [2.5.2] 的子节点:
节点39 [3.1.1] 的子节点:
节点40 [3.1.2] 的子节点:
节点41 [3.1.3] 的子节点:
节点42 [3.1.4] 的子节点:
节点44 [3.2.1] 的子节点:
节点45 [3.2.2] 的子节点:
节点47 [3.3.1] 的子节点:
节点48 [3.3.2] 的子节点:
节点49 [3.3.3] 的子节点:
节点50 [3.3.4] 的子节点:
节点51 [3.3.5] 的子节点:
节点52 [3.3.6] 的子节点:
节点54 [3.4.1] 的子节点:
节点55 [3.4.2] 的子节点:
节点59 [4.1.1] 的子节点:
节点60 [4.1.2] 的子节点:
节点61 [4.1.3] 的子节点:
节点65 [4.4.1] 的子节点:
节点66 [4.4.2] 的子节点:
节点67 [4.4.3] 的子节点:
节点71 [5.1.1] 的子节点:
节点72 [5.1.2] 的子节点:
节点73 [5.1.3] 的子节点:
节点75 [5.2.1] 的子节点:
节点76 [5.2.2] 的子节点:
节点79 [5.4.1] 的子节点:
节点80 [5.4.2] 的子节点:
节点89 [6.6.1] 的子节点:
节点90 [6.6.2] 的子节点:
节点94 [7.1.1] 的子节点:
节点95 [7.1.2] 的子节点:
节点97 [7.2.1] 的子节点:
节点98 [7.2.2] 的子节点:
节点100 [7.3.1] 的子节点:
节点101 [7.3.2] 的子节点:
节点102 [7.3.3] 的子节点:
节点103 [7.3.4] 的子节点:
节点107 [8.1.1] 的子节点:
节点108 [8.1.2] 的子节点:
节点109 [8.1.3] 的子节点:
节点110 [8.1.4] 的子节点:
节点112 [8.2.1] 的子节点:
节点113 [8.2.2] 的子节点:
节点114 [8.2.3] 的子节点:
节点116 [8.3.1] 的子节点:
节点117 [8.3.2] 的子节点:
节点119 [8.4.1] 的子节点:
节点120 [8.4.2] 的子节点:
节点121 [8.4.3] 的子节点:
节点122 [8.4.4] 的子节点:
节点124 [8.5.1] 的子节点:
节点125 [8.5.2] 的子节点:
节点126 [8.5.3] 的子节点:
节点127 [8.5.4] 的子节点:
节点129 [8.6.1] 的子节点:
节点130 [8.6.2] 的子节点:
节点131 [8.6.3] 的子节点:
节点138 [9.1.1] 的子节点:
节点139 [9.1.2] 的子节点:
节点141 [9.2.1] 的子节点:
节点142 [9.2.2] 的子节点:
节点144 [9.3.1] 的子节点:
节点145 [9.3.2] 的子节点:
节点147 [9.4.1] 的子节点:
节点148 [9.4.2] 的子节点:
节点150 [9.5.1] 的子节点:
节点151 [9.5.2] 的子节点:
节点152 [9.5.3] 的子节点:
节点154 [9.6.1] 的子节点:
节点155 [9.6.2] 的子节点:
节点162 [10.2.1] 的子节点:
节点163 [10.2.2] 的子节点:
节点165 [10.3.1] 的子节点:
节点166 [10.3.2] 的子节点:
节点168 [10.4.1] 的子节点:
节点169 [10.4.2] 的子节点:
节点177 [11.2.1] 的子节点:
节点178 [11.2.2] 的子节点:
节点179 [11.2.3] 的子节点:
节点181 [11.3.1] 的子节点:
节点182 [11.3.2] 的子节点:
节点184 [11.4.1] 的子节点:
节点185 [11.4.2] 的子节点:
节点186 [11.4.3] 的子节点:
节点187 [11.4.4] 的子节点:
希望去除其没有子节点的输出:
// 写入txt文件函数
void WriteToFile(const char* filename, ChapterTree* tree) {
if (!tree->root) return;
FILE* file = fopen(filename, "w");
if (!file) {
perror("无法打开文件");
return;
}
TreeNode* queue[2000];
int front = 0, rear = 0;
queue[rear++] = tree->root;
while (front < rear) {
TreeNode* current = queue[front++];
// 如果当前节点有子节点, 写入当前节点信息。
if (current->children[0] != NULL) {
fprintf(file, "节点%d [%s] 的子节点: ", current->id, current->longid);
// 如果使用name会输出乱码,因为无法识别中文字体,所以使用longid(主码)作为输出对象
}
fprintf(file, "节点%d [%s] 的子节点: ", current->id, current->longid);
// 遍历所有子节点位置(包括NULL)
for (int i = 0; i < MAX_CHILDREN; i++) {
if (current->children[i]==NULL) {
break;
} else {
fprintf(file, "[%d]%d ", i, current->children[i]->id);
queue[rear++] = current->children[i];
}
}
fprintf(file, "\n");
}
fclose(file);
}
使用二叉树仿真指针实现的二叉树结构的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char DataType1;
#include"标头.h"
#include <direct.h>
// 层次遍历输出树的结构,按照孩子兄弟表示法打印每个节点的自身编码、左孩子编码和右兄弟编码
void PrintAsChildSibling(ChapterTree* tree) {
if (!tree->root) return; // 如果树为空,直接返回
int max_nodes = 2000; // 队列的最大容量
BiTreeNode** queue = (BiTreeNode**)malloc(sizeof(BiTreeNode*) * max_nodes); // 创建队列,用于层次遍历
int front = 0, rear = 0; // 队列的头尾指针
queue[rear++] = tree->root; // 将根节点入队
while (front < rear) { // 队列不为空时循环
BiTreeNode* current = queue[front++]; // 出队一个节点
// 获取当前节点的左孩子和右兄弟的编码,若不存在则为0
int leftId = current->leftChild ? current->leftChild->id : 0;
int rightId = current->rightChild ? current->rightChild->id : 0;
// 打印当前节点的自身编码、左孩子编码和右兄弟编码
printf("%d %d %d\n", current->id, leftId, rightId);
// 遍历当前节点的所有孩子节点(通过左孩子和右兄弟链表)
BiTreeNode* child = current->leftChild;
while (child) {
if (rear >= max_nodes) { // 如果队列满,提示并退出
printf("队列溢出! 最大容量:%d\n", max_nodes);
free(queue);
return;
}
queue[rear++] = child; // 将孩子节点入队
child = child->rightChild; // 移动到下一个兄弟节点
}
}
free(queue); // 释放队列内存
}
// 辅助函数:通过节点编码查找对应的节点
BiTreeNode* FindNodeById(ChapterTree* tree, int id) {
if (!tree->root) return NULL; // 如果树为空,返回空
BiTreeNode** queue = (BiTreeNode**)malloc(sizeof(BiTreeNode*) * 2000); // 创建队列
int front = 0, rear = 0;
queue[rear++] = tree->root; // 根节点入队
while (front < rear) { // 队列不为空时循环
BiTreeNode* current = queue[front++]; // 出队一个节点
if (current->id == id) { // 如果找到目标节点
free(queue); // 释放队列内存
return current; // 返回该节点
}
// 遍历当前节点的所有孩子节点并入队
BiTreeNode* child = current->leftChild;
while (child) {
if (rear < 2000) { // 队列未满时
queue[rear++] = child; // 孩子节点入队
}
child = child->rightChild; // 移动到下一个兄弟节点
}
}
free(queue); // 释放队列内存
return NULL; // 未找到,返回空
}
// 读取文件并构建树(修正版)
void LoadFile(const char* filename, ChapterTree* tree) {
// 创建虚拟根节点,作为整棵树的根
tree->root = (BiTreeNode*)malloc(sizeof(BiTreeNode));
strcpy(tree->root->longid, "0"); // 设置虚拟根节点的longid
strcpy(tree->root->name, "Root"); // 设置虚拟根节点的名称
tree->root->pageStart = 0; // 设置虚拟根节点的起始页码
tree->root->pageEnd = 0; // 设置虚拟根节点的结束页码
tree->root->id = 0; // 设置虚拟根节点的编码
tree->root->parentId = -1; // 标记为虚拟根节点,父节点编码为-1
tree->root->parent = NULL; // 父节点指针为空
tree->root->leftChild = NULL; // 左孩子指针为空
tree->root->rightChild = NULL; // 右兄弟指针为空
tree->root->level = 0; // 层级为0
FILE* file = fopen(filename, "r"); // 打开文件
if (!file) { // 如果文件打开失败
perror("无法打开文件"); // 打印错误信息
free(tree->root); // 释放虚拟根节点内存
tree->root = NULL; // 树根置空
return; // 返回
}
char line[256]; // 用于存储每一行数据
// 按行读取文件内容
while (fgets(line, sizeof(line), file)) {
line[strcspn(line, "\n")] = 0; // 去掉换行符
char* token = strtok(line, "\t"); // 以制表符分割字符串
if (!token) continue; // 如果分割失败,跳过
char longid[50]; // 存储longid
strcpy(longid, token); // 获取longid
token = strtok(NULL, "\t"); // 获取下一个字段
if (!token) continue; // 如果分割失败,跳过
char name[256]; // 存储名称
strcpy(name, token); // 获取名称
token = strtok(NULL, "\t"); // 获取下一个字段
int pageStart = token ? atoi(token) : 0; // 获取起始页码
token = strtok(NULL, "\t"); // 获取下一个字段
int pageEnd = token ? atoi(token) : 0; // 获取结束页码
token = strtok(NULL, "\t"); // 获取下一个字段
int id = token ? atoi(token) : 0; // 获取节点编码
token = strtok(NULL, "\t"); // 获取下一个字段
int parentId = token ? atoi(token) : 0; // 获取父节点编码
// 创建新节点
BiTreeNode* newNode = (BiTreeNode*)malloc(sizeof(BiTreeNode));
strncpy(newNode->name, name, 99); // 设置名称
newNode->name[99] = '\0'; // 确保字符串以null结尾
newNode->pageStart = pageStart; // 设置起始页码
newNode->pageEnd = pageEnd; // 设置结束页码
newNode->id = id; // 设置节点编码
newNode->parentId = parentId; // 设置父节点编码
strncpy(newNode->longid, longid, 49); // 设置longid
newNode->longid[49] = '\0'; // 确保字符串以null结尾
newNode->level = 0; // 层级将在插入时更新
newNode->parent = NULL; // 父节点指针初始化为空
newNode->leftChild = NULL; // 左孩子指针初始化为空
newNode->rightChild = NULL; // 右兄弟指针初始化为空
// 查找父节点(parentId=0时查找虚拟根节点)
BiTreeNode* parent = (parentId == 0) ? tree->root : FindNodeById(tree, parentId);
if (parent) { // 如果找到父节点
if (!parent->leftChild) { // 如果父节点没有左孩子
parent->leftChild = newNode; // 设置为左孩子
newNode->parent = parent; // 设置父节点指针
newNode->level = parent->level + 1; // 更新层级
} else { // 如果父节点已有左孩子
// 找到父节点的最右边的兄弟节点
BiTreeNode* sibling = parent->leftChild;
while (sibling->rightChild) {
sibling = sibling->rightChild;
}
sibling->rightChild = newNode; // 设置为最右边兄弟的右兄弟
newNode->parent = parent; // 设置父节点指针
newNode->level = parent->level + 1; // 更新层级
}
} else { // 如果未找到父节点
printf("未找到父节点 %d,节点 %d 未被插入\n", parentId, id); // 提示信息
free(newNode); // 释放新节点内存,避免内存泄漏
}
}
fclose(file); // 关闭文件
}
// 将树的结构保存到文件中
void SaveToFile(ChapterTree* tree, const char* filename) {
if (!tree->root) return; // 如果树为空,直接返回
FILE* file = fopen(filename, "w"); // 打开文件,准备写入
if (!file) { // 如果文件打开失败
perror("无法创建文件");
return;
}
int max_nodes = 2000; // 队列的最大容量
BiTreeNode** queue = (BiTreeNode**)malloc(sizeof(BiTreeNode*) * max_nodes); // 创建队列,用于层次遍历
int front = 0, rear = 0; // 队列的头尾指针
queue[rear++] = tree->root; // 将根节点入队
while (front < rear) { // 队列不为空时循环
BiTreeNode* current = queue[front++]; // 出队一个节点
// 获取当前节点的左孩子和右兄弟的编码,若不存在则为0
int leftId = current->leftChild ? current->leftChild->id : 0;
int rightId = current->rightChild ? current->rightChild->id : 0;
// 将当前节点的自身编码、左孩子编码和右兄弟编码写入文件
fprintf(file, "%d %d %d\n", current->id, leftId, rightId);
// 遍历当前节点的所有孩子节点(通过左孩子和右兄弟链表)
BiTreeNode* child = current->leftChild;
while (child) {
if (rear >= max_nodes) { // 如果队列满,提示并退出
printf("队列溢出! 最大容量:%d\n", max_nodes);
free(queue);
fclose(file);
return;
}
queue[rear++] = child; // 将孩子节点入队
child = child->rightChild; // 移动到下一个兄弟节点
}
}
free(queue); // 释放队列内存
fclose(file); // 关闭文件
}
int main() {
ChapterTree tree;
tree.root = NULL; // 初始化树,根为空
// 加载文件,构建树
LoadFile("目录.txt", &tree);
// 按孩子兄弟表示法输出树的结构
printf("节点信息(自身编码 左孩子 右兄弟):\n");
PrintAsChildSibling(&tree);
// 将树的结构保存到文件中
SaveToFile(&tree, "二叉树树结构.txt");
getchar();
return 0;
}
结果:
同时生成了新文件,成功!
输出结果为:0 1 0
1 2 1
1 0 16
16 17 16
16 0 37
37 38 37
37 0 57
57 58 57
57 0 69
69 70 77
77 0 82
82 83 82
82 0 92
92 93 92
92 0 105
105 106 105
105 0 136
136 137 136
136 0 159
159 160 159
159 0 174
174 175 174
174 0 0
0 0 0
2 3 8
8 0 9
9 10 0
17 0 18
18 0 19
19 0 20
20 21 25
25 26 32
32 0 33
33 34 0
38 39 43
43 44 46
46 47 53
53 54 0
58 59 62
62 0 63
63 0 64
64 65 0
70 71 74
74 75 77
77 79 78
78 0 0
83 0 84
84 0 85
85 0 86
86 0 87
87 0 88
88 89 0
93 94 96
96 97 99
99 100 0
106 107 111
111 112 115
115 116 118
118 119 123
123 124 128
128 129 132
132 0 133
133 0 134
134 0 0
137 138 140
140 141 143
143 144 146
146 147 149
149 150 153
153 154 156
156 0 157
157 0 0
160 0 161
161 162 164
164 165 167
167 168 170
170 0 171
171 0 172
172 0 0
175 0 176
176 177 180
180 181 183
183 184 0
3 0 4
4 0 5
5 0 6
6 0 7
7 0 0
10 0 11
11 0 12
12 0 13
13 0 14
14 0 0
21 0 22
22 0 23
23 0 24
24 0 0
26 0 27
27 0 28
28 0 29
29 0 30
30 0 31
31 0 0
34 0 35
35 0 0
39 0 40
40 0 41
41 0 42
42 0 0
44 0 45
45 0 0
47 0 48
48 0 49
49 0 50
50 0 51
51 0 52
52 0 0
54 0 55
55 0 0
59 0 60
60 0 61
61 0 0
65 0 66
66 0 67
67 0 0
71 0 72
72 0 73
73 0 0
75 0 76
76 0 0
79 0 80
80 0 0
89 0 90
90 0 0
94 0 95
95 0 0
97 0 98
98 0 0
100 0 101
101 0 102
102 0 103
103 0 0
107 0 108
108 0 109
109 0 110
110 0 0
112 0 113
113 0 114
114 0 0
116 0 117
117 0 0
119 0 120
120 0 121
121 0 122
122 0 0
124 0 125
125 0 126
126 0 127
127 0 0
129 0 130
130 0 131
131 0 0
138 0 139
139 0 0
141 0 142
142 0 0
144 0 145
145 0 0
147 0 148
148 0 0
150 0 151
151 0 152
152 0 0
154 0 155
155 0 0
162 0 163
163 0 0
165 0 166
166 0 0
168 0 169
169 0 0
177 0 178
178 0 179
179 0 0
181 0 182
182 0 0
184 0 185
185 0 186
186 0 187
187 0 0
此处为普通目录格式(复制到txt文件即可):
第1章 绪论 1 1 1 0
1.1 数据结构的基本概念 1 1 2 1
1.1.1 数据、数据元素、数据元素的数据类型 1 2 3 2
1.1.2 数据的逻辑结构 2 3 4 2
1.1.3 数据的存储结构 3 3 5 2
1.1.4 数据的操作 3 4 6 2
1.1.5 本书的结构和主要内容 4 4 7 2
1.2 抽象数据类型 4 5 8 1
1.3 算法和算法的时间复杂度 5 5 9 1
1.3.1 算法 5 6 10 9
1.3.2 算法的性质和设计目标 6 7 11 9
1.3.3 算法的时间效率分析 7 10 12 9
1.3.4 算法耗时的实际测试 10 12 13 9
1.3.5 数据元素个数和时间复杂度 12 13 14 9
习题1 13 15 15 1
第2章 线性表 15 15 16 0
2.1 线性表概述 15 15 17 16
2.1.1 线性表的定义 15 15 18 16
2.1.2 线性表的抽象数据类型 15 16 19 16
2.2 线性表的顺序表示和实现 16 16 20 16
2.2.1 顺序表的存储结构 16 17 21 20
2.2.2 顺序表操作的实现 17 19 22 20
2.2.3 顺序表操作的效率分析 19 20 23 20
2.2.4 顺序表应用举例 20 22 24 20
2.3 线性表的链式表示和实现 22 22 25 16
2.3.1 单链表的存储结构 22 25 26 25
2.3.2 单链表的操作实现 25 29 27 25
2.3.3 单链表操作的效率分析 29 30 28 25
2.3.4 单链表应用举例 30 31 29 25
2.3.5 循环单链表 31 31 30 25
2.3.6 双向循环链表 31 34 31 25
2.4 静态链表 34 35 32 16
2.5 算法设计举例 35 35 33 16
2.5.1 顺序表算法设计举例 35 36 34 33
2.5.2 单链表算法设计举例 36 37 35 33
习题2 37 41 36 16
第3章 堆栈和队列 41 41 37 0
3.1 堆栈 41 41 38 37
3.1.1 堆栈的基本概念 41 42 39 38
3.1.2 堆栈的抽象数据类型 42 42 40 38
3.1.3 堆栈的顺序表示和实现 42 44 41 38
3.1.4 堆栈的链式表示和实现 44 47 42 38
3.2 堆栈应用 47 47 43 37
3.2.1 括号匹配问题 47 49 44 43
3.2.2 算术表达式计算问题 49 53 45 43
3.3 队列 53 53 46 37
3.3.1 队列的基本概念 53 54 47 46
3.3.2 队列的抽象数据类型 54 54 48 46
3.3.3 顺序队列及其存在的问题 54 55 49 46
3.3.4 顺序循环队列的表示和实现 55 58 50 46
3.3.5 链式队列 58 60 51 46
3.3.6 队列应用举例 60 64 52 46
3.4 优先级队列 64 64 53 37
3.4.1 顺序优先级队列的设计和实现 64 66 54 53
3.4.2 优先级队列应用举例 66 67 55 53
习题3 67 71 56 37
第4章 串 71 71 57 0
4.1 串概述 71 71 58 57
4.1.1 串及其基本概念 71 72 59 58
4.1.2 串的抽象数据类型 72 72 60 58
4.1.3 C语言的串函数 72 74 61 58
4.2 串的存储结构 74 76 62 57
4.3 串基本操作的实现算法 76 80 63 57
4.4 串的模式匹配算法 80 81 64 57
4.4.1 Brute-Force算法 81 83 65 64
4.4.2 KMP算法 83 88 66 64
4.4.3 Brute-Force算法和KMP算法的比较 88 90 67 64
习题4 90 92 68 57
第5章 数组 92 92 69 0
5.1 数组概述 92 92 70 69
5.1.1 数组的定义 92 92 71 70
5.1.2 数组的实现机制 92 93 72 70
5.1.3 数组的抽象数据类型 93 93 73 70
5.2 动态数组 93 93 74 69
5.2.1 动态数组的设计方法 93 96 75 74
5.2.2 动态数组和静态数组对比 96 97 76 74
5.3 特殊矩阵的压缩存储 97 99 77 69
5.4 稀疏矩阵的压缩存储 99 99 78 69
5.4.1 稀疏矩阵的三元组顺序表 99 100 79 77
5.4.2 稀疏矩阵的三元组链表 100 101 80 77
习题5 101 104 81 77
第6章 递归算法 104 104 82 0
6.1 递归的概念 104 105 83 82
6.2 递归算法的执行过程 105 107 84 82
6.3 递归算法的设计方法 107 109 85 82
6.4 递归过程和运行时栈 109 110 86 82
6.5 递归算法的时间效率分析 110 113 87 82
6.6 算法设计举例 113 113 88 82
6.6.1 一般递归算法设计举例 113 115 89 88
6.6.2 回溯算法及设计举例 115 118 90 88
习题6 118 120 91 82
第7章 广义表 120 120 92 0
7.1 广义表概述 120 120 93 92
7.1.1 广义表的概念 120 121 94 93
7.1.2 广义表的抽象数据类型 121 121 95 93
7.2 广义表的存储结构 121 122 96 92
7.2.1 头链和尾链存储结构 122 122 97 96
7.2.2 原子和子表存储结构 122 123 98 96
7.3 广义表操作的实现 123 123 99 92
7.3.1 头链和尾链存储结构下操作的实现 123 126 100 99
7.3.2 头链和尾链存储结构应用举例 126 128 101 99
7.3.3 原子和子表存储结构下操作的实现 128 130 102 99
7.3.4 原子和子表存储结构应用举例 130 130 103 99
习题7 130 132 104 92
第8章 树和二叉树 132 132 105 0
8.1 树 132 132 106 105
8.1.1 树的定义 132 133 107 106
8.1.2 树的表示方法 133 134 108 106
8.1.3 树的抽象数据类型 134 134 109 106
8.1.4 树的存储结构 134 137 110 106
8.2 二叉树 137 137 111 105
8.2.1 二叉树的定义 137 138 112 111
8.2.2 二叉树的抽象数据类型 138 138 113 111
8.2.3 二叉树的性质 138 140 114 111
8.3 二叉树的设计和实现 140 140 115 105
8.3.1 二叉树的存储结构 140 142 116 115
8.3.2 二叉树的操作实现 142 144 117 115
8.4 二叉树遍历 144 144 118 105
8.4.1 二叉树遍历的方法和结构 144 145 119 118
8.4.2 二叉链存储结构下二叉树遍历的实现 145 146 120 118
8.4.3 二叉树遍历应用举例 146 148 121 118
8.4.4 非递归的二叉树遍历算法 148 150 122 118
8.5 线索二叉树 150 150 123 105
8.5.1 线索二叉树及其用途 150 152 124 123
8.5.2 中序线索二叉树的设计 152 153 125 123
8.5.3 中序线索二叉树循环操作的设计 153 154 126 123
8.5.4 中序线索二叉树应用举例 154 155 127 123
8.6 哈夫曼树 155 155 128 105
8.6.1 哈夫曼树的基本概念 155 156 129 128
8.6.2 哈夫曼编码问题 156 157 130 128
8.6.3 哈夫曼编码问题设计和实现 157 161 131 128
8.7 等价问题 161 164 132 105
8.8 树与二叉树的转换 164 166 133 105
8.9 树的遍历 166 166 134 105
习题8 166 170 135 105
第9章 图 170 170 136 0
9.1 图概述 170 170 137 136
9.1.1 图的基本概念 170 172 138 137
9.1.2 图的抽象数据类型 172 173 139 137
9.2 图的存储结构 173 173 140 136
9.2.1 图的邻接矩阵存储结构 173 174 141 140
9.2.2 图的邻接表存储结构 174 175 142 140
9.3 图的实现 175 175 143 136
9.3.1 邻接矩阵存储结构下图操作的实现 175 178 144 143
9.3.2 邻接表存储结构下图操作的实现 178 181 145 143
9.4 图的遍历 181 181 146 136
9.4.1 图的深度和广度优先遍历算法 181 183 147 146
9.4.2 图的深度和广度优先遍历算法实现 183 185 148 146
9.5 最小生成树 185 185 149 136
9.5.1 最小生成树的基本概念 185 186 150 149
9.5.2 普里姆算法 186 190 151 149
9.5.3 克鲁斯卡尔算法 190 191 152 149
9.6 最短路径 191 191 153 136
9.6.1 最短路径的基本概念 191 195 154 153
9.6.2 每对顶点之间的最短路径 195 197 155 153
9.7 拓扑排序 197 200 156 136
9.8 关键路径 200 203 157 136
习题9 203 206 158 136
第10章 排序 206 206 159 0
10.1 排序的基本概念 206 207 160 159
10.2 插入排序 207 208 161 159
10.2.1 直接插入排序 208 209 162 161
10.2.2 希尔排序 209 211 163 161
10.3 选择排序 211 211 164 159
10.3.1 直接选择排序 211 212 165 164
10.3.2 堆排序 212 216 166 164
10.4 交换排序 216 216 167 159
10.4.1 冒泡排序 216 217 168 167
10.4.2 快速排序 217 220 169 167
10.5 归并排序 220 222 170 159
10.6 基数排序 222 225 171 159
10.7 排序算法性能比较 225 225 172 159
习题10 225 229 173 159
第11章 查找 229 229 174 0
11.1 查找的基本概念 229 230 175 174
11.2 静态查找 230 230 176 174
11.2.1 顺序表 230 231 177 176
11.2.2 有序顺序表 231 232 178 176
11.2.3 索引顺序表 232 235 179 176
11.3 动态查找 235 235 180 174
11.3.1 二叉排序树和平衡二叉树 235 241 181 180
11.3.2 B-树和B+树 241 246 182 180
11.4 哈希查找 246 246 183 174
11.4.1 哈希表的基本概念 246 248 184 183
11.4.2 哈希函数构造方法 248 249 185 183
11.4.3 哈希冲突解决方法 249 251 186 183
11.4.4 哈希表设计 251 254 187 183
习题11 254 258 188 174
参考文献 258 258 189 NULL
优化目录:*1 绪论 1 1 1 0
1.1 数据结构的基本概念 1 1 2 1
1.1.1 数据、数据元素、数据元素的数据类型 1 2 3 2
1.1.2 数据的逻辑结构 2 3 4 2
1.1.3 数据的存储结构 3 3 5 2
1.1.4 数据的操作 3 4 6 2
1.1.5 本书的结构和主要内容 4 4 7 2
1.2 抽象数据类型 4 5 8 1
1.3 算法和算法的时间复杂度 5 5 9 1
1.3.1 算法 5 6 10 9
1.3.2 算法的性质和设计目标 6 7 11 9
1.3.3 算法的时间效率分析 7 10 12 9
1.3.4 算法耗时的实际测试 10 12 13 9
1.3.5 数据元素个数和时间复杂度 12 13 14 9
*2 线性表 15 15 16 0
2.1 线性表概述 15 15 17 16
2.1.1 线性表的定义 15 15 18 16
2.1.2 线性表的抽象数据类型 15 16 19 16
2.2 线性表的顺序表示和实现 16 16 20 16
2.2.1 顺序表的存储结构 16 17 21 20
2.2.2 顺序表操作的实现 17 19 22 20
2.2.3 顺序表操作的效率分析 19 20 23 20
2.2.4 顺序表应用举例 20 22 24 20
2.3 线性表的链式表示和实现 22 22 25 16
2.3.1 单链表的存储结构 22 25 26 25
2.3.2 单链表的操作实现 25 29 27 25
2.3.3 单链表操作的效率分析 29 30 28 25
2.3.4 单链表应用举例 30 31 29 25
2.3.5 循环单链表 31 31 30 25
2.3.6 双向循环链表 31 34 31 25
2.4 静态链表 34 35 32 16
2.5 算法设计举例 35 35 33 16
2.5.1 顺序表算法设计举例 35 36 34 33
2.5.2 单链表算法设计举例 36 37 35 33
*3 堆栈和队列 41 41 37 0
3.1 堆栈 41 41 38 37
3.1.1 堆栈的基本概念 41 42 39 38
3.1.2 堆栈的抽象数据类型 42 42 40 38
3.1.3 堆栈的顺序表示和实现 42 44 41 38
3.1.4 堆栈的链式表示和实现 44 47 42 38
3.2 堆栈应用 47 47 43 37
3.2.1 括号匹配问题 47 49 44 43
3.2.2 算术表达式计算问题 49 53 45 43
3.3 队列 53 53 46 37
3.3.1 队列的基本概念 53 54 47 46
3.3.2 队列的抽象数据类型 54 54 48 46
3.3.3 顺序队列及其存在的问题 54 55 49 46
3.3.4 顺序循环队列的表示和实现 55 58 50 46
3.3.5 链式队列 58 60 51 46
3.3.6 队列应用举例 60 64 52 46
3.4 优先级队列 64 64 53 37
3.4.1 顺序优先级队列的设计和实现 64 66 54 53
3.4.2 优先级队列应用举例 66 67 55 53
*4 串 71 71 57 0
4.1 串概述 71 71 58 57
4.1.1 串及其基本概念 71 72 59 58
4.1.2 串的抽象数据类型 72 72 60 58
4.1.3 C语言的串函数 72 74 61 58
4.2 串的存储结构 74 76 62 57
4.3 串基本操作的实现算法 76 80 63 57
4.4 串的模式匹配算法 80 81 64 57
4.4.1 Brute-Force算法 81 83 65 64
4.4.2 KMP算法 83 88 66 64
4.4.3 Brute-Force算法和KMP算法的比较 88 90 67 64
*5 数组 92 92 69 0
5.1 数组概述 92 92 70 69
5.1.1 数组的定义 92 92 71 70
5.1.2 数组的实现机制 92 93 72 70
5.1.3 数组的抽象数据类型 93 93 73 70
5.2 动态数组 93 93 74 69
5.2.1 动态数组的设计方法 93 96 75 74
5.2.2 动态数组和静态数组对比 96 97 76 74
5.3 特殊矩阵的压缩存储 97 99 77 69
5.4 稀疏矩阵的压缩存储 99 99 78 69
5.4.1 稀疏矩阵的三元组顺序表 99 100 79 77
5.4.2 稀疏矩阵的三元组链表 100 101 80 77
*6 递归算法 104 104 82 0
6.1 递归的概念 104 105 83 82
6.2 递归算法的执行过程 105 107 84 82
6.3 递归算法的设计方法 107 109 85 82
6.4 递归过程和运行时栈 109 110 86 82
6.5 递归算法的时间效率分析 110 113 87 82
6.6 算法设计举例 113 113 88 82
6.6.1 一般递归算法设计举例 113 115 89 88
6.6.2 回溯算法及设计举例 115 118 90 88
*7 广义表 120 120 92 0
7.1 广义表概述 120 120 93 92
7.1.1 广义表的概念 120 121 94 93
7.1.2 广义表的抽象数据类型 121 121 95 93
7.2 广义表的存储结构 121 122 96 92
7.2.1 头链和尾链存储结构 122 122 97 96
7.2.2 原子和子表存储结构 122 123 98 96
7.3 广义表操作的实现 123 123 99 92
7.3.1 头链和尾链存储结构下操作的实现 123 126 100 99
7.3.2 头链和尾链存储结构应用举例 126 128 101 99
7.3.3 原子和子表存储结构下操作的实现 128 130 102 99
7.3.4 原子和子表存储结构应用举例 130 130 103 99
*8 树和二叉树 132 132 105 0
8.1 树 132 132 106 105
8.1.1 树的定义 132 133 107 106
8.1.2 树的表示方法 133 134 108 106
8.1.3 树的抽象数据类型 134 134 109 106
8.1.4 树的存储结构 134 137 110 106
8.2 二叉树 137 137 111 105
8.2.1 二叉树的定义 137 138 112 111
8.2.2 二叉树的抽象数据类型 138 138 113 111
8.2.3 二叉树的性质 138 140 114 111
8.3 二叉树的设计和实现 140 140 115 105
8.3.1 二叉树的存储结构 140 142 116 115
8.3.2 二叉树的操作实现 142 144 117 115
8.4 二叉树遍历 144 144 118 105
8.4.1 二叉树遍历的方法和结构 144 145 119 118
8.4.2 二叉链存储结构下二叉树遍历的实现 145 146 120 118
8.4.3 二叉树遍历应用举例 146 148 121 118
8.4.4 非递归的二叉树遍历算法 148 150 122 118
8.5 线索二叉树 150 150 123 105
8.5.1 线索二叉树及其用途 150 152 124 123
8.5.2 中序线索二叉树的设计 152 153 125 123
8.5.3 中序线索二叉树循环操作的设计 153 154 126 123
8.5.4 中序线索二叉树应用举例 154 155 127 123
8.6 哈夫曼树 155 155 128 105
8.6.1 哈夫曼树的基本概念 155 156 129 128
8.6.2 哈夫曼编码问题 156 157 130 128
8.6.3 哈夫曼编码问题设计和实现 157 161 131 128
8.7 等价问题 161 164 132 105
8.8 树与二叉树的转换 164 166 133 105
8.9 树的遍历 166 166 134 105
*9 图 170 170 136 0
9.1 图概述 170 170 137 136
9.1.1 图的基本概念 170 172 138 137
9.1.2 图的抽象数据类型 172 173 139 137
9.2 图的存储结构 173 173 140 136
9.2.1 图的邻接矩阵存储结构 173 174 141 140
9.2.2 图的邻接表存储结构 174 175 142 140
9.3 图的实现 175 175 143 136
9.3.1 邻接矩阵存储结构下图操作的实现 175 178 144 143
9.3.2 邻接表存储结构下图操作的实现 178 181 145 143
9.4 图的遍历 181 181 146 136
9.4.1 图的深度和广度优先遍历算法 181 183 147 146
9.4.2 图的深度和广度优先遍历算法实现 183 185 148 146
9.5 最小生成树 185 185 149 136
9.5.1 最小生成树的基本概念 185 186 150 149
9.5.2 普里姆算法 186 190 151 149
9.5.3 克鲁斯卡尔算法 190 191 152 149
9.6 最短路径 191 191 153 136
9.6.1 最短路径的基本概念 191 195 154 153
9.6.2 每对顶点之间的最短路径 195 197 155 153
9.7 拓扑排序 197 200 156 136
9.8 关键路径 200 203 157 136
*10 排序 206 206 159 0
10.1 排序的基本概念 206 207 160 159
10.2 插入排序 207 208 161 159
10.2.1 直接插入排序 208 209 162 161
10.2.2 希尔排序 209 211 163 161
10.3 选择排序 211 211 164 159
10.3.1 直接选择排序 211 212 165 164
10.3.2 堆排序 212 216 166 164
10.4 交换排序 216 216 167 159
10.4.1 冒泡排序 216 217 168 167
10.4.2 快速排序 217 220 169 167
10.5 归并排序 220 222 170 159
10.6 基数排序 222 225 171 159
10.7 排序算法性能比较 225 225 172 159
*11 查找 229 229 174 0
11.1 查找的基本概念 229 230 175 174
11.2 静态查找 230 230 176 174
11.2.1 顺序表 230 231 177 176
11.2.2 有序顺序表 231 232 178 176
11.2.3 索引顺序表 232 235 179 176
11.3 动态查找 235 235 180 174
11.3.1 二叉排序树和平衡二叉树 235 241 181 180
11.3.2 B-树和B+树 241 246 182 180
11.4 哈希查找 246 246 183 174
11.4.1 哈希表的基本概念 246 248 184 183
11.4.2 哈希函数构造方法 248 249 185 183
11.4.3 哈希冲突解决方法 249 251 186 183
11.4.4 哈希表设计 251 254 187 183
bibiliography 参考文献 258 258 189 0