First-fit takes the first block that works; best-fit hunts for the tightest one. Today you add best-fit as a selectable policy and pin a case where the two pick genuinely different blocks.
Add a best-fit search that picks the smallest adequate free block, and show it choosing differently from first-fit.
Which free block should a request take when several fit? First-fit takes the first adequate block it encounters - fast, but it can chew up a big block for a small request. Best-fit scans the whole free list and takes the smallest block that still fits, leaving larger blocks intact for larger requests, at the cost of a full scan. Neither wins outright; they trade speed for fragmentation differently, which is exactly why real allocators pick a policy deliberately.
The difference is real, not cosmetic. With a free list holding a 40-byte block at the head and a 24-byte block later, a request that needs only 24 bytes goes to the 40-byte block under first-fit (it is first) but to the 24-byte block under best-fit (it is the tightest). Same request, different block, different resulting layout. Keep first-fit as the default for the rest of the project; best-fit is the alternative you can now reach for.
// first-fit: return the first block that fits (today's search).// best-fit: scan the whole free list, keep the smallest Size >= need.best, bestSize := -1, math.MaxIntfor off := a.freeHead; off != -1; off = a.next(off) {if size, _ := a.blockAt(off); size >= need && size < bestSize {best, bestSize = off, size}}