Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose a search algorithm by the structure of the data and the answer you need: use bisect to find boundaries in an already-sorted sequence, a set or dictionary for exact membership in an arbitrary collection, a FIFO queue for breadth-first traversal, a stack for depth-first traversal, and a min-heap when the next item must be chosen by priority. The code below shows how to implement each pattern and avoid common errors involving duplicates, cycles, equal priorities, and weighted paths.

Choose an algorithm for the search you need

Need Input assumption Useful structure Important condition
Find an exact value or insertion boundary Sequence already sorted by the search comparison rule bisect_left or bisect_right Check the returned position if exact membership matters.
Test exact membership repeatedly Arbitrary hashable values set or dict Use a dictionary when values map to associated records.
Visit graph nodes by increasing number of edges from a start Unweighted graph represented by neighbors collections.deque Mark nodes discovered to prevent cycles and repeated queue entries.
Explore one branch deeply before backing up Graph or state space List as a LIFO stack Track visited nodes when paths can loop.
Repeatedly select the smallest tentative distance or priority Weighted graph or priority-driven state space heapq Dijkstra requires nonnegative edge weights; use a tie-breaker for arbitrary payloads.

These structures solve different problems. Binary search does not explore a graph, breadth-first search (BFS) does not minimize arbitrary weighted costs, and depth-first search (DFS) does not promise the shortest route. The right choice depends on both the input and the meaning of “found.”

Binary search and insertion boundaries with bisect

Python’s bisect module locates an insertion point in a sequence that is already ordered using the same comparison rule. It uses < to position values; it does not test equality to prove that a target exists. For exact matching, inspect the returned index and compare the item yourself. See the Python 3.14.7 bisect documentation.

Exact-match search, including an absent target

from bisect import bisect_left


def binary_search(items, target):
    """Return the first matching index, or -1 when target is absent.

    items must already be sorted in ascending order under the same
    comparison rule used for target.
    """
    index = bisect_left(items, target)
    if index != len(items) and items[index] == target:
        return index
    return -1


values = [2, 4, 4, 7, 10]
print(binary_search(values, 4))   # 1: first matching index
print(binary_search(values, 5))   # -1: absent

bisect_left returns the leftmost position at which the target can be inserted without disturbing the order. If duplicates exist, that position is the first equal value. The returned index can equal len(items), so guard against that before indexing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.

Inclusive and exclusive boundaries

The standard library handles the boundary logic without requiring a hand-written loop. bisect_right returns the position after all values equal to the target. Together, the two functions identify the half-open slice containing duplicates:

from bisect import bisect_left, bisect_right

values = [1, 3, 3, 3, 8]
left = bisect_left(values, 3)
right = bisect_right(values, 3)
print(left, right)       # 1 4
print(values[left:right])  # [3, 3, 3]

Think of the result as a half-open interval [left, right): it includes index left and stops before index right. If left == right, there are no equal values, though that location remains a valid insertion boundary. This is useful for range queries such as all values within a lower and upper bound, where each endpoint’s inclusivity must be handled deliberately.

Sorted-list maintenance is not logarithmic

insort finds the insertion point with a bisection search, but inserting into a Python list shifts later elements. The search portion is O(log n); the list insertion is O(n) and dominates. Repeated insertion into a sorted list should therefore not be described as logarithmic-time insertion. For repeated exact lookups, Python’s documentation notes that dictionaries are more performant than bisection-based searching. The bisect functions are also not thread-safe if another thread concurrently uses or mutates the same sequence; coordinate access or use an appropriate synchronization strategy.

Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.

Exact membership in an arbitrary collection

If values are not sorted and the question is simply “is this value present?”, sorting just to search once may add unnecessary work. A set is a direct representation for hashable values:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
blocked_ids = {18, 41, 77}

if 41 in blocked_ids:
    print("already present")

Use a dictionary when a key identifies a record or value, for example user_by_id[user_id]. Sets and dictionaries are not substitutes for ordered range lookup: they do not tell you where a value belongs among neighboring values. For a workload that changes over time, account for the cost of maintaining the chosen structure, not only the cost of one lookup.

Breadth-first search with a FIFO queue

