April 23, 2021, 11:33:38 AM

## News:

Juju thinks he's so clever by putting funny stuff here

### Discord Shoutbox

You can help CodeWalrus stay online by donating here.

## Heapsort, VATSort, and ListSort

Started by Zeda, July 04, 2018, 02:28:02 AM

0 Members and 1 Guest are viewing this topic.

#### Zeda

##### July 04, 2018, 02:28:02 AM
Hey all, I implemented the heapsort algorithm with some features inspired by Sean McLaughlin's implementation. Heapsort operates in O(n*log(n)) time, so it is fast even as array sizes increase. The cool perk to Sean's implementation that I wanted to include in mine is the ability to have a callback function that performs comparisons. This is fantastic if your array contains pointers to, say, an array of strings. The callback function can take the inputs (in my case, HL and DE), perform a string comparison, and return the result to the heapsort routine. Heapsort will then know whether or not to swap the elements.

As an example, I created a VAT sorting routine. It creates an array of pointers to the VAT entries of named variables (like Programs, Appvars, etc.), and then uses a fancy callback function that compares the names of the VAT entries. Returned is an alphabetically sorted array of pointers.

As well, I made a very fast routine to sort TI lists. The callback routine for this takes indices, constructs pointers to the actual list data, compares them, then returns the result. Since the OS routine uses an O(n2) algorithm, my program can perform way faster on larger lists. I ran a few tests on random lists and came up with:

* at 100 elements, the OS routine and my routine were pretty close in speed.
* at 400 elements, my routine sorted it in ~1.3 seconds, versus ~9.5. for the OS routine
* at 999 elements, my routine sorted it in ~3.0 seconds, versus ~55.5. for the OS.

Code (Heapsort) Select
`#ifndef scrap#define scrap 8000h.echo "Warning, 'scrap' not defined, defining scrap=8000h"#endif#ifndef SMCarraybase= scraparraylen = scrap+2#endifheapflags= 33curchild = 0heapsort:;   HL points to the array data;   BC is the size of the array. NOT GREATER THAN 32767;   IX points to the routine that compares the values#ifdef fast    call heapify    ld hl,(arraylen)#else    push bc    call heapify    pop hl#endif_:    dec hl    ld (arraylen),hl#ifndef fast    push hl#endif    ld de,(arraybase)    add hl,hl    inc de    add hl,de#ifdef fast    ld a,(de)    ldd    inc hl    ld (hl),a    dec hl    ld a,(de)    ldd    inc hl    ld (hl),a#else    call swap#endif    ld bc,1    call propogate#ifdef fast    ld hl,(arraylen)#else    pop hl#endif    ld a,h    or l    jr nz,-_        retheapify:;Inputs:;   HL points to the array data;   BC is the size of the array. NOT GREATER THAN 32767;   IX points to the routine that compares the values    ld (arraybase),hl    ld (arraylen),bc    srl b    rr c_:    push bc    call propogate    pop bc    dec bc    ld a,b    or c    jr nz,-_    retpropogate:;BC-1 is the parent index;2BC is the child1 index    res curchild,(iy+heapflags)proppost:    sla c    rl b    ld d,b    ld e,c#ifdef SMCarraylen=\$+1    ld hl,0#else    ld hl,(arraylen)#endif    sbc hl,de    add hl,de    ret c  ;no children;compare the two children#ifdef SMCarraybase=\$+1    ld hl,0#else    ld hl,(arraybase)#endif    add hl,de    add hl,de    inc hl    ld d,(hl)    dec hl    ld e,(hl)    dec hl    push hl    ld a,(hl)    dec hl    ld l,(hl)    ld h,a    ;HL holds the value of child0    ;DE holds the value of child1    jr z,+_    call callix    jr nc,+_    ex de,hl    pop de    inc de    inc de    set curchild,(iy+heapflags)    push de_:;{stack} points to the child;HL is the value of the child;BC points to the parent;now compare the child and parent    ex de,hl    ld hl,(arraybase)    add hl,bc    push hl    dec hl    ld a,(hl)    dec hl    ld l,(hl)    ld h,a    call callix    pop hl    pop de    ret nc    dec hl    call swap;values swapped, now set parent=child;BC is the index of child1    bit curchild,(iy+heapflags)    jp z,proppost    inc bc    jp propogateswap:;HL points to the top of one word;DE points to the top of another;Must preserve BC#ifdef fast    ld a,(de)    ldd    inc hl    ld (hl),a    dec hl    ld a,(de)    ldd    inc hl    ld (hl),a    inc c    inc bc#else    call +__:    ld a,(de)    ldd    inc hl    ld (hl),a    dec hl    inc bc#endif    retcallix:    jp (ix)`
Even when optimizing for speed over size, my code is smaller, but I'm fairly sure there are more optimizations to be found!

#### Lionel Debroux

##### July 04, 2018, 04:48:26 AM #1
Hi Zeda
That's another great display that TI uses silly, slow algorithms...
That reminds me of Samuel Stearley's faster next_expression_index() and list item access routines for the TI-68k series.

Out of curiosity:
* how much execution time does inlining the comparison function save ?
* what's the execution time of an implementation of shellsort with a reasonable sequence (not the original O(n^2) one) on the same-sized lists produced from the same random seeds ? There's no O(n*log(n)) implementation of shellsort, but there's usually a range of sizes where an implementation with a reasonable sequence it trounces the quadratic sorts while being competitive with some asymptotically better O(n*log(n)) sorts. 200 items could be within that range, but 999 usually isn't.
Member of the TI-Chess Team.
Co-maintainer of GCC4TI (GCC4TI online documentation), TIEmu and TILP.