Skip to content

Commit

Permalink
Concatenates both check bipatrite graphs(bfs&dfs) (TheAlgorithms#10708)
Browse files Browse the repository at this point in the history
* sync

* fixes#8098

* deleted:    graphs/check_bipartite_graph_all.py
	new file:   graphs/check_bipatrite,py

* renamed:    graphs/check_bipatrite,py -> graphs/check_bipatrite.py

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Add the new tests

---------

Co-authored-by: Christian Clauss <cclauss@me.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 20, 2023
1 parent 82fc24c commit 1976048
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 157 deletions.
10 changes: 0 additions & 10 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,7 @@

## Boolean Algebra
* [And Gate](boolean_algebra/and_gate.py)
* [Imply Gate](boolean_algebra/imply_gate.py)
* [Nand Gate](boolean_algebra/nand_gate.py)
* [Nimply Gate](boolean_algebra/nimply_gate.py)
* [Nor Gate](boolean_algebra/nor_gate.py)
* [Not Gate](boolean_algebra/not_gate.py)
* [Or Gate](boolean_algebra/or_gate.py)
Expand Down Expand Up @@ -180,9 +178,7 @@
## Data Structures
* Arrays
* [Equilibrium Index In Array](data_structures/arrays/equilibrium_index_in_array.py)
* [Find Triplets With 0 Sum](data_structures/arrays/find_triplets_with_0_sum.py)
* [Median Two Array](data_structures/arrays/median_two_array.py)
* [Pairs With Given Sum](data_structures/arrays/pairs_with_given_sum.py)
* [Permutations](data_structures/arrays/permutations.py)
* [Prefix Sum](data_structures/arrays/prefix_sum.py)
* [Product Sum](data_structures/arrays/product_sum.py)
Expand Down Expand Up @@ -402,7 +398,6 @@

## Financial
* [Equated Monthly Installments](financial/equated_monthly_installments.py)
* [Exponential Moving Average](financial/exponential_moving_average.py)
* [Interest](financial/interest.py)
* [Present Value](financial/present_value.py)
* [Price Plus Tax](financial/price_plus_tax.py)
Expand Down Expand Up @@ -711,7 +706,6 @@
* [Sin](maths/sin.py)
* [Sock Merchant](maths/sock_merchant.py)
* [Softmax](maths/softmax.py)
* [Solovay Strassen Primality Test](maths/solovay_strassen_primality_test.py)
* [Square Root](maths/square_root.py)
* [Sum Of Arithmetic Series](maths/sum_of_arithmetic_series.py)
* [Sum Of Digits](maths/sum_of_digits.py)
Expand Down Expand Up @@ -753,7 +747,6 @@
* [Spiral Print](matrix/spiral_print.py)
* Tests
* [Test Matrix Operation](matrix/tests/test_matrix_operation.py)
* [Validate Sudoku Board](matrix/validate_sudoku_board.py)

## Networking Flow
* [Ford Fulkerson](networking_flow/ford_fulkerson.py)
Expand Down Expand Up @@ -829,7 +822,6 @@
* [Rms Speed Of Molecule](physics/rms_speed_of_molecule.py)
* [Shear Stress](physics/shear_stress.py)
* [Speed Of Sound](physics/speed_of_sound.py)
* [Speeds Of Gas Molecules](physics/speeds_of_gas_molecules.py)

## Project Euler
* Problem 001
Expand Down Expand Up @@ -1220,7 +1212,6 @@
* [Capitalize](strings/capitalize.py)
* [Check Anagrams](strings/check_anagrams.py)
* [Credit Card Validator](strings/credit_card_validator.py)
* [Damerau Levenshtein Distance](strings/damerau_levenshtein_distance.py)
* [Detecting English Programmatically](strings/detecting_english_programmatically.py)
* [Dna](strings/dna.py)
* [Edit Distance](strings/edit_distance.py)
Expand Down Expand Up @@ -1255,7 +1246,6 @@
* [String Switch Case](strings/string_switch_case.py)
* [Strip](strings/strip.py)
* [Text Justification](strings/text_justification.py)
* [Title](strings/title.py)
* [Top K Frequent Words](strings/top_k_frequent_words.py)
* [Upper](strings/upper.py)
* [Wave](strings/wave.py)
Expand Down
92 changes: 0 additions & 92 deletions graphs/check_bipartite_graph_bfs.py

This file was deleted.

55 changes: 0 additions & 55 deletions graphs/check_bipartite_graph_dfs.py

This file was deleted.

179 changes: 179 additions & 0 deletions graphs/check_bipatrite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
from collections import defaultdict, deque


def is_bipartite_dfs(graph: defaultdict[int, list[int]]) -> bool:
"""
Check if a graph is bipartite using depth-first search (DFS).
Args:
graph: Adjacency list representing the graph.
Returns:
True if bipartite, False otherwise.
Checks if the graph can be divided into two sets of vertices, such that no two
vertices within the same set are connected by an edge.
Examples:
# FIXME: This test should pass.
>>> is_bipartite_dfs(defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 4]}))
Traceback (most recent call last):
...
RuntimeError: dictionary changed size during iteration
>>> is_bipartite_dfs(defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 1]}))
False
>>> is_bipartite_dfs({})
True
>>> is_bipartite_dfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]})
True
>>> is_bipartite_dfs({0: [1, 2, 3], 1: [0, 2], 2: [0, 1, 3], 3: [0, 2]})
False
>>> is_bipartite_dfs({0: [4], 1: [], 2: [4], 3: [4], 4: [0, 2, 3]})
True
>>> is_bipartite_dfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]})
False
>>> is_bipartite_dfs({7: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]})
Traceback (most recent call last):
...
KeyError: 0
# FIXME: This test should fails with KeyError: 4.
>>> is_bipartite_dfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 9: [0]})
False
>>> is_bipartite_dfs({0: [-1, 3], 1: [0, -2]})
Traceback (most recent call last):
...
KeyError: -1
>>> is_bipartite_dfs({-1: [0, 2], 0: [-1, 1], 1: [0, 2], 2: [-1, 1]})
True
>>> is_bipartite_dfs({0.9: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]})
Traceback (most recent call last):
...
KeyError: 0
# FIXME: This test should fails with TypeError: list indices must be integers or...
>>> is_bipartite_dfs({0: [1.0, 3.0], 1.0: [0, 2.0], 2.0: [1.0, 3.0], 3.0: [0, 2.0]})
True
>>> is_bipartite_dfs({"a": [1, 3], "b": [0, 2], "c": [1, 3], "d": [0, 2]})
Traceback (most recent call last):
...
KeyError: 1
>>> is_bipartite_dfs({0: ["b", "d"], 1: ["a", "c"], 2: ["b", "d"], 3: ["a", "c"]})
Traceback (most recent call last):
...
KeyError: 'b'
"""

def depth_first_search(node: int, color: int) -> bool:
"""
Perform Depth-First Search (DFS) on the graph starting from a node.
Args:
node: The current node being visited.
color: The color assigned to the current node.
Returns:
True if the graph is bipartite starting from the current node,
False otherwise.
"""
if visited[node] == -1:
visited[node] = color
for neighbor in graph[node]:
if not depth_first_search(neighbor, 1 - color):
return False
return visited[node] == color

visited: defaultdict[int, int] = defaultdict(lambda: -1)
for node in graph:
if visited[node] == -1 and not depth_first_search(node, 0):
return False
return True


def is_bipartite_bfs(graph: defaultdict[int, list[int]]) -> bool:
"""
Check if a graph is bipartite using a breadth-first search (BFS).
Args:
graph: Adjacency list representing the graph.
Returns:
True if bipartite, False otherwise.
Check if the graph can be divided into two sets of vertices, such that no two
vertices within the same set are connected by an edge.
Examples:
# FIXME: This test should pass.
>>> is_bipartite_bfs(defaultdict(list, {0: [1, 2], 1: [0, 3], 2: [0, 4]}))
Traceback (most recent call last):
...
RuntimeError: dictionary changed size during iteration
>>> is_bipartite_bfs(defaultdict(list, {0: [1, 2], 1: [0, 2], 2: [0, 1]}))
False
>>> is_bipartite_bfs({})
True
>>> is_bipartite_bfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]})
True
>>> is_bipartite_bfs({0: [1, 2, 3], 1: [0, 2], 2: [0, 1, 3], 3: [0, 2]})
False
>>> is_bipartite_bfs({0: [4], 1: [], 2: [4], 3: [4], 4: [0, 2, 3]})
True
>>> is_bipartite_bfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]})
False
>>> is_bipartite_bfs({7: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]})
Traceback (most recent call last):
...
KeyError: 0
# FIXME: This test should fails with KeyError: 4.
>>> is_bipartite_bfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 9: [0]})
False
>>> is_bipartite_bfs({0: [-1, 3], 1: [0, -2]})
Traceback (most recent call last):
...
KeyError: -1
>>> is_bipartite_bfs({-1: [0, 2], 0: [-1, 1], 1: [0, 2], 2: [-1, 1]})
True
>>> is_bipartite_bfs({0.9: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]})
Traceback (most recent call last):
...
KeyError: 0
# FIXME: This test should fails with TypeError: list indices must be integers or...
>>> is_bipartite_bfs({0: [1.0, 3.0], 1.0: [0, 2.0], 2.0: [1.0, 3.0], 3.0: [0, 2.0]})
True
>>> is_bipartite_bfs({"a": [1, 3], "b": [0, 2], "c": [1, 3], "d": [0, 2]})
Traceback (most recent call last):
...
KeyError: 1
>>> is_bipartite_bfs({0: ["b", "d"], 1: ["a", "c"], 2: ["b", "d"], 3: ["a", "c"]})
Traceback (most recent call last):
...
KeyError: 'b'
"""
visited: defaultdict[int, int] = defaultdict(lambda: -1)
for node in graph:
if visited[node] == -1:
queue: deque[int] = deque()
queue.append(node)
visited[node] = 0
while queue:
curr_node = queue.popleft()
for neighbor in graph[curr_node]:
if visited[neighbor] == -1:
visited[neighbor] = 1 - visited[curr_node]
queue.append(neighbor)
elif visited[neighbor] == visited[curr_node]:
return False
return True


if __name__ == "__main":
import doctest

result = doctest.testmod()
if result.failed:
print(f"{result.failed} test(s) failed.")
else:
print("All tests passed!")

0 comments on commit 1976048

Please sign in to comment.