Notes
Slide Show
Outline
1
"Brad Rippe"
  • Brad Rippe
2
Overview
  • 13.1   Nodes and Linked Lists
  • 13.2   Stacks and Queues
3
"Nodes and Linked Lists"
  • Nodes and Linked Lists
4
Nodes and Linked Lists
    • A linked list is a list that can grow and shrink while the program is running
    • A linked list is constructed using pointers
    • A linked list often consists of structs or classes that contain a pointer variable connecting them to other dynamic variables
    • A linked list can be visualized as items, drawn as boxes, connected to other items by arrows
5
Nodes
  • The boxes in the previous drawing represent the nodes of a linked list
    • Nodes contain the data item(s) and a pointer that can point to another node of the same type
      • The pointers point to the entire node, not an individual item that might be in the node
  • The arrows in the drawing represent pointers
6
Implementing Nodes
  • Nodes are implemented in C++ as structs or
    classes
    • Example:  A structure to store two data items and
                       a pointer to another node of the same type,
                       along with a type definition might be:

                          struct Node {
                              string data;
                              Node *next;
                           };

                          typedef Node* NodePtr;
7
The head of a List
  • The box labeled head, is not a
    node, but a pointer variable that points to a node
  • Pointer variable head is declared as:

                    NodePtr head;
8
 
9
Accessing Items in a Node
  • This one way to change the string in the first node from “Nissan 350z” to “Porsche 911”:

  •                      (*head).data = “Porsche 911”;


    • head is a pointer variable so *head is the node that head points to
    • The parentheses are necessary because the dot operator . has higher precedence than the
      dereference operator *

10
The Arrow Operator
  • The arrow operator -> combines the actions of  the dereferencing  operator * and the dot operator to specify a member of a struct or object pointed to by a pointer


    •   (*head). data = “Porsche 911”;
                         can be written as
                        head->data = “Porsche 911”;


    • The arrow operator is more commonly used
11
NULL
  • The defined constant NULL is used as…
    • An end marker for a linked list
      • A program can step through a list of nodes by following the pointers, but when it finds a node containing NULL, it knows it has come to the end of the list
    • The value of a pointer that has nothing to point to
  • The value of NULL is 0 (zero)
  • Any pointer can be assigned the value NULL:
                          int *p = NULL;
12
To Use NULL

  • A definition of NULL is found in several
    libraries, including <iostream> and <cstddef>


  • A using directive is not needed for NULL
13
Linked Lists
  • A linked list is a list of nodes in which each node has a member variable that is a pointer that points to the next node in the list
    • The first node is called the head
    • The pointer variable head, points to the first node
      • The pointer named head is not the head of the list…it points to the head of the list
    • The last node contains a pointer set to NULL
14
Building a Linked List:
The node definition
  • Let's begin with a simple node definition:
                    struct Node {
                                 string data;
                                 Node *next;
                              };
                            
                              typedef Node* NodePtr;
15
Building a Linked List:
Declaring Pointer Variable head
  • With the node defined and a type definition to make our code easier to understand, we can declare the pointer variable head:

        NodePtr head;


    • head is a pointer variable that will point to the
      head node when the node is created
16
Building a Linked List:
Creating the First Node
  • To create the first node, the operator new is used to create a new dynamic variable:

      head = new Node;


    • Now head points to the first, and only, node in the list
17
Building a Linked List:
Initializing the Node
  • Now that head points to a node, we need to
    give values to the member variables of the node:

      head->data = “Toyota Tercel”;
                       head->next = NULL;


    • Since this node is the first and last node, the next pointer is set to NULL
18
Transverse through the list
19
NULL Comparison
  • cur->next – incorrect
  • When cur points to the last node of  nonempty list cur->next is NULL
  • The loop would terminate before displaying the data in the last node


  • for (NodePtr cur = head; cur != NULL; cur = cur->next)
  • cout << cur->data << endl;


20
Link List Class
  • struct Node {
  • string data;
  • Node *next;
  • };  typedef Node* NodePtr;
  • class LinkList {
  • public: LinkList();
  • ~LinkList();
  • void insert(const string& aData);
  • bool insert(const string& aData1, const string& aData2);
  • NodePtr search(const string& target) const;
  • void deleteNode(const string& aData);
  • int getSize() const;
  • private:
  • NodePtr mHead; // users don't have access to the
  • int mSize;
  • };
21
First Function insert
  • It would be better to create a function to insert
    nodes at the head of a list, such as:
    •  void insert(const string& aData);
      • The first parameter is a string parameter that the data element for the node
    • insert() will create a new node for the string
      • The string will be copied to the new node
      • The new node will be inserted in the list as the new head node
22
Pseudocode for insert()
  • Create a new dynamic variable pointed to by
    aNode
  • Place the string in the new aNode->data
  • Make aNode’s next pointer variable point to the head node (now it will point to the original first node in the list)
  • Make the head pointer point to aNode
