algorithmmatrixadjacency-listundirected-graphweighted-graph

Converting a grid into a weighted adjacency list


const grid = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]

In the grid above, traversing left to right has a cost of 10 and up to down has a cost of 25. I'd like to represent this in a undirected weighted adjacency list like below:

const weightedAdjList = {
0: {1: 10, 3: 25},
1: {2: 10, 4: 25},
2: {5: 25},
3: {4: 10, 5: 25},
4: {5: 10, 7: 25},
5: {8: 25},
6: {7: 10},
7: {8: 10},
8: {}
}

Here is as far as I've gotten with my code:

const matrixToAdjList = (matrix) => {
  const graph = {};
  let i = 0;
  for (let r = 0; r < matrix.length; r++) {
    for (let c = 0; c < matrix[0].length; c++) {
      if (!(i in graph)) graph[i] = {}
      i++
    }
  }
  // populate(graph);
  return graph;
};

Can anyone help me out with populating the adjacencies in the graph?

Thank you!


Solution

  • You're almost there:

    const matrixToAdjList = (matrix) => {
      const graph = {};
      let i = 0;
      for (let r = 0; r < matrix.length; r++) {
        for (let c = 0; c < matrix[0].length; c++) {
          if (!(i in graph)) graph[i] = {}
          if (c < matrix[0].length-1) {
              graph[i][matrix[r][c+1]] = 10 // move right
          }
          if (r < matrix.length-1) {
              graph[i][matrix[r+1][c]] = 25 // move down
          }
          i++
        }
      }
      return graph;
    };
    

    A note about how you use i and increment it to name the nodes: This approach has some disadvantages, IMO, as follows:

    1. If the node names were not a sequence of numbers incremented by one, this approach wouldn't work. In other words, it isn't general enough.
    2. It makes the code less readable, since the node's name can be confused with indices of the matrix.

    I suggest the following approach:

    const matrixToAdjList = (matrix) => {
      const graph = {};
      const R, C = matrix.length, matrix[0].length
      for (let r = 0; r < R; r++) {
        for (let c = 0; c < C; c++) {
          const node = matrix[r][c]
          // if (!(node in graph)) graph[node] = {} this check is redundant. we visit each node only once. I assume that the node names are unique, otherwise this algo wouldn't work.
          graph[node] = {}
          if (c < C-1) {
              graph[node][matrix[r][c+1]] = 10 // move right
          }
          if (r < R-1) {
              graph[node][matrix[r+1][c]] = 25 // move down
          }
        }
      }
      return graph;
    };