最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

非遞歸分類樹

2023-08-01 18:18 作者:通略  | 我要投稿

分類樹這種結(jié)構(gòu)存在于頁面菜單、行政區(qū)劃、部門層級(jí)、用戶組等場景中,特點(diǎn)是有明確的上下級(jí)覆蓋關(guān)系,本質(zhì)數(shù)據(jù)結(jié)構(gòu)是N叉樹。

一、基礎(chǔ)實(shí)現(xiàn)

分類樹的基礎(chǔ)實(shí)現(xiàn)是遞歸查詢。在數(shù)據(jù)表中增加一個(gè)pid字段,儲(chǔ)存當(dāng)前記錄的上級(jí)id。通過遞歸查詢pid的方法將子節(jié)點(diǎn)集合從數(shù)據(jù)表中查出來放入children列表中,通過這種方式建成一棵樹。

二、優(yōu)化基礎(chǔ)實(shí)現(xiàn)

遞歸查詢建立分類樹的方式有查詢擴(kuò)散問題,就是不知道遞歸深度有多少,數(shù)據(jù)庫交互次數(shù)無法控制。針對(duì)這個(gè)問題,后來又出現(xiàn)了添加樹深度字段deep、添加樹路徑字段path等方法,通過冗余字段來降低分類樹的使用難度。

但是冗余字段造成一個(gè)問題——修改擴(kuò)散。例如當(dāng)分類樹中的一條記錄被修改,其深度發(fā)生變化時(shí),那么它的子節(jié)點(diǎn)深度也會(huì)發(fā)生變化,它子節(jié)點(diǎn)的子節(jié)點(diǎn)深度亦發(fā)生變化,路徑字段也是同理。一個(gè)修改導(dǎo)致多個(gè)修改,進(jìn)而導(dǎo)致更多修改,其最終修改范圍無法控制,可能遍布全表,這就是修改擴(kuò)散。

三、非遞歸實(shí)現(xiàn)

遞歸查詢會(huì)發(fā)生查詢擴(kuò)散、修改擴(kuò)散。我意在構(gòu)想一種算法,構(gòu)建樹的查詢次數(shù)與樹深度無關(guān),修改擴(kuò)散范圍可控,不會(huì)無限波及。

遞歸的層數(shù)是無法預(yù)知的,所以我放棄用遞歸實(shí)現(xiàn)。

首先,我構(gòu)造這樣的一個(gè)表,除節(jié)點(diǎn)本身信息之外,其結(jié)構(gòu)信息有主鍵id、子節(jié)點(diǎn)主鍵集合children、祖先節(jié)點(diǎn)主鍵集合ancestors。子節(jié)點(diǎn)主鍵集合children我采用Set避免重復(fù)。

在這里,我劃分分類樹為兩類,一類是葉子只有唯一父節(jié)點(diǎn)的singleTree,一類是子節(jié)點(diǎn)允許多個(gè)父節(jié)點(diǎn)的crossTree。singleTree的祖先節(jié)點(diǎn)主鍵集合ancestors我采用List,以便記錄其順序,此時(shí)ancestors可以當(dāng)作路徑path用。crossTree的祖先節(jié)點(diǎn)主鍵集合ancestors我采用Set,因其多父節(jié)點(diǎn)有可能會(huì)有同一源頭,采用Set去重。crossTree的優(yōu)勢在于,相同節(jié)點(diǎn)不必重復(fù)創(chuàng)建,可以復(fù)用節(jié)點(diǎn),例如指向同一個(gè)頁面的菜單項(xiàng)可以同時(shí)掛在不同的父菜單下,該菜單項(xiàng)地址修改時(shí)只需修改該項(xiàng),不必像singleTree同名菜單項(xiàng)全部去改一遍。除此之外兩類分類樹使用是非常相似的。

children、ancestors兩個(gè)字段,在數(shù)據(jù)庫中用表示數(shù)組的字符串存儲(chǔ),其格式形如:[]或["id1","id2"]。

現(xiàn)在,我詳細(xì)解釋如何解決上面提到的查詢擴(kuò)散、修改擴(kuò)散問題。

1、查詢擴(kuò)散

查詢之所以會(huì)擴(kuò)散,是因?yàn)闊o法穿透查詢隔代節(jié)點(diǎn)。

但是現(xiàn)在向下查詢各節(jié)點(diǎn)都有ancestors字段記錄全部祖先,通過ancestors like '%"rootId"%'就可以一次性查到所有子孫節(jié)點(diǎn)的列表,不論子孫節(jié)點(diǎn)跟查詢節(jié)點(diǎn)隔了幾代。

向上查詢的話,查詢節(jié)點(diǎn)的ancestors字段本身就記載了所有關(guān)聯(lián)的祖先,不會(huì)擴(kuò)散到此范圍之外。

2、修改擴(kuò)散

將一個(gè)新節(jié)點(diǎn)node插入樹中時(shí),首先取得插入點(diǎn)的父節(jié)點(diǎn)parent。新節(jié)點(diǎn)的ancestors字段,就是parent.ancestors以及parent.id,這是singleTree的情況。如果是crossTree且node.ancestors原來就有內(nèi)容,即還掛在別的父節(jié)點(diǎn)下,那除了parent.ancestors和parent.id之外,還要再加上node.ancestors原有內(nèi)容,其是Set會(huì)自動(dòng)去重。接著在parent.children集合中添加node自身id。

接著,根據(jù)node.children取得所有直接子節(jié)點(diǎn),以及直接子節(jié)點(diǎn)的所有子孫節(jié)點(diǎn)。這次查詢的結(jié)果列表就是所有ancestors字段需要修改的范圍。在所有子孫節(jié)點(diǎn)的祖先主鍵集合ancestors中,添加node.ancestors以及node.id。

修改、刪除節(jié)點(diǎn)也是同理。

綜上,修改一個(gè)節(jié)點(diǎn),所要關(guān)聯(lián)修改的所有其他記錄為其父節(jié)點(diǎn)、滿足ancestors like '%"nodeId"%'的節(jié)點(diǎn),不會(huì)擴(kuò)散到此范圍之外。

四、優(yōu)化非遞歸實(shí)現(xiàn)

以上實(shí)現(xiàn)因?yàn)槭褂昧薼ike條件,在表規(guī)模較小時(shí)尚無問題,規(guī)模大了就有可能出現(xiàn)查詢性能問題,因?yàn)閘ike條件中的id不確定位于字符串何處,無法使用索引。

既然如此,當(dāng)表規(guī)模膨脹了,可以將children字段和ancestors字段改為兩個(gè)新表記錄這兩種關(guān)聯(lián)關(guān)系,對(duì)childrenId和ancestorsId建立索引。這種改造對(duì)非樹形表也同樣可行,不需要修改原表結(jié)構(gòu)。


非遞歸分類樹的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
江油市| 射洪县| 焦作市| 二连浩特市| 宁乡县| 潼关县| 饶阳县| 漯河市| 鱼台县| 白朗县| 大化| 罗源县| 登封市| 封丘县| 巨野县| 武夷山市| 晋江市| 兰西县| 望都县| 抚松县| 星子县| 如皋市| 福建省| 丰原市| 宣汉县| 新龙县| 辉县市| 县级市| 图们市| 集贤县| 蓝山县| 林西县| 亚东县| 将乐县| 泰安市| 平度市| 阿合奇县| 惠来县| 南涧| 沂源县| 弥渡县|