abrash-black-book/15-01.md
2013-12-30 20:26:41 +11:00

139 lines
No EOL
7.7 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Chapter 15\
Linked Lists and plain Unintended Challenges {#Heading1}
---------------------------------------------
### Unfamiliar Problems with Familiar Data Structures {#Heading2}
After 21 years, this story still makes me wince. Oh, the humiliations I
suffer for your enlightenment....
It wasn't until ninth grade that I had my first real girlfriend. Okay,
maybe I was a little socially challenged as a kid, but hey, show me a
good programmer who wasn't; it goes with the territory. Her name was
Jeannie Schweigert, and she was about four feet tall, pretty enough, and
female—and willing to go out with me, which made her approximately as
attractive as Cheryl Tiegs, in my book.
Jeannie and I hung out together at school, and went to basketball games
and a few parties together, but somehow the two of us were never alone.
Being 14, neither of us could drive, so her parents tended to end up
chauffeuring us. That's a next-to-ideal arrangement, I now realize,
having a daughter of my own (ideal being exiling all males between the
ages of 12 and 18 to Tasmania), but at the time, it drove me nuts. You
see...ahem...I had never actually kissed Jeannie—or anyone, for that
matter, unless you count maiden aunts and the like—and I was dying to.
At the same time, I was terrified at the prospect. What if I turned out
to be no good at it? It wasn't as if I could go to Kisses ‘R' Us and
take lessons.
My long-awaited opportunity finally came after a basketball game. For a
change, *my* father was driving, and when we dropped her off at her
house, I walked her to the door. This was my big chance. I put my arms
around her, bent over with my eyes closed, just like in the movies....
And whacked her on the top of the head with my chin. (As I said, she was
only about four feet tall.) And I do mean whacked. Jeannie burst into
hysterical laughter, tried to calm herself down, said goodnight, and
went inside, still giggling. No kiss.
I was a pretty mature teenager, so this was only slightly more traumatic
than leading the Tournament of Roses parade in my underwear. On the next
try, though, I did manage to get the hang of this kissing business, and
eventually even went on to have a child. (Not with Jeannie, I might add;
the mind boggles at the mess I could have made of *that* with her.) As
it turns out, none of that stuff is particularly difficult; in fact,
it's kind of enjoyable, wink, wink, say no more.
When you're dealing with something new, a little knowledge goes a long
way. When it comes to kissing, we have to fumble along the learning
curve on our own, but there are all sorts of resources to help speed up
the learning process when it comes to programming. The basic mechanisms
of programming—searches, sorts, parsing, and the like—are
well-understood and superbly well-documented. Treat yourself to a book
like *Algorithms,* by Robert Sedgewick (Addison Wesley), or Knuth's *The
Art of Computer Programming* series (also from Addison Wesley; and where
was Knuth with *The Art of Kissing* when I needed him?), or practically
anything by Jon Bentley, and when you tackle a new area, give yourself a
head start. There's still plenty of room for inventiveness and
creativity on your part, but why not apply that energy on top of the
knowledge that's already been gained, instead of reinventing the wheel?
I know, reinventing the wheel is just the kind of challenge programmers
love—but can you really afford to waste the time? And do you honestly
think that you're so smart that you can out-think Knuth, who's spent a
lifetime at this stuff and happens to be a genius?
Maybe you can—but I sure can't. For example, consider the evolution of
my understanding of linked lists.
### Linked Lists {#Heading3}
Linked lists are data structures composed of discrete elements, or
nodes, joined together with links. In C, the links are typically
pointers. Like all data structures, linked lists have their strengths
and their weaknesses. Primary among the strengths are: simplicity;
speedy sequential processing; ease and speed of insertion and deletion;
the ability to mix nodes of various sizes and types; and the ability to
handle variable amounts of data, especially when the total amount of
data changes dynamically or is not always known beforehand. Weaknesses
include: greater memory requirements than arrays (the pointers take up
space); slow non-sequential processing, including finding arbitrary
nodes; and an inability to backtrack, unless doubly-linked lists are
used. Unfortunately, doubly linked lists need more memory, as well as
processing time to maintain the backward links.
Linked lists aren't very good for most types of sorts. Insertion and
bubble sorts work fine, but more sophisticated sorts depend on efficient
random access, which linked lists don't provide. Likewise, you wouldn't
want to do a binary search on a linked list. On the other hand, linked
lists are ideal for applications where nothing more than sequential
access is needed to data that's always sorted or nearly sorted.
Consider a polygon fill function, for example. Polygon edges are added
to the active edge list in x-sorted order, and tend to stay pretty
nearly x-sorted, so sophisticated sorting is never needed. Edges are
read out of the list in sorted order, just the way linked lists work
best. Moreover, linked lists are straightforward to implement, and with
linked lists an arbitrary number of polygon edges can be handled with no
fuss. All in all, linked lists work beautifully for filling polygons.
For an example of the use of linked lists in polygon filling, see my
column in the May 1991 issue of *Dr. Dobb's Journal.* Be warned, though,
that none of the following optimizations are to be found in that column.
You see, that column was my first heavy-duty use of linked lists, and
they seemed so simple that I didn't even open Sedgewick or Knuth. For
hashing or Boyer-Moore searching, sure, I'd have done my homework first;
but linked lists seemed too obvious to bother. I was much more concerned
with the polygon-related aspects of the implementation, and, in truth, I
gave the linked list implementation not a moment's thought before I
began coding. Heck, I had handled *much* tougher programming problems in
the past; surely it would be faster to figure this one out on my own
than to look it up.
Not!
The basic concept of a linked list—the one I came up with for that *DDJ*
column—is straightforward, as shown in Figure 15.1. A head pointer
points to the first node in the list, which points to the next node,
which points to the next, and so on, until the last node in the list is
reached (typically denoted by a **NULL** next-node pointer).
Conceptually, nothing could be simpler. From an implementation
perspective, however, there are serious flaws with this model.
The fundamental problem is that the model of Figure 15.1 unnecessarily
complicates link manipulation. In order to delete a node, for example,
you must change the preceding node's **NextNode** pointer to point to
the following node, as shown in Listing 15.1. (Listing 15.2 is the
header file LLIST.H, which is **\#include**d by all the linked list
listings in this chapter.) Easy enough—unless the preceding node happens
to be the head pointer, which doesn't *have* a **NextNode** field,
because it's not a node, so Listing 15.1 won't work. Cumbersome special
code and extra information (a pointer to the head of the list) are
required to handle the head-pointer case, as shown in Listing 15.3.
(I'll grant you that if you make the next-node pointer the first field
in the **LinkNode** structure, at offset 0, then you could successfully
point to the head pointer and pretend it was a **LinkNode**
structure—but that's an ugly and potentially dangerous trick, and we'll
see a better approach next.)
![](images/15-01.jpg)\
**Figure 15.1**  *The basic concept of a linked list.*