Algorithms #11

Graphs

How would you implement a map ?

Lets make an abstraction: a set of nodes connected with edges

This is a graph !

A Graph is a non-linear data structure consisting of nodes and edges.

A Graph consists of a finite set of vertices(or nodes) and set of Edges which connect a pair of nodes.

Use cases of graphs

1. Maps

The best way of drawing subway maps can be easily solved using graph theory.

2. Chemical models

Most widely used chemical models are graph models

3. Facebook  friends connection

Facebook (and almost all other social networks) model the users and their connections with their friends in a graph structure. And, they use this graph model to do their business by applying graph theory ideas, including how to populate your timeline, what advertisements to show, etc.

4. Your favorite search engine

Google, uses a graph representation to store/retreive the semantic relationship between different entities, which they call it, Knowledge Graph, as well as providing you with the top relevant webpages for your query, using PageRank algorithm, which is a graph theorethic algorithm.

5. Almost every recommendation system

 including the ones used by Amazon for recommending you the relevant books to buy, or Netflix for recommending you what to watch use graph theoretic algorithms.

6. Networking

Your entire Internet works on the principle of Graph Theory.

Also

  • Graph theory is used in biology and conservation efforts where a vertex represents regions where certain species exist and the edges represent migration path or movement between the regions.
  • Graph theoretical concepts are widely used in Operations Research.
  • Dependecy management / representation
  • File system
  • The networks may include paths in a telephone network.
  • Graphs are used to solve many real-life problems.

Graphs are important!

Terminology

Directed or undirected

In directed graphs, edges point from the node at one end to the node at the other end. In undirected graphs, the edges simply connect the nodes at each end.

Cyclic or acyclic

 graph is cyclic if it has a cycle—an unbroken series of nodes with no repeating nodes or edges that connects back to itself. Graphs without cycles are acyclic.

Weighted or unweighted

If a graph is weighted, each edge has a "weight." The weight could, for example, represent the distance between two locations, or the cost or time it takes to travel between the locations.

Types of graphs

BFS and DFS

Lots of graph problems can be solved using just these traversals:

Advanced graph algorithms

  • Dijkstra's Algorithm: Finds the shortest path from one node to all other nodes in a weighted graph.
  • Topological Sort: Arranges the nodes in a directed, acyclic graph in a special order based on incoming edges.
  • Minimum Spanning Tree: Finds the cheapest set of edges needed to reach all nodes in a weighted graph.

Is there a path between two nodes in this undirected graph?
Run DFS or BFS from one node and see if you reach the other one.
 

What's the shortest path between two nodes in this undirected, unweighted graph?
Run BFS from one node and backtrack once you reach the second. Note: BFS always finds the shortest path, assuming the graph is undirected and unweighted. DFS does not always find the shortest path.
 

Does this undirected graph have a cycle?

Run BFS, keeping track of the number of times we're visiting each node. If we ever visit a node twice, then we have a cycle.

How to represent a graph in code ?

2 main approaches

Adjacency list

Adjacency matrix

Adjacency Matrix

Adjacency Matrix is a 2D array of size V x V where V is the number of vertices in a graph. Let the 2D array be adj[][], a slot adj[i][j] = 1 indicates that there is an edge from vertex i to vertex j

Adjacency List

An array of lists is used. Size of the array is equal to the number of vertices. Let the array be array[]. An entry array[i] represents the list of vertices adjacent to the ith vertex. This representation can also be used to represent a weighted graph. The weights of edges can be represented as lists of pairs. Following is adjacency list representation of the above graph.

Which is better

Adjacency Matrix

  • Uses O(n^2) memory
  • It is fast to lookup and check for presence or absence of a specific edge
  • between any two nodes O(1)
  • It is slow to iterate over all edges
  • It is slow to add/delete a node; a complex operation O(n^2)
  • It is fast to add a new edge O(1)

