Download presentation
Presentation is loading. Please wait.
2
Lecture 6: Linked Data Structures
Let's concentrate on the drawbacks of contiguous memory Is there an alternative way of storing a collection of data that avoids these problems? What if we can allocate our memory in small, separate pieces, one for each item in the collection Now we allocate exactly as many pieces as we need Now we do not have to shift items, since all of the items are separate anyway Draw on board
3
Lecture 6: Linked Data Structures
But how do we keep track of all of the pieces? We let the pieces keep track of each other! Let each piece have 2 parts to it One part for the data it is storing One part to store the location of the next piece This is the idea behind a linked-list firstNode data data data data
4
Lecture 6: Linked Data Structures
Idea of Linked List: If we know where the beginning of the list is And each link knows where the next one is Then we can access all of the items in the list Our problems with contiguous memory now go away Allocation can be done one link at a time, for as many links as we need New links can be "linked up" anywhere in the list, without shifting needed Demonstrate on board
5
How can we implement linked lists?
Lecture 6: Linked Lists How can we implement linked lists? The key is how each link is implemented As we said, two parts are needed, one for data and one to store the location of the next link We can do this with a self-referential data type class Node { private T data; private Node next; … A NODE is a common name for a link in a linked-list Note why it is called "self-referential"
6
Lecture 6: Singly Linked Lists
Linked-List Implementation Variations Singly Linked List The simple linked-list we just discussed is a singly-linked list Links go in one direction only We can easily traverse the list from the front to the rear We CANNOT go backwards through the list at all This list is simple and (relatively) easy to implement, but has the limitations of any "one way street" This implementation is developed in Chapter 3 firstNode
7
Lecture 6: Singly Linked Lists
There are other variations of linked lists: Doubly linked list Circular linked list We will discuss these later For now we will keep things very simple
8
Lecture 6: Linked Bag Implementation
Let's look at this implementation a bit public class LinkedBag<T> implements BagInterface<T> { private Node firstNode; private int numberOfEntries; … private class Node private T data; private Node next; private Node(T dataPortion) { this(dataPortion, null); } private Node(T dataPortion, Node nextNode) { data = dataPortion; next = nextNode; } } // class Node } // class LinkedBag Note that Node is a private inner class
9
Lecture 6: Node As an Inner Class
Why is it done this way? Since Node is declared within LinkedBag, methods in LinkedBag can access private declarations within Node This is a way to get "around" the protection of the private data LinkedBag will be needing to access data and next of its Nodes in many of its methods We could write accessors and mutators within Node to allow this access However, it is simpler for the programmer if we can access data and next directly They are still private and cannot be accessed outside of LinkedBag On the downside, with this implementation, we cannot use Node outside of the LinkedBag class
10
Lecture 6: Linked Bag Implementation
Now let's see how we would implement some of our BagInterface methods public boolean add (T newEntry) { Node newNode = new Node(newEntry); // create Node newNode.next = firstNode; // link it to prev. front firstNode = newNode; // set front to new Node numberofEntries++; // increment entries return true; } // method add For the linked bag we add new values at the front, while we added new values at the end of the array. Since the Bag is not sorted, it does not logically matter. Compare to add() in the array implementation What is different? Is this a problem?
11
Lecture 6: Linked Bag Implementation
Trace on board Try a few adds in example Note insertion is at the front of the bag New node is created and newEntry is put in it New node becomes new front of list, push old front back Since BagInterface does not specify where to insert, we again do what is most convenient for our implementation Are there any special cases Ex: What if the bag is empty? firstNode will be null Will this be a problem? Any other special cases here?
12
Lecture 7: Linked Bag Implementation
Ok, that operation was simple How about something that requires a loop of some sort? Let’s look at the contains() method Just like for the array, we will use sequential search Just like for the array, we start at the beginning and proceed down the bag until we find the item or reach the end So what is different? How do we “move down” the bag? How do we know when we have reached the end? Discuss Let’s look at the code
13
Lecture 7: Linked Bag Implementation
public boolean contains(T anEntry) { boolean found = false; Node currentNode = firstNode; while (!found && (currentNode != null)) if (anEntry.equals(currentNode.data)) found = true; else currentNode = currentNode.next; } // end while return found; } // end getReferenceTo Loop will terminate when either found == true or null is reached (in which case found == false)
14
Lecture 7: Linked Bag Implementation
Let’s look at one more operation: public boolean remove(T anEntry) We want to remove an arbitrary item from the Bag How do we do this? Think about the contains() method that we just discussed How is remove similar and how is it different? Find the entry in question But now we need more than just a boolean result We must store a reference to the actual node so that we can do something with it Then remove it Must unlink the node from the list Let’s think about this
15
Lecture 7: Linked Bag Implementation
Consider again the properties of a Bag The data is in no particular order We could remove the actual Node in question but perhaps we can do it more easily The front Node is very easy to remove Trace on board So let’s copy the item in the front Node to the Node that we want to remove Then we remove the front Node Logically, we have removed the data we want to remove Keep in mind that the Nodes are not the data – they are simply a mechanism for accessing the data Also keep in mind that this would NOT be ok if the data needs to stay in some kind of order Note: The idea here is similar to what we did with the array implementation. However, there is an important difference. With the array, by moving an item into the empty spot rather than shifting, we are saving considerably on the runtime (going from linear runtime to constant runtime). For the linked implementation, the actual removal process is still only a few steps even in place, as we will see later with some other implementations. However, in either case, we are still required to find the object first, which takes linear time in an unordered collection such as a Bag.
16
Lecture 7: Linked Bag Implementation
private Node getReferenceTo(T anEntry) { boolean found = false; Node currentNode = firstNode; while (!found && (currentNode != null)) if (anEntry.equals(currentNode.data)) found = true; else currentNode = currentNode.next; } // end while return currentNode; } // end getReferenceTo Note that the logic here is the same as for contains What is different is what is returned
17
Lecture 7: Linked Bag Implementation
public boolean remove(T anEntry) { boolean result = false; Node nodeN = getReferenceTo(anEntry); if (nodeN != null) nodeN.data = firstNode.data; // copy data from firstNode = firstNode.next; // first Node and numberOfEntries--; // delete that Node result = true; // Operation succeeds } // end if return result; } // end remove Note that this returns boolean rather than the entry that is being removed
18
Lecture 7: Linked Bag Implementation
There are other methods that we have not discussed Look over them in the text and in the source code Look again at Example6.java Note (as we discussed) how the data is ordered differently in the different Bag implementations However, it is irrelevant to the functionality
19
Lecture 7: Node as a Separate Class
Node class as a separate (non-inner) class Some OO purists believe it is better to never "violate" the private nature of a class' data Making Node separate also allows it to be reused If done this way, the Node class must also be a parameterized type class Node<T> { private T data; // data portion private Node<T> next; // link to next node … And now in class LinkedList we would have private Node<T> firstNode;
20
Lecture 7: Node as a Separate Class
Access to next and data fields must now be done via accessors and mutators, so these must be included in the Node<T> class Ex: getData(), getNextNode() accessors Ex: setData(), setNextNode() mutators Look at rest of Node<T> class code See handout Let's look at a method in LinkedBag.java we have already discussed, but now using this variation remove() method Differences from previous version are shown in red
21
Lecture 7: Node as a Separate Class
public boolean remove(T anEntry) { boolean result = false; Node<T> nodeN = getReferenceTo(anEntry); if (nodeN != null) nodeN.setData(firstNode.getData()); firstNode = firstNode.getNextNode(); numberOfEntries-- result = true; } return result; Note that getReferenceTo() would also be different, using accessors and mutators rather than direct access to the nodes
22
Consider another ADT: the List
Lecture 7: ADT List Consider another ADT: the List We can define this in various ways – by its name alone it is perhaps only vaguely specified Let's look at how the text looks at it: Data: A collection of objects in a specific order and having the same data type The number of objects in the collection Operations: add(newEntry) add(newPosition, newEntry) remove(givenPosition)
23
See Ch. 12 for detailed specifications
Lecture 7: ADT List clear() replace(givenPosition, newEntry) getEntry(givenPosition) toArray() contains(anEntry) getLength() isEmpty() See Ch. 12 for detailed specifications Note that indexing for this ADT starts at 1, not 0 Odd but this is how the author defined it We will look at a few of these and see the similarities to and differences from our Bag ADT
24
Lecture 7: Using a List Recall that at this point we are looking at a List from a user's point of view So what can we use it for? A List is a very general and useful structure See ListInterface.java For example: We can use it for Last In First Out behavior (how?) We can use it for First in First Out behavior (how?) We can access the data by index and add/remove at a given location We can search for an item within the list
25
How about using it as a Bag?
Lecture 7: ADT List How about using it as a Bag? We could but would need to add the Bag methods It may not be the ideal ADT for some of these behaviors We will look at how some of these operations are done and their efficiencies soon However, we may choose to use it because it can do ALL of these things See Example7.java
26
Lecture 7: Java Standard List
Standard Java has a List interface Superset of the operations in author's ListInterface Some operations have different names Special cases may be handled differently Indexing starts at 0 But the idea is the same Look up List in the Java API See Example7b.java
27
Lecture 8: Implementing a List
Ok, now we need to look at a list from the implementer's point of view How to represent the data? Must somehow represent a collection of items (Objects) How to implement the operations? As discussed previously, the implementation of the operations will be closely related to the representation of the data Minimally the data representation will "suggest" ways of implementing the operations
28
Lecture 8: Linked List Implementation
Let’s first implement our ListInterface using a linked data structure [Note: The text uses array first but we are doing linked version first to aid with next assignment] Much of the implementation is identical to our LinkedBag Singly-linked list structure Node inner class with data and next fields Adding a new item at the front of the list is identical Finding an item in the list is identical However, there are some important differences between the two
29
Lecture 8: Linked List Implementation
The List interface requires data to be kept in positional order Thus, we cannot arbitrarily move data around Bag always removed Nodes from the front and moved data to allow arbitrary delete We can also insert and remove in a given position Will need to add and remove Nodes from the middle of the list This was not needed for LinkedBag Let’s focus on the parts of the LL that differ from the LinkedBag For example, consider the remove(int givenposition) method
30
Lecture 8: Linked List Implementation
public T remove(int givenPosition) What do we need to do here? We must first get to the object at givenPosition (i) There is a private method getNodeAt() to do this We will see the code soon Then we must "remove" it We must do this in such a way that the rest of the list is still connected We must link the previous node to the next node firstNode Previous Node Next Node i
31
Lecture 8: Linked List Implementation
But notice that by the time we find the node we want to delete, we have "passed" up the node we need to link Since the links are one way we can't go back Solution? Find the node BEFORE the one we want to remove Then get the one we want to remove and the one after that, and change the links appropriately firstNode nodeBefore nodeToRemove nodeAfter i
32
Lecture 8: Linked List Implementation
Let's look at the getNodeAt() method: Note that we start at the front of the list and follow the links down to the desired index Q: How does this compare to getting to a specific index in an array? /** Task: Returns a reference to the node at a given position. * Precondition: List is not empty; 1 <= givenPosition <= length. */ private Node getNodeAt(int givenPosition) { assert !isEmpty() && (1 <= givenPosition) && (givenPosition <= numberOfEntries); Node currentNode = firstNode; // traverse the list to locate the desired node for (int counter = 1; counter < givenPosition; counter++) currentNode = currentNode.getNextNode(); assert currentNode != null; return currentNode; } // end getNodeAt A: We can directly access any location in the array, but must traverse through the list to get to a location in the Linked List. This difference in access time for a specific location in a list is a significant difference in the array and linked implementations.
33
Lecture 8: Linked List Implementation
What if givenPosition > numberOfEntries? So why don't we handle this possible error? The method is private The idea is that as class designers, we make sure the error cannot occur – that is why it is an "assert" Users of the class cannot call this method, so there is no problem for them Ex: See public T getEntry(int givenPosition) The index test is done BEFORE getNodeAt() is called An assertion error This will crash our program!
34
Lecture 8: Linked List Implementation
Other issues? What else should we be concerned with when trying to delete a node? Are there any special cases we have to worry about? This is VERY IMPORTANT in many data structures and algorithms We discussed this for BagInterface but there were not really any problems But what about for ListInterface? if the index is invalid we cannot delete deleting the front node deleting the last remaining node (also the front node) Let's see, if the front node is deleted, the node before it will be ??????????? Special case!!!
35
Lecture 8: Linked List Implementation
Let's look at the code: public T remove(int givenPosition) { T result = null; // initialize return value if ((givenPosition >= 1) && (givenPosition <= numberOfEntries)) assert !isEmpty(); if (givenPosition == 1) // case 1: remove first entry result = firstNode.getData(); firstNode = firstNode.getNextNode(); } else // case 2: givenPosition > 1 Node nodeBefore = getNodeAt(givenPosition-1); Node nodeToRemove = nodeBefore.getNextNode(); result = nodeToRemove.getData(); Node nodeAfter = nodeToRemove.getNextNode(); nodeBefore.setNextNode(nodeAfter); } // end if numberOfEntries--; return result; // return result } // end if else throw new IndexOutOfBoundsException("Illegal Index"); } // end remove Special Case: First Node Normal Case Special Case: Invalid Index
36
Lecture 8: Singly Linked List Variations
First and Last References We discussed before that if we are inserting a node at the end of the list, we must traverse the entire list first to find the last previous node This is inefficient if we do a lot of adds to the end of the list [we'll discuss the particulars later] We could save time if we kept an additional instance variable (lastNode) that always refers to the end of the list Now adding to the end of the list is easy! However, it has some other interesting issues
37
Lecture 8: Singly Linked List Variations
See on board and discuss what the issues might be Thus, adding an extra instance variable to save time with one operation can increase the complexity of other operations Only by a small amount here, but we still need to consider it Let's look at an operation both without and with the lastNode reference Text looks at add() methods so let's look at a different one Let's try remove() Let's think about this
38
Lecture 8: Singly Linked List Variations
When, if at all, will we need to worry about the lastNode reference? With all of these methods we want to think about The "normal" case, or what we usually expect The "special" case that may only occur under certain circumstances Normal case: We remove a node from the "middle" of the list and the lastNode reference does not change at all Can we think of 2 special cases here? They are somewhat related
39
Lecture 8: Singly Linked List Variations
Removing the last node in the list This clearly will affect the lastNode reference How do we know when this case occurs? How do we handle it Removing the only node in the list Clearly this case is also 1) above, since the only node is also the last node However, we should consider it separately, since there may be special things that must be done if the list is becoming empty How do we handle it?
40
Lecture 8: Singly Linked List Variations
public T remove(int givenPosition) { T result = null; if ((givenPosition >= 1) && (givenPosition <= numberOfEntries)) assert !isEmpty(); if (givenPosition == 1) result = firstNode.getData(); firstNode = firstNode.getNextNode(); if (numberOfEntries == 1) lastNode = null; } else Node nodeBefore = getNodeAt(givenPosition-1); Node nodeToRemove = nodeBefore.getNextNode(); Node nodeAfter = nodeToRemove.getNextNode(); nodeBefore.setNextNode(nodeAfter); result = nodeToRemove.getData(); if (givenPosition == numberOfEntries) lastNode = nodeBefore; } // end if numberOfEntries--; } // end if else throw new IndexOutOfBoundsException("Illegal Index"); return result; } // end remove Code to handle deleting only node Code to handle deleting last node
41
Lecture 8: Singly Linked List Variations
Circular Linked List Now instead of null, the last node has a reference to the front node What is good about this? Which node(s) should we keep track of? Why? Think about adding at the beginning or end Can be effectively used for a Queue (see board) We will look at this more later lastNode
42
Lecture 8: Other Linked List Variations
Doubly Linked List Each node has a link to the one before and the one after Call them previous and next Now we can easily traverse the list in either direction Gives more general access and can be more useful This is more beneficial if we have a reference to the end of the list as well as the beginning, or we make it circular Used in standard JDK LinkedList and in author’s Deque Some operations may be somewhat faster But more overhead involved What overhead do we mean here? We may look in more detail if we have time
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.