Dr. Carlo Pescio
Sorting in Small Memories

Published in Electronic Design, Penton Publishing, Vol. 44 No. 8, April 15, 1996.
This paper won the "Best of the Issue" award.


Sorting is an essential routine used in most programs; still, in embedded applications we often have to struggle with extremely small memory for code and auxiliary data, including stack space. Saving memory raises new challenges even in well-known areas like sorting, since we canít always trade performance for space. The following implementation of the CombSort algorithm (average performance quite higher than BubbleSort, but lower than QuickSort) has been filed down to a very small footprint, while providing good performance in sorting arrays of integers using low-end Intel processors; here are the major features of the routine:



Although optimized for size, the CombSort algorithm is quite fast, and this tight implementation may even outperform a QuickSort routine implemented in high-level languages. If your target processor is a 386 or more, it is even possible to create a smaller and faster version of the program, although applications using a 386 are usually not memory-constrained.

The listing if fully commented with strategic and tactical annotations, so you can borrow some of the techniques used here and apply them to other problems, where saving memory is an essential part of the coding activity. I also include a short C program to show how to call the routine from C language.

An example of call in C language:
#include <stdio.h>

extern void sort( int size, int gap, int x[] ) ;
/* always call with size = gap */

int main()
  {
  #define SIZE 6
  int a[ SIZE ] = { 2, 5, 3, -6, 8, 1 } ;
  int i ;
  sort( SIZE, SIZE, a ) ;
  for( i = 0; i < SIZE; i++ )
    printf( "%d ", a[ i ] ) ;
  return( 0 ) ;
  }

The assembly code:
.model small
.code

public	_sort	; C prototype: void sort( int size, int gap, int data[] )
				; call using size = gap, size > 0
top:
	push	di		; must save value (used by C compilers)
	mov	dx, ax		; dx used as a "swap done" flag
	; prepare pointers to items to compare
	shl	ax, 1		; must index integers = 2 bytes in size
	mov	di, ax	
swapping:
	; swap [bx], [bx+di] if necessary
	mov	ax, [bx]
	cmp	ax, [bx+di]
	jle	already_sorted	; use jbe for unsigned integers sort
	; swap
	xchg	ax, [bx+di]
	xchg	ax, [bx]
	xor	dx, dx		; dx=gap if no swapping took place, 0 otherwise
already_sorted:
	; point to next items
	inc	bx
	inc	bx
	loop	swapping
	pop	di		; must restore now

	; if no switches made and gap = 1, items are all sorted
	; condition above is dx = gap and gap = 1
	; that means I can simply check for dx = 1
	dec	dx
	jz	all_sorted
_sort:
	pop	dx		; get return address
	pop	cx		; get size
	pop	ax		; get gap
	
	; a good approximation of gap = max( 1, gap / 1.3 )
	mov	bx, ax
	shr	bx, 1
	shr	bx, 1
	sub	ax, bx
	dec	ax
	jnz	gap_ok
	inc	ax
gap_ok:
	pop	bx		; get data address

	; here the stack is restored to the former, only the gap 
	; is changed to the next value, so I can iterate many 
	; times by falling into _sort from swapping.
	push	bx		; save data address
	push	ax		; save new gap
	push	cx		; save size
	push	dx		; save return address

	; iterate size - gap times
	sub	cx, ax
	jg	top		; if more than 1 element to sort

all_sorted:	
	ret
end

Reader's Map
Several visitors who have read
this article have also read:

Biography
Carlo Pescio holds a doctoral degree in Computer Science and is a consultant and mentor for various European companies and corporations, including the Directorate of the European Commission. He specializes in object oriented technologies and is a member of IEEE Computer Society, the ACM, and the New York Academy of Sciences. He lives in Savona, Italy and can be contacted at pescio@eptacom.net.