遵循Unix 哲学,让你的程序输出图形的描述(以文本格式,或者如果没有容易获得的纯文本格式,则以易于处理的形式输出)。
(请注意,这也适用于图像格式;NetPBM(.pnm、或 .pbm、.pgm 和 .ppm)格式很容易在纯 C 中生成(例如标准输出),如有必要,NetPBM 工具可以用于转换为您可能希望的任何其他图像格式。)
例如,如果您的程序输出
graph {
rankdir=LR;
"6" -- "4";
"4" -- "5";
"3" -- "4";
"3" -- "2";
"5" -- "2";
"5" -- "1";
"2" -- "1";
}
Run Code Online (Sandbox Code Playgroud)
然后将输出重定向到 egoutput.dot并运行dot -Tx11 output.dot将输出类似于Wikipedia Graph文章中显示的图形,
此处指定了DOT 语言,但它确实非常简单。--表示无向边和->有向边。该rankdir=LR;行是一个图形的属性,并告诉DOT,它应该尝试订购看到由左到右的节点。默认是从上到下。您也可以添加节点属性,例如"6" [ label="Six" ];将节点的标签更改"6"为Six。边缘属性的工作方式完全相同;因此使用"2" -- "1" [ taillabel="Z" ];在节点“2”和“1”之间的边缘的节点“2”端附近添加“Z”。最好引用节点名称,即使如果节点名称以字母开头且与图形属性名称不匹配,则不需要引号。
在打印树或链表时,这是一个有用的提示:
使用%p(指向节点的指针)作为节点名称,并将节点label="value"的可见标签设置为value。例如,如果你有
struct node {
struct node *left;
struct node *right;
int value;
};
Run Code Online (Sandbox Code Playgroud)
然后是一个简单的函数对,
void print_tree_recursive(FILE *out, struct node *curr)
{
fprintf(out, " \"%p\" [ label=\"%d\" ];\n", (void *)curr, curr->value);
if (curr->left) {
print_tree_recursive(out, curr->left);
fprintf(out, " \"%p\" -> \"%p\" [ taillabel="L" ];\n", curr, curr->left);
}
if (curr->right) {
print_tree_recursive(out, curr->right);
fprintf(out, " \"%p\" -> \"%p\" [ taillabel="R" ];\n", curr, curr->right);
}
}
void print_tree(FILE *out, struct node *tree)
{
fprintf(out, "digraph {\n");
if (tree)
print_tree_recursive(out, tree);
fprintf(out, "}\n");
fflush(out);
}
Run Code Online (Sandbox Code Playgroud)
将打印任何树的一个很好的有向图。修改打印链表很容易(单链表和双链表)。请注意辅助函数如何首先描述节点(带有 的 fprintf label=),然后分别描述边(带有 的 fprintfs taillabel=)。
如果您将图形打印到标准输出,您可以将输出重定向到一个文件并使用 显示或转换它dot -Tformat filename,或者您可以通过管道将输出直接| dot -Tx11用于查看生成的图形。
我经常使用 Graphviz DOT 格式来检查我对数据结构链接的心理图景是否与现实相符。我发现它是一个非常有用的工具,并不断向任何处理复杂数据结构的人推荐它。