遍历
数组的遍历
for/while
有进无出,所以只有前序位置。只适用于元素是固定的情况。
1 2 3 4 5 6 | // 数组的while/for遍历 function arr_traverse(arr){ for ( let i=0; i<arr.length; i++){ console.log(arr[i]); // 前序位置 } } |
递归
拥有后序位置,能回退,所以可以处理选择的情况。
比如,本来可能用for/while遍历的,但后来分析发现到达i=3时,可能出现多种情况的选择,需要每一种情况都去尝试一下,此时就可以用递归的遍历来解决。
1 2 3 4 5 6 7 8 9 | // 数组的递归遍历 function arr_traverse(arr, i = 0){ if (i >= arr.length){ return ; } console.log(arr[i]); // 前序位置 arr_traverse(arr, i+1); // 后序位置 } |
链表的遍历
for/while
1 2 3 4 5 6 | // 链表的while/for遍历 function link_traverse(root){ for ( let p = root; !!p; p = root.next){ console.log(p.val); // 前序位置 } } |
递归
1 2 3 4 5 6 7 8 9 | // 链表的递归遍历 function link_traverse(root){ if (!root){ return ; } console.log(root.val); // 前序位置 link_traverse(root.next); // 后序位置 } |
二叉树遍历
for/while迭代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | // 二叉树的for/while迭代前序遍历 function twotree_traverse(root) { if (root == null ) return ; let toVisit = [root], cur; while (toVisit.length > 0) { cur = toVisit.pop(); // 前序位置 console.log(cur.val); if (cur.right) toVisit.push(cur.right); // 右节点入栈 if (cur.left) toVisit.push(cur.left); // 左节点入栈 } } // 二叉树的for/while迭代中序遍历 function twotree_traverse(root) { let toVisit = [], cur = root; while (cur || toVisit.length > 0) { while (cur) { // 前序位置 toVisit.push(cur); // 添加根节点 cur = cur.left; // 循环添加左节点 } cur = toVisit.pop(); // 当前栈顶已经是最底层的左节点了,取出栈顶元素,访问该节点 // 中序位置 console.log(cur.val); cur = cur.right; // 添加右节点 } } // 二叉树的for/while迭代后序遍历 function twotree_traverse(root) { let toVisit = [], cur = root, pre = null ; while (cur || toVisit.length > 0) { while (cur) { toVisit.push(cur); // 添加根节点 cur = cur.left; // 循环添加左节点 } cur = toVisit[toVisit.length - 1]; // 已经访问到最左的节点了 //在不存在右节点或者右节点已经访问过的情况下,访问根节点 if (!cur.right || cur.right === pre) { toVisit.pop(); // 后序位置 console.log(cur.val); pre = cur; cur = null ; } else { cur = cur.right; // 右节点还没有访问过就先访问右节点 } } } |
递归
1 2 3 4 5 6 7 8 9 10 11 | // 二叉树的递归遍历 function twotree_traverse(root){ if (!root){ return ; } console.log(root.val); // 前序位置 twotree_traverse(root.left); console.log(root.val); // 中序位置 twotree_traverse(root.right); console.log(root.val); // 后序位置 } |
对于数组表示的完全二叉树的结构: arr = ['c', null, 'd', 'k', 'u', null, 'i', ...]
层序遍历,直接就是正序遍历arr数组
对于深度优先的遍历,不管是迭代法还是递归法,都可以用前面的方法。因为根节点已知为0,对于任一节点i,其子节点为 2*i+1 和 2*i+2。
多叉树的遍历
递归
1 2 3 4 5 6 7 8 9 10 11 | // 多叉树的遍历 function nTree_traverse(root){ if (!root){ return ; } root.children.forEach(child=>{ // 遍历该节点的所有子元素 // 前序位置 nTree_traverse(child); // 后序位置 }); } |
for/while迭代的前序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 多叉树的dsf前序遍历 function nTree_traverse(root) { let q = [root]; while (q.length > 0) { let node = q.pop(); if (!node){ continue ; } // 在这里输出 console.log(node.val); for ( let i = node.children.length - 1; i > -1; i--) { // 注意,这里是倒序遍历 let child = node.children[i]; q.push(child); } } } |
for/while迭代的后序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // 多叉树的dsf后序遍历 function nTree_traverse(root) { let q = [root], result = []; while (q.length > 0) { let node = q.pop(); if (!node) { continue ; } // 记录到一个中间数组中 result.push(node); // 注意,这里是放到最前面 for ( let i = 0; i < node.children.length; i++) { // 注意,这里是正序遍历 let child = node.children[i]; q.push(child); } } for ( let i = result.length - 1; i > -1; i--) { // 这里倒序遍历 // 在这里输出 console.log(node.val); } } |
for/while迭代bsf遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // 多叉树的bsf遍历 function nTree_traverse(root) { let q = [root]; while (q.length > 0) { let newQ = []; for ( let i = 0; i < q.length; i++) { let node = q[i]; if (!node) { continue ; } // 在这里输出 console.log(node.val); node.children.forEach(child => { // 遍历该节点的所有子元素 newQ.push(child); }); } q = newQ; } } |
图的遍历
无向图中如果没有环存在,则这个图等价于一棵或多棵树(也就是说,任意一个图,只要去掉其所有的环,就是N(n>=1)棵树)
而如果将一棵树中的两节点连接,就能得到环,这样就是一个图了。
所以图相比于树,最主要的就是可能多了些环而已。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 图的遍历 let visited = {}; function graph_traverse(root){ if (!root){ return ; } if (visited[root.id]){ // 防止进入环,产生死循环(如果已经知道图中没有环,就可以不要这个判断) return ; } visited[root.id] = true ; // 标记已经遍历 root.children.forEach(child=>{ // 遍历该节点的所有子元素 // 前序位置 nTree_traverse(child); // 后序位置 }); } |
d
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?