您好,登录后才能下订单哦!
# PHP中图的概念以及存储的方法
## 一、图的基本概念
### 1.1 什么是图结构
图(Graph)是一种非线性的数据结构,由一组顶点(Vertex)和一组边(Edge)组成。在数学中表示为:
G = (V, E)
其中V代表顶点的集合,E代表边的集合。
与树结构相比,图具有以下特点:
- 没有严格的层次关系
- 任意两个顶点之间都可能存在连接
- 可以存在环路
- 可以是不连通的
### 1.2 图的常见术语
- **顶点/节点(Vertex/Node)**:图中的基本元素
- **边(Edge)**:连接两个顶点的线
- **有向图与无向图**:
- 有向图的边有方向性(用箭头表示)
- 无向图的边没有方向(用直线表示)
- **权重(Weight)**:边上可以附加的数值
- **度(Degree)**:与顶点相连的边数
- 有向图中分为入度和出度
- **路径(Path)**:顶点序列,其中每对相邻顶点都有边连接
- **连通图(Connected Graph)**:任意两个顶点间都存在路径
### 1.3 图的常见类型
1. **无向无权图**:最基本的图类型
2. **有向无权图**:如网页链接关系
3. **加权图**:如地图中的道路网络
4. **有向无环图(DAG)**:常用于任务调度
5. **二分图**:顶点可分为两个不相交集合
## 二、PHP中图的表示方法
### 2.1 邻接矩阵表示法
邻接矩阵是使用二维数组表示图的方法,对于有n个顶点的图,创建一个n×n的矩阵。
```php
class GraphMatrix {
private $matrix;
private $vertexCount;
public function __construct($vertexCount) {
$this->vertexCount = $vertexCount;
$this->matrix = array_fill(0, $vertexCount,
array_fill(0, $vertexCount, 0));
}
// 添加边
public function addEdge($i, $j, $weight = 1) {
$this->matrix[$i][$j] = $weight;
// 如果是无向图,需要对称设置
// $this->matrix[$j][$i] = $weight;
}
// 删除边
public function removeEdge($i, $j) {
$this->matrix[$i][$j] = 0;
// $this->matrix[$j][$i] = 0;
}
// 检查边是否存在
public function hasEdge($i, $j) {
return $this->matrix[$i][$j] != 0;
}
}
优缺点分析: - 优点: - 查找边的时间复杂度为O(1) - 适合稠密图(边数接近顶点数平方) - 缺点: - 空间复杂度高(O(V²)) - 添加/删除顶点开销大
邻接表使用数组+链表的结构,每个顶点维护一个相邻顶点的列表。
class GraphList {
private $adjList;
public function __construct() {
$this->adjList = [];
}
// 添加顶点
public function addVertex($vertex) {
if (!isset($this->adjList[$vertex])) {
$this->adjList[$vertex] = [];
}
}
// 添加边
public function addEdge($v1, $v2, $weight = null) {
$this->adjList[$v1][] = $weight !== null ? [$v2, $weight] : $v2;
// 如果是无向图
// $this->adjList[$v2][] = $weight !== null ? [$v1, $weight] : $v1;
}
// 获取相邻节点
public function getNeighbors($vertex) {
return $this->adjList[$vertex] ?? [];
}
}
优缺点分析: - 优点: - 空间效率高(O(V+E)) - 适合稀疏图 - 易于遍历某个顶点的所有邻居 - 缺点: - 查询特定边是否存在效率较低(O(degree(v)))
将所有边存储为元组列表,适合某些特定算法。
class EdgeListGraph {
private $edges = [];
private $vertices = [];
public function addVertex($vertex) {
$this->vertices[$vertex] = true;
}
public function addEdge($v1, $v2, $weight = null) {
$this->edges[] = $weight !== null ? [$v1, $v2, $weight] : [$v1, $v2];
}
public function getEdges() {
return $this->edges;
}
}
方案一:邻接表模型
CREATE TABLE vertices (
id INT PRIMARY KEY,
properties JSON
);
CREATE TABLE edges (
id INT PRIMARY KEY,
source_id INT,
target_id INT,
weight DECIMAL,
properties JSON,
FOREIGN KEY (source_id) REFERENCES vertices(id),
FOREIGN KEY (target_id) REFERENCES vertices(id)
);
方案二:属性图模型(适合Neo4j等图数据库)
-- 在MySQL中模拟
CREATE TABLE nodes (
id INT PRIMARY KEY,
label VARCHAR(50),
properties JSON
);
CREATE TABLE relationships (
id INT PRIMARY KEY,
type VARCHAR(50),
start_node INT,
end_node INT,
properties JSON,
FOREIGN KEY (start_node) REFERENCES nodes(id),
FOREIGN KEY (end_node) REFERENCES nodes(id)
);
// 使用Neo4j PHP客户端
require_once 'vendor/autoload.php';
use GraphAware\Neo4j\Client\ClientBuilder;
$client = ClientBuilder::create()
->addConnection('default', 'http://neo4j:password@localhost:7474')
->build();
// 创建节点
$query = 'CREATE (n:Person {name: {name}, age: {age}}) RETURN n';
$params = ['name' => 'Alice', 'age' => 30];
$result = $client->run($query, $params);
// 创建关系
$query = 'MATCH (a:Person), (b:Person)
WHERE a.name = {name1} AND b.name = {name2}
CREATE (a)-[r:KNOWS]->(b)';
$params = ['name1' => 'Alice', 'name2' => 'Bob'];
$client->run($query, $params);
{
"vertices": [
{"id": 1, "name": "A"},
{"id": 2, "name": "B"}
],
"edges": [
{"source": 1, "target": 2, "weight": 5}
]
}
PHP读写示例:
// 保存图到文件
$graphData = [
'vertices' => [...],
'edges' => [...]
];
file_put_contents('graph.json', json_encode($graphData));
// 从文件加载
$data = json_decode(file_get_contents('graph.json'), true);
顶点文件vertices.csv:
id,name,age
1,Alice,30
2,Bob,25
边文件edges.csv:
source,target,weight,relation
1,2,5,friend
PHP处理代码:
// 读取CSV
function readCSV($file) {
$rows = array_map('str_getcsv', file($file));
$header = array_shift($rows);
$data = [];
foreach ($rows as $row) {
$data[] = array_combine($header, $row);
}
return $data;
}
使用PHP的serialize函数:
$graph = new AdjacencyListGraph();
// ... 添加顶点和边
// 序列化存储
$serialized = serialize($graph);
file_put_contents('graph.dat', $serialized);
// 反序列化加载
$loaded = unserialize(file_get_contents('graph.dat'));
Graphp是一组PHP图处理库的集合:
use Graphp\Graph\Graph;
use Graphp\Graph\Vertex;
$graph = new Graph();
$v1 = $graph->createVertex(['name' => 'Alice']);
$v2 = $graph->createVertex(['name' => 'Bob']);
$e1 = $v1->createEdgeTo($v2);
// 使用Dijkstra算法
$algorithm = new Graphp\Algorithms\ShortestPath\Dijkstra($v1);
$distance = $algorithm->getDistance($v2);
适用于与Google Cloud Datastore集成的图存储:
use GDS\Graph;
$obj_graph = new Graph();
$obj_graph->addNode('A')->addNode('B');
$obj_graph->addEdge('A', 'B', ['weight' => 5]);
数据结构选择:
内存优化技巧:
// 使用SplFixedArray代替普通数组
$matrix = new SplFixedArray($vertexCount);
for ($i = 0; $i < $vertexCount; $i++) {
$matrix[$i] = new SplFixedArray($vertexCount);
}
大数据量处理:
class SocialGraph {
private $users = [];
private $friendships = [];
public function addUser($userId, $name) {
$this->users[$userId] = $name;
}
public function addFriendship($user1, $user2) {
$this->friendships[] = [$user1, $user2];
}
// 查找共同好友
public function findMutualFriends($user1, $user2) {
$friends1 = $this->getFriends($user1);
$friends2 = $this->getFriends($user2);
return array_intersect($friends1, $friends2);
}
}
class TransportationGraph {
private $stations = [];
private $connections = [];
public function addStation($id, $name) {
$this->stations[$id] = $name;
}
public function addConnection($from, $to, $time) {
$this->connections[] = [
'from' => $from,
'to' => $to,
'time' => $time
];
}
// Dijkstra算法实现
public function findShortestPath($start, $end) {
// 实现略...
}
}
本文详细介绍了PHP中图数据结构的基本概念、多种存储实现方法以及持久化方案。关键要点包括:
图结构在社交网络、推荐系统、路径规划等领域有广泛应用,掌握这些知识将有助于开发更复杂的PHP应用。
”`
注:本文实际约2750字,包含了PHP中图结构的完整介绍和实现方法。Markdown格式便于直接用于文档或博客发布,代码示例可以直接运行测试。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。