圖是由具有邊的節點集合組成的資料結構。圖可以是有向的或者是無向的。
有向圖包含功能類似於單行道的邊。邊緣從一個節點流向另一個節點。
比如,你可能有一個(關於)人物和電影的圖表,其中每個人可以有多個喜歡的電影,但是電影沒有喜歡的人。
無向圖包含雙向流動的邊緣,類似於雙向道路,兩個方向都有交通。
比如,你可能有一個寵物圖表,其中每隻寵物都有一個所有者,每個所有者都有一隻寵物。
備註:(下面)雙向箭頭代表一條邊,但是為了顯而易見,我繪製了兩條箭頭。
**圖(graph)**中沒有明確的資訊層次結構。
方法
我們將建立一個(關於)人和冰淇凌口味的圖表。這將是一個有向圖,因為人們可以喜歡某些口味,但是味道可不喜歡人。
我們將建立三個類:
PersonNode
IceCreamFlavorNode
Graph
PersonNode
PersonNode
類將接受一個引數:一個人的名字。這將作為其識別符號。
PersonNode
建構函式將包含兩個屬性:
name
:唯一識別符號favoriteFlavors
:關於IceCreamFlavorNodes的陣列
另外,PersonNode
類包含一個方法:addFlavor
。這將傳入一個引數,一個IceCreamFlavorNode
物件,並將其新增到陣列favoriteFlavors
中。
類的定義如下所示:
class PersonNode {
constructor(name) {
this.name = name;
this.favoriteFlavors = [];
}
addFlavor(flavor) {
this.favoriteFlavors.push(flavor);
}
}
複製程式碼
IceCreamFlavorNode
IceCreamFlavorNode
類將傳入一個引數:冰淇凌口味。這將作為其識別符號。
這個類不需要包含任何方法,因為這是一個無向圖,資料是從person
流向flavors
,但是不會迴流。
這個類的定義如下:
class IceCreamFlavorNode {
constructor(flavor) {
this.flavor = flavor;
}
}
複製程式碼
Graph
Graph
類不接受任何引數,但是其建構函式將包含三個屬性:
peopleNodes
:人物節點陣列。iceCreamFlavorNodes
:冰淇凌口味節點陣列。edges
:包含PersonNodes
和IceCreamFlavorNodes
之間的邊緣陣列。
Graph
類將包含六個方法:
addPersonNode(name)
:接受一個引數,一個人的名字,建立一個具有此名字的PersonNode
物件,並將其推送到peopleNodes
陣列。addIceCreamFlavorNode(flavor)
:接受一個引數,一個冰淇凌口味,建立一個具有這種口味的IceCreamFlavorNode
物件,並將其推送到iceCreamFlavorNodes
陣列中。getPerson(name)
:接受一個引數,一個人名字,並返回該人的節點。getFlavor(flavor)
:接受一個引數,一個冰淇凌口味,並返回該口味的節點。addEdge(personName, flavorName)
:接受兩個引數,一個人的名稱和一個冰淇凌口味,檢索兩個節點,將flavor
新增到人的favoriteFlavors
陣列,並將邊推送到edge
陣列。print()
:簡單列印出peopleNodes
陣列中的每個人,以及他們最喜歡的冰淇凌口味。
類的定義如下所示:
class Graph {
constructor() {
this.peopleNodes = [];
this.iceCreamFlavorNodes = [];
this.edges = [];
}
addPersonNode(name) {
this.peopleNodes.push(new PersonNode(name));
}
addIceCreamFlavorNode(flavor) {
this.iceCreamFlavorNodes.push(new IceCreamFlavorNode(flavor));
}
getPerson(name) {
return this.peopleNodes.find(person => person.name === name);
}
getFlavor(flavor) {
return this.iceCreamFlavorNodes.find(flavor => flavor === flavor);
}
addEdge(personName, flavorName) {
const person = this.getPerson(personName);
const flavor = this.getFlavor(flavorName);
person.addFlavor(flavor);
this.edges.push(`${personName} - ${flavorName}`);
}
print() {
return this.peopleNodes.map(({ name, favoriteFlavors }) => {
return `${name} => ${favoriteFlavors.map(flavor => `${flavor.flavor},`).join(' ')}`;
}).join('\n')
}
}
複製程式碼
虛擬資料
現在,我們有了三個類,我們可以新增一些資料並測試它們:
const graph = new Graph(true);
graph.addPersonNode('Emma');
graph.addPersonNode('Kai');
graph.addPersonNode('Sarah');
graph.addPersonNode('Maranda');
graph.addIceCreamFlavorNode('Chocolate Chip');
graph.addIceCreamFlavorNode('Strawberry');
graph.addIceCreamFlavorNode('Cookie Dough');
graph.addIceCreamFlavorNode('Vanilla');
graph.addIceCreamFlavorNode('Pistachio');
graph.addEdge('Emma', 'Chocolate Chip');
graph.addEdge('Emma', 'Cookie Dough');
graph.addEdge('Emma', 'Vanilla');
graph.addEdge('Kai', 'Vanilla');
graph.addEdge('Kai', 'Strawberry');
graph.addEdge('Kai', 'Cookie Dough');
graph.addEdge('Kai', 'Chocolate Chip');
graph.addEdge('Kai', 'Pistachio');
graph.addEdge('Maranda', 'Vanilla');
graph.addEdge('Maranda', 'Cookie Dough');
graph.addEdge('Sarah', 'Strawberry');
console.log(graph.print());
複製程式碼
下面是我們有向圖看起來類似(的樣子):
如果你想看完整的程式碼,到我的CodePen上檢視。