1. 程式人生 > >左右值無限分類 預排序遍歷樹演算法:modified preorder tree traversal algorithm

左右值無限分類 預排序遍歷樹演算法:modified preorder tree traversal algorithm

介紹:
什麼是左右值無限級分類:
左右值無限級分類,也稱為預排序樹無限級分類,是一種有序的樹狀結構,位於這些樹狀結構中的每一個節點都有一個“左值”和“右值”,其規則是:每一個後代節點的左值總是大於父類,右值總是小於父級,右值總是小於左值。處於這些結構中的每一個節點,都可以輕易的算出其祖先或後代節點。因此,可以用它來實現無限分類。
左右值無限分類的優缺點:
優點:
通過一條SQL就可以獲取所有的祖先或後代,這在複雜的分類中非常必要
通過簡單的四則運算就可以得到後代的數量
缺點
分類操作麻煩

無法簡單的獲取子代(請看請“子代”和"後代")


1. 測試資料準備

CREATE TABLE `nested_category` (
  `category_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  `name` varchar(18) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '名稱',
  `lft` int(4) NOT NULL,
  `rgt` int(4) NOT NULL,
  KEY `category_id` (`category_id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO `nested_category` VALUES 
(1,'商品',1,26),
(2,'化妝品',2,7),
(3,'食品',8,9),
(4,'酒',10,15),
(5,'服裝',16,17),
(6,'家電',18,23),
(7,'鞋帽',24,25),
(8,'面霜',3,4),
(9,'面膜',5,6),
(10,'白酒',11,12),
(11,'紅酒',13,14),
(12,'冰箱',19,20),
(13,'空調',21,22);

資料檢視
mysql> select * from nested_category;
+-------------+-----------+-----+-----+
| category_id | name      | lft | rgt |
+-------------+-----------+-----+-----+
|           1 | 商品    |   1 |  26 |
|           2 | 化妝品 |   2 |   7 |
|           3 | 食品    |   8 |   9 |
|           4 | 酒       |  10 |  15 |
|           5 | 服裝    |  16 |  17 |
|           6 | 家電    |  18 |  23 |
|           7 | 鞋帽    |  24 |  25 |
|           8 | 面霜    |   3 |   4 |
|           9 | 面膜    |   5 |   6 |
|          10 | 白酒    |  11 |  12 |
|          11 | 紅酒    |  13 |  14 |
|          12 | 冰箱    |  19 |  20 |
|          13 | 空調    |  21 |  22 |
+-------------+-----------+-----+-----+

2. 插入分類思路

分析一下兩種情況:
插入最頂級節點:它的左右值與該樹中最大的右值有關:左值=最大右值+1,右值=最大右值+2,你可以自己模擬一下;
插入子節點:它的左右值與它的父級有關:左值=父級的右值,右值=當前的左值+1,這時要更新的資料有:父級的右值,所有左值大於父級左級,右值大於低階右值的節點左右值都應該+2;
下載例項

3. 獲取所有的後代節點

從圖中可以看出找出某個節點的所有子節點,lft 大於左值 rgt 小於右值

select * from nested_category where lft > 18 and rgt < 23;
+-------------+--------+-----+-----+
| category_id | name   | lft | rgt |
+-------------+--------+-----+-----+
|          12 | 冰箱 |  19 |  20 |
|          13 | 空調 |  21 |  22 |
+-------------+--------+-----+-----+
2 rows in set (0.00 sec)
4. 計算所有子類的數量

有人認為使用 count 配合上面的語句就可以算出,這當然是可以的,但有更快的方式:每有子類節點中每個節點佔用兩個值,而這些值都是不一樣且連續的,那些就可以計算出子代的數 量=(右值-左值-1)/2。減少1的原因是排除該節點,你可以想像一個,一個單節點,左值是1,右值是2,沒有子類節點,而這時它的右值-左值=1.

5. 檢索單一路徑

方法:通過上述結果可以發子類的lft,rgt 都可以父類的lft,rgt之前

select 
	parent.name,
	parent.category_id, 
	parent.lft,
	parent.rgt
from 
	nested_category as node, nested_category as parent 
where 
	node.lft between parent.lft and parent.rgt and node.name = '空調' 
	order by parent.lft;

+--------+-------------+-----+-----+
| name   | category_id | lft | rgt |
+--------+-------------+-----+-----+
| 商品 |           1 |   1 |  26 |
| 家電 |           6 |  18 |  23 |
| 空調 |          13 |  21 |  22 |
+--------+-------------+-----+-----+
3 rows in set (0.00 sec)
6. 檢索所有葉子節點

檢索出所有的葉子節點,使用巢狀集合模型的方法比鄰接表模型的LEFT JOIN方法簡單多了。如果你仔細得看了nested_category表,你可能已經注意到葉子節點的左右值是連續的。要檢索出葉子節點,我們只要查詢滿足rgt=lft+1的節點:

select 
	*
from 
	nested_category
where rgt = lft + 1;
+-------------+--------+-----+-----+
| category_id | name   | lft | rgt |
+-------------+--------+-----+-----+
|           3 | 食品 |   8 |   9 |
|           5 | 服裝 |  16 |  17 |
|           7 | 鞋帽 |  24 |  25 |
|           8 | 面霜 |   3 |   4 |
|           9 | 面膜 |   5 |   6 |
|          10 | 白酒 |  11 |  12 |
|          11 | 紅酒 |  13 |  14 |
|          12 | 冰箱 |  19 |  20 |
|          13 | 空調 |  21 |  22 |
+-------------+--------+-----+-----+
9 rows in set (0.01 sec)
7. 獲取分類的深度
select 
	node.name as name,  (count(parent.name) - 1) as deep
from 
	nested_category as node,
	nested_category as parent
where node.lft between parent.lft and parent.rgt
group by node.name
order by node.lft
+-----------+------+
| name      | deep |
+-----------+------+
| 商品    |    0 |
| 化妝品 |    1 |
| 面霜    |    2 |
| 面膜    |    2 |
| 食品    |    1 |
| 酒       |    1 |
| 白酒    |    2 |
| 紅酒    |    2 |
| 服裝    |    1 |
| 家電    |    1 |
| 冰箱    |    2 |
| 空調    |    2 |
| 鞋帽    |    1 |
+-----------+------+
13 rows in set (0.03 sec)
8. 檢索節點的直接子節點

可以想象一下,你在零售網站上呈現電子產品的分類。當用戶點選分類後,你將要呈現該分類下的產品,同時也需列出該分類下的直接子分類,而不是該分類下的全部分類。為此,我們只呈現該節點及其直接子節點,不再呈現更深層次的節點
如上述獲取深度的例子,可以根椐深度來小於等於1獲得直接子節點

select * from (
	select 
		node.name as name,  
		(count(parent.name) - 1) as deep 
	from 
		nested_category as node,
		nested_category as parent 
	where node.lft between parent.lft and parent.rgt 
	group by node.name 
	order by node.lft
) as a where a.deep <= 1; 
+-----------+------+
| name      | deep |
+-----------+------+
| 商品    |    0 |
| 化妝品 |    1 |
| 食品    |    1 |
| 酒       |    1 |
| 服裝    |    1 |
| 家電    |    1 |
| 鞋帽    |    1 |
+-----------+------+
7 rows in set (0.00 sec)
9. 刪除分類
刪除分類是基礎操作,刪除分類的處理過程跟節點在分層中所處的位置是有關,在刪除時需要考慮兩種情況,1 刪除單個的葉子分類  2 刪除子節點  相對而言刪除單個的葉子分類比較簡單,
就好比新增的逆過程,我們刪除節點的同時該節點右邊所有的左右值和該父節點的右值都會減去該節點的寬度值
lock table nested_category write;
select @myleft := lft, @myright := rgt, @mywidth := rgt-lft+1 from nested_category where name = '家電';
delete from nested_category where lft between @myleft and @myright;
update nested_category set lft = lft - @mywidth where rgt > @myright
update nested_category set rgt = rgt - @mywidth where lft > @myright
unlock tables;

轉載請註明來源:http://blog.csdn.net/i_bruce/article/details/41558063

相關推薦

左右無限分類 排序演算法modified preorder tree traversal algorithm

介紹: 什麼是左右值無限級分類:左右值無限級分類,也稱為預排序樹無限級分類,是一種有序的樹狀結構,位於這些樹狀結構中的每一個節點都有一個“左值”和“右值”,其規則是:每一個後代節點的左值總是大於父類,右值總是小於父級,右值總是小於左值。處於這些結構中的每一個節點,都可以輕易

資料庫設計 採用左右編碼來儲存無限分級樹形結構_2 排序演算法modified preorder tree traversal algorithm

預排序遍歷樹演算法 更新操作:先講述筆者那時候的思路 筆者最初的方法是:偽刪除後偽插入 先更新該節點為根整個樹以外的節點左右值資料(筆者稱之偽刪除) 再更新該節點為根整個樹左右值資料(筆者稱之偽插

C#泛型效能進階之(排序後輸出元素

而foreach語句是通過迭代變數來列舉集合的元素,為集合的每個元素執行嵌入語句。也就是說,foreach語句是通過迭代變數在集合內對其自身的引用來實現遍歷的,ArrayList類列表同樣是通過物件值引用來實現的。 而這也是稱之為強型別的原因,因為在編譯時沒有辦法告訴我們列表中資料的實際型別

資料結構實驗-C語言-二叉的建立,前、中、後序遍歷的遞迴演算法和非遞迴演算法,求葉子結點數目,求二叉深度,判斷二叉是否相似,求二叉樹左右互換,二叉層序遍歷演算法,判斷二叉是否是完全二叉

1.實驗目的 熟練掌握二叉樹的二叉連結串列儲存結構的C語言實現。掌握二叉樹的基本操作-前序、中序、後序遍歷二叉樹的三種方法。瞭解非遞迴遍歷過程中“棧”的作用和狀態,而且能靈活運用遍歷演算法實現二叉樹的其它操作。 2.實驗內容 (1)二叉樹的二叉連結串列的建立 (2)二叉樹的前、中、後

陣列的分類,定義和技巧

  一、陣列分類   1.陣列是由一組有序的值或鍵值對組成的資料結構   2.陣列根據鍵名型別分為:索引陣列 與 關聯陣列 二大類   3.索引陣列:鍵名是元素的位置索引,預設從0開始,採用系統自動處理可以省略鍵名   4.關聯陣列:鍵名是自定義的字

python 其他.py 與tkinter介面傳的方法(以資料夾進度為例)

本小白沒深入瞭解過python的原理,多個檔案只知道在一個.py檔案裡import另一個.py檔案但是問題來了 ,帶著介面的被import後會又多出來一個視窗! 就算是呼叫一下函式都會再彈出一個介面!於是,經過不斷嘗試我分享一下我的方法……(本小白還沒用到類)本人做了一個小工

動態二維數組賦及for循環和toString

nbsp pub for循環 () pac i++ static pri package package com.Summer_0421.cn; import java.util.Arrays; /** * @author Summer * 動態二維

POJ 1849 Two()

bold cost spa align div col sizeof 最小 turn POJ 1849 Two(遍歷樹) http://poj.org/problem?id=1849 題意: 有一顆n個結點的帶權的無向樹, 在s結點放兩個機器人,

js39---組合模式,查找

arr div composite ini 2個 需求 沒有 error nts /** *有這樣一個需求 *有一個學校有2個班(一班,二班) *每個班級分2個小組(一班一組,一班二組,二班一組,二班二組) *學校計算機教室有限,每一個小組分著來上課. *考試的

前序和中序構造二叉

fin traversal dtree 構造二叉樹 div integer break param val 根據前序遍歷和中序遍歷樹構造二叉樹 樣例: 給出中序遍歷:[1,2,3]和前序遍歷:[2,1,3]. 返回如下的樹: 2 / \ 1 3 我們知道前序遍歷

根據中序和後序構造二叉

eno build 中序遍歷樹 oot post rsa uil cnblogs 找到 根據中序遍歷和後序遍歷樹構造二叉樹 樣例: 給出樹的中序遍歷: [1,2,3] 和後序遍歷: [1,3,2] 返回如下的樹: 2 / \ 1 3 借鑒上一篇《前序遍歷和中序遍

組合模式(

用戶 麻煩 -- 層次 沒有 結構型 類型 葉子節點 對待 組合模式多個對象形成樹形結構以表示“整體--部分”的結構層次。組合模式對單個對象(即葉子對象)和組合對象(即容器對象)的使用具有一致性。 組合模式又可以稱為“合成模式“ 或 ”整體-部

圖的算法DFS、BFS

TE 需要 rst ash 圖的遍歷 目標 detail 基礎篇 中一 在圖的基本算法中,最初需要接觸的就是圖的遍歷算法,根據訪問節點的順序,可分為深度優先搜索(DFS)和廣度優先搜索(BFS)。 DFS(深度優先搜索)算法 Depth-First-Search 深度優先算

72 中序和後序構造二叉

實的 dong scrip size turn -c -h red 左右子樹 原題網址:https://www.lintcode.com/problem/construct-binary-tree-from-inorder-and-postorder-traversal/d

(原始碼,具體的細節請查閱相關資料)哈弗曼的構造以及非遞迴

  寫了一點haffman樹的建立和二叉樹的非遞迴遍歷. 如果編寫程式碼的時候出現了,思維斷點,可以借鑑一下, 避免浪費一些不必要的時間. 我是佔位符我是佔位符我是佔位符我是佔位符我是佔位符我是佔位符我是佔位符我是佔位符我是佔位符我是佔位符我是佔位符我是佔

【資料結構週週練】016 利用遞迴演算法及孩子兄弟表示法建立並求的深度

一、前言 從今天起,就給大家分享一些樹的程式碼啦,不僅僅是二叉樹,我們要弄明白,普通的樹用資料結構怎麼儲存,它有哪些操作,它可以實現哪些功能? 可能大家要問了,二叉樹不是還沒有寫完嗎,線索二叉樹呢?二叉排序樹呢?平衡二叉樹呢?大家不要急,我們通過二叉樹來入門樹的演算法及程式碼實現,然後學

實戰c++中的vector系列--vector的(stl演算法、vector迭代器(不要在迴圈中判斷不等於end())、operator[])【轉】

(轉自:https://blog.csdn.net/wangshubo1989/article/details/50374914?utm_source=blogxgwz29) 遍歷一個vector容器有很多種方法,使用起來也是仁者見仁。 通過索引遍歷: for (i = 0; i<

前中後序遞迴的體會 with Python

前序:跟->左->右 中序:左->根->右 後序:左>右->根 採用遞迴遍歷時,編譯器/直譯器負責將遞迴函式呼叫過程壓入棧並保護現場,在不同位置處理根節點即可實現不同順序的遍歷。 import Tree def preOrderTraversa

16_資料結構與演算法_(前序、中序、後序)_Python實現

#Created By: Chen Da #定義一個二叉樹的類 class Binary_Tree(object): def __init__(self,root): self.key = root self.left_child = None

資料結構篇圖的(二廣度優先

廣度優先遍歷,又稱廣度優先搜尋,縮寫BFS 如果說深度優先遍歷是相當於樹的前序遍歷,那麼,廣度優先遍歷就相當於樹的層序遍歷。 以上面那張圖為例就是,ABFCIGEDH 程式碼實現 void AdjacencyList::BFSTraverse(GraphAdjList *G