数据结构与算法14: 利用Graphviz快速可视化树(visualizing Trees with Graphviz easily )
来源:互联网 发布:淘宝水果许可证怎么办 编辑:程序博客网 时间:2024/05/16 06:44
可视化树的算法有很多,这里我们借助Graphviz实现二叉搜索树BST(二叉树)和B-Tree(多叉树)的快速可视化。关于一般的算法,可以到知网或者万方数据中去查阅,不在此处详谈。
基本的思想就是利用Gphviz可视化树的基本思想,将树转换为dot文件,然后利用Graphviz将其转换为图片。这种方法的特点就是,简单,快速,高效。这种方法可以用于辅助理解程序运行过程、调试程序。
请在使用前确认,你的系统已经正确安装了Graphviz,并配置了dot命令。
下面的程序依赖于命令:
dot example.dot -Tpng -o 1.png
完整的代码地址,可以在github BST和github BTree得到。
下面给出一些例子,文章末尾也摘取了c++实现的自动转换代码。
1. 例子
遍历可视化
将转换的图片,链接成gif图片,即可得到运行时动态效果:
先序遍历:
广度优先遍历:
AVL可视化
DSW算法可视化
省略中间过程,创建主链为:
中间过程省略,则最终生成的平衡BST为:
Splay Tree例子此处省略。
B-Tree可视化
注意下面的代码,给出了转换部分的实现;转换部分依赖于你的节点的定义,你可以根据需要调整。在你程序中合适地方插入toPng函数来生成图片。
2. 二叉树可视化实现
定义文件:
/** * 二叉树搜索树结点类BSTNode * 暂时处理整型数据 */class BSTNode {public: BSTNode(const int& e,BSTNode*p ,BSTNode *l=0,BSTNode *r=0):key(e),height(1) ,parent(p), left(l),right(r){ } std::string toString() const{ // 用于调试 std::ostringstream oss; oss << key; return oss.str(); }private: int key; int height; // 以这个结点为根的树的高度 BSTNode *parent,*left,*right; friend class BiTreePrinter; // 将BST转换为图片的类};/** * BST边类 */struct BSTEdge { BSTEdge(const std::string &f,const std::string &t,bool vis=true): from(f), to(t), isVisiable(vis) { } std::string toString() { if(isVisiable) return from+"->"+to; else return from+"->"+to+"[weight=100 style=invis]"; } std::string from; std::string to; bool isVisiable;};/** * 利用绘制二叉树 * 1)将树形写入.dot文件 * 2)利用Graphviz程序转换.dot文件为png图片 * dot转换为图片阶段 系统必须安装有graphviz并配置有dot命令 否则失效 * 利用系统命令例如: system ("dot example.dot -Tpng -o 1.png");转换为图片 * 关于Graphviz更多内容参见:http://www.graphviz.org */class BiTreePrinter {public: static void toPng(const BST *bst,const std::string &desp=std::string(),const BSTNode* pcur=0); static std::string fontColor,fillColor,currentFillColor,currentFontColor,edgeColor,arrowheadType,width,height,fontsize; // 参数 static std::string prefix; // 文件名前缀 static long fileCounter; //文件编号private: static void addEdge(std::vector<std::string> &invisNodeVec,std::vector<BSTEdge> &edgeVec,const BSTNode* from); static void writePng(std::vector<std::string> &invisNodeVec,std::vector<BSTEdge> &edgeVec,const std::string& desp,const BSTNode* pcur=0); static std::string getNextFilename();};
实现文件:
/* * treeprinter.cpp * * Created on: 2015年5月21日 * Author: wangdq */#include <cstdlib> // std::system#include <queue>#include <iostream>#include <fstream>#include <sstream>#include "treeprinter.h"std::string BiTreePrinter::fontColor="black",BiTreePrinter::fillColor="#FFFFFF", BiTreePrinter::currentFillColor="red",BiTreePrinter::width="0.5", BiTreePrinter::height="0.5",BiTreePrinter::fontsize="16",BiTreePrinter::currentFontColor="black", BiTreePrinter::edgeColor="blue",BiTreePrinter::arrowheadType="normal";long BiTreePrinter::fileCounter = 1;std::string BiTreePrinter::prefix="BST";/** * 将绑定的BST转换为图片 * desp为描述字符串 * pcur指向当前节点 */void BiTreePrinter::toPng(const BST *bst,const std::string &desp,const BSTNode* pcur){ if(bst == 0) { std::cerr << "Printer not bind to any BST"<<std::endl; return; } if(bst->isEmpty()) return; std::vector<std::string> invisNodeVec; std::vector<std::string> visNodeVec; std::vector<BSTEdge> edgeVec; std::queue<const BSTNode *> nodeQueue; nodeQueue.push(bst->getRoot()); while(!nodeQueue.empty()) { // 广度优先遍历 const BSTNode * current = nodeQueue.front(); nodeQueue.pop(); if(current->left != 0) nodeQueue.push(current->left); if(current->right != 0) nodeQueue.push(current->right); if(current->left != 0 || current->right != 0) addEdge(invisNodeVec,edgeVec,current); } writePng(invisNodeVec,edgeVec,desp,pcur);}/** * 添加结点from相关的边 */void BiTreePrinter::addEdge(std::vector<std::string> &invisNodeVec,std::vector<BSTEdge> &edgeVec,const BSTNode* from){ std::string fromId = from->toString(); std::string virtualId=std::string("v")+fromId; if(from->left == 0 && from->right == 0) return; invisNodeVec.push_back(virtualId); if(from->left != 0 && from->right != 0) { edgeVec.push_back(BSTEdge(fromId,from->left->toString())); edgeVec.push_back(BSTEdge(fromId,virtualId,false)); edgeVec.push_back(BSTEdge(fromId,from->right->toString())); }else if(from->left == 0) { edgeVec.push_back(BSTEdge(fromId,virtualId,false)); edgeVec.push_back(BSTEdge(fromId,from->right->toString())); }else { edgeVec.push_back(BSTEdge(fromId,from->left->toString())); edgeVec.push_back(BSTEdge(fromId,virtualId,false)); }}/** * 写入dot文件并转换为png * 可以根据需要修改此部分参数 */void BiTreePrinter::writePng(std::vector<std::string> &invisNodeVec,std::vector<BSTEdge> &edgeVec,const std::string& desp,const BSTNode* pcur) { long count = fileCounter; std::string filename = getNextFilename(); std::ofstream stream(filename.c_str()); // print author and contact info stream << "/************************************************" <<std::endl << "Auto generated by my program which transfer Binary Search Tree to dot file." << std::endl << "Author: wangdq " <<std::endl << "Time: 2015-05-30" <<std::endl << "CSDN: http://blog.csdn.net/wangdingqiaoit"<<std::endl << "************************************************/" <<std::endl<<std::endl; // print description stream << "digraph BST {" << std::endl; stream << "\tlabel=\"(" << count <<")\t" << desp << "\";"<< "labelloc=b;labeljust=center;"<<std::endl; // print settings stream << "\tnodesep=0.35" << std::endl << "\tordering=out" << std::endl << "\tnode[width=" << width << ",height=" <<height << ",fontsize=" << fontsize << ",fixedsize=true,style=\"filled\", fillcolor=\"" << fillColor << "\",fontcolor=\"" << fontColor << "\"];" << std::endl << "\tedge[color=\"" << edgeColor << "\", arrowhead=\"" << arrowheadType << "\"];"<< std::endl; // print invisible node stream << "\t/* invisible nodes*/" << std::endl; stream << " \t{ node[style=invis]" << std::endl; for(std::vector<std::string>::iterator it = invisNodeVec.begin(); it != invisNodeVec.end();++it) stream << "\t\t" << *it << std::endl; stream << "\t}" << std::endl; //set current node color if(pcur != 0) { stream << "\t/* set current node color attributes*/" << std::endl; stream <<"\t" << pcur->toString() << "[fillcolor=\"" << currentFillColor << "\",fontcolor=\"" << currentFontColor <<"\"];"<<std::endl; } //print edges stream << "\t/* edges*/" << std::endl; for(std::vector<BSTEdge>::iterator it = edgeVec.begin(); it != edgeVec.end();++it) stream <<"\t" << (*it).toString() << std::endl; stream << "}"<< std::endl; stream.close(); //transfer from dot file to png picture std::string cmd("dot -Tpng"); cmd += " "+filename+" -o"+filename+".png"; std::system(cmd.c_str()); std::cout << "tree saved in file: " << filename<< std::endl;}/** * 获取下一个文件名 */std::string BiTreePrinter::getNextFilename() { const std::string ext = ".dot"; std::string filename(prefix); std::ostringstream oss; oss << fileCounter++; filename += oss.str(); filename += ext; return filename;}
转换的dot文件如下所示:
/************************************************Auto generated by my program which transfer Binary Search Tree to dot file.Author: wangdq Time: 2015-05-30CSDN: http://blog.csdn.net/wangdingqiaoit************************************************/digraph BST { label="(23) search: 88";labelloc=b;labeljust=center; nodesep=0.35 ordering=out node[width=0.5,height=0.5,fontsize=16,fixedsize=true,style="filled", fillcolor="#FFFFFF",fontcolor="black"]; edge[color="blue", arrowhead="normal"]; /* invisible nodes*/ { node[style=invis] v66 v44 v99 v77 } /* set current node color attributes*/ 88[fillcolor="red",fontcolor="black"]; /* edges*/ 66->44 66->v66[weight=100 style=invis] 66->99 44->v44[weight=100 style=invis] 44->55 99->77 99->v99[weight=100 style=invis] 77->v77[weight=100 style=invis] 77->88}
3. B-Tree转换实现
B-Tree节点定义如下:
/** * M阶B-Tree结点 * 每个节点包含M-1个键值和M个指针 * 实际上每个结点多分配一个键值和指针用于辅助空间 */template<typename T,int M> class BTree;template<typename T,int M=5>class BTreeNode {public: BTreeNode():parent(0),keynum(0),isLeaf(true) { for(int i=0;i < M+1;++i) childs[i] = 0; } BTreeNode(const T& k,BTreeNode *p=0) { keys[0]=k; parent = p; keynum = 1; isLeaf = true; for(int i=0;i < M+1;++i) childs[i] = 0; } std::string toString() const{ // 用于调试 std::stringstream ss; ss << keys[0]; return ss.str(); }private: T keys[M]; // 键 BTreeNode *childs[M+1]; // 孩子指针 BTreeNode *parent; // 父节点指针 int keynum; // 键数目 bool isLeaf; // 是否是叶子结点 friend class BTree<T,M>; friend class BTreePrinter; // 打印B-Tree为图片};
实现如下:
/* * btreeprinter.h * * Created on: 2015年5月18日 * Author: wangdq */#ifndef BTREEPRINTER_H_#define BTREEPRINTER_H_#include <string>#include <fstream>#include <sstream>#include <vector>#include "btree.h"/** * B-Tree边类 */struct BTreeEdge { BTreeEdge(const std::string &f,const std::string &t,int fIndex,int tIndex,bool isWest=true): from(f), fromIndex(fIndex),toIndex(tIndex),to(t),west(isWest) { } std::string toString() const{ std::string dir = ":se"; std::stringstream ss; ss << fromIndex; std::string fIndex = ss.str(); ss << toIndex; std::string tIndex = ss.str(); if(west) dir = std::string(":sw"); std::stringstream oss; oss << "\"" << from<< "\":f"<< fIndex<< dir<< "->"<< "\""<< to<< "\":f"<< toIndex; return oss.str(); } std::string from; int fromIndex,toIndex; std::string to; bool west;};/** * 利用绘制B-Tree * 1)将树形写入.dot文件 * 2)利用Graphviz程序转换.dot文件为png图片 * dot转换为图片阶段 系统必须安装有graphviz并配置有dot命令 否则失效 * 利用系统命令例如: system ("dot example.dot -Tpng -o 1.png");转换为图片 * 关于Graphviz更多内容参见:http://www.graphviz.org */class BTreePrinter {public: static std::string fontColor,fillColor,edgeColor,arrowheadType,width,height,fontsize; // 参数 static std::string prefix; // 文件名前缀 static long fileCounter; //文件编号 static std::string intToString(int i) { std::ostringstream oss; oss << i; return oss.str(); } /** * 将btree转换为图片 * desp为描述内容 */ template<typename T,int M> static void toPng(const BTree<T,M>* btree,const std::string &desp=std::string()) { if(btree == 0) { std::cerr << "Printer not bind to any B-Tree"<<std::endl; return; } if(btree->isEmpty()) return; std::vector<std::string> visNodeVec; std::vector<BTreeEdge> edgeVec; std::queue<const BTreeNode<T,M>*> nodeQueue; nodeQueue.push(btree->getRoot()); while(!nodeQueue.empty()) { // 广度优先遍历 const BTreeNode<T,M>* current = nodeQueue.front(); nodeQueue.pop(); if(!current->isLeaf) for(int i=0;i <= current->keynum;++i) nodeQueue.push(current->childs[i]); addEdge(visNodeVec,edgeVec,current); } writePng(visNodeVec,edgeVec,desp); }private: static std::string getNextFilename() { const std::string ext = ".dot"; std::string filename(prefix); std::ostringstream oss; oss << fileCounter++; filename += oss.str(); filename += ext; return filename; } template<typename T,int M> static void addEdge(std::vector<std::string> & visNodeVec,std::vector<BTreeEdge> &edgeVec, const BTreeNode<T,M>* from) { if(from->keynum < 0 ) return; std::string label = from->toString()+"[label=\""; for(int i=0;i < from->keynum;++i) { label += std::string("<f")+intToString(i)+"> "+intToString(from->keys[i]); if(i != from->keynum-1) label += "|"; } label+="\"];"; visNodeVec.push_back(label); if(from->isLeaf) return; for(int i=0;i < from->keynum;++i) edgeVec.push_back(BTreeEdge(from->toString(),from->childs[i]->toString(),i,from->childs[i]->keynum-1,true)); edgeVec.push_back(BTreeEdge(from->toString(),from->childs[from->keynum]->toString(), from->keynum-1,from->childs[from->keynum]->keynum /2,false)); } static void writePng(std::vector<std::string> & visNodeVec,std::vector<BTreeEdge> &edgeVec ,const std::string& desp) { long count = fileCounter; std::string filename = getNextFilename(); std::ofstream stream(filename.c_str()); // print author and contact info stream << "/************************************************" <<std::endl << "Auto generated by my program which transfer B-Tree to dot file." << std::endl << "Author: wangdq " <<std::endl << "Time: 2015-06-08" <<std::endl << "CSDN: http://blog.csdn.net/wangdingqiaoit"<<std::endl << "************************************************/" <<std::endl<<std::endl; // print description stream << "digraph BTree {" << std::endl; stream << "\tlabel=\"(" << count <<")\t" << desp << "\";"<< "labelloc=b;labeljust=center;"<<std::endl; // print settings stream << "\tordering=out" << std::endl << "\tnode[shape=record,width=" << width << ",height=" <<height << ",fontsize=" << fontsize << ",style=\"filled\", fillcolor=\"" << fillColor << "\",fontcolor=\"" << fontColor << "\"];" << std::endl << "\tedge[color=\"" << edgeColor << "\", arrowhead=\"" << arrowheadType << "\"];"<< std::endl; //print visible node for(std::vector<std::string>::iterator it = visNodeVec.begin(); it != visNodeVec.end();++it) stream << "\t\t" << *it << std::endl; //print edges stream << "\t/* edges*/" << std::endl; for(std::vector<BTreeEdge>::iterator it = edgeVec.begin(); it != edgeVec.end();++it) stream <<"\t" << (*it).toString() << std::endl; stream << "}"<< std::endl; stream.close(); //transfer from dot file to png picture std::string cmd("dot -Tpng"); cmd += " "+filename+" -o"+filename+".png"; std::system(cmd.c_str()); std::cout << "tree saved in file: " << filename<< std::endl; }};std::string BTreePrinter::fontColor="black",BTreePrinter::fillColor="#FFFFFF",BTreePrinter::width="0.5", BTreePrinter::height="0.5",BTreePrinter::fontsize="16", BTreePrinter::edgeColor="blue",BTreePrinter::arrowheadType="normal";long BTreePrinter::fileCounter = 1;std::string BTreePrinter::prefix="B-Tree";#endif /* BTREEPRINTER_H_ */
转换成的dot文件如下所示:
/************************************************Auto generated by my program which transfer B-Tree to dot file.Author: wangdq Time: 2015-06-08CSDN: http://blog.csdn.net/wangdingqiaoit************************************************/digraph BTree { label="(1) initial B-Tree";labelloc=b;labeljust=center; ordering=out node[shape=record,width=0.5,height=0.5,fontsize=16,style="filled", fillcolor="#FFFFFF",fontcolor="black"]; edge[color="blue", arrowhead="normal"]; 16[label="<f0> 16"]; 3[label="<f0> 3|<f1> 8"]; 22[label="<f0> 22|<f1> 25"]; 1[label="<f0> 1|<f1> 2"]; 5[label="<f0> 5|<f1> 6|<f2> 7"]; 13[label="<f0> 13|<f1> 14|<f2> 15"]; 18[label="<f0> 18|<f1> 20"]; 23[label="<f0> 23|<f1> 24"]; 27[label="<f0> 27|<f1> 37"]; /* edges*/ "16":f0:sw->"3":f1 "16":f0:se->"22":f1 "3":f0:sw->"1":f1 "3":f1:sw->"5":f2 "3":f1:se->"13":f1 "22":f0:sw->"18":f1 "22":f1:sw->"23":f1 "22":f1:se->"27":f1}
0 0
- 数据结构与算法14: 利用Graphviz快速可视化树(visualizing Trees with Graphviz easily )
- 二叉树可视化--Graphviz
- 二叉树可视化--Graphviz
- graphviz数据可视化 与Python交互
- GraphViz
- Graphviz
- Graphviz
- Graphviz
- Graphviz
- Graphviz
- 可视化图形软件 Graphviz
- connect graphviz with matlab
- graphviz快速上手
- 利用Graphviz 画结构图
- 利用Graphviz 画结构图
- 利用Graphviz 画结构图
- 利用Graphviz 画结构图
- 用 Graphviz 可视化函数调用
- 插入排序
- javax.ws.rs.core Class UriBuilder
- 链表各类操作详解
- sql查看cpu使用最多的和經常重編譯的
- Linux-df与du不一致情况分析【重点】
- 数据结构与算法14: 利用Graphviz快速可视化树(visualizing Trees with Graphviz easily )
- j2se 随记
- 不要在大城市中迷失了自己
- IOS SDK详解之UIAlertController(IOS8之后替代AlertView和ActionSheet)
- 每个Javascript开发者都应当知道的那些事(转载)
- (5)LinuxI2C驱动--浅谈LinuxI2C驱动架构
- linux命令:cd命令
- 二叉树
- 报数问题