BFS visits a start node, then its neighbors, then nodes one edge farther away. In an unweighted graph this makes it suitable for finding a path with the fewest edges. Python’s tutorial demonstrates a FIFO queue using collections.deque, removing from the left with popleft() and appending generated moves. A visited/discovered set is essential for a general graph with cycles or multiple routes to a node.

Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.

Runnable BFS path finder

from collections import deque


def bfs_path(graph, start, goal):
    """Return a shortest-by-edge-count path, or None if unreachable.

    graph maps each node to an iterable of its neighboring nodes.
    Nodes must be hashable.
    """
    queue = deque([start])
    parent = {start: None}  # Also marks nodes as discovered.

    while queue:
        node = queue.popleft()
        if node == goal:
            path = []
            while node is not None:
                path.append(node)
                node = parent[node]
            return list(reversed(path))

        for neighbor in graph.get(node, ()):
            if neighbor not in parent:
                parent[neighbor] = node
                queue.append(neighbor)

    return None


graph = {
    "A": ["B", "C"],
    "B": ["D"],
    "C": ["D", "E"],
    "D": ["F"],
    "E": ["F"],
    "F": [],
}
print(bfs_path(graph, "A", "F"))  # ['A', 'B', 'D', 'F']
print(bfs_path(graph, "A", "Z"))  # None

The implementation records a node’s parent when it is enqueued, rather than waiting until it is removed. That prevents the same node from being queued repeatedly through different routes. The parent map both serves as the discovered set and allows reconstruction of the path. If only reachability is needed, return a boolean instead.

Depth-first search with a stack

DFS uses a LIFO frontier: the most recently discovered node is explored next. It is useful for reachability, component exploration, and state-space traversal when breadth-first ordering is not needed. It does not guarantee a minimum-edge path. An explicit stack avoids Python recursion-depth limitations on deep or unbounded traversals.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
def dfs_path(graph, start, goal):
    """Return one path if goal is reachable, otherwise None."""
    stack = [start]
    parent = {start: None}

    while stack:
        node = stack.pop()
        if node == goal:
            path = []
            while node is not None:
                path.append(node)
                node = parent[node]
            return list(reversed(path))

        # Reverse to visit neighbors in their listed order with a LIFO stack.
        for neighbor in reversed(list(graph.get(node, ()))):
            if neighbor not in parent:
                parent[neighbor] = node
                stack.append(neighbor)

    return None

As with BFS, marking a node when it is added to the frontier prevents cycles and duplicate work. The reverse is optional; it only makes traversal order align with the listed neighbor order. If neighbor order has no meaning, it can be omitted.

Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft

Priority queues with heapq

heapq maintains a min-heap in a regular Python list: the smallest item is at index zero. heapify converts an existing list into a heap in linear time. When two entries have equal priorities, payload objects may not support ordering against one another; put a unique increasing counter between the priority and payload. These behaviors are documented in Python 3.14.7 heapq. The documentation reports explicit max-heap APIs as added in Python 3.14.

Stable priority entries with non-comparable tasks

import heapq
from itertools import count

sequence = count()
frontier = []

heapq.heappush(frontier, (5, next(sequence), {"job": "alpha"}))
heapq.heappush(frontier, (5, next(sequence), {"job": "beta"}))
heapq.heappush(frontier, (2, next(sequence), {"job": "urgent"}))

while frontier:
    priority, _, task = heapq.heappop(frontier)
    print(priority, task)

The second tuple field breaks ties without asking Python to compare the dictionaries. It also gives a consistent order among tasks with equal priorities. Without it, a tuple such as (priority, task) can raise TypeError when tied task objects are not orderable.

Dijkstra’s algorithm for nonnegative weighted edges

Dijkstra’s algorithm uses a min-heap to expand the currently cheapest known distance. It applies when edge weights are nonnegative. The example assumes a graph shaped like {node: [(neighbor, weight), ...]} and hashable node values:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
import heapq
from itertools import count