Adjacency List

  • Memory usage depends on the number of edges (not number of nodes),
  • which might save a lot of memory if the adjacency matrix is sparse
  • Finding the presence or absence of specific edge between any two nodes
  • is slightly slower than with the matrix O(k); where k is the number of neighbors nodes
  • It is fast to iterate over all edges because you can access any node neighbors directly
  • It is fast to add/delete a node; easier than the matrix representation
  • It fast to add a new edge O(1)

Lets try to implement our own Graph (Adjacency list)

class Graph {

    constructor() {
        // implement this
    }

    addVertex(name) {
        // implement this
    }

    addEdge(v1, v2) {
        // implement this  
    }

    removeEdge(v1, v2) {
        // implement this
    }

    removeVertex(v) {
        // implement this
    }

    DFS(from = '') {
        // implement this
    }

    hasPath(from, to) {
        // implement this
    }

}

const g = new Graph();

g
.addVertex('A')
.addVertex('B')
.addVertex('C')
.addVertex('D')
.addVertex('F')
.addEdge('A', 'B')
.addEdge('A', 'C')
.addEdge('B', 'C')
.addEdge('C', 'D')
.addEdge('D', 'A')
.addEdge('D', 'F');


// g.removeVertex('C');

// console.log(g.DFS('A'));
// console.log(g.hasPath('A', 'C'));
// console.log(g.hasPath('A', 'F'));

Thank you!

But first

let us recap previous topics

The complexity

What complexity  is worse here:

1

1. O(2^n)

2. O(n^2)

 

 

What complexity  is worse here:

2

1. O(2^n)

2. O(n!)

 

 

log(n) vs n ?

3

O(10n^2 + 1000) = ?

4

Simplify this:

O(n^2 + n!) = ?

5

Simplify this:

O(n*(10 + n*log(n))) = ?

6

Simplify this:

7

Represents the fastest possible running time:

Big Ω , Big θ, Big O ?

9

Represents the worst possible running time:

Big Ω , Big θ, Big O ?

10

Find the time complexity

function log(n) {
   for (var i = 1; i <= Math.min(n, 100); i++) {
       console.log(i);
   }
}

11

Find the space complexity

function evenElementsArray(array) {
     const newArray = Array(Math.ceil(array.length / 2));
     for (var i = 0; i < array.length; i++) {
         if (i % 2 === 0) {
             newArray[i / 2] = array[i];
         }
         for (var j = 0; j < i; j++) { console.log(“hello”); }
   }
   return newArray;
}

12

Given an array of integers of size ‘n’.
Our aim is to calculate the maximum sum of ‘k’ 
consecutive elements in the array.
Input  : arr = [100, 200, 300, 400]
         k = 2
Output : 700

Window Sliding

13

Binary search time complexity

1. O(n)

2. O(n log(n))

3. O(log(n))

14

More uneversal algorithm

1. Linear search

2. Binary search

15

More fast algorithm

1. Linear search

2. Binary search

16

Big O (worst case) of quick sort

1. O(n^2)

2. O(n log(n))

17

Big O (worst case) of bubble sort

1. O(n^2)

2. O(n log(n))

18

QuickSort or Bubble sort ?

19

Stable sorting ?

20

Ok google what is it:

20

Ok google what is it:

21

Can we sort faster then O(n log n) ?

Recap

22

Linked list .push(data) complexity 

1. O(n)

2. O(1)

3. O(log(n))

23

Is this a good idea to use binary search on a linked list ?

24

How to check that linked list has a loop ? 

25

LIFO

1. Stack

2. Queue

26

Examples of using stacks ?

27

Stack vs Queue ?

28

What is a map ?

29

Time complexity of .put(data)

1. O(n)

2. O(1)

30

new Map() vs {} ???

31

BST - what is it ?

32

How to iterate over a tree ?

33

Recursive or iterative traversing ?

OK we are good

Algorithms #11

By Vladimir Vyshko

Algorithms #11

BFT, DFT, Graphs overview

  • 595