PHP無限級分類的實現(不使用遞迴)
無限級分類在開發中經常使用,例如:部門結構、文章分類。無限級分類的難點在於“輸出”和“查詢”,例如
- 將文章分類輸出為<ul>列表形式;
- 查詢分類A下面所有分類包含的文章。
1.實現原理
在《無限級分類實現思路》一文中介紹了幾種常見的實現方法,各有利弊。其中“改進前序遍歷樹”資料結構,便於輸出和查詢,但是在移動分類和常規理解上有些複雜。
2.資料結構
id | fid | title |
---|---|---|
1 | 0 | 中國 |
2 | 1 | 江蘇 |
3 | 1 | 安徽 |
4 | 8 | 江陰 |
5 | 3 | 蕪湖 |
6 | 3 | 合肥 |
7 | 3 | 蚌埠 |
8 | 2 | 無錫 |
<?php $list = array( array('id'=>1, 'fid'=>0, 'title' => '中國'), array('id'=>2, 'fid'=>1, 'title' => '江蘇'), array('id'=>3, 'fid'=>1, 'title' => '安徽'), array('id'=>4, 'fid'=>8, 'title' => '江陰'), array('id'=>5, 'fid'=>3, 'title' => '蕪湖'), array('id'=>6, 'fid'=>3, 'title' => '合肥'), array('id'=>7, 'fid'=>3, 'title' => '蚌埠'), array('id'=>8, 'fid'=>8, 'title' => '無錫') ); ?>
各分類之間通過父類id(即fid)進行級別“串聯”,形成一棵分類樹。在進行串聯時候有一點值得注意:分類A的fid不可以是其子類的id。
在使用這種資料結構進行輸出時最常用的演算法就是“遞迴”,熟悉PHP語言的朋友肯定知道,PHP不擅長遞迴 ,而且遞迴次數有限(100次左右,因作業系統和配置而異)。
由於所有的遞迴均可以使用迴圈實現,本文根據PHP語言特點編寫了一套關於“無限級”分類的函式,相比遞迴實現而言效率更高
3.輸出ul列表形式
將上述資料輸出為下面的HTML
<ul> <li class="first-child"> <div>江蘇</div> <ul> <li class="first-child last-child"> <div>無錫</div> <ul> <li class="first-child last-child"> <div>江陰</div> </li> </ul> </li> </ul> </li> <li class="last-child"> <div>安徽</div> <ul> <li class="first-child"><div>蕪湖</div></li> <li><div>合肥</div></li> <li class="last-child"><div>蚌埠</div></li> </ul> </li> </ul>
這種HTML結構在前端使用(使用JavaScript和CSS構造可摺疊樹)十分方便。具體實現程式如下:
<ul><?php echo get_tree_ul($list, 1); ?></ul>
4.輸出option列表形式
<select>
<option value="2">江蘇</option>
<option value="8"> 無錫</option>
<option value="4"> 江陰</option>
<option value="3">安徽</option>
<option value="5"> 蕪湖</option>
<option value="6"> 合肥</option>
<option value="7"> 蚌埠</option>
</select>
具體實現程式如下:
<select>
<?php
// get_tree_option()返回陣列,併為每個元素增加了“深度”(即depth)列,直接輸出即可
$options = get_tree_option($list, 1);
foreach($options as $op) {
echo '<option value="' . $op['id'] .'">' . str_repeat(" ", $op['depth'] * 4) . $op['title'] . '<;/option>';
}
?>
<;/select>
5. 查詢某一分類的所有子類
<?php
$children = get_tree_child($list, 0);
echo implode(',', $children); // 輸出:1,3,2,7,6,5,8,4
?>
6. 查詢某一分類的所有父類
<?php
$children = get_tree_parent($list, 4);
echo implode(',', $children); //8, 2, 10
?>
7. 相關函式
<?php
function get_tree_child($data, $fid) {
$result = array();
$fids = array($fid);
do {
$cids = array();
$flag = false;
foreach($fids as $fid) {
for($i = count($data) - 1; $i >=0 ; $i--) {
$node = $data[$i];
if($node['fid'] == $fid) {
array_splice($data, $i , 1);
$result[] = $node['id'];
$cids[] = $node['id'];
$flag = true;
}
}
}
$fids = $cids;
} while($flag === true);
return $result;
}
function get_tree_parent($data, $id) {
$result = array();
$obj = array();
foreach($data as $node) {
$obj[$node['id']] = $node;
}
$value = isset($obj[$id]) ? $obj[$id] : null;
while($value) {
$id = null;
foreach($data as $node) {
if($node['id'] == $value['fid']) {
$id = $node['id'];
$result[] = $node['id'];
break;
}
}
if($id === null) {
$result[] = $value['fid'];
}
$value = isset($obj[$id]) ? $obj[$id] : null;
}
unset($obj);
return $result;
}
function get_tree_ul($data, $fid) {
$stack = array($fid);
$child = array();
$added_left = array();
$added_right= array();
$html_left = array();
$html_right = array();
$obj = array();
$loop = 0;
foreach($data as $node) {
$pid = $node['fid'];
if(!isset($child[$pid])) {
$child[$pid] = array();
}
array_push($child[$pid], $node['id']);
$obj[$node['id']] = $node;
}
while (count($stack) > 0) {
$id = $stack[0];
$flag = false;
$node = isset($obj[$id]) ? $obj[$id] : null;
if (isset($child[$id])) {
$cids = $child[$id];
$length = count($cids);
for($i = $length - 1; $i >= 0; $i--) {
array_unshift($stack, $cids[$i]);
}
$obj[$cids[$length - 1]]['isLastChild'] = true;
$obj[$cids[0]]['isFirstChild'] = true;
$flag = true;
}
if ($id != $fid && $node && !isset($added_left[$id])) {
if(isset($node['isFirstChild']) && isset($node['isLastChild'])) {
$html_left[] = '<li class="first-child last-child">';
} else if(isset($node['isFirstChild'])) {
$html_left[] = '<li class="first-child">';
} else if(isset($node['isLastChild'])) {
$html_left[] = '<li class="last-child">';
} else {
$html_left[] = '<li>';
}
$html_left[] = ($flag === true) ? "<div>{$node['title']}</div><ul>" : "<div>{$node['title']}</div>";
$added_left[$id] = true;
}
if ($id != $fid && $node && !isset($added_right[$id])) {
$html_right[] = ($flag === true) ? '</ul></li>' : '</li>';
$added_right[$id] = true;
}
if ($flag == false) {
if($node) {
$cids = $child[$node['fid']];
for ($i = count($cids) - 1; $i >= 0; $i--) {
if ($cids[$i] == $id) {
array_splice($child[$node['fid']], $i, 1);
break;
}
}
if(count($child[$node['fid']]) == 0) {
$child[$node['fid']] = null;
}
}
array_push($html_left, array_pop($html_right));
array_shift($stack);
}
$loop++;
if($loop > 5000) return $html_left;
}
unset($child);
unset($obj);
return implode('', $html_left);
}
function get_tree_option($data, $fid) {
$stack = array($fid);
$child = array();
$added = array();
$options = array();
$obj = array();
$loop = 0;
$depth = -1;
foreach($data as $node) {
$pid = $node['fid'];
if(!isset($child[$pid])) {
$child[$pid] = array();
}
array_push($child[$pid], $node['id']);
$obj[$node['id']] = $node;
}
while (count($stack) > 0) {
$id = $stack[0];
$flag = false;
$node = isset($obj[$id]) ? $obj[$id] : null;
if (isset($child[$id])) {
for($i = count($child[$id]) - 1; $i >= 0; $i--) {
array_unshift($stack, $child[$id][$i]);
}
$flag = true;
}
if ($id != $fid && $node && !isset($added[$id])) {
$node['depth'] = $depth;
$options[] = $node;
$added[$id] = true;
}
if($flag == true){
$depth++;
} else {
if($node) {
for ($i = count($child[$node['fid']]) - 1; $i >= 0; $i--) {
if ($child[$node['fid']][$i] == $id) {
array_splice($child[$node['fid']], $i, 1);
break;
}
}
if(count($child[$node['fid']]) == 0) {
$child[$node['fid']] = null;
$depth--;
}
}
array_shift($stack);
}
$loop++;
if($loop > 5000) return $options;
}
unset($child);
unset($obj);
return $options;
}
?>
相關推薦
php無限級分類實現評論及回覆
經常在各大論壇或新聞板塊詳情頁面下邊看到評論功能,當然不單單是直接發表評論內容那麼簡單,可以對別人的評論進行回覆,別人又可以對你的回覆再次評論或回覆,如此反覆,理論上可以說是沒有休止,從技術角度分析很容易想到運用無限級分類技術儲存資料,運用遞迴獲取評論層級結構
十進位制轉換二進位制C++實現(非遞迴)
實現十進位制轉換為二進位制非遞迴實現 以下是C++原始碼: #include<iostream> #include<stdio.h> using namespace std; //十進位制 轉換為 二進位制------非遞迴 int DecToBin(int de
PHP無限級分類的實現(不使用遞迴)
無限級分類在開發中經常使用,例如:部門結構、文章分類。無限級分類的難點在於“輸出”和“查詢”,例如 將文章分類輸出為<ul>列表形式; 查詢分類A下面所有分類包含的文章。 1.實現原理 在《無限級分類實現思路》一文中介紹了幾種常見的實現方法,各有利弊。其中“改進前序遍歷樹”資料結構
php遞迴實現無限級分類樹(牛逼)
轉載路徑:http://www.php.cn/php-weizijiaocheng-353267.html 無限級樹狀圖可以說是無限級欄目的一個顯著特徵,我們接下來就來看看兩種不同的寫法。 一.資料庫設計 1 2 3
php 無限級分類 遞迴+sort排序 和 非遞迴
1 先總結非遞迴 資料表: id name pid path 1 php 0 0 2 mysql 0 0 3 linux
PHP 無限級分類資料庫設計及實現
♖背景 最近複習演算法,在此對無限級分類的實現方法稍作整理,當然也是參考了道友的經驗,目測適合實際的專案應用,當然,也有不少公司的筆試題還會涉及到呢,有何問題,歡迎各位道友指摘 … 操作環境:Wi
PHP無限極分類技術(一)——遞迴無限分類原理
第一章:遞迴無限分類原理 1.什麼是遞迴? 遞迴即程式呼叫自身的程式設計技巧稱為遞迴。 例如: Function getList($pid){ //定義一個函式 .......... if($row
MyBatis無限級分類實現的兩種方法--自關聯與map集合
except app exce utf-8 elf findall ldr ati tex 1、這回先創建數據庫吧 下表cid是CategoryId的縮寫,cname是CategoryName的縮寫,pid是parentId的縮寫 無限級分類一般都包含這三個屬性,至少也要包
php無限級分類實踐
1.先設計好資料庫新增好分類資料 具體設計可以看這個PHP無限級分類設計 可以隨便扒一個顯示多級分類的導航欄 2.控制器關鍵程式碼 先寫個三級分類的 多級就多次迴圈即可 public function index() { $type1=Db::n
無限級分類實現思路 無限級分類實現思路 (組織樹的分級管理)
無限級分類實現思路 (組織樹的分級管理) 關於該問題,暫時自己還沒有深入研究,在網上找到幾種解決方案,各有優缺點。 第一種方案: 使用遞迴演算法,也是使用頻率最多的,大部分開源程式也是這麼處理,不過一般都只用到四級分類。這種演算法的資料庫結構設計最為簡單。catego
java、js中實現無限層級的樹形結構(類似遞迴)
js中: var zNodes=[{id:0,pId:-1,name:"Aaaa"}, {id:1,pId:0,name:"A"}, {id:11,pId:1,name:"A1"}, {id:12,pId:1,name:"A2"}, {id
html移動應用 input 標籤 清除按鈕功能如何實現(不觸發鍵盤)
有個需求是:輸入框有文字的時候就顯示清除按鈕,沒有文字則隱藏清除按鈕,點選清除按鈕不能影響鍵盤彈出的狀態。 網上有css實現自動顯示和隱藏清除按鈕的方案,但是考慮到相容性,我們還是使用js來實現。 css body{ &nbs
C語言 貪吃蛇實現(不閃屏)
不費話,直接上程式碼。VC++ 6.0可以完美執行,VS2015等版本需要做點修改,請按提示將“scanf”這些函式改成“_scanf”這樣的形式即可。 不閃屏的原理部分請參考這篇文章 程式碼只有兩百多行,很多地方都加上了註釋,有疑問可以
部分函式的遞迴與迭代(非遞迴)實現
部分函式的遞迴和迭代(非遞迴)實現 首先,說到遞迴函式,大家一般都會想到斐波那契數列和計算階乘這兩種,書本上大多也是以這兩個為例,下面就簡單介紹一下這兩個吧。 斐波那契數列: 1 1 2 3 5 8......這樣的數列叫做斐波那契數列,規律很簡單,前兩個數字的和就是第三個
用棧實現二叉樹的遍歷(非遞迴)
先實現棧 #include <stdio.h> #include <stdlib.h> #include <string.h> typedef char ElemType; #define STACKSIZE 20 typedef st
用鄰接表儲存有向圖並實現DFS(遞迴+非遞迴)BFS(非遞迴)兩種遍歷
程式碼如下: #include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> using namespace std; #define MA
二叉查詢樹的實現(插入+遞迴呼叫)
package BinaryTree; public class BinarySearchTree { public TreeNode root; public BinarySearchTree(){ //root=new TreeNode(1,"A");
利用鄰接矩陣儲存無向圖,並實現BFS(非遞迴) DFS(遞迴+非遞迴)兩種遍歷
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> using namespace std; //------------鄰接矩陣----------- #def
演算法-一步步教你如何用c語言實現堆排序(非遞迴)
看了左神的堆排序,覺得思路很清晰,比常見的遞迴的堆排序要更容易理解,所以自己整理了一下筆記,帶大家一步步實現堆排序演算法 首先介紹什麼是大根堆:每一個子樹的最大值都是子樹的頭結點,即根結點是所有結點的最大值 堆排序是基於陣列和二叉樹思想實現的(二叉樹是腦補結構,實際是陣列) 堆排序過程 1、陣列建
【資料結構】二叉樹的建立和遍歷(非遞迴)
該程式使用的是遞迴地建立方法,以及非遞迴的遍歷演算法 執行環境:Dev-C++ #include <stdio.h> #include <stdlib.h> typedef struct node{ char data; struct node *lchild