A binary tree is a hierarchical data structure in which every node has at most two children, conventionally called the left child and right child. It's one of the most foundational shapes in computer science — far more structures than you'd expect (binary search trees, heaps, syntax trees, decision trees) are really just binary trees with an extra rule layered on top.

Unlike a linked list, where each node points to exactly one "next" node, a binary tree node can branch in two directions at once. That branching is what makes trees good at representing hierarchical relationships — file systems, organization charts, and decision logic all map naturally onto this shape.

Basic Structure of a Binary Tree Node

A binary tree node bundles a value with references to its left and right children. Either reference can be None if that child doesn't exist.

class Node:
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

# Manually building a tiny tree:
#        1
#       / \
#      2   3
#     /
#    4
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)

print(root.left.value, root.right.value, root.left.left.value)

Output:

2 3 4

Full, Complete, and Perfect Binary Trees

These three terms get mixed up constantly, so it's worth pinning them down:

Full binary tree — every node has either 0 or 2 children, never exactly 1. Complete binary tree — every level is fully filled except possibly the last, which fills left to right with no gaps (this is the shape a heap relies on). Perfect binary tree — every internal node has exactly 2 children and every leaf sits at the same depth, so the tree is as "full" as it can possibly be.

A perfect tree is automatically full and complete, but a complete tree isn't necessarily perfect — the last level just needs to be filled left-to-right, not entirely full.

Why This Shape Matters

A plain binary tree by itself doesn't guarantee fast search — in the worst case you still have to visit every node, which is O(n). What makes binary trees powerful is the rules you can layer on top of the basic shape:

Add an ordering invariant (left child smaller, right child larger) and you get a binary search tree, with O(log n) search on average. Add a heap-order invariant (every parent is smaller — or larger — than its children) and you get a heap, ideal for always grabbing the minimum or maximum value quickly. The node structure above is the shared skeleton; everything else is a constraint you choose to enforce.

That's really the throughline across most tree-based structures in DSA: start from this same two-child node, then pick which invariant you want it to maintain.