{
  "slug": "quick-sort",
  "title": "Quick Sort",
  "category": "Sorting",
  "difficulty": "medium",
  "complexity": {
    "time": "O(n log n) avg",
    "space": "O(log n)"
  },
  "idea": "Pick a pivot (here the last element). Move everything smaller to its left and larger to its right, so the pivot lands in its final spot. Then sort each side the same way.",
  "code": [
    "sort(lo, hi):",
    "    if lo >= hi: return",
    "    p = partition(lo, hi)   # pivot = a[hi]",
    "    for j in lo..hi-1: if a[j] < pivot: swap into place",
    "    sort(lo, p-1); sort(p+1, hi)"
  ],
  "example": {
    "array": [
      7,
      2,
      9,
      1,
      6,
      3,
      8,
      5
    ]
  },
  "invariant": "Each step is the real data structure at that step — the picture is a pure function of it.",
  "stepCount": 32,
  "steps": [
    {
      "i": 0,
      "op": "say",
      "caption": "Quick sort: partition around a pivot, then recurse on each side.",
      "note": null,
      "codeLine": 1,
      "stats": null,
      "array": [
        7,
        2,
        9,
        1,
        6,
        3,
        8,
        5
      ],
      "focus": [
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null
      ],
      "markers": [],
      "regions": []
    },
    {
      "i": 1,
      "op": "read",
      "caption": "Pivot is 5 — the last element of [0..7].",
      "note": null,
      "codeLine": 3,
      "stats": null,
      "array": [
        7,
        2,
        9,
        1,
        6,
        3,
        8,
        5
      ],
      "focus": [
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        "read"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        }
      ],
      "regions": []
    },
    {
      "i": 2,
      "op": "compare",
      "caption": "Is 7 < pivot 5?",
      "note": "no → leave it",
      "codeLine": 4,
      "stats": {
        "compares": 1
      },
      "array": [
        7,
        2,
        9,
        1,
        6,
        3,
        8,
        5
      ],
      "focus": [
        "compare",
        null,
        null,
        null,
        null,
        null,
        null,
        "compare"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 0,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 0,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 3,
      "op": "compare",
      "caption": "Is 2 < pivot 5?",
      "note": "yes → belongs left",
      "codeLine": 4,
      "stats": {
        "compares": 2
      },
      "array": [
        7,
        2,
        9,
        1,
        6,
        3,
        8,
        5
      ],
      "focus": [
        null,
        "compare",
        null,
        null,
        null,
        null,
        null,
        "compare"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 0,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 1,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 4,
      "op": "swap",
      "caption": "Swap 7 and 2.",
      "note": null,
      "codeLine": 4,
      "stats": {
        "compares": 2,
        "swaps": 1
      },
      "array": [
        2,
        7,
        9,
        1,
        6,
        3,
        8,
        5
      ],
      "focus": [
        "swap",
        "swap",
        null,
        null,
        null,
        null,
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 0,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 1,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 5,
      "op": "compare",
      "caption": "Is 9 < pivot 5?",
      "note": "no → leave it",
      "codeLine": 4,
      "stats": {
        "compares": 3,
        "swaps": 1
      },
      "array": [
        2,
        7,
        9,
        1,
        6,
        3,
        8,
        5
      ],
      "focus": [
        null,
        null,
        "compare",
        null,
        null,
        null,
        null,
        "compare"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 1,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 2,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 6,
      "op": "compare",
      "caption": "Is 1 < pivot 5?",
      "note": "yes → belongs left",
      "codeLine": 4,
      "stats": {
        "compares": 4,
        "swaps": 1
      },
      "array": [
        2,
        7,
        9,
        1,
        6,
        3,
        8,
        5
      ],
      "focus": [
        null,
        null,
        null,
        "compare",
        null,
        null,
        null,
        "compare"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 1,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 3,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 7,
      "op": "swap",
      "caption": "Swap 7 and 1.",
      "note": null,
      "codeLine": 4,
      "stats": {
        "compares": 4,
        "swaps": 2
      },
      "array": [
        2,
        1,
        9,
        7,
        6,
        3,
        8,
        5
      ],
      "focus": [
        null,
        "swap",
        null,
        "swap",
        null,
        null,
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 1,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 3,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 8,
      "op": "compare",
      "caption": "Is 6 < pivot 5?",
      "note": "no → leave it",
      "codeLine": 4,
      "stats": {
        "compares": 5,
        "swaps": 2
      },
      "array": [
        2,
        1,
        9,
        7,
        6,
        3,
        8,
        5
      ],
      "focus": [
        null,
        null,
        null,
        null,
        "compare",
        null,
        null,
        "compare"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 2,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 4,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 9,
      "op": "compare",
      "caption": "Is 3 < pivot 5?",
      "note": "yes → belongs left",
      "codeLine": 4,
      "stats": {
        "compares": 6,
        "swaps": 2
      },
      "array": [
        2,
        1,
        9,
        7,
        6,
        3,
        8,
        5
      ],
      "focus": [
        null,
        null,
        null,
        null,
        null,
        "compare",
        null,
        "compare"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 2,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 5,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 10,
      "op": "swap",
      "caption": "Swap 9 and 3.",
      "note": null,
      "codeLine": 4,
      "stats": {
        "compares": 6,
        "swaps": 3
      },
      "array": [
        2,
        1,
        3,
        7,
        6,
        9,
        8,
        5
      ],
      "focus": [
        null,
        null,
        "swap",
        null,
        null,
        "swap",
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 2,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 5,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 11,
      "op": "compare",
      "caption": "Is 8 < pivot 5?",
      "note": "no → leave it",
      "codeLine": 4,
      "stats": {
        "compares": 7,
        "swaps": 3
      },
      "array": [
        2,
        1,
        3,
        7,
        6,
        9,
        8,
        5
      ],
      "focus": [
        null,
        null,
        null,
        null,
        null,
        null,
        "compare",
        "compare"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 3,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 6,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 12,
      "op": "swap",
      "caption": "Drop the pivot 5 into index 3.",
      "note": null,
      "codeLine": 4,
      "stats": {
        "compares": 7,
        "swaps": 4
      },
      "array": [
        2,
        1,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        null,
        null,
        null,
        "swap",
        null,
        null,
        null,
        "swap"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 3,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 6,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 13,
      "op": "settle",
      "caption": "5 is now in its final position (index 3).",
      "note": null,
      "codeLine": 4,
      "stats": {
        "compares": 7,
        "swaps": 4
      },
      "array": [
        2,
        1,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        null,
        null,
        null,
        "settled",
        null,
        null,
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 3,
          "tone": "bound"
        }
      ],
      "regions": []
    },
    {
      "i": 14,
      "op": "read",
      "caption": "Pivot is 3 — the last element of [0..2].",
      "note": null,
      "codeLine": 3,
      "stats": {
        "compares": 7,
        "swaps": 4
      },
      "array": [
        2,
        1,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        null,
        null,
        "read",
        null,
        null,
        null,
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 2,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 3,
          "tone": "bound"
        }
      ],
      "regions": []
    },
    {
      "i": 15,
      "op": "compare",
      "caption": "Is 2 < pivot 3?",
      "note": "yes → belongs left",
      "codeLine": 4,
      "stats": {
        "compares": 8,
        "swaps": 4
      },
      "array": [
        2,
        1,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        "compare",
        null,
        "compare",
        null,
        null,
        null,
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 2,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 0,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 0,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 16,
      "op": "compare",
      "caption": "Is 1 < pivot 3?",
      "note": "yes → belongs left",
      "codeLine": 4,
      "stats": {
        "compares": 9,
        "swaps": 4
      },
      "array": [
        2,
        1,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        null,
        "compare",
        "compare",
        null,
        null,
        null,
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 2,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 1,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 1,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 17,
      "op": "settle",
      "caption": "3 is now in its final position (index 2).",
      "note": null,
      "codeLine": 4,
      "stats": {
        "compares": 9,
        "swaps": 4
      },
      "array": [
        2,
        1,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        null,
        null,
        "settled",
        null,
        null,
        null,
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 2,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 2,
          "tone": "bound"
        }
      ],
      "regions": []
    },
    {
      "i": 18,
      "op": "read",
      "caption": "Pivot is 1 — the last element of [0..1].",
      "note": null,
      "codeLine": 3,
      "stats": {
        "compares": 9,
        "swaps": 4
      },
      "array": [
        2,
        1,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        null,
        "read",
        null,
        null,
        null,
        null,
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 1,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 2,
          "tone": "bound"
        }
      ],
      "regions": []
    },
    {
      "i": 19,
      "op": "compare",
      "caption": "Is 2 < pivot 1?",
      "note": "no → leave it",
      "codeLine": 4,
      "stats": {
        "compares": 10,
        "swaps": 4
      },
      "array": [
        2,
        1,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        "compare",
        "compare",
        null,
        null,
        null,
        null,
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 1,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 0,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 0,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 20,
      "op": "swap",
      "caption": "Drop the pivot 1 into index 0.",
      "note": null,
      "codeLine": 4,
      "stats": {
        "compares": 10,
        "swaps": 5
      },
      "array": [
        1,
        2,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        "swap",
        "swap",
        null,
        null,
        null,
        null,
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 1,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 0,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 0,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 21,
      "op": "settle",
      "caption": "1 is now in its final position (index 0).",
      "note": null,
      "codeLine": 4,
      "stats": {
        "compares": 10,
        "swaps": 5
      },
      "array": [
        1,
        2,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        "settled",
        null,
        null,
        null,
        null,
        null,
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 1,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 0,
          "tone": "bound"
        }
      ],
      "regions": []
    },
    {
      "i": 22,
      "op": "read",
      "caption": "Pivot is 7 — the last element of [4..7].",
      "note": null,
      "codeLine": 3,
      "stats": {
        "compares": 10,
        "swaps": 5
      },
      "array": [
        1,
        2,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        "read"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 0,
          "tone": "bound"
        }
      ],
      "regions": []
    },
    {
      "i": 23,
      "op": "compare",
      "caption": "Is 6 < pivot 7?",
      "note": "yes → belongs left",
      "codeLine": 4,
      "stats": {
        "compares": 11,
        "swaps": 5
      },
      "array": [
        1,
        2,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        null,
        null,
        null,
        null,
        "compare",
        null,
        null,
        "compare"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 4,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 4,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 24,
      "op": "compare",
      "caption": "Is 9 < pivot 7?",
      "note": "no → leave it",
      "codeLine": 4,
      "stats": {
        "compares": 12,
        "swaps": 5
      },
      "array": [
        1,
        2,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        null,
        null,
        null,
        null,
        null,
        "compare",
        null,
        "compare"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 5,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 5,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 25,
      "op": "compare",
      "caption": "Is 8 < pivot 7?",
      "note": "no → leave it",
      "codeLine": 4,
      "stats": {
        "compares": 13,
        "swaps": 5
      },
      "array": [
        1,
        2,
        3,
        5,
        6,
        9,
        8,
        7
      ],
      "focus": [
        null,
        null,
        null,
        null,
        null,
        null,
        "compare",
        "compare"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 5,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 6,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 26,
      "op": "swap",
      "caption": "Drop the pivot 7 into index 5.",
      "note": null,
      "codeLine": 4,
      "stats": {
        "compares": 13,
        "swaps": 6
      },
      "array": [
        1,
        2,
        3,
        5,
        6,
        7,
        8,
        9
      ],
      "focus": [
        null,
        null,
        null,
        null,
        null,
        "swap",
        null,
        "swap"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 5,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 6,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 27,
      "op": "settle",
      "caption": "7 is now in its final position (index 5).",
      "note": null,
      "codeLine": 4,
      "stats": {
        "compares": 13,
        "swaps": 6
      },
      "array": [
        1,
        2,
        3,
        5,
        6,
        7,
        8,
        9
      ],
      "focus": [
        null,
        null,
        null,
        null,
        null,
        "settled",
        null,
        null
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 5,
          "tone": "bound"
        }
      ],
      "regions": []
    },
    {
      "i": 28,
      "op": "read",
      "caption": "Pivot is 9 — the last element of [6..7].",
      "note": null,
      "codeLine": 3,
      "stats": {
        "compares": 13,
        "swaps": 6
      },
      "array": [
        1,
        2,
        3,
        5,
        6,
        7,
        8,
        9
      ],
      "focus": [
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        "read"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 5,
          "tone": "bound"
        }
      ],
      "regions": []
    },
    {
      "i": 29,
      "op": "compare",
      "caption": "Is 8 < pivot 9?",
      "note": "yes → belongs left",
      "codeLine": 4,
      "stats": {
        "compares": 14,
        "swaps": 6
      },
      "array": [
        1,
        2,
        3,
        5,
        6,
        7,
        8,
        9
      ],
      "focus": [
        null,
        null,
        null,
        null,
        null,
        null,
        "compare",
        "compare"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 6,
          "tone": "bound"
        },
        {
          "name": "j",
          "index": 6,
          "tone": "compare"
        }
      ],
      "regions": []
    },
    {
      "i": 30,
      "op": "settle",
      "caption": "9 is now in its final position (index 7).",
      "note": null,
      "codeLine": 4,
      "stats": {
        "compares": 14,
        "swaps": 6
      },
      "array": [
        1,
        2,
        3,
        5,
        6,
        7,
        8,
        9
      ],
      "focus": [
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        "settled"
      ],
      "markers": [
        {
          "name": "pivot",
          "index": 7,
          "tone": "pivot"
        },
        {
          "name": "i",
          "index": 7,
          "tone": "bound"
        }
      ],
      "regions": []
    },
    {
      "i": 31,
      "op": "settle",
      "caption": "Sorted.",
      "note": null,
      "codeLine": 4,
      "stats": {
        "compares": 14,
        "swaps": 6
      },
      "array": [
        1,
        2,
        3,
        5,
        6,
        7,
        8,
        9
      ],
      "focus": [
        "settled",
        "settled",
        "settled",
        "settled",
        "settled",
        "settled",
        "settled",
        "settled"
      ],
      "markers": [],
      "regions": [
        {
          "label": "sorted",
          "from": 0,
          "to": 7,
          "tone": "settled"
        }
      ]
    }
  ]
}