1. 问题描述
用递归算法绘制一棵树
2. 解决思路
用二叉树的数据结构来描述树的结构,首先创建一个二叉树,创建时要初始化节点的一些信息,伪代码如下:
If current depth is last
then return null
End If
Create a branch
If current branch is left
then initial the branch as a left branch
Else
then initial the branch as a right branch
End If
Create the left branch of this recursively
Create the right branch of this recursively
return the root branch
then return null
End If
Create a branch
If current branch is left
then initial the branch as a left branch
Else
then initial the branch as a right branch
End If
Create the left branch of this recursively
Create the right branch of this recursively
return the root branch
然后再遍历二叉树,遍历的同时绘制树枝,伪代码如下:
If current branch has left branch
then paint the left branch
End If
If current branch has right branch
then paint the left branch
End If
Paint the left branch of this recursively
Paint the right branch of this recursively
then paint the left branch
End If
If current branch has right branch
then paint the left branch
End If
Paint the left branch of this recursively
Paint the right branch of this recursively
3. 代码实现
创建树的代码:
- Branch *DrawTrees::createTree(Branch *preRoot, bool isLeft)
- {
- if(preRoot->depth > depth)//判断是否到达设置的深度
- return NULL;
- Branch *root = new Branch();
- if(!root)
- return NULL;
- root->depth = preRoot->depth + 1;
- if(root->depth < 3)
- {//最底下三层的树枝角度较小
- if(isLeft)
- {
- root->angle = preRoot->angle + qrand()%15;
- root->length = preRoot->length - preRoot->length / (3+qrand()%7);
- }
- else
- {
- root->angle = preRoot->angle - qrand()%15;
- root->length = preRoot->length - preRoot->length / (3+qrand()%7);
- }
- root->width = preRoot->width * 0.8;
- }
- else
- {
- if(branchNumCount[root->depth] >= maxBranchNum[root->depth])
- return NULL;
- else
- {
- if(isLeft)
- root->angle = preRoot->angle+(45-root->depth*3+qrand()%(40-root->depth*2));
- else
- root->angle = preRoot->angle-(45-root->depth*3+qrand()%(40-root->depth*2));
- root->length = preRoot->length-preRoot->length/(3+qrand()%7);
- root->width = preRoot->width * 0.618;
- branchNumCount[root->depth]++;
- }
- }
- //计算当前树枝起点的坐标
- root->x= preRoot->x + root->length*cos(root->angle*ONEANGLE);
- root->y= preRoot->y - root->length*sin(root->angle*ONEANGLE);
- //当树枝宽带减小到1时不再减小
- if(root->width < 1)
- root->width = 1;
- root->left = createTree(root, true); //递归创建左子树
- root->right = createTree(root, false); //递归创建右子树
- return root ;
- }
绘制树的代码:
- void DrawTrees::paintTree(Branch *root)
- {
- if(!root)
- return;
- int dstX,dstY;
- if(!root->left)
- {//左子树为空则画叶子
- dstX=root->x+1;
- dstY=root->y+1;
- painter->setPen(QPen(QBrush(QColor(0,140,0,255)),
- LEAVE_WIDTH,
- Qt::SolidLine,
- Qt::RoundCap));
- painter->drawLine(root->x,root->y,dstX,dstY);
- }
- else
- {//否则画树枝
- dstX=root->left->x;
- dstY=root->left->y;
- painter->setPen(QPen(QColor(160, 82, 45),
- root->width,
- Qt::SolidLine,
- Qt::RoundCap));
- painter->drawLine(root->x,root->y,dstX,dstY);
- }
- if(!root->right)
- {
- dstX=root->x+1;
- dstY=root->y+1;
- painter->setPen(QPen(QBrush(QColor(0,140,0,255)),
- LEAVE_WIDTH,
- Qt::SolidLine,
- Qt::RoundCap));
- painter->drawLine(root->x,root->y,dstX,dstY);
- }
- else
- {
- dstX=root->right->x;
- dstY=root->right->y;
- painter->setPen(QPen(QColor(160, 82, 45),
- root->width,
- Qt::SolidLine,
- Qt::RoundCap));
- painter->drawLine(root->x,root->y,dstX,dstY);
- }
- paintTree(root->left);//递归绘制左子树
- paintTree(root->right);//递归绘制右子树
- }
4. 运行结果
5. 小结
主要思路就是使用二叉树创建一棵树,然后遍历。为了使显示效果更好,加入一个随机控制,比如控制树枝的角度和每层节点的数量,使最终效果不是一个完全二叉树,这样使每层上都有叶子。
源代码:点击打开链接