Professional Documents
Culture Documents
cc)
1. Giới thiệu
Bất cứ khi nào chúng ta muốn xây dựng forum, gửi các message từ mail list trên website, viết
CMS: sẽ có một lúc nào đó chúng ta sẽ muốn lưu trữ dữ liệu phân cấp trong 1 database ( trong tài liệu
này dữ liệu phân cấp sẽ được hiểu là : hierarchical data ).
Việc lưu trữ có thể thực hiện thông qua XML ( một kiểu lưu trữ dữ liệu theo kiểu cấu trúc phân
cấp), rất phù hợp với dữ liệu phân cấp. vậy còn đối với table database thì sao, rõ ràng như chúng ta thấy
thì tables không phải là kiểu lưu trữ dữ liệu phân cấp mà nó lưu dưới dạng các mối quan hệ giữa các
bảng => tables chỉ là kiểu flat list.
Vậy thì làm sao chúng ta lưu được dữ liệu kiểu phân cấp trong một table, trong bài hướng dẫn
này chúng ta sẽ cùng tìm ra cách để làm chiện đó )
Lưu trữ dạng cây là một vấn đề hết sức phổ biến với những giải pháp lưu trữ khác nhau. Nhưng
vẫn có 2 cách tiếp cận việc lưu trữ dữ liệu dạng cây mà hay được sử dụng đó là:
+ mô hình danh sách kế cận ( the adjacency list model )
+ thuật toán duyệt cây theo thứ tự đã được định trước đó.
Trong bài hướng dẫn này, chúng ta sẽ khám phá 2 phương pháp trên bằng cách xem xét qua 1 ví
dụ. Dùng cây sau cho ví dụ của chúng ta:
Hoang Nguyen – vietnam_hoangminhnguyen@yahoo.com from http://tech-vnit.tk (or: kattyflea.co.cc)
Như ở bảng trên bạn cũng hình dung được phần nào, trong phương pháp danh sách liền kề.
Chúng ta sẽ lưu 'parent' của mỗi node (như bạn đã thấy cột parent ở trên): “Pear” là một node con của
“Fruit”, “Red” là node con của “Fruit” …
Giải sử trong database của bạn đã lưu như ở trên, bây giờ chúng ta sẽ thực hiện việc lấy dữ liệu
phân cấp ra. Phương pháp như sau: chúng ta sẽ bắt đầu ở node cha ( root node ) và sau đó sẽ lấy các
node con của node cha đó. Đối với mỗi node con, chúng ta lại tiếp tục lấy các node của con của node
con đó và tiếp tục làm như vậy cho tới khi không còn node con nào.... ( chúng ta cũng thấy được ý
nghĩa đệ qui ở đây... )
Ví dụ đoạn code sau sẽ thực hiện việc mô hình danh sách liền kề ( ở đây mình viết bằng php ).
Các bạn có thể dựa vào đó để chuyển qua ngôn ngữ mà bạn sử dụng )
Hoang Nguyen – vietnam_hoangminhnguyen@yahoo.com from http://tech-vnit.tk (or: kattyflea.co.cc)
Cũng tương tự như đoạn code trước, code tìm path chúng ta cũng thực hiện đệ qui ( bởi vậy mà
phương pháp mô hình danh sách gần kề còn được gọi là phương pháp đệ qui như đã nói ở trên )
nếu $node ='Cherry' thì phương thức trên sẽ trả về giá trị $path là một mảng, nó sẽ có dạng như
sau:
Array
(
[0] => Food
[1] => Fruit
[2] => Red
)
Hoang Nguyen – vietnam_hoangminhnguyen@yahoo.com from http://tech-vnit.tk (or: kattyflea.co.cc)
Ở trên chúng ta đã đi qua phương pháp mô hình danh sách kế cận, như các pạn đã thấy thì
phương pháp này đơn giản, dễ hiểu. Nhưng có một điểm bất lợi của phương pháp này đó là nó rất là
chậm ( do chúng ta sử dụng hàm đệ qui và chi phí cho việc query toàn bộ table rất tốn kém tài nguyên )
Hồi nãy chúng ta trình bày cây theo chiều dòng, bây giờ hãy xem xét nó theo hướng chiều
ngang. Đầu tiên bắt đầu ở root node ( 'Food' ) và đánh số thứ tự cho nó là 1. Tiếp theo là đến 'Fruit” và
đánh số cho nó là 2. Bằng cách này, bạn sẽ đi qua các các node và đánh số tương ứng ở mỗi phía của
node đó ..... Số cuối cùng là được viết phía bên phải của node 'Food'. Như hình bên dưới, chúng ta thấy
toàn bộ cây đã được đánh số, và mũi tên tương ứng chỉ thứ tự số đã được gán cho mỗi node
Chúng ta gọi những số này là những số bên trái và số bên phải( ví dụ: số bên trái của 'Food' là 1,
số bên phải của nó là 18 ). Như bạn thấy ở hình trên thì, những số này biểu thị mối quan hệ của mỗi
node. Ví dụ, 'Red' có số 3 và số 6 => chứng tỏ nó là cháu chắt gì đó của node 'Food' ( có giá trị 1 và 18
). Tương tự, chúng ta thấy các số có giá trị bên trái lớn hơn 2 và nhỏ hơn 11 thì sẽ là hậu duệ của 'Fruit'
( vì Fruit có giá trị là 2-11 ). ==> như vậy, cấu trúc cây của chúng ta bây giờ được lưu trữ theo kiểu giá
trị trái và phải.
Hoang Nguyen – vietnam_hoangminhnguyen@yahoo.com from http://tech-vnit.tk (or: kattyflea.co.cc)
Trước khi chúng ta tiếp tục, thì hãy xem bảng giá trị bên dưới:
***note***
các từ 'left' và 'right' có ý nghĩa đặc biệt trong SQL, do đó mà chúng ta phải sử dụng 'lft' và 'rgt' để đánh
tên cho column trong bảng của chúng ta ( tránh trùng với từ khóa của SQL ). Ngoài ra, bây giờ chúng
ta thực sự không cần cột 'parent' nữa. Bây giờ, chúng ta có giá trị 'lft' và 'rgt' để lưu trữ cấu trúc của cây
với một câu query đơn giản, chúng ta dễ dàng thu về dữ liệu mong muốn mà ko cần phải duyệt
qua từng node như trong code php đã làm trước đó ( trong phần ví dụ ở trên )
Công việc còn lại là thực hiện indentation để hiển thị cấu trúc của cây, các node con sẽ được
indent so với node cha của nó. Chúng ta có thể làm việc này bằng cách giữ 1 stack của giá trị bên phải.
Mỗi lần chúng ta bắt đầu một node con của node đó, thì chúng ta phải thêm giá trị bên phải của nó đó
tới stack. Như bạn đã biết thì tất cả các node con của node cha đó đều có giá trị bên pahri nhỏ hơn giá
Hoang Nguyen – vietnam_hoangminhnguyen@yahoo.com from http://tech-vnit.tk (or: kattyflea.co.cc)
trị của node cha, vì vậy bằng cách so sánh giá trị bên phải của node hiện tại với giá trị bên phải của
node trước đó trong stack thì bạn sẽ thấy được sự phân cấp rõ ràng trong cấu trúc cây của chúng.
Các bạn xem đoạn code bên dưới:
Hoang Nguyen – vietnam_hoangminhnguyen@yahoo.com from http://tech-vnit.tk (or: kattyflea.co.cc)
+-------+
| title |
+-------+
| Food |
| Fruit |
| Red |
+-------+
Nhưng pạn yên tâm, với đoạn script đơn giản sau, việc đó sẽ được thực hiện một cách dễ dàng
( với điều kiện là bạn đã có sẵn table, việc tiếp theo là thêm cột left, right và điền giá trị vào cho nó )
Hoang Nguyen – vietnam_hoangminhnguyen@yahoo.com from http://tech-vnit.tk (or: kattyflea.co.cc)
Một điểm bất lợi của phương pháp này đó là update thì chúng ta phải thực hiện update 2 lần
cho 2 giá trị phải và trái tương ứng. Dĩ nhiên, lợi điểm lớn nhất của phương pháp này đó là tốc độ thực
hiện của nó lớn hơn rất nhìu so với phương pháp mô hình danh sách kế cận.
Welcome mọi feedback của các bạn để chúng ta sẽ có một bản full hơn về vấn đề: làm thế
nào để lưu trữ kiểu dữ liệu phân cấp trong table database