def dijkstra(graph, start):
    """Return shortest distances and predecessors from start.

    All edge weights must be nonnegative.
    """
    distances = {start: 0}
    parent = {start: None}
    sequence = count()
    frontier = [(0, next(sequence), start)]

    while frontier:
        distance, _, node = heapq.heappop(frontier)
        if distance != distances.get(node):
            continue  # Ignore a stale, more expensive heap entry.

        for neighbor, weight in graph.get(node, ()):
            if weight < 0:
                raise ValueError("Dijkstra requires nonnegative edge weights")
            candidate = distance + weight
            if candidate < distances.get(neighbor, float("inf")):
                distances[neighbor] = candidate
                parent[neighbor] = node
                heapq.heappush(
                    frontier, (candidate, next(sequence), neighbor)
                )

    return distances, parent


def reconstruct_path(parent, goal):
    if goal not in parent:
        return None
    path = []
    node = goal
    while node is not None:
        path.append(node)
        node = parent[node]
    return list(reversed(path))


weighted = {
    "A": [("B", 4), ("C", 1)],
    "B": [("D", 1)],
    "C": [("B", 2), ("D", 7)],
    "D": [],
}
distances, parent = dijkstra(weighted, "A")
print(distances["D"])                 # 4
print(reconstruct_path(parent, "D"))  # ['A', 'C', 'B', 'D']

The heap may contain an older entry for a node after a shorter route is discovered; comparing the popped distance against the current best distance discards that stale entry. Distances are returned only for nodes reachable from the start. A negative edge invalidates Dijkstra's assumptions, so choose an algorithm designed for the graph's weight rules instead. Runtime depends on graph representation and heap operations; do not apply one complexity figure without stating those assumptions.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Adapting the patterns to your data

  • Sorted records by a key: keep the sequence sorted under the same key/comparison rule used in lookup. For complex records, use the documented key support in bisect carefully and ensure the searched value is in the expected key domain.
  • Multiple equivalent values: use left and right boundaries to retrieve a duplicate range; validate exact equality separately when checking membership.
  • Directed graphs: include only outgoing neighbors in the adjacency list. If you need reverse reachability, represent or construct reverse edges explicitly.
  • State-space search: make states immutable/hashable or derive a stable key for the discovered set. If the state omits relevant information, two distinct situations may be incorrectly treated as the same state.
  • Need a weighted minimum path: use a priority-driven algorithm with assumptions appropriate to the edge costs. Do not substitute BFS unless all steps have equal cost.

Common errors and fixes

Symptom Likely cause Fix
Binary search misses a value that appears in the input The input is unsorted, or sorted with a different key/comparison rule. Sort or maintain the sequence under the same ordering before calling bisect.
IndexError after bisect_left The target belongs after the final item, so the insertion point is len(items). Check the index against the sequence length before indexing.
A lookup reports a match for a value that is not present The code treats the insertion point as proof of membership. Compare items[index] == target after confirming the index is in range.
BFS or DFS loops or grows without bound Nodes are not marked discovered, or the state key does not represent the full state. Record each node/state when adding it to the frontier; revisit the state model if needed.
Heap raises TypeError for tied priorities Tuple comparison reaches non-comparable task values. Use a unique counter as a tie-breaker between priority and payload.
Dijkstra returns an implausible result with negative edges The algorithm's nonnegative-weight precondition is violated. Use a shortest-path method that supports negative weights, or correct the input if weights should be nonnegative.
Results change unpredictably during bisection Another thread is using or mutating the same sequence concurrently. Protect access with synchronization or search an immutable/safely isolated sequence.

Or skip the browser setup

If your work also needs website screenshots for algorithm documentation, link previews, or test fixtures, ScreenshotNeo accepts a URL in one API request and returns an image or PDF. Its cookie/consent-banner handling and removal of more than 60 known consent platforms, newsletter popups, and chat widgets can be turned off step by step. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; response headers report the page verdict and billing status. It also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI agents.

Use this cURL request; replace YOUR_API_KEY with your key and change the target URL as needed. See the ScreenshotNeo API documentation for request options and response details.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up for free ScreenshotNeo access.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Does bisect confirm that an item exists?

No. It returns an insertion point; exact-match code must check that the index is in range and the indexed value equals the target.

Can breadth-first search find the cheapest path in a weighted graph?

Not in general. BFS minimizes edge count in an unweighted graph; use an algorithm whose assumptions match the edge weights, such as Dijkstra for nonnegative weights.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.