23
 
24
Translating insert() to C++
  • The pseudocode for head_insert can be written
    in C++ using these lines in place of the lines of
    pseudocode:
  • // Construct a new node
  • NodePtr aNode = new Node;
  • aNode->data = aData; // set data string to the // node’s  data
  • aNode->next = head; // set next pointer to head
  • head = aNode; // now head pts to the first
  • // element aNode
25
An Empty List
  • A list with nothing in it is called an empty list
  • An empty linked list has no head node
  • The head pointer of an empty list is NULL

                            head = NULL;
    • Any functions written to manipulate a linked list
      should check to see if it works on the empty list
26
Losing Nodes
  • You might be tempted to write insert() using
    the head pointer to construct the new node:

                           head = new Node;
                           head->data = aData;
  • Now to attach the new node to the list
    • The node that head used to point to is now lost!


27
 
28
Memory Leaks
  • Nodes that are lost by assigning their pointers a
    new address are not accessible any longer
  • The program has no way to refer to the nodes
    and cannot delete them to return their memory
    to the freestore (Heap)
  • Programs that lose nodes have a memory leak
    • Significant memory leaks can cause system crashes
29
Searching a Linked List
  • To design a function that will locate a particular node in a linked list:
    • We want the function to return a pointer to the node so we can use the data if we find it, else return NULL
    • The data (string) we wish to find is the argument
    • This declaration will work:


    • NodePtr& search(NodePtr& cur, const string& target) const
30
Function search
  • Refining our function
    • We will use a pointer variable, named cur, to move through the list checking for the target
      • The only way to move around a linked list is to follow pointers
    • We will start with here pointing to the first node and move the pointer from node to node following the pointer out of each node
31
Pseudocode for search
  • Parameter pointer variable cur point to the head node
  • while(cur does not point to the last node) {
        check if cur data is the target
        if so return address of cur
        make here point to the next node
     }
  • return cur; // the empty pointer
32
Moving Through the List
  • The pseudocode for search requires that pointer cur step through the list
    • How does cur follow the pointers from node to node?
    • When cur points to a node, cur->next is the
       address of the next node
    • To make cur point to the next node, make the
      assignment:
                          cur = cur->next;
33
A code for search
  • The search function can be refined in this way:


  • for(NodePtr cur = head; cur != NULL; cur = cur->next){
  • if(cur->data == target)
  • return cur;
  • }
  • return NULL;
34
Searching an Empty List
  • Does the search algorithm handle the empty list
    • If the list is empty, and the pointer is not handled appropriately it can lead to undefined pointer errors
      • cur->data is undefined
      • cur->next is undefined
    • The search function that handles an empty list
35
Pointers as Iterators
  • An iterator is a construct that allows you to
    cycle through the data items in a data structure
    to perform an action on each item
    • An iterator can be an object of an iterator class,
      an array index, or simply a pointer
  • A general outline using a pointer as an iterator:
            
                for (NodePtr cur = head; cur != NULL; cur = cur->next)
                //perform the action on the node iter
    • head is a pointer to the head node of the list
  • This is what the search algorithm uses to transverse each node
36
Inserting a Node after a node
  • To insert a node after a specified node in the
    linked list:
    • Use cur again and iterator through the list to find the node with the data (aData1) we’re looking for
    • Construct a new node to place the new string (aData2)
    • Point the new node’s next pointer to cur->next
    • Set cur->next to the new node


    • bool insert(const string& aData1, const string& aData2);
37
Inserting the New Node
  • Function insert creates the new node just as
    previous insert did
  • We do not want our new node at the head of the list however, so…
    • We use the pointer cur to insert the new node
38
Inserting the New Node
  • This code will accomplish the insertion of the
    new node,after the node pointed to by cur:
  • aNode->next = cur->next;
  • cur->next = aNode;


39
Caution!
  • The order of pointer assignments is critical
    • If we changed cur->next to point to
      aNode first, we would loose the rest of the list!
40
insert() - Code
  • NodePtr cur = mHead;
  • bool found = false;
  • while(cur != NULL) {
  • if(cur->data == aData1) {
  • found = true;
  • break;
  • }
  • cur = cur->next; // go to the next node and test
  • }
  • if(found) {
  • NodePtr aNode = new Node;
  • aNode->data = aData2; // set the data to the string
  • aNode->next = cur->next; // set next ptr to the node after cur
  • cur->next = aNode; // set cur to point to the new node
  • mSize++;
  • }
  • return false;
41
Function insert Again
  • Notice that inserting into a linked list requires
    that you only change two pointers
    • This is true regardless of the length of the list
    • Using an array for the list would involve copying as many as all of the array elements to new locations to make room for the new item
  • Inserting into a linked list is often more efficient than inserting into an array
