The Performance Challenge Throughout this series, we learned three different sorting algorithms: Bubble Sort (Part 94), Insertion Sort (Part 96), and Quicksort (Part 95). The final question is: which one is truly the fastest on the Z80? The answer depends entirely on the size and initial state of the data. The Benchmarking Strategy To accurately compare performance, we measure the time taken in T-states (clock cycles) to sort three different datasets of 16-bit words. ...
Z80 Assembly 99: Merge Sort (The Memory-Hungry Sort)
The Speed of Merge Sort Merge Sort is another highly efficient sorting algorithm that runs in optimal $O(n \log n)$ time, regardless of the initial state of the data. It is highly valued for its predictability and stability (it preserves the relative order of equal elements). The Principle: Merge Sort is a recursive algorithm that continually splits the array into two halves until it has many arrays of size one. It then merges these small, sorted arrays back together in the correct order. ...
Z80 Assembly 98: Shell Sort (The Gap-Based Improvement)
The Drawback of Insertion Sort Insertion Sort (Part 96) is very fast for nearly sorted data, but slow for completely unsorted data because it can only move an element one position at a time. An element near the end must be swapped many times to reach the beginning. The Solution: Shell Sort Shell Sort (invented by Donald Shell) is an enhancement of Insertion Sort. It allows for large moves by sorting elements that are far apart, drastically reducing the number of total comparisons needed. ...
Z80 Assembly 97: Selection Sort (Minimizing Memory Writes)
The Advantage of Selection Sort Both Bubble Sort (Part 94) and Insertion Sort (Part 96) frequently swap adjacent elements, leading to many memory write operations. If you are sorting data that resides on a slow medium (like a disk cache) or requires complex I/O to access, minimizing these writes is critical. Selection Sort does exactly this. The Principle: Selection Sort makes one pass over the unsorted portion of the array to select the smallest (or largest) element. It then performs only one swap to move that selected element into its final sorted position. ...
Z80 Assembly 96: Insertion Sort (The Efficient Simple Sort)
The Advantage of Insertion Sort While Quicksort (Part 95) is fastest for large, random arrays, Insertion Sort is often faster for two specific scenarios: Small Arrays: Its low overhead makes it faster than Quicksort for arrays under 20-30 elements. Nearly Sorted Arrays: It is extremely fast, running in nearly linear time ($O(n)$), if the array is already mostly sorted. The Principle: The algorithm builds the final sorted array one item at a time. It iterates through the input elements and inserts each element into its correct position within the already sorted portion of the array. ...
Z80 Assembly 95: Quicksort (The Divide-and-Conquer Sorting Algorithm)
The Need for Quicksort While Bubble Sort (Part 94) is easy, its slow $O(n^2)$ time complexity makes it unusable for sorting large arrays. Quicksort is the fastest widely used sorting algorithm, running in $O(n \log n)$ time on average, making it ideal for sorting large high-score tables or data structures. The Principle: Quicksort uses a “divide-and-conquer” strategy: it picks an element (the pivot) and partitions the other elements into two sub-arrays according to whether they are less than or greater than the pivot. It then recursively sorts the sub-arrays. ...
Z80 Assembly 94: Bubble Sort (The Simplest Sorting Algorithm)
The Need for Sorting Sorting arrays of data (e.g., high scores, tile IDs, or inventory items) is a fundamental task. While complex algorithms exist, Bubble Sort is the simplest to implement on the Z80 due to its minimal memory requirements and straightforward logic. The Principle: Bubble Sort works by repeatedly stepping through the list, comparing adjacent elements, and swapping them if they are in the wrong order. This process is repeated until no swaps are needed, meaning the list is sorted. ...
Z80 Assembly 93: Binary Search (Dichotomic Search) on a Sorted Array
The Need for Fast Lookup If you have a large list of data (e.g., all font character pointers, or a list of game variables) that is sorted alphabetically or numerically, checking every item sequentially (`memchr′ in Part 89) is inefficient. Binary Search is the solution: it finds the target by repeatedly dividing the search space in half. The Principle: After each comparison, the algorithm eliminates half of the remaining elements. This makes the search time logarithmic, drastically speeding up large lookups. ...
Z80 Assembly 92: Block Compare with Difference (memcmp and Mismatch)
The Need for a Detailed Compare The standard `memcmp′ routine (Part 89) tells you only if two blocks are the same or different. For debugging purposes, you often need to know where the corruption or difference first occurred. Goal: Compare two memory blocks, and if they differ, return the address of the first byte that does not match. The Comparison Strategy We will modify the simple comparison loop to preserve the address and exit immediately upon the first failure. ...
Z80 Assembly 91: Fast 16-bit Block Clear (memset to Zero)
The Need for a Fast Block Clear Initializing memory to zero is one of the most common tasks in low-level programming (the equivalent of calling memset(ptr, 0, size) in C). Since the Z80 needs to clear large buffers, a highly optimized routine is essential. Goal: Fill a specified memory range (START_ADDR′ to END_ADDR′) with the byte value `00H′ as quickly as possible. The Optimized Strategy: Using LDIR The fastest method is a slight modification of the Block Fill routine (Part 85), exploiting the `LDIR′ (Load, Increment, Repeat) instruction. ...