/** * Definition for a binary tree node. * function TreeNode(val, left, right) { * this.val = (val===undefined ? 0 : val) * this.left = (left===undefined ? null : left) * this.right = (right===undefined ? null : right) * } */ /** * @param {TreeNode} root * @return {number} */ const countNodes = function (root) { }; /* 思路:以任何方式遍历一遍,统计个数 */ function f1(root) { let count = 0; // 中序遍历递归函数 const inTarverse = (node) => { // 如果root为空直接返回 if (!node) return; // 调用左子树 inTarverse(node.left); // 统计当前节点 count++; // 调用右子树 inTarverse(node.right); }; inTarverse(root); return count; } /* 除了遍历所有节点统计个数,还可以利用完全二叉树个数与位置的关系通过二分查找来判断节点的个数,分为两步, 第一步:首先获得这棵完全二叉树的高度,通过高度我们可以判断一颗完全二叉树的节点数量范围[2^n, 2^n - 1]个节点 第二步:节点个数的二进制和位置右某种关系,[1,2,3],来看这个例子,首先根节点,也就是第一个节点,那么它的二进制就是 1,再来看第二个,2,二进制位10,3,位11,这还不够明显再加四个数[1,2,3,4,5,6,7],4->100,5->101,6->110,7->111,这个规律就是 二进制位决定了这个节点从根节点到这个位置的路径,7->111,第一个1表示的是根节点,第二个1表示这个节点在根节点的右子树,第三个1 表示的是在更节点的右节点的右节点。 过程,编写一个exists 判断指定位置的节点是否在root中存在,接收三个参数,根节点root,树的高度,指定要判断的节点 */ /** * * @param {*} root 根节点 * @param {*} h 完全二叉树的高度 * @param {*} k 最后一层的某一个节点 [2^n, 2^n - 1] */ const exists = (root, h, k) => { // 初始bits位 1 << (h-1),假设h是3,那么默认值位100,如果我们要查找第12个数是否存在就可以通过 1100 & 0100来 // 判断是在右子树还是在左子树 let bits = 1 << (h - 1); let node = root; while (bits) { if (bits & k) { // bits&k不等于0表示这个节点应该往右子树查找 node = root.right; } else { // 反之在左子树 node = root.left; } bits >>= 1; } // 判断node是否等于空 return node === null; }; function f2(root) { if (!root) return 0; // 查找树的深度 let h = 0; let node = root.left; while (node) { h++; node = node.left; } // 通过树的深度计数出数量的范围 low和high let low = 2 ** h; let high = 2 ** (h + 1) - 1; // 二分查找,知道low===high结束查找, 以h=3来思考[8,15] while (low < high) { // 计数出中间位置 const mid = low + Math.floor((high - low) / 2); if (exists(root, h, mid)) { // 如果这个树存在,那么节点个数大于等于这个数,将左边界移动到mid low = mid; } else { high = mid - 1; } } // 此时low和high会相等,这个位置就是二叉树的个数 return low; }