@ -0,0 +1,20 @@ | |||
cmake_minimum_required(VERSION 3.9) | |||
project(chapter5) | |||
# set(CMAKE_CXX_STANDARD 11) | |||
# include_directories( | |||
# include | |||
# ) | |||
add_executable(bitree | |||
main.cpp) | |||
SET(EXECUTABLE_OUTPUT_PATH R:/) | |||
if (CMAKE_BUILD_TYPE STREQUAL Release) | |||
# # 也可以set(CMAKE_CXX_FLAGS_RELEASE ...) | |||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fexec-charset=GBK") | |||
endif() | |||
target_link_libraries(bitree) |
@ -0,0 +1,177 @@ | |||
// | |||
// Created by 423A35C7 on 2023-11-12. | |||
// | |||
// #include <functional> | |||
// #include <list> | |||
#include <cassert> | |||
#include <queue> | |||
#include <string> | |||
struct Node { | |||
int num = 0; | |||
std::string text; | |||
// 线索化的标记 | |||
bool if_left_chain = false; | |||
bool if_right_chain = false; | |||
// 左右子树或前驱后继 | |||
Node* left = nullptr; | |||
Node* right = nullptr; | |||
Node(int num, const std::string& text) | |||
: num(num), | |||
text(text) { | |||
} | |||
~Node() { | |||
remove_left(); | |||
remove_right(); | |||
} | |||
void remove_left() { | |||
if (left != nullptr && !if_left_chain) { | |||
// delete the node | |||
left->~Node(); | |||
// delete the memory | |||
delete left; | |||
// set the pointer to nullptr | |||
left = nullptr; | |||
} | |||
} | |||
void remove_right() { | |||
if (right != nullptr && !if_right_chain) { | |||
// delete the node | |||
right->~Node(); | |||
// delete the memory | |||
delete right; | |||
// set the pointer to nullptr | |||
right = nullptr; | |||
} | |||
} | |||
}; | |||
class BiTree { | |||
Node *find(int num) { | |||
Node *temp; | |||
// 遍历查找num | |||
for (temp = head; temp && temp->num < num; temp = temp->right); | |||
return temp; | |||
} | |||
void insert_left(Node *parent, const std::string& text) { | |||
// 断言parent不为空 | |||
assert(parent != nullptr); | |||
// parent->remove_left(); | |||
// 如果parent->left为空,则插入新节点 | |||
if (parent->left == nullptr) | |||
parent->left = new Node {0, text}; | |||
else | |||
insert_right(parent->left, text); | |||
} | |||
void insert_right(Node *parent, const std::string& text) { | |||
// 断言parent不为空 | |||
assert(parent != nullptr); | |||
// 记录tail | |||
Node *tail = parent; | |||
// 遍历查找tail->right | |||
for (; !tail->if_right_chain && tail->right; tail = tail->right); | |||
// 插入新节点 | |||
tail->right = new Node {0, text}; | |||
tail->if_right_chain = false; | |||
} | |||
public: | |||
Node *head; | |||
int length = 0; | |||
BiTree() { | |||
// 初始化头节点 | |||
this->head = new Node(0, ""); | |||
// 初始化节点数量 | |||
this->length = 1; | |||
} | |||
~BiTree() { | |||
// 删除头节点的左右子节点 | |||
this->head->remove_left(); | |||
this->head->remove_right(); | |||
// 删除头节点 | |||
delete this->head; | |||
} | |||
void update() { | |||
// 左节点入队,出队时扩展到所有的右节点 | |||
std::queue<Node*> q; | |||
Node *current = head, *next = head->left; | |||
int current_num = 0; | |||
// while (!q.empty()) { | |||
// current->if_right_chain = true; | |||
// current->right = q.front(); | |||
// current = q.front(); | |||
// q.pop(); | |||
// Node *next = current; | |||
// for (; next && !next->if_right_chain; current = next, next = next->right) { | |||
// next->num = current_num++; | |||
// if (next->left) { | |||
// q.push(next->left); | |||
// } | |||
// } | |||
// 当前节点为空,则跳出循环 | |||
while (current) { | |||
// 当前节点的编号 | |||
current->num = current_num++; | |||
// 如果当前节点有左子节点,则将左子节点放入队列 | |||
if (current->left) { | |||
q.push(current->left); | |||
} | |||
// 发生间断,从队列中重新取值 | |||
if (!current->right || current->if_right_chain) { | |||
// 如果当前节点没有右子节点,或者当前节点已经处理完右子节点,则跳出循环 | |||
if (q.empty()) break; | |||
// 从队列中取出下一个节点 | |||
next = q.front(); | |||
// 从队列中删除该节点 | |||
q.pop(); | |||
// 标记当前节点是线索化右子节点 | |||
current->if_right_chain = true; | |||
} else { | |||
// 标记当前节点不是线索化右子节点 | |||
current->if_right_chain = false; | |||
} | |||
// 将当前节点的右子节点设置为下一个节点 | |||
current->right = next; | |||
// 将当前节点设置为下一个节点 | |||
current = next; | |||
// 将下一个节点设置为下一个节点的右子节点 | |||
next = next->right; | |||
} | |||
// 更新树的层数 | |||
this->length = current_num; | |||
} | |||
void insert(int num, std::queue<std::string> &children) { | |||
// 找到要插入的父节点 | |||
Node *parent = this->find(num); | |||
// 断言父节点不为空 | |||
assert(parent != nullptr); | |||
// 如果子节点为空,则直接返回 | |||
if (children.empty()) return; | |||
// 插入左子节点 | |||
this->insert_left(parent, children.front()); | |||
// 从队列中弹出第一个子节点 | |||
children.pop(); | |||
// 将父节点指向左子节点 | |||
parent = parent->left; | |||
// 如果队列不为空,则插入右子节点 | |||
while (!children.empty()) { | |||
this->insert_right(parent, children.front()); | |||
// 从队列中弹出第一个子节点 | |||
children.pop(); | |||
// 将父节点指向右子节点 | |||
parent = parent->right; | |||
} | |||
// 更新树的序号 | |||
this->update(); | |||
} | |||
}; | |||
@ -0,0 +1,94 @@ | |||
// | |||
// Created by 423A35C7 on 2023-11-12. | |||
// | |||
// 14:55 | |||
// 16:57 | |||
#include "view.cpp" | |||
int main() { | |||
// 创建二叉树 | |||
BiTree bi_tree; | |||
// 父节点编号 | |||
int parent = 0; | |||
// 子节点队列 | |||
std::queue<std::string> children; | |||
// 文本 | |||
std::string text; | |||
// 文本长度 | |||
text.reserve(100); | |||
// 临时变量 | |||
int temp; | |||
// 错误信息 | |||
std::string error_message; | |||
// 重新输入 | |||
next_input: | |||
// 清屏 | |||
clear_screen(); | |||
// 输出二叉树 | |||
output(bi_tree.head, 1, 1); | |||
// 移动光标到指定位置 | |||
moveto(100, 1); | |||
// 输出提示信息 | |||
std::cout << error_message << std::endl << "输入整数编号和字符串文本,空格分隔,输入单个非数字字符表示结束:" << std::endl;; | |||
// 循环输入 | |||
while (std::cin >> parent) { | |||
// 如果编号不存在 | |||
if (parent >= bi_tree.length) { | |||
// 设置错误信息 | |||
error_message = "输入的编号不存在,请重新输入:"; | |||
// 忽略输入 | |||
std::cin.ignore(1024, '\n'); | |||
// 重新输入 | |||
goto next_input; | |||
} | |||
// 循环输入 | |||
while ((temp = std::cin.get()) > 0) { | |||
// 根据输入的值进行判断 | |||
switch (temp) { | |||
// 换行符 | |||
case '\n': | |||
// 如果文本不为空 | |||
if (!text.empty()) { | |||
// 将文本添加到子节点队列中 | |||
children.push(text); | |||
// 清空文本 | |||
text.clear(); | |||
} | |||
// 将父节点编号和子节点队列插入二叉树 | |||
bi_tree.insert(parent, children); | |||
// 重新输入 | |||
goto next_input; | |||
// 空格 | |||
case ' ': | |||
// 如果文本不为空 | |||
if (!text.empty()) { | |||
// 将文本添加到子节点队列中 | |||
children.push(text); | |||
// 清空文本 | |||
text.clear(); | |||
} | |||
break; | |||
// 其他字符 | |||
default: | |||
// 将字符添加到文本中 | |||
text.push_back(temp); | |||
break; | |||
} | |||
} | |||
} | |||
// 添加节点 | |||
// children.emplace("张三"); | |||
// children.emplace("李四"); | |||
// children.emplace("王五"); | |||
// bi_tree.insert(parent, children); | |||
// parent = 2; | |||
// children.emplace("师大"); | |||
// children.emplace("统计"); | |||
// children.emplace("计算机"); | |||
// bi_tree.insert(parent, children); | |||
// parent = 0; | |||
// children.emplace("赵六"); | |||
// bi_tree.insert(parent, children); | |||
return 0; | |||
} |
@ -0,0 +1,97 @@ | |||
// | |||
// Created by 423A35C7 on 2023-11-12. | |||
// | |||
// 11:47 | |||
// 14:55 | |||
#include <algorithm> | |||
#include <iostream> | |||
#include <string> | |||
#include "bitree.cpp" | |||
#define move_and_output(x, y, str) printf("\033[s\033[%d;%dH%s\033u", x, y, str) | |||
// 移动并输出到指定位置 | |||
#define moveto(x, y) printf("\033[s\033[%d;%dH", x, y) | |||
// 移动到指定位置 | |||
#define movedown(x) printf("\033[%dB", (x)) | |||
// 向下移动指定行 | |||
#define save_cursor() printf("\033[s") | |||
// 保存光标位置 | |||
#define restore_cursor() printf("\033[u") | |||
// 恢复光标位置 | |||
#define clear_char(num) \ | |||
for (int i = 0; i < num; i++) \ | |||
printf(" ") | |||
// 清空指定位置的字符 | |||
#define clear_screen() printf("\033[2J") | |||
// class ViewBox { | |||
// Node *left_node; | |||
// int x, y; | |||
// int width; | |||
// int height; | |||
// struct Size { | |||
// int width; | |||
// int height; | |||
// }; | |||
// Size calculate_size(Node *left_node) { | |||
// Size size {left_node->text.length(), 1}; | |||
// if (left_node->left) { | |||
// Size increment; | |||
// increment = calculate_size(left_node->left); | |||
// | |||
// } | |||
// } | |||
// }; | |||
enum LINE {NONE, HORIZONTAL, VERTICAL}; | |||
int get_length(Node *node) { | |||
// 2是_和空格的长度 | |||
return std::to_string(node->num).length() + 2 + node->text.length(); | |||
} | |||
void print(Node *node, int x, int y, LINE line_type) { | |||
// 移动到指定位置 | |||
moveto(2 * x, y); | |||
// 保存当前光标位置 | |||
save_cursor(); | |||
// 如果line_type为VERTICAL,则输出“|” | |||
if (line_type == VERTICAL) { | |||
std::cout << "|"; | |||
} | |||
// 恢复光标位置 | |||
restore_cursor(); | |||
// 向下移动1个单位 | |||
movedown(1); | |||
// 如果line_type为HORIZONTAL,则输出“——” | |||
if (line_type == HORIZONTAL) { | |||
std::cout << "——"; | |||
} | |||
// 输出node的num和text | |||
std::cout << node->num << "_" << node->text << " "; | |||
} | |||
int output(Node *left_node, int x, int y) { | |||
int width = 0; | |||
if (left_node == nullptr) return width; | |||
// 打印左节点 | |||
print(left_node, x, y, VERTICAL); | |||
// 计算宽度 | |||
width += std::max(get_length(left_node), output(left_node->left, x + 1, y + width)); | |||
// 遍历右节点 | |||
for (Node *temp = left_node; temp->right && !temp->if_right_chain; temp = temp->right) { | |||
// 打印右节点 | |||
print(temp->right, x, y + width, HORIZONTAL); | |||
// 计算宽度 | |||
// 2是——的长度 | |||
width += std::max(2 + get_length(temp->right), output(temp->right->left, x + 1, y + width)); | |||
// width += temp->right->text.length(); | |||
} | |||
return width; | |||
// if (left_node->left == nullptr) { | |||
// return width; | |||
// } | |||
// depth += 1; | |||
// return std::max(width, output(left_node->left, depth)); | |||
} |