/ /(ルートノードには親ノードがありません)if($ row ['parent']!= ''){
$ノードへのパスの最後の部分は、このノードの親へのパスです
/ / / パスへ
$ PATH = Array_Merge (Get_path ($ Row ['Parent']), $ PATH);
?>;
「Cherry」にこの関数を使用する場合: print_r(get_path(' Cherry'))、次のような配列が得られます:
コードをコピーします
コードは次のとおりです:
Array (
[0] => Food
[1] => Fruit
[2] =>レッド
)
希望の形式で印刷する方法はあなた次第です。
欠点:
この方法は非常にシンプルで、理解しやすく、使いやすいです。しかし、いくつかの欠点もあります。主な理由は、実行速度が非常に遅いこと、各ノードでデータベース クエリが必要であること、データ量が多い場合にはツリーを完成させるために多くのクエリが必要になることです。さらに、再帰的な操作が必要なため、再帰の各レベルである程度のメモリを占有する必要があるため、スペースの利用効率は比較的低くなります。
2. プレオーダー ツリー トラバーサル アルゴリズム
次に、再帰計算を使用しない別の高速な方法を見てみましょう。これは、修正されたプレオーダー ツリー トラバーサル アルゴリズムです。この方法は、あまり使われていないかもしれません。初めて使用する場合は、上記の方法ほど理解しにくいですが、この方法は再帰的なクエリ アルゴリズムを使用しないため、クエリ効率が高くなります。
まず次のように紙にマルチレベルデータを描きます。ルートノード「食べ物」の左側に「1」を書き込み、次にツリーを下に進み、「果物」の左側に「2」を書き込み、全体に沿って移動を続けます。ツリーの端には、各ノードの左右に番号が付けられています。最後の数字は Food の右側にマークされた 18 です。下の図では、番号が付けられたマルチレベル構造全体が表示されます。 (わかりませんか?指で数字を指して、1から18まで数えてみるとわかります。それでもわからない場合は、指の動きに注意してもう一度数えてください。)
これらの数字は各ノード間の関係を示しています。「Red」の数字は「Food」1~18の子孫ノードである3と6です。 同様に、左側の値が 2 より大きく、右側の値が 11 未満であるすべてのノードが、「Fruit」2-11 の子孫ノードであることがわかります。以下はコードです:
コードをコピーします コード
1 食品 18. ----------++--------------+
3 赤 6 7 黄 10 13 牛肉 14 15 豚肉 16
4 チェリー 5 8 バナナ 9
これ ツリー構造全体を左右の値とともにデータベースに保存できます。続行する前に、以下の編集されたデータ表を見てみましょう。
コードは次のとおりです:
コードをコピーします
コードは次のとおりです:
+----------+------------+ -----+ -----+
| 親の名前 |+----------+----------+-- ---+-----+| 食品 2 | 6 | |果物 | 7 | 10 | | 肉 12 | 肉 | ----------+------------+-----+-----+
注:
「左」と「右」が使用されているため、 SQL では特別な意味があるため、「lft」と「rgt」を使用して左右のフィールドを表す必要があります。 さらに、この構造ではツリー構造を表すために「親」フィールドは必要なくなりました。つまり、次のようなテーブル構造であれば十分です。
コードは次のとおりです:
コードをコピーします
コードは次のとおりです:
+-----+-----+-----+
| 名前 |
+------ ---- +-----+-----+
| 1 | 11 |
| | 黄色 | 7 |
| 12 | 16 |
| ---+ -----+-----+
さて、これでデータベースからデータを取得できるようになりました。たとえば、「Fruit」項目の下にあるすべてのノードを取得する必要がある場合は、次のようになります。次のようにクエリ ステートメントを記述します:
コードをコピー
コードは次のとおりです:
SELECT * FROM Tree WHERE lft BETWEEN 2 AND 11;このクエリは次の結果を取得しました。 コードは次のとおりです:
コードをコピーします
コードは次のとおりです:
+------------+-----+----- +| 名前 |+-----+-----+|レッド | 3 | 6 || 4 | 8 |
| +-----+
ほら、たった 1 つのクエリでこれらすべてのノードを取得できます。上記の再帰関数のようにツリー構造全体を表示できるようにするには、そのようなクエリを並べ替える必要もあります。ノードの左辺値で並べ替えます:
コードをコピーします
コードは次のとおりです:
SELECT * FROM Tree WHERE lft BETWEEN 2 AND 11 ORDER BY lft ASC;
残りの質問は、次の方法です。レベルのインデントを表示します。 以下はコードです:
コードをコピーします
コードは次のとおりです:
function display_tree($root) {
// の左と右の値を取得します。ルートノード
$result = mysql_query(" SELECT lft , rgt FROM ツリー WHERE name = '" . $root . "' ) ; // ルートポイントのすべての子孫ノードを取得します
$result = mysql_query( 「lft、from from where "" 'lft' ['rgt']。 ($ right) & gt; 0) {
// ノードをスタックから移動する必要があるかどうかを確認します
($ right [count ($ right) - 1] & lt; $ row ['rgt']) {
array_pop
上記の関数を実行すると、再帰関数と同じ結果が得られます。ただ、データベース クエリが 2 つしかないため、新しい関数の方が高速になる可能性があります。
Cherry のパスを知りたい場合は、その左右の値 4 と 5 を使用してクエリを作成する方が簡単です。
コードをコピーしますコードは次のとおりです:
SELECT name FROM Tree WHERE lft < 4 AND rgt > 5 ORDER BY lft ASC;
これにより、次の結果が得られます。以下はコードです:
コードをコピーします コードは次のとおりです:
+---------------------+
|
+----------------+
| 食べ物 |
| 赤 |
+----------+
特定のノードにはいくつの子孫ノードがありますか?非常に単純で、子孫の総数 = (右の値 - 左の値 - 1) / 2
コードをコピーします
コードは次のとおりです:descendants = (右 - 左の値 - 1) / 2
信じられないですか?自分で計算してください。
この簡単な式を使用すると、「フルーツ 2-11」ノードには 4 つの子孫ノードがある一方、「バナナ 8-9」ノードには子孫ノードがない、つまり親ノードではないことがすぐに計算できます。
すごいですよね?私はこの方法を何度も使ってきましたが、それでもやるたびに素晴らしい気分になります。
これは確かに良い方法ですが、左と右の値を持つこのようなデータテーブルを作成するのに役立つ方法はありますか?もう 1 つの関数を紹介します。この関数は、名前と親構造を持つテーブルを、左と右の値を持つデータ テーブルに自動的に変換します。
次はコードです:コードをコピーします
コードは次のとおりです:function再構築_tree($parent, $left) {
// このノードの正しい値は左の値 + 1
$right = $left+1;
// このノードのすべての子を取得します
$result = mysql_query("
SELECT name
FROM Tree
WHEREparent = '" . $parent . "'
; "
);
while ($row = mysql_fetch_array($result)) {
を使用する 使用する ' d ' ' ' ' ' を通して を通して を通して を通して を通して を通して を通してを通して を通してを通して を通してを通してright out right out'' through out through out through over'''' ‐to'‐'''-''-'-‐ s $right =再構築_tree($row['name'], $right);
}
// 左の値が得られ、処理が完了しました
// このノードの子も右の値を知っています
mysql_query("
UPDATE Tree
SET
lft = '" . $left . "',
rgt= '" . $right . "'
WHERE name = '" . $parent . "'
; "
) ;
// このノードの正しい値を返します
return $right + 1 ;
}
?>
もちろん、この関数は再帰関数です。バンドを再構築するにはルート ノードからこの関数を実行する必要があります。左と右の値を持つツリー
コードをコピーします
コードは次のとおりです:
rebuild_tree('Food',1);
この関数は少し複雑に見えますが、その機能はテーブルに手動で番号を付けるのと同じで、3 次元の多層構造を左右の値を持つデータ テーブルに変換することです。
では、このような構造のノードを追加、更新、削除するにはどうすればよいでしょうか?
通常、ノードを追加するには 2 つの方法があります:
1 つ目の方法は、元の名前と親構造を保持し、古い方法を使用してデータをデータに追加し、rebuild_tree 関数を使用してノードを更新します。各データが追加された後、データ全体の番号が付け直されます。
2 番目のより効率的な方法は、新しいノードの右側にあるすべての値を変更することです。たとえば、「Red」ノードの最後の子ノードとなる新しいフルーツ「Strawberry」を追加したいとします。まず、そのためのスペースを作る必要があります。 「赤」の右側の値を6から8に、「黄7~10」の左右の値を9~12に変更します。類推して、新しい値のための余地を作りたい場合は、左右の値が 5 より大きいすべてのノードに 2 を追加する必要があることがわかります (5 は「Red」の最後の子ノードの正しい値です) )。したがって、次のようなデータベース操作を実行します:
コードをコピー コードは次のとおりです:
UPDATE ツリー SET rgt = rgt + 2 WHERE rgt > 5;
UPDATE ツリー SET lft = lft + 2 WHERE lft; > 5;
これにより、新しく挿入された値のためのスペースが解放され、その左と右の値はそれぞれ 6 と 7 になります
。 コードは次のとおりです:
INSERT INTO Tree SET lft=6, rgt=7, name='Strawberry';
別のクエリを実行して見てみましょう!どうでしょうか?すぐ。
4. 結論
さて、マルチレベルのデータベース構造を設計するために 2 つの異なる方法を使用できますが、どちらの方法を使用するかは完全に個人的な判断に依存しますが、多くのレベルと大量の構造の場合は、 2番目のアプローチ。クエリの量は少ないが、データを頻繁に追加および更新する必要がある場合は、最初の方法の方が簡単です。 さらに、データベースがサポートしている場合は、データベース側でトリガー関数としてrebuild_tree()と領域解放操作を記述し、挿入および更新時に自動的に実行することもでき、より高い操作効率を実現できます。新しいノードを追加できるようになり、SQL ステートメントがより簡単になります。
http://www.bkjia.com/PHPjc/327714.html
www.bkjia.comtruehttp://www.bkjia.com/PHPjc/327714.html技術記事 1. はじめに 製品分類、マルチレベルのツリー構造のフォーラム、メーリング リスト、その他多くの場所で、このような問題に遭遇します。マルチレベル構造のデータをどのように保存するか? PHP アプリケーションでは、次のように記述します...