摘要:面試中,經(jīng)常遇到的一個簡單算法題查找兩個單鏈表的公共節(jié)點最近在讀源碼的時候發(fā)現(xiàn)一個樹中對該算法的運用見函數(shù),在此做簡單的記錄。地址在樹中獲取當前實例節(jié)點的父節(jié)點實例組件對應(yīng)的,比如的表示為類組件,其為對應(yīng)元素。
面試中,經(jīng)常遇到的一個簡單算法題:查找兩個單鏈表的公共節(jié)點
最近在讀react源碼的時候發(fā)現(xiàn)一個react樹中對該算法的運用(見getLowestCommonAncestor函數(shù)),在此做簡單的記錄。
git地址
在react樹中獲取當前實例節(jié)點的父節(jié)點實例
//HostComponent組件對應(yīng)的DOM,比如App的tag=3, 表示為類組件,其child為tag=5對應(yīng)div元素。 function getParent(inst) { do { inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. // That is depending on if we want nested subtrees (layers) to bubble // events to their parent. We could also go through parentNode on the // host node but that wouldn"t work for React Native and doesn"t let us // do the portal feature. } while (inst && inst.tag !== HostComponent); if (inst) { return inst; } return null; }getLowestCommonAncestor
獲取節(jié)點A與B的最近的公共祖先節(jié)點
算法題:找到兩個鏈表的公共節(jié)點
export function getLowestCommonAncestor(instA, instB) { //獲取子節(jié)點A在樹中的深度 let depthA = 0; for (let tempA = instA; tempA; tempA = getParent(tempA)) { depthA++; } //獲取子節(jié)點B在樹中的深度 let depthB = 0; for (let tempB = instB; tempB; tempB = getParent(tempB)) { depthB++; } // If A is deeper, crawl up. // 如果A的高度高,那么A節(jié)點先往上走depthA - depthB個節(jié)點,最后同時走,直到父節(jié)點是同一個 while (depthA - depthB > 0) { instA = getParent(instA); depthA--; } // 如果B的高度高,那么B節(jié)點先往上走depthB - depthB個節(jié)點,最后同時走,直到父節(jié)點是同一個 // If B is deeper, crawl up. while (depthB - depthA > 0) { instB = getParent(instB); depthB--; } // Walk in lockstep until we find a match. // 現(xiàn)在,指針所處的位置的高度一致,可以同時往上查找,直到找到公共的節(jié)點 let depth = depthA; while (depth--) { if (instA === instB || instA === instB.alternate) { return instA; } instA = getParent(instA); instB = getParent(instB); } return null; }isAncestor
判斷A節(jié)點是否是B節(jié)點的祖先節(jié)點
export function isAncestor(instA, instB) { while (instB) { if (instA === instB || instA === instB.alternate) { return true; } instB = getParent(instB); } return false; }getParentInstance
對getParent的export封裝:
export function getParentInstance(inst) { return getParent(inst); }traverseTwoPhase
對inst及其以上的樹執(zhí)行冒泡捕獲的操作,執(zhí)行fn。類似事件的冒泡捕獲
export function traverseTwoPhase(inst, fn, arg) { const path = []; //將inst的父節(jié)點入棧,數(shù)組最后的為最遠的祖先 while (inst) { path.push(inst); inst = getParent(inst); } let i; //從最遠的祖先開始向inst節(jié)點捕獲執(zhí)行fn for (i = path.length; i-- > 0; ) { fn(path[i], "captured", arg); } //從inst節(jié)點開始向最遠的祖先節(jié)點冒泡執(zhí)行fn for (i = 0; i < path.length; i++) { fn(path[i], "bubbled", arg); } }traverseEnterLeave
當關(guān)注點從from節(jié)點移出然后移入to節(jié)點的時候,在from執(zhí)行執(zhí)行類似移入移出的操作,from節(jié)點
export function traverseEnterLeave(from, to, fn, argFrom, argTo) { const common = from && to ? getLowestCommonAncestor(from, to) : null; const pathFrom = []; while (true) { if (!from) { break; } if (from === common) { break; } const alternate = from.alternate; if (alternate !== null && alternate === common) { break; } pathFrom.push(from); from = getParent(from); } const pathTo = []; while (true) { if (!to) { break; } if (to === common) { break; } const alternate = to.alternate; if (alternate !== null && alternate === common) { break; } pathTo.push(to); to = getParent(to); } //以上代碼將from節(jié)點到from與to節(jié)點的最近公共祖先節(jié)點(不包括公共祖先節(jié)點)push到pathFrom數(shù)組 //以上代碼將to節(jié)點到from與to節(jié)點的最近公共祖先節(jié)點(不包括公共祖先節(jié)點)push到pathTo數(shù)組 // 以下代碼用于對pathFrom冒泡,執(zhí)行fn for (let i = 0; i < pathFrom.length; i++) { fn(pathFrom[i], "bubbled", argFrom); } // 以下代碼用于對pathTo捕獲,執(zhí)行fn for (let i = pathTo.length; i-- > 0; ) { fn(pathTo[i], "captured", argTo); } }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/102128.html
摘要:對于同一層級的一組子節(jié)點,它們可以通過唯一進行區(qū)分。基于以上三個前提策略,分別對以及進行算法優(yōu)化。鏈表的每一個節(jié)點是,而不是在之前的虛擬節(jié)點。是當前層的第一個節(jié)點。再次提醒,是的一層。 文章首發(fā)于個人博客 這是我 Deep In React 系列的第二篇文章,如果還沒有讀過的強烈建議你先讀第一篇:詳談 React Fiber 架構(gòu)(1)。 前言 我相信在看這篇文章的讀者一般都已經(jīng)了解...
摘要:因為版本將真正廢棄這三生命周期到目前為止,的渲染機制遵循同步渲染首次渲染,更新時更新時卸載時期間每個周期函數(shù)各司其職,輸入輸出都是可預測,一路下來很順暢。通過進一步觀察可以發(fā)現(xiàn),預廢棄的三個生命周期函數(shù)都發(fā)生在虛擬的構(gòu)建期間,也就是之前。 showImg(https://segmentfault.com/img/bVbweoj?w=559&h=300); 背景 前段時間準備前端招聘事項...
摘要:異步實戰(zhàn)狀態(tài)管理與組件通信組件通信其他狀態(tài)管理當需要改變應(yīng)用的狀態(tài)或有需要更新時,你需要觸發(fā)一個把和載荷封裝成一個。的行為是同步的。所有的狀態(tài)變化必須通過通道。前端路由實現(xiàn)與源碼分析設(shè)計思想應(yīng)用是一個狀態(tài)機,視圖與狀態(tài)是一一對應(yīng)的。 React實戰(zhàn)與原理筆記 概念與工具集 jsx語法糖;cli;state管理;jest單元測試; webpack-bundle-analyzer Sto...
摘要:目前,前端領(lǐng)域中勢頭正盛,使用者眾多卻少有能夠深入剖析內(nèi)部實現(xiàn)機制和原理。當發(fā)現(xiàn)節(jié)點已經(jīng)不存在,則該節(jié)點及其子節(jié)點會被完全刪除掉,不會用于進一步的比較。 目前,前端領(lǐng)域中 React 勢頭正盛,使用者眾多卻少有能夠深入剖析內(nèi)部實現(xiàn)機制和原理。本系列文章希望通過剖析 React 源碼,理解其內(nèi)部的實現(xiàn)原理,知其然更要知其所以然。 React diff 作為 Virtual DOM 的加速...
showImg(https://segmentfault.com/img/bVbw3tK?w=1240&h=827); 前端工程師這個崗位,真的是反人性的 我們來思考一個問題: 一個6年左右經(jīng)驗的前端工程師: 前面兩年在用jQuery 期間一直在用React-native(一步一步踩坑過來的那種) 最近兩年還在寫微信小程序 下面一個2年經(jīng)驗的前端工程師: 并不會跨平臺技術(shù),他的兩年工作都是Reac...
閱讀 3725·2021-10-12 10:11
閱讀 1992·2019-08-30 15:53
閱讀 1599·2019-08-30 13:15
閱讀 2312·2019-08-30 11:25
閱讀 1810·2019-08-29 11:24
閱讀 1658·2019-08-26 13:53
閱讀 3533·2019-08-26 13:22
閱讀 1776·2019-08-26 10:24