---
tags: Data structure and algorithm
---
# Graph -- Basic concept
## Relative articles
1. [Graph -- Basic concept](https://hackmd.io/@Justin123/graph1) (You're reading now!)
2. [Graph -- Shortest path algorithm](https://hackmd.io/@Justin123/graph2)
3. [Graph – Spanning Tree](https://hackmd.io/@Justin123/graph3)
## Content
1. [What is graph?]()
2. [Why graph is so important?]()
3. [Types of graph]()
4. [Walking through the graph]()
5. [Summary]()
6. [Reference]()
## What is graph?
Graph is the relationship between each nodes. For example:
```graphviz
graph test {
// title
labelloc="t";
label = "Facebook Social Network\n\n";
rankdir=LR;
Justin -- Katie;
Justin -- Joyce;
Justin -- Alex;
Joyce -- Katie
Joyce -- Alex;
Katie -- Alex;
}
```
On Facebook which indicated by the lines between us. So all of us is the **vertexs** in graph and the lines are **edges**. ==To be more precisly, **Graph** is a **Data Structure** form by the set of **vertexs** and **edges**.==
## Why graph is so important?
Let's discuss the following problems:
---
1. ++Friends Suggestion++
Suppose FB wants to recommend Justin's Friends to Alex, then the number of edges should be crossed equals to 2. One of the edges is **connenct Justin and Alex** and the other one is that **connect Justin and his friends**.
---
2. ++Products Suggestion++
Once Justin browse a product on Shopee, **Shopee will make an edge from that product to Justin**. Therefore, the suggestion that Justin will notice next time should be the prouducts that **connect to the last product Justin saw before**.
---
3. ++Network Connection++
Given the specific IP address, Justin wanted to access some special Japan websites. However, Justin didn't directly connect to that server. Therefore, there should be a path (a set of edges) that formed a method to connect to that website.
---
==With the real life examples above, we can deal with plenty of problems through graph theoroy(algorithm).==
## Types of graph
* Undirected graph
> There are no direction for each edges.
```graphviz
graph test {
// title
labelloc="t";
label = "Undirected graph\n\n";
rankdir=LR;
a -- b;
b -- c;
b -- d;
d -- a;
e -- a;
e -- d;
}
```
* Directed graph (digraph)
> Each edges has specific direction
```graphviz
digraph test {
// title
labelloc="t";
label = "Directed graph\n\n";
rankdir=LR;
a -> b;
b -> c;
b -> d;
d -> a;
a -> e;
e -> d;
}
```
* Weighted graph
> Each edge has its own weight
```graphviz
graph test {
// title
labelloc="t";
label = "Weighted graph\n\n";
rankdir=LR;
a -- b [ label = "2" ]
b -- c [ label = "5" ]
b -- d [ label = "1" ]
d -- a [ label = "3" ]
e -- a [ label = "6" ]
e -- d [ label = "4" ]
}
```
* cycle graph
> There exist at least a cycle in digraph or undirected graph
```graphviz
digraph test {
// title
labelloc="t";
label = "Directed cyclic graph\n\n";
rankdir=LR;
a -> b;
b -> c;
c -> a
}
```
**<center>a->b->c form a cycle, but c->b->a doesn't.</center>**
```graphviz
graph test {
// title
labelloc="t";
label = "Undirected cyclic graph\n\n";
rankdir=LR;
a -- b;
b -- c;
c -- a
}
```
**<center>Both a-b-c or c-b-a form cycles.</center>**
* DAG (Directed Acyclic graph)
```graphviz
digraph test {
// title
labelloc="t";
label = "DAG\n\n";
rankdir=LR;
a -> b;
a -> d;
a -> c;
b -> c;
b -> d;
c -> d;
}
```
## Approaches to represent the graph
1. **Adjancency matrix**
Using 2 dimension matrix to show the graph. If two vertex are connected, the value in matrix is 1, otherwise, 0.
* Undirected graph
```graphviz
graph test {
rankdir=LR;
b -- c;
c -- a;
d -- a;
d -- c;
}
```
$$Matrix=
\left\{
\begin{matrix}
0 & 0 & 1 & 1 \\
0 & 0 & 1 & 0 \\
1 & 1 & 0 & 1 \\
1 & 0 & 1 & 0 \\
\end{matrix}
\right\}
$$
* Digraph
```graphviz
digraph test {
rankdir=LR;
b -> c;
c -> a;
d -> a;
d -> c;
}
```
$$Matrix=
\left\{
\begin{matrix}
0 & 0 & 0 & 0 \\
0 & 0 & 1 & 0 \\
1 & 0 & 0 & 0 \\
1 & 0 & 1 & 0 \\
\end{matrix}
\right\}
$$
---
2. **Adjancency linked list**
Using a 1D matrix to store the vertex and using Linked list to show the connection with other vertex.
* Undirected graph
```graphviz
graph test {
rankdir=LR;
b -- c;
c -- a;
d -- a;
d -- c;
}
```
```graphviz
digraph g {
rankdir=LR
edge[arrowsize=1.0, arrowhead=vee]
node[shape=record fontsize=20];
list [label = "<a> a|<b> b|<c> c|<d> d", height=3];
nodea [label = "{c | d}"]
nodeb [label = "{c}"]
nodec [label = "{a | b | d}"]
noded [label = "{a | c}"]
list:a -> nodea
list:b -> nodeb
list:c -> nodec
list:d -> noded
}
```
* Digraph
```graphviz
digraph test {
rankdir=LR;
b -> c;
c -> a;
d -> a;
d -> c;
}
```
```graphviz
digraph g {
rankdir=LR
edge[arrowsize=1.0, arrowhead=vee]
node[shape = record, fontsize=20];
list [label = "<a> a | <b> b | <c> c | <d> d", height=3];
nodeb [label = "{c}"]
nodec [label = "{a}"]
noded [label = "{a | c}"]
list:b -> nodeb
list:c -> nodec
list:d -> noded
}
```
---
3. **Edges container**
> Using container to store both vertexs and edges
```cpp=
// Class for edges
template <typename T>
class edge {
// Start node and end node
T start, end;
// Add weight for weighted graph
int weight
}
int main() {
// Container to store both edges and vertex
std::vector<edge<T> > edges;
std::vector<int> vertexs;
...
}
```
```graphviz
digraph g {
node[shape=record, fontsize=20];
label = "\nContainer for vertexs"
list_vertexs [label = "vertex1 | vertex2 | vertex3 | ..."]
}
```
```graphviz
digraph g {
node[shape=record, fontsize=20];
label = "\nContainer for edges"
list_edges [label = "edges1 | edges2 | edges3 | ..."];
}
```
## Walking through the graph
```graphviz
graph test {
labelloc = "t"
label = "Example graph\n\n"
rankdir=LR;
b -- c;
c -- a;
d -- a;
d -- c;
}
```
In this example, I will use adjacency matrix to represent the graph
```cpp=
int graph = [[0, 0, 1, 1],
[0, 0, 1, 0],
[1, 1, 0, 1],
[1, 0, 1, 0]];
```
---
* **DFS**
> Go as deep as one node can!
For example, we start from node **a**.
```graphviz
graph test {
labelloc = "t"
label = "First step\n\n"
rankdir=LR;
a [ color="red" ]
}
```
We then explore other node connected to node **a**. Next node is **c**. Change our position from **a** to **c**.
```graphviz
graph test {
labelloc = "t"
label = "Second step\n\n"
rankdir=LR;
c [ color="red" ]
a -- c;
}
```
Check the node connected to **c**. The first node we would encounter was **a**, however, **a** had already been visited. Therefore, we move next to **b**.
```graphviz
graph test {
labelloc = "t"
label = "Third step\n\n"
rankdir=LR;
b [ color="red" ]
a -- c;
c -- b;
}
```
Check the node connected to **b**. There are no avaliable nodes for **b** because **a** had been already visited. Move back to **c**
```graphviz
graph test {
labelloc = "t"
label = "Fourth step\n\n"
rankdir=LR;
c [ color="red" ]
a -- c;
c -- b;
}
```
Visit node **d**.
```graphviz
graph test {
labelloc = "t"
label = "Fifth step\n\n"
rankdir=LR;
d [ color="red" ]
a -- c;
c -- b;
c -- d;
}
```
Alredy visited **c** and **a**. No node to visit from **d**. Move back to **c**.
```graphviz
graph test {
labelloc = "t"
label = "Sixth step\n\n"
rankdir=LR;
c [ color="red" ]
a -- c;
c -- b;
c -- d;
}
```
No more node to visit from **c**. Move back to **a**.
```graphviz
graph test {
labelloc = "t"
label = "Seventh step\n\n"
rankdir=LR;
a [ color="red" ]
a -- c;
c -- b;
c -- d;
}
```
No more node to visit from **a**. Stop program. The order is:
```cpp
a c b d
```
==Notice that we were passing through the graph not drawing the graph. We don't have to show every edges in the graph.==
Code:
```cpp=
void DFS(int graph[][4], int start) {
// Array to check visited
static int visited[4] = {0};
// Set visited and print out
visited[start] = 1;
std::cout << start << " ";
// Check for connected edges
for (int i = 0; i < 4; ++i) {
// if not visited and has the connection then move to that node
if (graph[start][i] == 1 && !visited[i]) {
DFS(graph, graph[start][i]);
}
}
}
```
---
* BFS
> See as much as one node can!
>
For example, we start from node **a**.
```graphviz
graph test {
labelloc = "t";
label = "First step\n\n";
rankdir=LR;
a [ color="red" ]
}
```
Next, check all the connected edges from **a**. Node **c** will be encountered first. Instead of moving to node **c**, we save it in queue and still stay at node **a**.
```graphviz
digraph g {
node[shape=record, fontsize=20];
labelloc = "t";
label = "Queue for saving visited node\n";
list_vertexs [label = "c"];
}
```
```graphviz
graph test {
labelloc = "t";
label = "Second step\n\n";
rankdir=LR;
a [ color="red" ]
a -- c
}
```
Visit node **d** and save it into queue.
```graphviz
digraph g {
node[shape=record, fontsize=20];
labelloc = "t";
label = "Queue for saving visited node\n\n";
list_vertexs [label = "c | d"]
}
```
```graphviz
graph test {
labelloc = "t";
label = "Third step\n\n";
rankdir=LR;
a [ color="red" ]
a -- c
a -- d
}
```
The nodes connected to **a** had already been visited. Pop out **c** from queue.
```graphviz
digraph g {
node[shape=record, fontsize=20];
labelloc = "t";
label = "Queue for saving visited node\n\n";
list_vertexs [label = "d"]
}
```
```graphviz
graph test {
labelloc = "t";
label = "Fourth step\n\n";
rankdir=LR;
c [ color="red" ]
a -- c
a -- d
}
```
Continue visiting other nodes connect to **c**.
```graphviz
digraph g {
node[shape=record, fontsize=20];
labelloc = "t";
label = "Queue for saving visited node\n\n";
list_vertexs [label = "d | b"]
}
```
```graphviz
graph test {
labelloc = "t";
label = "Fifth step\n\n";
rankdir=LR;
c [ color="red" ]
a -- c;
a -- d;
c -- b;
}
```
Finish node **c**. Pop out **d**
```graphviz
digraph g {
node[shape=record, fontsize=20];
labelloc = "t";
label = "Queue for saving visited node\n\n";
list_vertexs [label = "b"]
}
```
```graphviz
graph test {
labelloc = "t";
label = "Sixth step\n\n";
rankdir=LR;
a -- c;
a -- d;
d [ color="red" ]
c -- b;
}
```
Finish node **d**. Pop out **b**.
```graphviz
digraph g {
node[shape=record, fontsize=20];
labelloc = "t";
label = "Queue for saving visited node\n\n"
list_vertexs [label = ""]
}
```
```graphviz
graph test {
labelloc = "t";
label = "Seventh step\n\n";
rankdir=LR;
a -- c;
a -- d;
c -- b;
b [ color="red" ]
}
```
Finish node **b**. Also, queue is empty. Stop program. The order is:
```cpp
a c d b
```
Code:
```cpp=
void BFS(int graph[][4], int start) {
// queue for saving the visited node
std::queue<int> node;
// Array for checking visited
int visited[4] = {0};
// Push the start node into queue
node.push(start);
// Start passing through the graph
while (!node.empty()) {
// Get the node from queue
int current_node = node.front(); node.pop();
// Print out the node
std::cout << current_node << " ";
// Check the connected edges
for (int i = 0; i < 4; ++i) {
// if not visited and has the connection then push to queue
if (graph[current_node][i] == 1 && !visited[i]) {
node.push(graph[current_node][i]);
}
}
}
std::cout << std::endl;
}
```
## Summary
So far, we have introduced the basic concept of graph. We introduced the types of graph, how can we express the graph using different structures and how to pass through the graph. In next article, we're going to discuss how can we find the shortest path.
## Reference
1. [培養與鍛鍊程式設計的邏輯腦 第二版](https://www.books.com.tw/products/0010616945?gclid=Cj0KCQjwoub3BRC6ARIsABGhnyamNtOnA0U1z3yzZeFonqM2HT7jnj1WZcRX8ArR1_KwV3YEgkkkPlIaAlCZEALw_wcB)
## Contribution
* Thanks @JoyceFang1213 for checking the misspells.