Ophis/book/x719.html
2012-06-16 02:07:47 -07:00

444 lines
9.7 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>A modest example: Insertion sort on linked lists</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Programming with Ophis"
HREF="book1.html"><LINK
REL="UP"
TITLE="Structured Programming"
HREF="c543.html"><LINK
REL="PREVIOUS"
TITLE="Data structures"
HREF="x666.html"><LINK
REL="NEXT"
TITLE="Pointers and Indirection"
HREF="c748.html"></HEAD
><BODY
CLASS="SECTION"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming with Ophis</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x666.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Structured Programming</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="c748.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECTION"
><H1
CLASS="SECTION"
><A
NAME="AEN719"
>A modest example: Insertion sort on linked lists</A
></H1
><P
> To demonstrate these techniques, we will now produce code to
perform insertion sort on a linked list. We'll start by defining
our data structure, then defining the routines we want to write,
then producing actual code for those routines. A downloadable
version that will run unmodified on a Commodore 64 closes the
chapter.
</P
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN722"
>The data structure</A
></H2
><P
> We don't really want to have to deal with pointers if we can
possibly avoid it, but it's hard to do a linked list without
them. Instead of pointers, we will
use <I
CLASS="EMPHASIS"
>cursors</I
>: small integers that represent
the index into the array of values. This lets us use the
many-small-byte-arrays technique for our data. Furthermore, our
random data that we're sorting never has to move, so we may
declare it as a constant and only bother with changing the
values of <TT
CLASS="LITERAL"
>head</TT
> and
the <TT
CLASS="LITERAL"
>next</TT
> arrays. The data record definition
looks like this:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
> head : byte;
data : const int[16] = [838, 618, 205, 984, 724, 301, 249, 946,
925, 43, 114, 697, 985, 633, 312, 86];
next : byte[16];</PRE
></TD
></TR
></TABLE
><P
> Exactly how this gets represented will vary from assembler to
assembler. Ophis does it like this:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>.data
.space head 1
.space next 16
.text
lb: .byte &#60;$838,&#60;$618,&#60;$205,&#60;$984,&#60;$724,&#60;$301,&#60;$249,&#60;$946
.byte &#60;$925,&#60;$043,&#60;$114,&#60;$697,&#60;$985,&#60;$633,&#60;$312,&#60;$086
hb: .byte &#62;$838,&#62;$618,&#62;$205,&#62;$984,&#62;$724,&#62;$301,&#62;$249,&#62;$946
.byte &#62;$925,&#62;$043,&#62;$114,&#62;$697,&#62;$985,&#62;$633,&#62;$312,&#62;$086</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN731"
>Doing an insertion sort</A
></H2
><P
> To do an insertion sort, we clear the list by setting the 'head'
value to -1, and then insert each element into the list one at a
time, placing each element in its proper order in the list. We
can consider the lb/hb structure alone as an array of 16
integers, and just insert each one into the list one at a
time.
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>procedure insertion_sort
head := -1;
for i := 0 to 15 do
insert_elt i
end
end</PRE
></TD
></TR
></TABLE
><P
> This translates pretty directly. We'll have insert_elt take its
argument in the X register, and loop with that. However, given
that insert_elt is going to be a complex procedure, we'll save
the value first. The assembler code becomes:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; insertion'sort: Sorts the list defined by head, next, hb, lb.
; Arguments: None.
; Modifies: All registers destroyed, head and next array sorted.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
insertion'sort:
lda #$FF ; Clear list by storing the terminator in 'head'
sta head
ldx #$0 ; Loop through the lb/hb array, adding each
insertion'sort'loop: ; element one at a time
txa
pha
jsr insert_elt
pla
tax
inx
cpx #$10
bne insertion'sort'loop
rts</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN737"
>Inserting an element</A
></H2
><P
> The pseudocode for inserting an element is a bit more
complicated. If the list is empty, or the value we're inserting
goes at the front, then we have to update the value
of <TT
CLASS="LITERAL"
>head</TT
>. Otherwise, we can iterate through
the list until we find the element that our value fits in after
(so, the first element whose successor is larger than our
value). Then we update the next pointers directly and exit.
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>procedure insert_elt i
begin
if head = -1 then begin
head := i;
next[i] := -1;
return;
end;
val := data[i];
if val &#60; data[i] then begin
next[i] := head;
head := i;
return;
end;
current := head;
while (next[current] &#60;&#62; -1 and val &#60; data[next[current]]) do
current := next[current];
end;
next[i] := next[current];
next[current] := i;
end;</PRE
></TD
></TR
></TABLE
><P
> This produces the following rather hefty chunk of code:
</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; insert_elt: Insert an element into the linked list. Maintains the
; list in sorted, ascending order. Used by
; insertion'sort.
; Arguments: X register holds the index of the element to add.
; Modifies: All registers destroyed; head and next arrays updated
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.data
.space lbtoinsert 1
.space hbtoinsert 1
.space indextoinsert 1
.text
insert_elt:
ldy head ; If the list is empty, make
cpy #$FF ; head point at it, and return.
bne insert_elt'list'not'empty
stx head
tya
sta next,x
rts
insert_elt'list'not'empty:
lda lb,x ; Cache the data we're inserting
sta lbtoinsert
lda hb,x
sta hbtoinsert
stx indextoinsert
ldy head ; Compare the first value with
sec ; the data. If the data must
lda lb,y ; be inserted at the front...
sbc lbtoinsert
lda hb,y
sbc hbtoinsert
bmi insert_elt'not'smallest
tya ; Set its next pointer to the
sta next,x ; old head, update the head
stx head ; pointer, and return.
rts
insert_elt'not'smallest:
ldx head
insert_elt'loop: ; At this point, we know that
lda next,x ; argument &#62; data[X].
tay
cpy #$FF ; if next[X] = #$FF, insert arg at end.
beq insert_elt'insert'after'current
lda lb,y ; Otherwise, compare arg to
sec ; data[next[X]]. If we insert
sbc lbtoinsert ; before that...
lda hb,y
sbc hbtoinsert
bmi insert_elt'goto'next
insert_elt'insert'after'current: ; Fix up all the next links
tya
ldy indextoinsert
sta next,y
tya
sta next,x
rts ; and return.
insert_elt'goto'next: ; Otherwise, let X = next[X]
tya ; and go looping again.
tax
jmp insert_elt'loop</PRE
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="SECTION"
><H2
CLASS="SECTION"
><A
NAME="AEN744"
>The complete application</A
></H2
><P
> The full application, which deals with interfacing with CBM
BASIC and handles console I/O and such, is
in <A
HREF="x1026.html"
><I
><I
>structuredemo.oph</I
></I
></A
>.
</P
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="x666.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="c748.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Data structures</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c543.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Pointers and Indirection</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>