在一個樹型結構資料中,查詢相鄰有相同屬性的節點的最大數量的方法
本文介紹的是一個在一個樹型資料結構中,查詢 type 屬性均為 a 的相鄰節點的最長鏈路的節點數量,如果中間有任何其他節點插在其中,那這個長度就結束了,必須是相鄰的。一個最簡單的示例就是在一個樹型結構中,有兩個節點要進行連線,但是連線的節點如果都是 type 為 a 的話,則最長不能超過5個,超過五個則節點不能進行連線。
如下圖:
在進行節點之間的連線時,如過相鄰的節點 type 屬性均為 a 的超過五個就不能連線。假設上圖的節點都有 type 屬性,且都為 a ,則在連線時 2.1 節點是可以和 3.1 節點連線的,而 2.3 是不能和 3.3 進行連線的,因為連線後,最長的到了 6.1 節點,長度超過了 5 個。5.1後面也不能來連線其他 type 為 a 的節點了。那要怎麼判斷在進行連線時這個長度是否超過 5 個,這就是本文要介紹的內容,一個演算法,但是是有前提條件的。
首先這些節點上要有這些資訊:這個節點的 ID、它父節點的 ID、它子節點的 ID;每個節點都有 type 屬性,標記這個節點是什麼節點;有方法可以獲取所有節點的資訊,方便通過 ID 進行查詢。
有人會說,那該怎麼獲取所有節點的資訊呢?其實只要在建立時,把節點的資訊儲存在一個物件中即可,以 ID 作為 key,以其資訊作為 key值;
如下物件中表示:
const nodes = { ... //還有其他節點資訊 id21: { nodeId: id21, type: 'a', parentNodeIds: { id11: true, id12: true, }, childNodeIds: { id31: true, id32: true, }, }, ... //還有其他節點資訊 }
nodes 裡儲存著在建立時每個節點的一些資訊,在有改動(連線、斷開連線、刪除)操作時,同時進行資料的修改,則可以通過 nodes 來很方便的獲得所有節點的連線資訊、type 資訊及其他儲存在其中的資訊。之後再連線節點時候就可以直接獲取到節點的 type 型別了。
只有查詢相鄰的 type 屬性均為某一值的節點總數的時侯才能用這個方法,當然,查詢的思路也可以用到別的地方,看各位的腦洞了。
先說下思路,在連線時,我們可以先判斷所連線的兩個節點是不是都是 type 為 a,只有都是為 a 的情況下,才有進行後續計算的必要;之後分為向上查詢所連線的相鄰的 type 為 a 的節點組成的最長鏈路層數是幾;還有就是向下查詢所連線的相鄰的 type 為 a 的節點組成的最長鏈路層數是幾;之後通過這兩個值來判斷長度是否有超過 5 個。這就是進行編寫程式碼的一個思路了。
向上與向下查詢所用的思路是一樣的,都是先查詢該節點的所有子節點的型別 type,將 type 為 a 的節點 ID 記錄一下,再將這些子節點的所有子節點都取出來,以作下次運算。這裡要用到遞迴了,遞迴的結束條件就是子節點的 type 型別沒有一個是 a,則遞迴結束了。
直接上虛擬碼:
function statisticalNodeNumber(node1, node2) { const type1 = node1.type; const type2 = node2.type; if (type1 === 'a' && type2 === 'a') { const beforeNum = statisticalBeforeNodeNumber([node1.nodeId], 0); const nextNum = statisticalNextNodeNumber([node2.nodeId], 0); return beforeNum + nextNum > 5; } } function statisticalNextNodeNumber(nodeIds, num) { let total = num; let nodeTypeIsA = []; let childNodeIds = []; const nodes = nodes; // 獲取所有節點資訊的方法或物件 nodeIds.forEach((val) => { const type = nodes[val].type; if (type === 'a') { // 如果type為a的話,則儲存到陣列 nodeTypeIsA 中,之後判斷陣列 nodeTypeIsA 是否長度為0 // 如果不為0則表示這一層級中有節點 type 為 a,則總數可加一,再取出所有type為a的節點的子 // 節點進行下一輪計算,直到該層級中沒有 type 為 a 的節點為止 nodeTypeIsA.push(val); const n = nodes[val].childNodeIds ? Object.keys(nodes[val].childNodeIds) : []; childNodeIds = [...childNodeIds, ...n]; } }); if (nodeTypeIsA.length === 0) { return total; } ++total; return statisticalNextNodeNumber(childNodeIds, total); } function statisticalBeforeNodeNumber(nodeIds, num) { let total = num; let nodeTypeIsA = []; let beforeNodeIds = []; const nodes = nodes; // 獲取所有節點資訊的方法或物件 nodeIds.forEach((val) => { const type = nodes[val].type; if (type === 'a') { nodeTypeIsA.push(val); const n = nodes[val].parentNodeIds ? Object.keys(nodes[val].parentNodeIds) : []; beforeNodeIds = [...beforeNodeIds, ...n]; } }); if (nodeTypeIsA.length === 0) { return total; } ++total; return statisticalNextNodeNumber(beforeNodeIds, total); }
上面兩個函式最重要想法就是按照層級去查詢,只有該層級中有 type 為 a 時,則數量加 1,並只對 type 為 a 的節點的子節點進行後續的計算。所以就可以查出在兩個節點相連時,相鄰的節點type為a的最長數量是多少。
以上就是這次分享的內容,希望對大家有所幫