使用javascript+canvas显示二叉树

1  创建二叉树节点类

首先,需要一个TreeNode类表示二叉树节点:

class TreeNode {
  constructor(val) {
    this.val = val;
    this.left = null;
    this.right = null;
  }
}

2. 生成二叉树

lass FullBinaryTree {
  constructor(level) {
    const _Root = this.getFullBinaryTree(level);
    this.getRoot = () => {
      return _Root;
    };
  }
  getFullBinaryTree(level) {
    let index = 0;
    function fullTree(n) {
      if (n === 0) return null;
      let root = new TreeNode(index++);
      root.left = fullTree((n - 1) / 2);
      root.right = fullTree((n - 1) / 2);
      return root;
    }
    // 2的level次方 -1 = 总节点数
    return fullTree(Math.pow(2, level) - 1);
  }
}

3.  计算二叉树深度

const getTreeDepth = (root) => {
  				let depth = 0; // 当前深度
  				let max = 0; // 当前最大深度
  				const solve = (node) => {
    			if (!node) {
      				if (depth >= max) {
        					max = depth;
     				}
      				return 0;
    			}
    			depth++;
    			solve(node.left);
    			solve(node.right);
    			depth--; // 回到当前节点,深度减回来
    			return max;
  				};
  			return solve(root);
		}

4   Canvas 渲染器

//render
		class CanvasRender {
  			constructor(container) {
    			this.canvas = document.createElement('canvas');
    			this.container = container;
    			this.ctx = this.canvas.getContext('2d');
  			}
  			initSize(w, h) {
    			this.canvas.width = w;
    			this.canvas.height = h;
    			this.container.appendChild(this.canvas);
 			}
  			setStyle(ctx) {
    			ctx.font = "20px serif";
    			ctx.textAlign = "center";
    			ctx.textBaseline = "middle";
  			}
  			renderNode(x, y, r, text) {
  				this.ctx.strokeStyle="#000000"
  				this.ctx.fillStyle='#ff00ff'
    			this.ctx.beginPath();
    			this.ctx.arc(x, y, r, 0, Math.PI * 2); // 绘制圆
    			this.ctx.stroke();
    			this.setStyle(this.ctx); // 设置样式
    			this.ctx.fillText(text, x, y); // 填充节点的value
  			}
  			renderLine(x1, y1, x2, y2) {
    			this.ctx.moveTo(x1, y1);
    			this.ctx.lineTo(x2, y2);
    			this.ctx.stroke();
  			}
		}

5   树的绘制器

树的绘制器使用draw绘制二叉树的节点drawNode和连线linkNode。

//drawer
		class TreeDrawer {
 			constructor(render) {
    			this.render = render;
  			}

 		    layout(root, nodeW, nodeH) {
    			function computeWidth(root) {
      				if (!root) return 0;
      				if (!(root.left || root.right)) {
        				root.width = nodeW;
        				return root.width;
      				}
      				root.width = computeWidth(root.left) + computeWidth(root.right) + nodeW;
      				return root.width;
    				}
    				function computePosition(root, left, right, curY = nodeH) {
      					if (!root) return;
      				let x;
      				if (root.left) {
        			x = left + root.left.width + nodeW;
      				} else {
        			x = left + nodeW;
      				}
      				root.position = [x, curY];
      				computePosition(root.left, left, x, curY + nodeH);
      				computePosition(root.right, x, right, curY + nodeH);
    			}
    			computeWidth(root);
    			computePosition(root, 0, root.width);
    			return root.width;
  			}
  			

  			draw(root, nodeW = 40, nodeH = 40) {
    			let depth = getTreeDepth(root); // 获取深度
    			let width = this.layout(root, nodeW, nodeH);// canvas宽度
    			let height = depth * nodeH + nodeH; 
    			// canvas高度
    			this.render.initSize(width + nodeW, height);
    			
    			const getVector = (x, y, x1, y1) => {
      			let dis = Math.sqrt((x - x1) ** 2 + (y - y1) ** 2);
      			return [
        			(x1 - x) / dis,
        			(y1 - y) / dis
      				]
    			}
    			const linkNode = (root, child) => {
      			let [px, py] = root.position;
      			let [cx, cy] = child.position;
      			let [dx, dy] = getVector(px, py, cx, cy);
      			this.render.renderLine(px + (nodeW / 2) * dx, py + (nodeW / 2) * dy,
        		cx - (nodeW / 2) * dx, cy - (nodeW / 2) * dy)
    			}
    			
    			const drawNode = (root) => {
      				let [x, y] = root.position;
      				this.render.renderNode(x, y, nodeW / 2, root.val);
    			}
    			      
    		function draw(root) {
      			if (!root) return;
     			drawNode(root);
     			if (root.left) linkNode(root, root.left);
      			if (root.right) linkNode(root, root.right);
      			draw(root.left);
      			draw(root.right);
    		}
    		draw(root);
  			} 			                                                                       
		}

6   使用示例

// 创建一个深度为3的二叉树
const root = new FullBinaryTree(4).getRoot();
// 创建Canvas渲染器
const render = new CanvasRender(document.body);
// 创建树的绘制器
const drawer = new TreeDrawer(render);
// 绘制二叉树
drawer.draw(root);
		

此示例创建一个深度为3 的完全二叉树,并使用canvas将其绘制 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值