SharedSchoolSpace/作业/数据结构-金健/C++/第五章作业/bitree.cpp

178 lines
5.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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();
}
};