Pathfinding yayayay

idea: (we are NOT finding the most efficient path; just “a” path) )

  • Recursion
    • base cases: If we are at the destination OR there are no other neighbours to go to.
  • Recursive step/case
    • Keep track of a list of nodes you’ve already been to (otherwise you might search things you’ve already searched and cycle infinitely!)
    • If the node is not null (i.e. not base case) we try to find a path from the node’s unvisited neighbors
    • Note that every time the recursive step is run, it reduces the size of the graph (by adding new nodes in our “already searched” list)

Depth-first search: going as far from the start as possible, and branching from the end. That is what we implement

#define GRAPH_SIZE 64
 
int find_path(int adj_mat[GRAPH_SIZE][GRAPH_SIZE], int at, int goal, int visited[GRAPH_SIZE])
{
	if (at == goal) return 1;
	
	visited[i] = 1; // We have visited it!
	
	for (int i = 0; i < GRAPH_SIZE; i++)
	{
		if (adj_mat[at][i] != 0 && visited[i] == 0)
		{
			if (find_path(adj_mat, i, goal, visited) == 1)
			{
				printf("<-%i", i);
				return 1;
			}
		}
	}
	
	return 0;
}

The adj matrix is for 16 nodes, so the size is 16x16 where each row represents the connections to other nodes

  • O(N) for the # of nodes we’re entering
  • O(N) for the # of checks for each node we’ve entered So the complexity is O(N^2) (?) Because of edge-querying, adjacency linked lists will be faster cuz you dont need to look for the nodes that a node is attached to.

Breath-first-search (BFS)

  • U basically start at the point, queue each neighboring node. The queue is ordered by closest to furthest nodes!
  • U track the predecessors in order to actually store the path.

The DFS_FindPath code we wrote has 6 total boxes (4 for the args; 1 local var; 1 return box)

  • When calling recursively, in memory, we create new “frames” or big boxes with all the same 6 boxes as in any other call.
  • Reserving space for function calls takes time! Stack management takes time. So loops are usually faster.
  • Creating too many frames will cause you to run out of memory and the program will be kill.

Recursion optimization!

  • Problem with recursion: it uses a lot of memory! And it does a lot of work managing the call stack!
  • Instead of waiting for a function to wait for another function’s result, instead we utilize “Tail Recursion Optimization”.
    • Old compilers may not recognize this optimization though.
    • For instance if u have two fncs
return func(x) + 1;

vs

return func(x)
  • Then the first one doesn’t qualify for the optimization; the bottom one does!
  • Can we do this optimization for all recursive functions ?
  • todo He didnt say

Tutorial Time

Graphs

for adding a node, it’s nlog(N). U gotta copy the n entries of the array. So it’s log(N)