Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
COSC 2006: Data Structures I Low Level List Processing 5/24/2017 BGA 1 Arrays and linked structures (1) Array and Linked structures can both be used to represent a sequence of elements. An array, through its index, can also provide random access to its elements so locating an element is an O(1) operation. A linked structure consists of elements (nodes) having a data part and a link (reference) to the the next node so locating an element at a given position is an O(n) operation (traversal). 5/24/2017 BGA 2 Arrays and linked structures (2) Arrays are not dynamic: their size is fixed To extend the size of an array dynamically it is necessary to create a bigger array copy existing elements to it delete the original array This can be inefficient in cases where the storage needed grows or shrinks with time. Linked structures are dynamic and can easily grow and shrink automatically with time. 5/24/2017 BGA 3 Arrays and linked structures (3) Inserting and removing elements from an array are both O(n) operations. For a linked list they are O(1) operations. Linked lists are more efficient than arrays in case there are a lot of insertions and deletions to be made over time and the processing required is mostly sequential rather than random access. 5/24/2017 BGA 4 Picture of a node A node consists of a data part which is normally a reference to an object and a link part which contains a reference to the next node in the list. References are denoted by arrows (box and arrow notation): objec t e primitive type 5/24/2017 object type BGA To save space in diagrams we often use the primitive type notation in the object case and interpret d as a reference. 5 Picture of a linked structure A linked list structure is obtained by linking some nodes together sequentially. The last node in the list is indicated by a null reference and the head or first element of the list is indicated by a reference to the first node: Here e0,e1,... are either primitive values or references to objects. e0 e1 e2 e3 head 5/24/2017 BGA 6 Low level linked list operations A linked list structure or sequence can be used at a high-level. We do this later by writing a LinkedList class. It can also be viewed at a low level by manipulating links and nodes directly to add and remove nodes and traverse the structure. It is useful to understand this approach if we want to write linked implementations of other data types such as stacks and queues. 5/24/2017 BGA 7 Low-level testing example We will illustrate low-level operations using a Book class and a generic node class. To experiment with the low-level operations we write a tester class called LowLevelListTester that has the generic node class as an inner class Then we can write methods in the outer class to 5/24/2017 construct lists, add and remove elements at various positions write list traversals BGA 8 LowLevelListTester structure The LowLevelListTester class consists of an inner Node class and test methods that illustrate and test low level list operations public class LowLevelListTester { public void doTest01(String title) {...} public void doTest02(String title) {...} // ... public static void main(String[] args) { LowLevelListTester tester = new LowLevelListTester(); tester.doTest01("description"); // ... } private static class Node<E> {...} } 5/24/2017 BGA 9 Inner Node class (1) Node is a generic class for nodes of any object type. Each node has a data field and a next field private static class Node<E> { private E data; private Node<E> next; // constructor with given data and next link public Node(E data, Node<E> next) { this.data = data; thus.next = next; } // continued on next slide 5/24/2017 BGA 10 Inner Node class (2) Default constructor can call the general one. We also provide a toString method that can be used to display a list beginning at this node public Node() { this(null, null); } Don't need get and set methods since this is an inner class // toString on next slide 5/24/2017 BGA 11 Inner Node class (3) The toString method uses a list traversal beginning at "this" public String toString() { StringBuilder s = new StringBuilder(); s.append("["); Node<E> cursor = this; // start at head of list while (cursor != null) { if (cursor.next != null) // second last node { s.append(cursor.data.toString()); s.append(",\n"); } else s.append(cursor.data.toString()); cursor = cursor.next; // advance to next node } s.append("]"); return s.toString(); } 5/24/2017 BGA 12 Book class (1) It can be used for testing low-level operations. Other classes could also be used. public class Book implements Comparable<Book> { private String title; private String author; private double price; private int inStock; // number available public Book(String title, String author, double price, int inStock) { this.title = title; this.author = author; this.price = price; this.inStock = inStock; } 5/24/2017 BGA 13 Book class (2) Get methods for returning data fields public String getTitle() { return title; } public String getAuthor() { return author; } public double getPrice() { return price; } public int getInStock() { return inStock; } 5/24/2017 BGA 14 Book class (3) compareTo implements the Comparable<Book> interface. Here we use only the title to compare books. public String toString() { return "Book[" + title + "," + author + "," + price + "," + inStock + "]"; } // use String class compareTo public int compareTo(Book b) { return title.compareTo(b.title); } 5/24/2017 BGA 15 Book class (4) The equals method compares only the title of the books. Here we try out the getClass() method which returns the class name of the object instead of using instance of which cannot distinguish different classes in an inheritance hierarchy (returns true for all the subclasses) public boolean equals(Object obj) { if (obj == null) || getClass() != obj.getClass()) return false; return title.equals( ((Book) obj).title); } } // end of Book class 5/24/2017 BGA 16 Constructing Nodes Node<Book> node = new Node<Book>(null,null); Node<Book> node = new Node<Book>(null, anotherNode); Book b = new Book(...); Node<Book> node = new Node<Book(b, null); objec t Book b = new Book(...); Node<Book> node = new Node<Book>(b, anotherNode); objec t 5/24/2017 BGA 17 Constructing a linked list (1) b0 list To save space we have not shown the objects referenced by b0,b1,b2 and b3 b0 b1 list New elements are added to the end of the list b0 b1 b2 b0 b1 b2 (a) (b) (c) list (d) b3 list 5/24/2017 BGA 18 Constructing a linked list (2) Construct some book objects Book Book Book Book b0 b1 b2 b3 = = = = new new new new Book("Title Book("Title Book("Title Book("Title 0","Author 1","Author 2","Author 3","Author 0",39.95,10); 1",67.50,50); 2",23.49,12); 3",15.60,17); Link them together by adding new books at tail end Node<book> head = new Node<Book>(b0, null); head.next = new Node<Book>(b1, null); head.next.next = new Node<Book>(b2, null); head.next.next.next = new Node<Book>(b3, null); 5/24/2017 BGA 19 Constructing a linked list (3) Can do it in one step Node<Book> list = new Node<Book>(b0, new Node<Book>(b1, new Node<Book>(b2, new Node<Book>(b3, null)))); 5/24/2017 BGA 20 Inserting at head of list (1) b0 b1 b2 b3 head b0 b1 b2 b3 head b head = new Node<Book>(b, head); 5/24/2017 BGA 21 Inserting at head of list (2) public void doTest03(String title) { System.out.println(); System.out.println(title); Book b = new Book("New Title", "New Author", 39.95, 10); Node<Book> head = new Node<Book>(b0, new Node<Book>(b1, new Node<Book>(b2, new Node<Book>(b3,null)))); head = new Node<Book>(b, head); System.out.println(head); } 5/24/2017 BGA 22 Inserting after first node (1) current b0 b1 b2 b3 head newNode current b0 b1 b2 b3 head b step 2 5/24/2017 step 1 BGA 23 Inserting after first node (2) Inserting b after first node: [b0, b1, b2, b3] becomes [b0, b, b1, b2, b3] Node<Book> current = head; Node<Book> newNode = new Node<Book>(b, current.next); current.next = newNode; This can be done more directly using Node<book> current = head; current.next = new Node<Book>(b, current.next); 5/24/2017 BGA 24 Inserting b after 2nd node (1) current b0 b1 b2 b3 head newNode current b0 b1 b2 b3 head b Step 2 Step 1 5/24/2017 BGA 25 Inserting b after 2nd node (2) Inserting b after second node: [b0, b1, b2, b3] becomes [b0, b1, b, b2, b3] Node<Book> current = head.next; Node<Book> newNode = new Node<Book>(b, current.next); current.next = newNode; This can be done more directly using Node<Book> current = head.next; current.next = new Node<Book>(b, current.next); 5/24/2017 BGA 26 Inserting b at end of list (1) current b0 b1 b2 b3 head newNode b0 b1 b2 b3 b head 5/24/2017 BGA current 27 Inserting b at end of list (2) Inserting b at end of list: [b0, b1, b2, b3] becomes [b0, b1, b2, b3, b] Node<Book> current = head.next.next.next; Node<Book> newNode = new Node<Book>(b, null); current.next = newNode; This can be done more directly using Node<Book> current = head.next.next.next; current.next = new Node<Book>(b, null); 5/24/2017 BGA 28 Delete the first node (1) b0 b1 b2 b3 head head orpha n b0 5/24/2017 b1 BGA b2 b3 29 Delete the first node (2) Delete the first node of the list: [b0, b1, b2, b3] becomes [b1, b2, b3] This is easy: just skip over the first node so that head references the second node head = head.next; 5/24/2017 BGA 30 Delete the second node (1) previous current b0 b1 b2 b3 head orpha n previous b0 b1 current b2 b3 head 5/24/2017 BGA 31 Delete the second node (2) Delete the second node of the list: [b0, b1, b2, b3] becomes [b0, b2, b3] Get references to node previous to b1, and to b1 Node<Book> previous = head; // node before b1 Node<Book> current = head.next; // b1 Skip over b1. Make b2 the new current node previous.next = current.next; // skip over b1 current = current.next; 5/24/2017 BGA 32 Delete the last node (1) previous b0 b1 b2 b3 head orpha n b0 b1 b2 b3 head 5/24/2017 BGA 33 Delete the last node (2) Delete the last node of the list: [b0, b1, b2, b3] becomes [b0, b1, b2] This is easy only if we have a reference to the previous node, otherwise a traversal is needed. head.next.next.next = null; Given previous it is we can just make the assigment previous.next = null; 5/24/2017 BGA 34 Traversals Processing a collection such as a linked structure from the first element (head) to the last element (tail) in sequence is called a traversal. While and for loops can be used to traverse a list Lists are ordered structures so the traversal visits them in order one element at a time Unordered collections such as a set or a bag can also be traversed in some arbitrary order. 5/24/2017 BGA 35 Simple list traversal model Assume that list is a reference to the first node in a list. The following while loop can be used to traverse the list current = head; while (current != null) { // process the list element here current = current.next;// move to next element } 5/24/2017 BGA 36 Simple list traversal model (1) each time through the loop current references the next node in the list current e0 e1 e2 e3 head 5/24/2017 BGA 37 Simple list traversal model (2) each time through the loop current references the next node in the list current e0 e1 e2 e3 head 5/24/2017 BGA 38 Simple list traversal model (3) each time through the loop current references the next node in the list current e0 e1 e2 e3 head 5/24/2017 BGA 39 Simple list traversal model (4) each time through the loop current references the next node in the list current e0 e1 e2 e3 head 5/24/2017 BGA 40 toString in Node class The toString method in the Node<E> class is a list traversal public String toString() { StringBuilder s = new StringBuilder(); s.append("["); Node<E> cursor = this; // head of "this" list while (cursor != null) { if (cursor.next != null) // second last element { s.append(cursor.data.toString()); s.append(",\n"); } else s.append(cursor.data.toString()); cursor = cursor.next; } s.append("]"); return s.toString(); } 5/24/2017 BGA 41 Print a list Print a list one item per line (similar to toString) . Here we are in the outer class LowLevelListTester Node<Book> cursor = head; while (cursor != null) { System.out.println(cursor.data); cursor = cursor.next; } 5/24/2017 BGA 42 Finding data in a list (1) A method to search a given list for a given element private static <E> boolean find(E element, Node<E> head) { Node<E> cursor = head; while (cursor != null && ! element.equals(cursor.data)) cursor = cursor.next; return cursor != null; } The node could also be returned here with null indicating that the element was not found in the list. 5/24/2017 BGA 43 Finding data in a list (2) A method to search a given list for a book given its 0-based position k in the range 0,1,2,3,... (could also return the node) private static <E> E find(int k, Node<E> head) { // Here we assume index k is in range int position = k; Node<E> cursor = head; while (position > 0) { cursor = cursor.next; position--; } return cursor.data; // (inner class) } 5/24/2017 BGA 44 Insert at end of list This is the general case of insertion at end of list. Unless the head is null it is necessary to traverse the list to find the tail reference private static <E> Node<E> insertAtEnd( Node<E> list, E element) { Node<E> head = list; Node<E> newNode = new Node<E>(element, null); if (head == null) head = newNode else // find a reference to the tail node { Node<E> cursor = head; while (cursor.next != null) cursor = cursor.next; cursor.next = newNode; } return head; } 5/24/2017 BGA 45 Delete tail of list (1a) General case of deleting the tail of the list. We return the new list with the tail deleted. private static <E> Node<E> removeTail(Node<E> list) { // Assume that the list is not empty Node<E> head = list; if (head.next == null) // one-element list { head = null; // remove element from one-element list } else { Node<E> previous = null; Node<E> current = head; while (current.next != null) { previous = current; current = current.next; } previous.next = null; // remove the tail } return head; } 5/24/2017 BGA 46 Delete tail of list (1b) General case of deleting the tail of the list. This version doesn't use the current reference, only previous private static <E> Node<E> removeTail2(Node<E> list) { // Assume that the list is not empty Node<E> head = list; if (head.next == null) // one-element list { head = null; // remove element from one-element list } else // find second last node { Node<E> previous = head; while (previous.next.next != null) { previous = previous.next; } previous.next = null; // remove the tail } return head; } 5/24/2017 BGA 47 Delete tail of list (2) previous current e0 e1 e2 e3 head 5/24/2017 BGA 48 Delete tail of list (3) previous current e0 e1 e2 e3 head 5/24/2017 BGA 49 Delete tail of list (4) previous current e0 e1 e2 e3 head 5/24/2017 BGA 50 Delete tail of list (5) previous current e0 e1 e2 e3 head 5/24/2017 BGA 51 Delete tail of list (6) previous current e0 e1 e2 e3 head 5/24/2017 BGA 52 Delete tail of list (7) orpha n e0 e1 e2 e3 head 5/24/2017 BGA 53 Delete tail of list (8) General case of deleting the tail of the list. This version doesn't use the current reference, only previous private static <E> Node<E> removeTail2(Node<E> list) { // Assume that the list is not empty Node<E> head = list; if (head.next == null) // one-element list { head = null; // remove element from one-element list } else // find second last node { Node<E> previous = head; while (previous.next.next != null) { previous = previous.next; } previous.next = null; // remove the tail } return head; } 5/24/2017 BGA 54 Insert at given index Given an index k (0,1,2,...) insert a new node at position k. Element previously at index k is now at position k + 1 private static <E> Node<E> insert(Node<E> list, E element, int k) { Node<E> head = list; int index = k; if (head == null || index <= 0) // insert at head head = new Node<E>(element, head); else { Node<E> cursor = head; while (index > 1 && cursor.next != null) { cursor = cursor.next; index--; } cursor.next = new Node<E>(element, cursor.next); } return head; } 5/24/2017 BGA 55 Delete at given index (1) Given an index k (0,1,2,...) delete the node at position k. Element previously at index k+1 is now at position k private static <E> Node<E> remove(Node<E> list, int k) { Node<E> head = list; int index = k; if (index <= 0) { head = head.next; // remove first node } else { Node<E> previous = null; Node<E> current = head; while (index > 0 && current.next != null) { previous = current; current = current.next; index--; } previous.next = current.next; } return head; } 5/24/2017 BGA 56 Delete at given index (2) This version of remove does not use the current reference private static <E> Node<E> remove2(Node<E> list, int k) { Node<E> head = list; int index = k; if (index <= 0) { head = head.next; // remove first node } else { Node<E> previous = head; while (index > 1 && previous.next.next != null) { previous = previous.next; index--; } previous.next = previous.next.next; } return head; } 5/24/2017 BGA 57 length of a list Use standard traversal and count the number of elements traversed private static <E> int length(Node<E> list) { Node<E> head = list; int count = 0; while (current != null) { count++; current = current.next; } return count; } 5/24/2017 BGA 58 Total value of all books Write a method that computes the total value of all books in a list Prototype is 5/24/2017 private static double totalValue(Node<Book> list) BGA 59 Delete books not in stock (1) Write a low-level method with prototype private static Node<Book> deleteBooks( Node<Book> list) The method should delete from the list all books whose inStock value is 0 Put your method in the LowLevelListTester class. It shouldn't use any of the other static methods in this class 5/24/2017 BGA 60 Delete books not in stock (2) Basic structure (finish it yourself) private static Node<Book> deleteBooks(Node<Book> list) { Node<Book> first = list; Node<Book> current = first; Node<Book> previous = null; while (current != null) { if (current.data.getInstock() == 0) { // delete this node } else { // move to next node in the list } } return first; // reference to the list } 5/24/2017 BGA 61 Append two lists Write a method with prototype private static <E> Node<E> append( Node<E> list1, Node<E> list2) The method returns a list obtained by putting list2 on the end of list1 (concatenation) Put your method in LowLevelListTester 5/24/2017 BGA 62 Reverse a list Write a low-level method with prototype private static <E> Node<E> reverse( Node<E> list) The method should return a list that is the reverse of list. Put your method in the LowLevelListTester class. 5/24/2017 BGA 63 Replace operation (1) Write a low-level method that replaces the first occurrence of an object in a list with a new object. Prototype is 5/24/2017 private static <E> Node<E> replace( Node<E> list, E element, E newElement) BGA 64 Replace operation (2) Write a low-level method that replaces the object at index i (0,1,...) with a new object. Prototype is 5/24/2017 private static <E> Node<E> replace( Node<E> list, int k, E newElement) BGA 65 Code slide Use box like this for comment Put code here 5/24/2017 BGA 66