Algorithm 设置绘制二叉树的位置
我想用图形框架(Qt)绘制一棵二叉树,如下所示:Algorithm 设置绘制二叉树的位置,algorithm,tree,drawing,binary-tree,drawing2d,Algorithm,Tree,Drawing,Binary Tree,Drawing2d,我想用图形框架(Qt)绘制一棵二叉树,如下所示: 9 / \ 1 10 / \ \ 0 5 11 / / \ -1 2 6 但我有一个问题,为每个节点设置X和Y,你知道设置和固定位置吗?(我只有每个节点的高度以及左子节点和右子节点)改进Pavel Zaichenkov的解决方案 让根的索引为1,对于另一个节点: leftNodeIndex = parentNodeIndex * 2
9
/ \
1 10
/ \ \
0 5 11
/ / \
-1 2 6
但我有一个问题,为每个节点设置X和Y,你知道设置和固定位置吗?(我只有每个节点的高度以及左子节点和右子节点)改进Pavel Zaichenkov的解决方案 让根的
索引为1,对于另一个节点:
leftNodeIndex = parentNodeIndex * 2 - 1
rightNodeIndex = parentNodeIndex * 2 + 1
Y为(考虑从1开始的深度):
该算法使得如果一个节点有两个子节点,则该节点与左子节点之间的距离与该节点与右子节点之间的距离相等:
Y - leftChlidY = rightChlidY - Y
(1, 1/2)
/ \
(2, 1/4) (2, 3/4)
/ \ \
(3, 1/8) (3, 3/8) (3, 7/8)
/ / \
(4, 1/16) (4, 5/16) (4, 7/16)
给定画布的宽度canvasWidth
和高度canvasHeight
,您可以计算每个节点的位置
首先,让我们为每个节点分配两个数字:节点的深度和完全填充行中节点的序列索引。在您的示例中,对于每个节点,我们将(深度,索引)
指定为
(0, 1)
/ \
(1, 1) (1, 2)
/ \ \
(2, 1) (2, 2) (2, 4)
/ / \
(3, 1) (3, 3) (3, 4)
这可以使用BFS(成本:O(n))来完成。在这个遍历过程中,我们还要保存关于整个树的深度的信息treeDepth
。在我们的例子中,treeDepth=3
然后将canvaswitch
、canvaswith
和treeDepth
作为全局常量,每个节点的位置如下所示:
9
/ \
1 10
/ \ \
0 5 11
/ / \
-1 2 6
def位置(深度、索引):
x=索引*画布宽度/(2^深度+1)
y=深度*画布高度/树顶高度
返回y,x
因此,在您的情况下,每个节点的位置都是(canvashight/treeDepth*y,canvashwidth*x)
,其中(y,x)
(0, 1/2)
/ \
(1, 1/3) (1, 2/3)
/ \ \
(2, 1/5) (2, 2/5) (2, 4/5)
/ / \
(3, 1/9) (3, 3/9) (3, 4/9)
(0, 1/2)
/ \
(1, 1/3) (1, 2/3)
/ \ \
(2, 1/5) (2, 2/5) (2, 4/5)
/ / \
(3, 1/9) (3, 3/9) (3, 4/9)
成本:o(n)
< p>我用C++框架(OpenGraseWork)将它写成图形界面。< /P>
////////////////////////
void BSTree:: paint()
{
ppx=ofGetWidth()/(2+numNode());
ppy=ofGetHeight()/(2+findHeight());
draw(root,1,1);
}
////////////////////////
int BSTree:: draw(TreeNode *n,int x,int y)
{
int xr=x;
if(n==NULL) return xr
int lx=draw(n->l,x,y+1);
xr+=numNode2(n->l);
int rx=draw(n->r,xr+1,y+1);
n->draw(xr*ppx,y*ppy);
if(n->l!=NULL) ofLine(xr*ppx,y*ppy,lx*ppx,(y+1)*ppy);
if(n->r!=NULL) ofLine(xr*ppx,y*ppy,rx*ppx,(y+1)*ppy);
return xr;
}
///////////////////////
void TreeNode::draw(int x,int y)
{
ofSetColor(255,130,200);
float radius = 25 ;
ofFill(); // draw "filled shapes"
ofCircle(x,y,radius);
ofSetHexColor(0x000000);
char xx[100] ;
sprintf(xx,"%d",data);
ofDrawBitmapString(xx, x-5,y);
}
我正在寻找一种在Qt中绘制二叉树的方法,但我找不到一个示例,所以我制作了一个库来绘制二叉树,就是这样
您的方法一开始似乎是正确的(这是我首先做的),但如果最后一层没有填满,则显示的树的宽度将太大。我已经写了一篇关于这个主题的文章。可以在这里找到:
本质上,您需要将每个子节点尽可能地向左移动,但需要注意的是,子节点必须分别位于父节点的左侧和右侧。然后尽可能向右移动左分支,注意事项相同。+1。说白了,在BFS期间,从父节点计算子节点的索引的方法是左子节点的parentIndex*2-1
,右子节点的parentIndex*2
。在你的定义中,你说的是order
,我相信你的意思是index
。
(0, 1/2)
/ \
(1, 1/3) (1, 2/3)
/ \ \
(2, 1/5) (2, 2/5) (2, 4/5)
/ / \
(3, 1/9) (3, 3/9) (3, 4/9)
////////////////////////
void BSTree:: paint()
{
ppx=ofGetWidth()/(2+numNode());
ppy=ofGetHeight()/(2+findHeight());
draw(root,1,1);
}
////////////////////////
int BSTree:: draw(TreeNode *n,int x,int y)
{
int xr=x;
if(n==NULL) return xr
int lx=draw(n->l,x,y+1);
xr+=numNode2(n->l);
int rx=draw(n->r,xr+1,y+1);
n->draw(xr*ppx,y*ppy);
if(n->l!=NULL) ofLine(xr*ppx,y*ppy,lx*ppx,(y+1)*ppy);
if(n->r!=NULL) ofLine(xr*ppx,y*ppy,rx*ppx,(y+1)*ppy);
return xr;
}
///////////////////////
void TreeNode::draw(int x,int y)
{
ofSetColor(255,130,200);
float radius = 25 ;
ofFill(); // draw "filled shapes"
ofCircle(x,y,radius);
ofSetHexColor(0x000000);
char xx[100] ;
sprintf(xx,"%d",data);
ofDrawBitmapString(xx, x-5,y);
}