42
Removing a Node
  • To remove a node from a linked list
    • Position a pointer, prevPtr,  to point at the node prior to the node to remove
    • Position a pointer, targetPtr,  to point at the node
      to remove
    • Perform:    prevPtr->next = target->next;
      • The node is removed from the list, but is still in memory
    • Return targetPtr  to the freestore:  delete targetPtr;
43
deleteNode()
  • NodePtr targetPtr = mHead;
  • NodePtr prevPtr = NULL; // no previous for the first node
  • if(targetPtr == NULL)
  • return;
  • for(;targetPtr != NULL;) {
  • if(targetPtr->data == aData) {
  • if(prevPtr == NULL) {
  • mHead = targetPtr->next;
  • } else {
  • prevPtr->next = targetPtr->next;
  • }
  • delete targetPtr;
  • targetPtr = NULL;
  • mSize--;
  • } else {
  • prevPtr = targetPtr;
  • targetPtr = targetPtr->next;
  • }
  • }
44
Deleting and adding Nodes
  • The best way to understand how a link list works is to draw the nodes out on paper
  • Trace through your code and determine if it is handling the situations appropriately
  • Remember a picture is worth a thousand words
45
Assignment With Pointers
  • If head1 and head2 are pointer variables and
    head1 points to the head node of a list:

                           head2 = head1;
    causes head2 and head1 to point to the same list
    • There is only one list!


  • If you want head2 to point to a separate copy,
    you must copy the list node by node or
    overload the assignment operator appropriately
46
Section 13.1 Conclusion
  • Can you
    • Write type definitions for the nodes and pointers in a linked list?  Call the node type NodeType and call the pointer type PointerType.  The linked lists will be lists of letters.
    • Explain why inserting into an array can be less
      efficient than inserting into a linked list?
47
"Stacks and Queues"
  • Stacks and Queues
48
A Linked List Application
  • A stack is a data structure that retrieves data in
    the reverse order the data was stored
    • If 'A', 'B', and then 'C' are placed in a stack, they will be removed in the order 'C', 'B', and then 'A'
  • A stack is a last-in/first-out data structure like
    the stack of plates in a cafeteria; adding a plate
    pushes down the stack and the top plate is the
    first one removed
49
 
50
Program Example:
A Stack Class
  • We will create a stack class to store characters
    • Adding an item to a stack is pushing onto the stack
    • Member function push will perform this task
    • Removing an item from the stack is popping the the item off the stack
    • Member function pop will perform this task
51
Using the stack Class
  • StackRunner.cpp, Stack.h and Stack.cpp demonstrates the use of the stack class
52
Function push
  • The push function adds an item to the stack
    • It uses a parameter of the type stored in the stack

            void push(const string& aString);
    • Pushing an item onto the stack is precisely the same task accomplished by function insert() of the linked list
    • For a stack, a pointer named top is used instead of a pointer named head
53
Function pop
  • The pop function returns the item that was at
    the top of the stack
                             string pop();
    • Before popping an item from a stack, pop checks
      that the stack is not empty
    • pop stores the top item in a local variable data,
      and the  item is "popped" by:   top = top->next;
      • A temporary pointer must point to the old top item
        so it can be "deleted"  to prevent a memory leak in a variable called, “frame”
    • pop then returns variable data which is the string that was at the original top


54
Empty Stack
  • An empty stack is identified by setting the
    top pointer to NULL

      top = NULL;


55
The Copy Constructor
  • Because the stack class uses a pointer and
    creates new nodes using new, a copy constructor is needed
    • The copy constructor must make a copy of each item in the stack and store the copies in a new stack
      • Items in the new stack must be in the same position in the stack as in the original
  • What happens if we don’t define a copy constructor?
56
The stack destructor
  • Because function pop calls delete each time an
    item is popped off the stack, ~stack only needs
     to call pop until the stack is empty


  •     while(!isEmpty()) {
  • pop();
  • }
  • top = NULL;
57
stack Class Implementation
  • The stack class implementation is
    found in  Stack.cpp
58
Queue
  • A queue is a first in/first out (FIFO) data structure
  • It utilizes two pointers one at the front of the queue and one at the back of the queue
  • We’ll define them as front and back
59
 
60
Queue declaration
  • class Queue {
  • public:
  • Queue();
  • Queue(const Queue& aQueue);
  • ~Queue();
  • void enqueue(const string& aString);
  • string dequeue();
  • bool isEmpty() const;
  • friend ostream& operator <<(ostream& out, const Queue& aQueue);
  • private:
  • QueueNodePtr front;
  • QueueNodePtr back;
  • };
61
Section 13.2 Conclusion
  • Can you
    • Give the definition of member function push?
    • Create a definition for the stack class copy
      constructor?