目录
什么是SVGSVG定义SVG优点预定义元素圆形最近一直在刷二叉树题目,但在要验证结果时,通常用中序遍历、层序遍历查看结果,验证起来没有画图来得直观,所有想到自己动手制作二叉树的树形图。 直接开干,先从svg入手:
什么是SVG
SVG定义
SVG是可伸缩矢量图形 (Scalable Vector Graphics),于2003年1月14日成为 W3C 推荐标准。
SVG 用来定义用于网络的基于矢量的图形
【资料图】
SVG 使用 XML 格式定义图形
SVG 是万维网联盟的标准
SVG 与诸如 DOM 和 XSL 之类的 W3C 标准是一个整体
SVG优点
SVG 可被非常多的工具读取和修改(比如记事本)SVG 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性更强。SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失SVG 图像可在任何的分辨率下被高质量地打印SVG 可在图像质量不下降的情况下被放大SVG 图像中的文本是可选的,同时也是可搜索的(很适合制作地图)SVG 可以与 JavaScript 技术一起运行SVG 是开放的标准SVG 文件是纯粹的 XML预定义元素
矩形制作二叉树的树形图,就使用圆形、直线、文字三种即可:
圆形
cx和cy属性定义圆点的x和y坐标;r属性定义圆的半径
如果省略cx和cy,圆的中心会被设置为(0, 0)
直线
x1,y2 属性定义线条的起始端点坐标
x2,y2 属性定义线条的结束端点坐标
文字
x,y 属性定义文字左对齐显示时的起始坐标(居中对齐则是文字中间点)
fill 属性定义文字的颜色
结点SVG格式
根结点
由
1
子树结点
比根结点多出
2
叶结点
与子树结点相同,为区别显示把
3
结点坐标
坐标的确定
结点坐标确定,把二叉树还原成满二叉树,结点位置标记为:
[ [0,0], [1,0], [1,1], [2,0], [2,1], [2,2], [2,3], [3,0]......],再用循环计算出各点坐标。
连线的夹角
实际上不用考虑连线夹角,只要计算出连线始终两端点的坐标即可:
结点文本
以字符串形式保存好属性变量的特征关键词,用于遍历二叉树时替换成实际数据:
func XmlNode(M, N, X, Y int, Data string, Color ...string) string {
var cColor, tColor string
R := 30
Node := `
DATA
`
if len(Color) == 0 {
cColor, tColor = "orange", "red"
} else if len(Color) == 1 {
cColor, tColor = Color[0], "red"
} else {
cColor, tColor = Color[0], Color[1]
}
Node = strings.Replace(Node, "M", strconv.Itoa(M), 1)
Node = strings.Replace(Node, "N", strconv.Itoa(N), 1)
Node = strings.Replace(Node, "X", strconv.Itoa(X), 2)
Node = strings.Replace(Node, "Y", strconv.Itoa(Y), 2)
Node = strings.Replace(Node, "RC", strconv.Itoa(R), 1)
Node = strings.Replace(Node, "DATA", Data, 1)
Node = strings.Replace(Node, "COLOR", cColor, 1)
Node = strings.Replace(Node, "TextColor", tColor, 1)
Node = strings.Replace(Node, "", "\n", -1)
Node = strings.Replace(Node, "", "\t", -1)
Node = strings.Replace(Node, "\n\t\t", " ", -1)
return Node
} 二叉树转SVG
遍历二叉树对应的满二叉树,读出数据域并计算坐标,转成svg格式:
格式转换
func (bt *biTree) Xml4Tree() string {
var Xml, Node string
Head := ""
Line := ` `
Link := `
Hann"s CSDN Homepage `
List := bt.LevelNullwith()
Levels := len(List)
for i := Levels - 1; i >= 0; i-- {
negative := -1
TmpXml := ""
for j := 0; j < Pow2(i); j++ {
t := Pow2(Levels - i - 1)
x, y := 50*(2*t*j+t), 120*i+50
if List[i][j] != nil {
fillColor := "orange"
if i == Levels-1 || i > 0 && i < Levels-1 &&
List[i+1][j*2] == nil && List[i+1][j*2+1] == nil {
fillColor = "lightgreen"
}
TmpStr := ""
switch List[i][j].(type) {
case int:
TmpStr = strconv.Itoa(List[i][j].(int))
case float64:
TmpStr = strconv.FormatFloat(List[i][j].(float64), "g", -1, 64)
case string:
TmpStr = List[i][j].(string)
default:
TmpStr = "Error Type"
}
Xml = XmlNode(i, j, x, y, TmpStr, fillColor)
}
if i > 0 {
line1 := strings.Replace(Line, "X1", strconv.Itoa(x), 1)
line1 = strings.Replace(line1, "Y1", strconv.Itoa(y-30), 1)
negative *= -1
x0, y0 := 21, 21
x += 50*negative*(2*t*j%2+t) - negative*x0
line1 = strings.Replace(line1, "X2", strconv.Itoa(x), 1)
line1 = strings.Replace(line1, "Y2", strconv.Itoa(y-120+y0), 1)
Xml = strings.Replace(Xml, " ", line1, 1)
}
if List[i][j] != nil {
TmpXml += Xml
}
}
Node = TmpXml + Node
}
Xml = strings.Replace(Head, "CONTENT", Node, 1)
Xml = strings.Replace(Xml, "Width", strconv.Itoa(Pow2(Levels)*50), 1)
Xml = strings.Replace(Xml, "Height", strconv.Itoa(Levels*120), 1)
Xml = strings.Replace(Xml, " ", Link, 1)
return Xml
}写入文件、调取浏览
//......
for index, text := range texts {
svgFile := "./biTree0" + strconv.Itoa(index+1) + ".svg"
file, err1 = os.Create(svgFile)
if err1 != nil {
panic(err1)
}
_, err1 = io.WriteString(file, text)
if err1 != nil {
panic(err1)
}
file.Close()
exec.Command("cmd", "/c", "start", svgFile).Start()
//Linux 代码:
//exec.Command("xdg-open", svgFile).Start()
//Mac 代码:
//exec.Command("open", svgFile).Start()
}
//......全部源代码
package main
import (
"fmt"
"io"
"os"
"os/exec"
"strconv"
"strings"
)
type btNode struct {
Data interface{}
Lchild *btNode
Rchild *btNode
}
type biTree struct {
Root *btNode
}
func Build(data interface{}) *biTree {
var list []interface{}
if data == nil {
return &biTree{}
}
switch data.(type) {
case []interface{}:
list = append(list, data.([]interface{})...)
default:
list = append(list, data)
}
if len(list) == 0 {
return &biTree{}
}
node := &btNode{Data: list[0]}
list = list[1:]
Queue := []*btNode{node}
for len(list) > 0 {
if len(Queue) == 0 {
//panic("Given array can not build binary tree.")
return &biTree{Root: node}
}
cur := Queue[0]
val := list[0]
Queue = Queue[1:]
if val != nil {
cur.Lchild = &btNode{Data: val}
if cur.Lchild != nil {
Queue = append(Queue, cur.Lchild)
}
}
list = list[1:]
if len(list) > 0 {
val := list[0]
if val != nil {
cur.Rchild = &btNode{Data: val}
if cur.Rchild != nil {
Queue = append(Queue, cur.Rchild)
}
}
list = list[1:]
}
}
return &biTree{Root: node}
}
func (bt *biTree) AppendNode(data interface{}) {
root := bt.Root
if root == nil {
bt.Root = &btNode{Data: data}
return
}
Queue := []*btNode{root}
for len(Queue) > 0 {
cur := Queue[0]
Queue = Queue[1:]
if cur.Lchild != nil {
Queue = append(Queue, cur.Lchild)
} else {
cur.Lchild = &btNode{Data: data}
return
}
if cur.Rchild != nil {
Queue = append(Queue, cur.Rchild)
} else {
cur.Rchild = &btNode{Data: data}
break
}
}
}
func Copy(bt *biTree) *biTree {
root := bt.Root
if root == nil {
return &biTree{}
}
node := &btNode{Data: root.Data}
Queue1, Queue2 := []*btNode{root}, []*btNode{node}
for len(Queue1) > 0 {
p1, p2 := Queue1[0], Queue2[0]
Queue1, Queue2 = Queue1[1:], Queue2[1:]
if p1.Lchild != nil {
Node := &btNode{Data: p1.Lchild.Data}
p2.Lchild = Node
Queue1 = append(Queue1, p1.Lchild)
Queue2 = append(Queue2, Node)
}
if p1.Rchild != nil {
Node := &btNode{Data: p1.Rchild.Data}
p2.Rchild = Node
Queue1 = append(Queue1, p1.Rchild)
Queue2 = append(Queue2, Node)
}
}
return &biTree{Root: node}
}
func Mirror(bt *biTree) *biTree {
root := bt.Root
if root == nil {
return &biTree{}
}
node := &btNode{Data: root.Data}
Queue1, Queue2 := []*btNode{root}, []*btNode{node}
for len(Queue1) > 0 {
p1, p2 := Queue1[0], Queue2[0]
Queue1, Queue2 = Queue1[1:], Queue2[1:]
if p1.Lchild != nil {
Node := &btNode{Data: p1.Lchild.Data}
p2.Rchild = Node
Queue1 = append(Queue1, p1.Lchild)
Queue2 = append(Queue2, Node)
}
if p1.Rchild != nil {
Node := &btNode{Data: p1.Rchild.Data}
p2.Lchild = Node
Queue1 = append(Queue1, p1.Rchild)
Queue2 = append(Queue2, Node)
}
}
return &biTree{Root: node}
}
func (bt *biTree) BForder2D() [][]interface{} {
var res [][]interface{}
root := bt.Root
if root == nil {
return res
}
Queue := []*btNode{root}
for len(Queue) > 0 {
Nodes := []interface{}{}
Levels := len(Queue)
for Levels > 0 {
cur := Queue[0]
Queue = Queue[1:]
Nodes = append(Nodes, cur.Data)
Levels--
if cur.Lchild != nil {
Queue = append(Queue, cur.Lchild)
}
if cur.Rchild != nil {
Queue = append(Queue, cur.Rchild)
}
}
res = append(res, Nodes)
}
return res
}
func (bt *biTree) LevelNullwith(Fills ...interface{}) [][]interface{} {
var Nodes [][]interface{}
var Fill0 interface{}
if len(Fills) == 0 {
Fill0 = nil
} else if len(Fills) == 1 {
Fill0 = Fills[0]
} else {
panic("Error: number of parameters is greater than 1")
}
root := bt.Root
if root == nil {
return Nodes
}
Count := 0
Queue := []*btNode{root}
for len(Queue) > 0 {
nodes := []interface{}{}
Level := len(Queue)
for Level > 0 {
cur := Queue[0]
Queue = Queue[1:]
nodes = append(nodes, cur.Data)
Count++
Level--
if cur.Lchild != nil {
Queue = append(Queue, cur.Lchild)
}
if cur.Rchild != nil {
Queue = append(Queue, cur.Rchild)
}
}
Nodes = append(Nodes, nodes)
}
newbiTree := Copy(bt)
for i := 1; i < Pow2(len(Nodes))-Count; i++ {
newbiTree.AppendNode(Fill0)
}
return newbiTree.BForder2D()
}
func XmlNode(M, N, X, Y int, Data string, Color ...string) string {
var cColor, tColor string
R := 30
Node := `
DATA
`
if len(Color) == 0 {
cColor, tColor = "orange", "red"
} else if len(Color) == 1 {
cColor, tColor = Color[0], "red"
} else {
cColor, tColor = Color[0], Color[1]
}
Node = strings.Replace(Node, "M", strconv.Itoa(M), 1)
Node = strings.Replace(Node, "N", strconv.Itoa(N), 1)
Node = strings.Replace(Node, "X", strconv.Itoa(X), 2)
Node = strings.Replace(Node, "Y", strconv.Itoa(Y), 2)
Node = strings.Replace(Node, "RC", strconv.Itoa(R), 1)
Node = strings.Replace(Node, "DATA", Data, 1)
Node = strings.Replace(Node, "COLOR", cColor, 1)
Node = strings.Replace(Node, "TextColor", tColor, 1)
Node = strings.Replace(Node, "", "\n", -1)
Node = strings.Replace(Node, "", "\t", -1)
Node = strings.Replace(Node, "\n\t\t", " ", -1)
return Node
}
func Pow2(x int) int { //x>=0
res := 1
for i := 0; i < x; i++ {
res *= 2
}
return res
}
func Xml4Full(Levels int) string {
var Xml, Node string
Head := ""
Line := ` `
Link := `
Hann"s CSDN Homepage `
for i := 0; i < Levels; i++ {
negative := -1
for j := 0; j < Pow2(i); j++ {
t := Pow2(Levels - i - 1)
x, y := 50*(2*t*j+t), 120*i+50
if Levels != 1 && i == Levels-1 {
Xml = XmlNode(i, j, x, y, strconv.Itoa(Pow2(i)+j), "lightgreen")
} else {
Xml = XmlNode(i, j, x, y, strconv.Itoa(Pow2(i)+j))
}
if i > 0 {
line1 := strings.Replace(Line, "X1", strconv.Itoa(x), 1)
line1 = strings.Replace(line1, "Y1", strconv.Itoa(y-30), 1)
negative *= -1
x0, y0 := 21, 21
//过连线起始端的半径与纵轴线夹角取45度时x,y坐标修正值21,21[30/1.414]
//取30度时 x0,y0:= 15,30-26;取60度时 x0,y0:= 26[15*1.732],15
x += 50*negative*(2*t*j%2+t) - negative*x0
line1 = strings.Replace(line1, "X2", strconv.Itoa(x), 1)
line1 = strings.Replace(line1, "Y2", strconv.Itoa(y-120+y0), 1)
Xml = strings.Replace(Xml, " ", line1, 1)
}
Node += Xml
}
}
Xml = strings.Replace(Head, "CONTENT", Node, 1)
Xml = strings.Replace(Xml, "Width", strconv.Itoa(Pow2(Levels)*50), 1)
Xml = strings.Replace(Xml, "Height", strconv.Itoa(Levels*120), 1)
Xml = strings.Replace(Xml, " ", Link, 1)
return Xml
}
func (bt *biTree) Xml4Tree() string {
var Xml, Node string
Head := ""
Line := ` `
Link := `
Hann"s CSDN Homepage `
List := bt.LevelNullwith()
Levels := len(List)
for i := Levels - 1; i >= 0; i-- {
negative := -1
TmpXml := ""
for j := 0; j < Pow2(i); j++ {
t := Pow2(Levels - i - 1)
x, y := 50*(2*t*j+t), 120*i+50
if List[i][j] != nil {
fillColor := "orange"
if i == Levels-1 || i > 0 && i < Levels-1 &&
List[i+1][j*2] == nil && List[i+1][j*2+1] == nil {
fillColor = "lightgreen"
}
TmpStr := ""
switch List[i][j].(type) {
case int:
TmpStr = strconv.Itoa(List[i][j].(int))
case float64:
TmpStr = strconv.FormatFloat(List[i][j].(float64), "g", -1, 64)
case string:
TmpStr = List[i][j].(string)
default:
TmpStr = "Error Type"
}
Xml = XmlNode(i, j, x, y, TmpStr, fillColor)
}
if i > 0 {
line1 := strings.Replace(Line, "X1", strconv.Itoa(x), 1)
line1 = strings.Replace(line1, "Y1", strconv.Itoa(y-30), 1)
negative *= -1
x0, y0 := 21, 21
x += 50*negative*(2*t*j%2+t) - negative*x0
line1 = strings.Replace(line1, "X2", strconv.Itoa(x), 1)
line1 = strings.Replace(line1, "Y2", strconv.Itoa(y-120+y0), 1)
Xml = strings.Replace(Xml, " ", line1, 1)
}
if List[i][j] != nil {
TmpXml += Xml
}
}
Node = TmpXml + Node
}
Xml = strings.Replace(Head, "CONTENT", Node, 1)
Xml = strings.Replace(Xml, "Width", strconv.Itoa(Pow2(Levels)*50), 1)
Xml = strings.Replace(Xml, "Height", strconv.Itoa(Levels*120), 1)
Xml = strings.Replace(Xml, " ", Link, 1)
return Xml
}
func main() {
var file *os.File
var err1 error
list1 := []interface{}{"-", "*", 6, "+", 3, nil, nil, 2, 8}
list2 := []interface{}{1, 2, 3, 4, 5, nil, 6, 7, 8}
tree1 := Build(list1)
tree2 := Build(list2)
tree3 := Mirror(tree2)
texts := []string{tree1.Xml4Tree(), tree2.Xml4Tree(), tree3.Xml4Tree(), Xml4Full(4)}
for index, text := range texts {
svgFile := "./biTree0" + strconv.Itoa(index+1) + ".svg"
file, err1 = os.Create(svgFile)
if err1 != nil {
panic(err1)
}
_, err1 = io.WriteString(file, text)
if err1 != nil {
panic(err1)
}
file.Close()
exec.Command("cmd", "/c", "start", svgFile).Start()
//Linux 代码:
//exec.Command("xdg-open", svgFile).Start()
//Mac 代码:
//exec.Command("open", svgFile).Start()
}
fmt.Println("Welcome to my homepage: https://blog.csdn.net/boysoft2002")
exec.Command("cmd", "/c", "start", "https://blog.csdn.net/boysoft2002").Start()
} 至此,已达成自己的预想结果,算法实在有点笨拙,但总算成功了。
到此这篇关于Go语言制作svg格式树形图的示例代码的文章就介绍到这了,更多相关Go语言树形图内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
X 关闭
X 关闭
- 15G资费不大降!三大运营商谁提供的5G网速最快?中国信通院给出答案
- 2联想拯救者Y70发布最新预告:售价2970元起 迄今最便宜的骁龙8+旗舰
- 3亚马逊开始大规模推广掌纹支付技术 顾客可使用“挥手付”结账
- 4现代和起亚上半年出口20万辆新能源汽车同比增长30.6%
- 5如何让居民5分钟使用到各种设施?沙特“线性城市”来了
- 6AMD实现连续8个季度的增长 季度营收首次突破60亿美元利润更是翻倍
- 7转转集团发布2022年二季度手机行情报告:二手市场“飘香”
- 8充电宝100Wh等于多少毫安?铁路旅客禁止、限制携带和托运物品目录
- 9好消息!京东与腾讯续签三年战略合作协议 加强技术创新与供应链服务
- 10名创优品拟通过香港IPO全球发售4100万股 全球发售所得款项有什么用处?

