970 likes | 991 Views
Building Java Programs Chapter 16. Linked Lists. A swap method?. Does the following swap method work? Why or why not? public static void main(String[] args) { int a = 7; int b = 35; // swap a with b swap(a, b); System.out.println(a + " " + b); }
E N D
Building Java ProgramsChapter 16 Linked Lists
A swap method? • Does the following swap method work? Why or why not? public static void main(String[] args) { int a = 7; int b = 35; // swap a with b swap(a, b); System.out.println(a + " " + b); } public static void swap(int a, int b) { int temp = a; a = b; b = temp; }
Value semantics • value semantics: Behavior where values are copied when assigned to each other or passed as parameters. • When one primitive is assigned to another, its value is copied. • Modifying the value of one variable does not affect others. int x = 5; int y = x; // x = 5, y = 5 y = 17; // x = 5, y = 17 x = 8; // x = 8, y = 17
Reference semantics a1 a2 • reference semantics: Behavior where variables actually store the address of an object in memory. • When one reference variable is assigned to another, the object is not copied; both variables refer to the same object. int[] a1 = {4, 5, 2, 12, 14, 14, 9}; int[] a2 = a1; // refers to same array as a1 a2[0] = 7; System.out.println(a1[0]); // 7
References and objects panel1 panel2 • In Java, objects and arrays use reference semantics. Why? • efficiency. Copying large objects slows down a program. • sharing. It's useful to share an object's data among methods. DrawingPanel panel1 = new DrawingPanel(80, 50); DrawingPanel panel2 = panel1; // same window panel2.setBackground(Color.CYAN);
References as fields private Queue<HtmlTag> tags; ... HtmlValidator front ... ... ... back Queue HtmlTag HtmlTag private String element; ... private String element; ... h t m l String b o d y String • Objects can store references to other objects as fields. Example: Homework 3 (HTML Validator) • HtmlValidator stores a reference to a Queue • the Queue stores many references to HtmlTag objects • each HtmlTag object stores a reference to its element String
Null references • null : A value that does not refer to any object. • The elements of an array of objects are initialized to null. String[] words = new String[5]; • not the same as the empty string "" or the string "null" • Why does Java have null ? What is it used for? words
Null references • Unset reference fields of an object are initialized to null. public class Student { String name; int id; } Student timmy = new Student(); timmy
Things you can do w/ null • store null in a variable or an array element String s = null; words[2] = null; • print a null reference System.out.println(timmy.name); // null • ask whether a variable or array element is null if (timmy.name == null) { ... // true • pass null as a parameter to a method • some methods don't like null parameters and throw exceptions • return null from a method (often to indicate failure) return null;
Dereferencing • dereference: To access data or methods of an object. • Done with the dot notation, such as s.length() • When you use a . after an object variable, Java goes to the memory for that object and looks up the field/method requested. Student timmy = new Student(); timmy.name = "Timmah"; String s = timmy.name.toUpperCase(); Student String timmy public int indexOf(String s) {...} public int length() {...} public String toUpperCase() {...}
Null pointer exception • It is illegal to dereference null (it causes an exception). • null does not refer to any object, so it has no methods or data. Student timmy = new Student(); String s = timmy.name.toUpperCase(); // ERROR Output: Exception in thread "main" java.lang.NullPointerException at Example.main(Example.java:8) timmy
References to same type • What would happen if we had a class that declared one of its own type as a field? public class Strange { private String name; private Strange other; } • Will this compile? • If so, what is the behavior of the other field? What can it do? • If not, why not? What is the error and the reasoning behind it?
Linked data structures • All of the collections we will use and implement in this course use one of the following two underlying data structures: • an array of all elements • ArrayList, Stack, HashSet, HashMap • a set of linked objects, each storing one element,and one or more reference(s) to other element(s) • LinkedList, TreeSet, TreeMap front
A list node class public class ListNode { int data; ListNode next; } • Each list node object stores: • one piece of integer data • a reference to another list node • ListNodes can be "linked" into chains to store a list of values:
List node client example public class ConstructList1 { public static void main(String[] args) { ListNode list = new ListNode(); list.data = 42; list.next = new ListNode(); list.next.data = -3; list.next.next = new ListNode(); list.next.next.data = 17; list.next.next.next = null; System.out.println(list.data + " " + list.next.data + " " + list.next.next.data); // 42 -3 17 } } list
List node w/ constructor public class ListNode { int data; ListNode next; public ListNode(int data) { this.data = data; this.next = null; } public ListNode(int data, ListNode next) { this.data = data; this.next = next; } } • Exercise: Modify the previous client to use these constructors.
Linked node problem 1 • What set of statements turns this picture: • Into this? list list
Linked node problem 2 • What set of statements turns this picture: • Into this? list list
Linked node problem 3 • What set of statements turns this picture: • Into this? list1 list2 list1 list2
Linked node problem 4 • What set of statements turns this picture: • Into this? list ... list ...
References vs. objects variable = value; a variable (left side of = ) is an arrow (the base of an arrow) a value (right side of = ) is an object (a box; what an arrow points at) • For the list at right: • a.next = value;means to adjust where points • variable = a.next;means to make variable point at 2 a 1 1 2
Reassigning references • when you say: • a.next = b.next; • you are saying: • "Make the variable a.next refer to the same value as b.next." • Or, "Make a.next point to the same place that b.next points." a b
Linked node question • Suppose we have a long chain of list nodes: • We don't know exactly how long the chain is. • How would we print the data values in all the nodes? list ...
Algorithm pseudocode • Start at the front of the list. • While (there are more nodes to print): • Print the current node's data. • Go to the next node. • How do we walk through the nodes of the list? list = list.next; // is this a good idea? list ...
Traversing a list? • One (bad) way to print every value in the list: while (list != null) { System.out.println(list.data); list = list.next; // move to next node } • What's wrong with this approach? • (It loses the linked list as it prints it!) list ...
A current reference current • Don't change list. Make another variable, and change that. • A ListNode variable is NOT a ListNode object ListNode current = list; • What happens to the picture above when we write: current = current.next; list ...
Traversing a list correctly • The correct way to print every value in the list: ListNode current = list; while (current != null) { System.out.println(current.data); current = current.next; // move to next node } • Changing current does not damage the list. list ...
Algorithm to print list values: ListNode front = ...; ListNode current = front; while (current != null) { System.out.println(current.data); current = current.next; } Similar to array code: int[] a = ...; int i = 0; while (i < a.length) { System.out.println(a[i]); i++; } Linked list vs. array
A LinkedIntList class • Let's write a collection class named LinkedIntList. • Has the same methods as ArrayIntList: • add, add, get, indexOf, remove, size, toString • The list is internally implemented as a chain of linked nodes • The LinkedIntList keeps a reference to its front as a field • null is the end of the list; a null front signifies an empty list LinkedIntList ListNode ListNode ListNode front add(value) add(index, value) indexOf(value) remove(index) size() toString() element 0 element 1 element 2
LinkedIntList class v1 public class LinkedIntList { private ListNode front; public LinkedIntList() { front = null; } methods go here } LinkedIntList front =
Implementing add // Adds the given value to the end of the list. public void add(int value) { ... } • How do we add a new node to the end of a list? • Does it matter what the list's contents are before the add? front = element 0 element 1 element 2
Adding to an empty list • Before adding 20: After: • We must create a new node and attach it to the list. front = front = element 0
The add method, 1st try // Adds the given value to the end of the list. public void add(int value) { if (front == null) { // adding to an empty list front = new ListNode(value); } else { // adding to the end of an existing list ... } }
Adding to non-empty list • Before adding value 20 to end of list: • After: front = element 0 element 1 front = element 0 element 1 element 2
Don't fall off the edge! • To add/remove from a list, you must modify the next reference of the node before the place you want to change. • Where should current be pointing, to add 20 at the end? • What loop test will stop us at this place in the list? front = element 0 element 1
The add method // Adds the given value to the end of the list. public void add(int value) { if (front == null) { // adding to an empty list front = new ListNode(value); } else { // adding to the end of an existing list ListNode current = front; while (current.next != null) { current = current.next; } current.next = new ListNode(value); } }
Implementing get // Returns value in list at given index. public int get(int index) { ... } • Exercise: Implement the get method. front = element 0 element 1 element 2
The get method // Returns value in list at given index. // Precondition: 0 <= index < size() public int get(int index) { ListNode current = front; for (int i = 0; i < index; i++) { current = current.next; } return current.data; }
Implementing add (2) // Inserts the given value at the given index. public void add(int index, int value) { ... } • Exercise: Implement the two-parameter add method. front = element 0 element 1 element 2
The add method (2) // Inserts the given value at the given index. // Precondition: 0 <= index <= size() public void add(int index, int value) { if (index == 0) { // adding to an empty list front = new ListNode(value, front); } else { // inserting into an existing list ListNode current = front; for (int i = 0; i < index - 1; i++) { current = current.next; } current.next = new ListNode(value, current.next); } }
Conceptual questions • What is the difference between a LinkedIntList and a ListNode? • What is the difference between an empty list and a null list? • How do you create each one? • Why are the fields of ListNode public? Is this bad style? • What effect does this code have on a LinkedIntList? ListNode current = front; current = null;
Conceptual answers • A list consists of 0 to many node objects. • Each node holds a single data element value. • null list: LinkedIntList list = null;empty list: LinkedIntList list = new LinkedIntList(); • It's okay that the node fields are public, because client code never directly interacts with ListNode objects. • The code doesn't change the list.You can change a list only in one of the following two ways: • Modify its front field value. • Modify the next reference of a node in the list.
Implementing remove // Removes and returns the list's first value. public int remove() { ... } • How do we remove the front node from a list? • Does it matter what the list's contents are before the remove?
Removing front element • Before removing front element: • After first removal: After second removal: front = element 0 element 1 front = front = element 0
remove solution // Removes and returns the first value. // Throws a NoSuchElementException on empty list. public int remove() { if (front == null) { throw new NoSuchElementException(); } else { int result = front.data; front = front.next; return result; } }
Implementing remove (2) // Removes value at given index from list. // Precondition: 0 <= index < size public void remove(int index) { ... } • How do we remove any node in general from a list? • Does it matter what the list's contents are before the remove?
Removing from a list • Before removing element at index 1: • After: front = element 0 element 1 element 2 front = element 0 element 1
Removing from the front • Before removing element at index 0: • After: front = element 0 element 1 element 2 front = element 0 element 1
Removing the only element • Before: After: • We must change the front field to store null instead of a node. • Do we need a special case to handle this? front = front = element 0
remove (2) solution // Removes value at given index from list. // Precondition: 0 <= index < size() public void remove(int index) { if (index == 0) { // special case: removing first element front = front.next; } else { // removing from elsewhere in the list ListNode current = front; for (int i = 0; i < index - 1; i++) { current = current.next; } current.next = current.next.next; } }