Compare commits

...

5 Commits

5 changed files with 101 additions and 2 deletions

View File

@@ -1,3 +1,5 @@
import traceback
class Node: class Node:
def __init__(self, value, left=None, right=None, parent=None, is_red=False): def __init__(self, value, left=None, right=None, parent=None, is_red=False):
self.value = value self.value = value
@@ -451,8 +453,10 @@ def run_tests():
print(" Your rebalance likely created a cycle or otherwise broke the") print(" Your rebalance likely created a cycle or otherwise broke the")
print(" tree structure (a child pointing back up at an ancestor).\n") print(" tree structure (a child pointing back up at an ancestor).\n")
continue continue
except Exception as e: except Exception:
print(f" RESULT: ERROR - {type(e).__name__}: {e}\n") print(f" RESULT: ERROR - see stack trace below\n")
print(traceback.format_exc())
print("")
continue continue
# Guard the author (you) against a typo when adding a new case: the # Guard the author (you) against a typo when adding a new case: the

View File

@@ -0,0 +1,13 @@
## Breadth-first search (BFS)
In the notes on [depth-first search](./depth-first-search.md), we mention that the difference between DFS and BFS is the order in which nodes are traversed.
Using the same example, what would a breadth-first traversal look like if we start at vertex 0 in this graph?
```
0 --- 1
| |
3 --- 2
```
Can we also formalize an algorithm for breadth-first search?

View File

@@ -0,0 +1,46 @@
## Traversal introduction
Many algorithms that involve graphs must involve some way to traverse the elements of a graph. The two simplest ways of traversal are depth-first search (DFS) and [breadth-first search (BFS)](https://en.wikipedia.org/wiki/Breadth-first_search). The major difference here is the *order* in which nodes are traversed.
If we start from vertex 0 in the tree, in what order would you expect depth-first search to traverse the nodes? (There are multiple correct answers!)
```
0
/ \
1 2
/ \
3 4
```
Note that a single traversal step checks for already-visited nodes. So, if the path is `0 -> 1 -> 3`, the path cannot become `0 -> 1 -> 3 -> 1`.
What about starting from vertex 0 in this graph?
```
0 --- 1
| |
3 --- 2
```
What about this one?
```
0
/ \
1 5
/ \ \
2 3 6
\ / /
4 7
\ /
8
```
## Formalizing the algorithm
Based on these examples, can we create a formal algorithm that takes a starting node, producing a valid traversal path for all three graphs?
Some starter questions:
- Could recursion help us here?
- What are some ways we can track already-visited nodes? What's the most *time-efficient* way to do so?

View File

@@ -0,0 +1,25 @@
# Adjacency list
first_graph = {
1: [3, 20],
2: [20],
3: [1, 20],
20: [2, 3]
}
# First exercise: go from 1, to 20, to 2
first_graph[first_graph[1][1]][0]
# pass visited by reference
def depth_first_search(graph: dict, start, visited=set()):
print(start)
if len(visited)==len(graph):
return visited
for x in graph[start]:
if x not in visited:
visited.add(x)
return depth_first_search(graph, x, visited)
pass
depth_first_search(first_graph, 1)

View File

@@ -0,0 +1,11 @@
## Outline
To make our knowledge of graphs useful, we'll go over our first traversal method today: [depth-first search](./depth-first-search.md). We will also go over [breadth-first search](./breadth-first-search.md), and how both algorithms can be useful.
Assignment: write functions for depth-first search and breadth-first search. Because there is no starter file, the constraints are listed below:
- You may use either an adjacency list or adjacency matrix to represent your graph
- You should demonstrate that your algorithm works by running it through some test cases
- For each test case, specify the graph, starting point, and expected output(s)
Bonus: can you output *all* the valid paths for both DFS and BFS in a particular case?