- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在尝试在c++中打印如下的二叉树时有点“迷”:
8
/ \
/ \
/ \
5 10
/ \ / \
2 6 9 11
Get height
int tree::getHeight(No *node) {
if (node == NULL) return 0;
return 1 + max(getHeight(node->esq), getHeight(node->dir));
}
Get number of nodes per line
void tree::getLine(const No *root, int depth, vector<int>& vals){
int placeholder = 10;
if (depth <= 0 && root != nullptr) {
vals.push_back(root->chave);
return;
}
if (root->esq != nullptr)
getLine(root->esq, depth-1, vals);
else if (depth-1 <= 0)
vals.push_back(placeholder);
if (root->dir != nullptr)
getLine(root->dir, depth-1, vals);
else if (depth-1 <= 0)
vals.push_back(placeholder);
}
最佳答案
这是创建二进制树的基于文本的表示形式的代码示例。本演示使用了最小有用的二叉树类(BinTree),并且具有很小的占用空间,只是为了避免膨胀示例的大小。
它的文本呈现成员函数更严重,使用迭代而不是递归,如该类其他部分所述。
这分三步完成,首先将一个由字符串值组成的行 vector 放在一起。
然后,这用于格式化代表树的文本字符串行。
然后,将字符串清理干净并转交给cout。
此外,该演示还包括“随机树”功能,可连续播放数小时。
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <random>
using std::vector;
using std::string;
using std::cout;
template <typename T>
class BinTree {
struct Node {
T value;
Node *left,*right;
Node() : left(nullptr),right(nullptr) {}
Node(const T& value) :value(value),left(nullptr),right(nullptr) {}
// stack-abusing recursion everywhere, for small code
~Node() { delete left; delete right; }
int max_depth() const {
const int left_depth = left ? left->max_depth() : 0;
const int right_depth = right ? right->max_depth() : 0;
return (left_depth > right_depth ? left_depth : right_depth) + 1;
}
};
Node *root;
public:
BinTree() : root(nullptr) {}
~BinTree() { delete root; }
int get_max_depth() const { return root ? root->max_depth() : 0; }
void clear() { delete root; root = nullptr; }
void insert() {}
template <typename ...Args>
void insert(const T& value, Args...more) {
if(!root) {
root = new Node(value);
} else {
Node* p = root;
for(;;) {
if(value == p->value) return;
Node* &pchild = value < p->value ? p->left : p->right;
if(!pchild) {
pchild = new Node(value);
break;
}
p = pchild;
}
}
insert(more...);
}
struct cell_display {
string valstr;
bool present;
cell_display() : present(false) {}
cell_display(std::string valstr) : valstr(valstr), present(true) {}
};
using display_rows = vector< vector< cell_display > >;
// The text tree generation code below is all iterative, to avoid stack faults.
// get_row_display builds a vector of vectors of cell_display structs
// each vector of cell_display structs represents one row, starting at the root
display_rows get_row_display() const {
// start off by traversing the tree to
// build a vector of vectors of Node pointers
vector<Node*> traversal_stack;
vector< std::vector<Node*> > rows;
if(!root) return display_rows();
Node *p = root;
const int max_depth = root->max_depth();
rows.resize(max_depth);
int depth = 0;
for(;;) {
// Max-depth Nodes are always a leaf or null
// This special case blocks deeper traversal
if(depth == max_depth-1) {
rows[depth].push_back(p);
if(depth == 0) break;
--depth;
continue;
}
// First visit to node? Go to left child.
if(traversal_stack.size() == depth) {
rows[depth].push_back(p);
traversal_stack.push_back(p);
if(p) p = p->left;
++depth;
continue;
}
// Odd child count? Go to right child.
if(rows[depth+1].size() % 2) {
p = traversal_stack.back();
if(p) p = p->right;
++depth;
continue;
}
// Time to leave if we get here
// Exit loop if this is the root
if(depth == 0) break;
traversal_stack.pop_back();
p = traversal_stack.back();
--depth;
}
// Use rows of Node pointers to populate rows of cell_display structs.
// All possible slots in the tree get a cell_display struct,
// so if there is no actual Node at a struct's location,
// its boolean "present" field is set to false.
// The struct also contains a string representation of
// its Node's value, created using a std::stringstream object.
display_rows rows_disp;
std::stringstream ss;
for(const auto& row : rows) {
rows_disp.emplace_back();
for(Node* pn : row) {
if(pn) {
ss << pn->value;
rows_disp.back().push_back(cell_display(ss.str()));
ss = std::stringstream();
} else {
rows_disp.back().push_back(cell_display());
} } }
return rows_disp;
}
// row_formatter takes the vector of rows of cell_display structs
// generated by get_row_display and formats it into a test representation
// as a vector of strings
vector<string> row_formatter(const display_rows& rows_disp) const {
using s_t = string::size_type;
// First find the maximum value string length and put it in cell_width
s_t cell_width = 0;
for(const auto& row_disp : rows_disp) {
for(const auto& cd : row_disp) {
if(cd.present && cd.valstr.length() > cell_width) {
cell_width = cd.valstr.length();
} } }
// make sure the cell_width is an odd number
if(cell_width % 2 == 0) ++cell_width;
// formatted_rows will hold the results
vector<string> formatted_rows;
// some of these counting variables are related,
// so its should be possible to eliminate some of them.
s_t row_count = rows_disp.size();
// this row's element count, a power of two
s_t row_elem_count = 1 << (row_count-1);
// left_pad holds the number of space charactes at the beginning of the bottom row
s_t left_pad = 0;
// Work from the level of maximum depth, up to the root
// ("formatted_rows" will need to be reversed when done)
for(s_t r=0; r<row_count; ++r) {
const auto& cd_row = rows_disp[row_count-r-1]; // r reverse-indexes the row
// "space" will be the number of rows of slashes needed to get
// from this row to the next. It is also used to determine other
// text offsets.
s_t space = (s_t(1) << r) * (cell_width + 1) / 2 - 1;
// "row" holds the line of text currently being assembled
string row;
// iterate over each element in this row
for(s_t c=0; c<row_elem_count; ++c) {
// add padding, more when this is not the leftmost element
row += string(c ? left_pad*2+1 : left_pad, ' ');
if(cd_row[c].present) {
// This position corresponds to an existing Node
const string& valstr = cd_row[c].valstr;
// Try to pad the left and right sides of the value string
// with the same number of spaces. If padding requires an
// odd number of spaces, right-sided children get the longer
// padding on the right side, while left-sided children
// get it on the left side.
s_t long_padding = cell_width - valstr.length();
s_t short_padding = long_padding / 2;
long_padding -= short_padding;
row += string(c%2 ? short_padding : long_padding, ' ');
row += valstr;
row += string(c%2 ? long_padding : short_padding, ' ');
} else {
// This position is empty, Nodeless...
row += string(cell_width, ' ');
}
}
// A row of spaced-apart value strings is ready, add it to the result vector
formatted_rows.push_back(row);
// The root has been added, so this loop is finsished
if(row_elem_count == 1) break;
// Add rows of forward- and back- slash characters, spaced apart
// to "connect" two rows' Node value strings.
// The "space" variable counts the number of rows needed here.
s_t left_space = space + 1;
s_t right_space = space - 1;
for(s_t sr=0; sr<space; ++sr) {
string row;
for(s_t c=0; c<row_elem_count; ++c) {
if(c % 2 == 0) {
row += string(c ? left_space*2 + 1 : left_space, ' ');
row += cd_row[c].present ? '/' : ' ';
row += string(right_space + 1, ' ');
} else {
row += string(right_space, ' ');
row += cd_row[c].present ? '\\' : ' ';
}
}
formatted_rows.push_back(row);
++left_space;
--right_space;
}
left_pad += space + 1;
row_elem_count /= 2;
}
// Reverse the result, placing the root node at the beginning (top)
std::reverse(formatted_rows.begin(), formatted_rows.end());
return formatted_rows;
}
// Trims an equal number of space characters from
// the beginning of each string in the vector.
// At least one string in the vector will end up beginning
// with no space characters.
static void trim_rows_left(vector<string>& rows) {
if(!rows.size()) return;
auto min_space = rows.front().length();
for(const auto& row : rows) {
auto i = row.find_first_not_of(' ');
if(i==string::npos) i = row.length();
if(i == 0) return;
if(i < min_space) min_space = i;
}
for(auto& row : rows) {
row.erase(0, min_space);
} }
// Dumps a representation of the tree to cout
void Dump() const {
const int d = get_max_depth();
// If this tree is empty, tell someone
if(d == 0) {
cout << " <empty tree>\n";
return;
}
// This tree is not empty, so get a list of node values...
const auto rows_disp = get_row_display();
// then format these into a text representation...
auto formatted_rows = row_formatter(rows_disp);
// then trim excess space characters from the left sides of the text...
trim_rows_left(formatted_rows);
// then dump the text to cout.
for(const auto& row : formatted_rows) {
std::cout << ' ' << row << '\n';
}
}
};
int main() {
BinTree<int> bt;
// Build OP's tree
bt.insert(8,5,2,6,10,9,11);
cout << "Tree from OP:\n\n";
bt.Dump();
cout << "\n\n";
bt.clear();
// Build a random tree
// This toy tree can't balance, so random
// trees often look more like linked lists.
// Just keep trying until a nice one shows up.
std::random_device rd;
std::mt19937 rng(rd());
int MaxCount=20;
int MaxDepth=5;
const int Min=0, Max=1000;
std::uniform_int_distribution<int> dist(Min,Max);
while(MaxCount--) {
bt.insert(dist(rng));
if(bt.get_max_depth() >= MaxDepth) break;
}
cout << "Randomly generated tree:\n\n";
bt.Dump();
}
Tree from OP:
8
/ \
/ \
/ \
5 10
/ \ / \
2 6 9 11
Randomly generated tree:
703
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
137 965
/ \ /
/ \ /
/ \ /
/ \ /
/ \ /
/ \ /
/ \ /
41 387 786
\ / \ / \
\ / \ / \
\ / \ / \
95 382 630 726 813
\
841
关于c++ - 使用C++以漂亮的方式打印二叉树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64310533/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!