We have discussed linked lists for implementing stacks and queues. Always add/delete at one end of the list. Now look at more general operations on linked lists.

Trying to emphasize what's important. Book covers more, but not all of it is as essential. Hard topic to understand the first time.

Chapter 7 in Shiflet text.

Linked List Traversal

NodeType {
    Item_type item;
    NodeType *pNodeNext;
};

NodeType *pNodeHead;      /* head of the linked list */
NodeType *pNode;          /* general node */

for (pNode = pNodeHead; pNode != NULL; pNode = pNode->pNodeNext)
    /* do something with the pNode element */

Linked list traversal is a basic operation. Must understand. Analagous to traversing an array of elements.

for (i = 0; i < MAXQUEUE; i++)
    /* do something with the ith array element */

One use is to have a generic traversal function that prints each node. (It is also possible to pass functions as arguments).

/*
 * /cs/cs2005/pub/example/morell.C -- more linked list stuff 
 */

#include <iostream.h>

typedef char Item_type;

struct NodeType {
    Item_type item;
    NodeType *pNodeNext;
};

class LinkedList {
  private:
    NodeType *pNodeHead;
    NodeType *MakeNode(Item_type item);
  public:
    LinkedList();
    void Traverse();
    int InsertItem(Item_type);
    int DeleteItem(Item_type);
};

main()
{
    LinkedList list;

    // ignoring return values
    list.InsertItem('d');
    list.InsertItem('a');
    list.InsertItem('k');
    list.InsertItem('a');
    list.Traverse();
    list.DeleteItem('d');
    list.DeleteItem('a');
    list.DeleteItem('k');
    list.Traverse();
}

/*
 * LinkedList -- set up the list
 */
LinkedList::LinkedList()
{
    pNodeHead = NULL;
}

/*
 * Traverse -- traverse a linked list and print each node
 */
void LinkedList::Traverse()
{
    NodeType *pNode;

    for (pNode = pNodeHead; pNode != NULL; pNode = pNode->pNodeNext)
        cout << "Item: " << pNode->item << "\n";
}

Linked List Insertion

Common to maintain a sorted linked list (for example a sorted queue). Rather than insert at the beginning or the end we must traverse the list to find where to insert.

Insertion in an arbitrary location can be tricky. We must always have a pointer to the node previous to the node we with to insert at (show picture).

Many approaches to do so. We will save a second pointer which points to the previous node.

/*
 * InsertItem -- insert the item into a sorted list, 0=success, -1=failure
 */
int LinkedList::InsertItem(Item_type item)
{
    NodeType *pNode, *pNodeTmp, *pNodeSave;

    if ((pNode = MakeNode(item)) == NULL)
        return(-1);
    else {
        if (pNodeHead == NULL) {
            /* first node in the list */
            pNodeHead = pNode;
        }
        else if (item < pNodeHead->item) {
            /* insert at the head */
            pNode->pNodeNext = pNodeHead;
            pNodeHead = pNode;
        }
        else {
            pNodeSave = pNodeHead; /* trailing pointer */
            pNodeTmp = pNodeHead->pNodeNext; 
            while ((pNodeTmp != NULL) && (item >= pNodeTmp->item)) {
                pNodeSave = pNodeTmp;
                pNodeTmp = pNodeTmp->pNodeNext;
            }
            pNode->pNodeNext = pNodeSave->pNodeNext;
            pNodeSave->pNodeNext = pNode;
        }
        return(0);
    }
}

Linked List Deletion

Similar to insertion we must retain a pointer to the node before the one to be deleted.

/*
 * DeleteItem -- delete the first occurrence of item in the list, 
 *               0=success, -1=failure 
 */
int LinkedList::DeleteItem(Item_type item)
{
    NodeType *pNodeTmp, *pNodeSave;

    if (pNodeHead == NULL)
        return(-1);
    else if (pNodeHead->item == item) {
        pNodeTmp = pNodeHead;
        pNodeHead = pNodeHead->pNodeNext;
        delete pNodeTmp;
        return(0);
    }
    else {
        pNodeSave = pNodeHead; /* trailing pointer */
        pNodeTmp = pNodeHead->pNodeNext; 
        while ((pNodeTmp != NULL) && (item != pNodeTmp->item)) {
            pNodeSave = pNodeTmp;
            pNodeTmp = pNodeTmp->pNodeNext;
        }
        if (pNodeTmp == NULL)
            return(-1);                /* not found */
        else {
            pNodeSave->pNodeNext = pNodeTmp->pNodeNext;
            delete pNodeTmp;
            return(0);
        }
    }
}

Doubly-Linked Lists

To make insertions and deletions easier and allow traversals in forward or backward order we can use a doubly linked list.

struct NodeType {
    Item_type item;
    NodeType *pNodeNext;
    NodeType *pNodePrev;
};

Comparisons of Implementations

Linked Lists versus Contiguous Storage

Polynomial Again Revisited

Polynomial example in book is different than what we did. First assignment could be implemented using linked lists. Would not need the degree.

struct PolyNode {
    float fCoeff;
    int wExp;
    PolyNode *pPolyNext;
};

Array Implementation of Linked Lists

Can use array indices instead of pointers. Same idea.