Chapter 7 Linked Lists 1 Chap.7 Contents 7.1 What is a Linked List? 7.2 Singly Linked List 7.2.1 Fields and Method Definitions in the SinglyLinkedList Class 7.2.2 Iterating through a SinglyLinkedList Object 7.3 Doubly linked List 7.4 An Application: Line Editor 7.4.1 Design of the Editor Class 7.4.2 Method Definitions for the Editor Class 7.4.3 Design of the EditorDriver Class 7.4.4 Implementation of the EditorDriver Class 2 By writing “interface”, the properties of software can be clarified. 藉著撰寫“interface”, 可以釐清軟體的性質. For example, the LIST interface clarifies properties such as: 例如, LIST interface 釐清下列字眼的性質: empty, element, index, higher index, lower index. 3 7.1 What is a Linked List A linked list is a List object Linked list 是一種 List object. (that is, an object of a class that implements the List interface) 那是一種實作 List interface 的 class 的物件 in which the following property is satisfied: 且滿足下面的性質: 4 Each element is contained in an entry object that includes a reference, called a link, to the entry object that holds the next element in the list. 每個 element 都包含在一個 entry object 裡 且 object 含有 reference (稱為 link) 指向 裝有 next element 的 entry object. 5 element link 張三 李四 王五 entry 6 If each Entry object also includes a link to the Entry object that holds the previous element in the list, we have a doubly linked list. 如果每個 Entry object 也含有連結 連到 list 中 previous element 的 Entry object. 我們就有雙向連結 list. 7 張三 李四 王五 8 The beauty of a linked list is that: Linked list 的優點是: insertions and removals are made without moving any elements. 插入和移除並 不需要移動任何 element. Only the links are altered. 只需改變 links. 9 張三 張三 李四 李四 王五 王五 10 7.2 The SinglyLinkedList Class ─ A Singly Linked, TOY Class We will devote most of this chapter to the study of the LinkedList class, a doubly-linked data structure that is part of the Java collections framework. 我們將於這章專心研習 LinkedList class (doubly-linked data structure) 它是 Java collection framework 的一部份. As a warm-up to that class, we start with a toy class: 作為對那個 class 的熱身準備, 我們從玩具 class 開始: SinglyLinkedList. 11 The Entry class will be a nested class within SinglyLinkedList: Entry class 將會是 nested class 在 SinglyLinkedList. protected class Entry <E> {E element; Entry<E> next; } // Entry Then, methods in SinglyLinkedList can access the Entry fields (element or next). 然後, SinglyLinkedList 中的 method 可以存取 Entry field (element 或是 next). 12 public class SinglyLinkedList <E> implements List<E> { // We’ll fill this part in shortly protected class Entry<E> {E element; Entry<E>next; }//Entry } // SinglyLinkedList 13 We will specify and define just enough methods for you to get a feel for the SinglyLinkedList class. 我們將 specify 和定義剛好足夠的 method 讓你對於 SinglyLinkedList class 有一點感覺. 14 /** SinglyLinkedList * initializes this SinglyLinkedList object to be empty, * with elements to be of type E. * */ public SinglyLinkedList() 15 /** isEmpty * 決定 SinglyLinkedList object 是否有任何 elements. * * @return true – 如果 SinglyLinkedList object * 沒有任何的 elements; * 否則, false. * */ public boolean isEmpty () 16 /** add * 在 SinglyLinkedList object 的最前面 * 插入指定的 element. * * @param element – 要被插入的 element * (在最前面). * @return true. */ public boolean add (E element) If true is always returned, why bother to return boolean? ANS: Because it should match the Collection interface. 17 /** size * 決定這 SinglyLinkedList object 中 elements 的數目. * * The worstTime(n) is O(n). * * @return: elements 的數目. * */ public int size () 18 /** contains * 決定 SinglyLinkedList object 是否包含 * 指定的 element. The worstTime(n) is O(n). * * @param obj – 要搜尋的指定 element . * * @return true – 如果 SinglyLinkedList object 包含 obj; * 否則, false. */ public boolean contains (Object obj) Warning: 確定 element class 有實做 equals method. 19 SinglyLinkedList<String> linked = new SinglyLinkedList<String>(); linked.add (“yes”); linked.add (“no” ); if (linked.size() == 2) if (linked.contains (“maybe”)) linked.add (“true”); else linked.add (“maybe”); What does linked consist of now? 現在 linked 由什麼構成? Ans: [maybe no yes] 20 7.2.1 Fields and Method Definitions in the SinglyLinkedList Class Fields (data structure) and implementation of the: SinglyLinkedList class: 21 How can we indicate the end of a SinglyLinkedList object? 我們如何指出 SinglyLinkedList object 的尾端? How can we indicate the beginning of a SinglyLinkedList object? 我們如何指出 SinglyLinkedList object 的開頭? 22 To indicate the end of a SinglyLinkedList object, 為了指出 SinglyLinkedList object 的尾端, the next field in the last Entry should be null. 在最後一個 Entry 的 next field 應該是 null doe ray me null 23 To indicate the beginning of a SinglyLinkedList object, 為了指出 SinglyLinkedList object 的開頭, we need a reference to the first Entry: 我們需要一個 reference 指向第一個 Entry: protected Entry<E> head; 24 head doe ray me null 25 public SinglyLinkedList( ) {head = null; } //default constructor 26 public boolean isEmpty( ) {return head == null;} 27 For the add (E element) method, let’s start with some examples: 對於 add (E element) method, 讓我們以一些例子開始吧: 28 SinglyLinkedList<String> myLinked = new SinglyLinkedList<String> ( ); myLinked.add (“me”); myLinked.add (“ray”); myLinked.add (“doe”); 29 myLinked .head doe ray me null 30 myLinked.add (“tea”); 31 // Construct a new Entry: Entry<E> newEntry = new Entry<E>( ); 32 myLinked. head newEntry null doe ray null me null 33 newEntry.element = element; 34 myLinked. head newEntry tea doe ray null me null 35 newEntry.next = head; 36 newEntry myLinked. head tea doe ray me null 37 head = newEntry; 38 newEntry myLinked. head tea doe ray me null 39 Here is the complete definition of add: 這裡是 add 的完整定義: public boolean add (E element) { Entry<E> newEntry = new Entry<E>(); newEntry.element = element; newEntry.next = head; head = newEntry; return true; } // add 40 Let us develop another method: 讓我們開發另一個 method: size() public int size( ) { ??? /* 我們認為我們需要一個 counter 來計算 size. */ int count = 0; 41 /* 需要 for loop 來計算每一個 element */ for loop: /* 需要 reference 來指出在 for loop 中的 current element */ Entry<E> current; 42 for loop initialization: current = head; 43 for loop continuation condition: current != null; 44 for loop incrementation: current = current.next; 45 public int size( ) { int count = 0; for (Entry<E> current = head; current != null; current = current.next) count++; return count; } // size 46 public boolean contains (Object obj) { if (obj instanceof E) for (Entry<E> current = head; current != null; current = current.next) if (obj.equals (current.element)) return true; return false; } // contains The actual definition is slightly more complicated, because it is legal for an element to be null. 實際的定義稍微複雜些, 因為它允許 element 為 null. 47 If the element’s class does not implement equals, there could be trouble. Why? 如果 element 的 class 沒有實做 equals, 可能會有問題. 為什麼? The Object class’s equals method tests for equality of references, not objects! Object class 的 equals method 測試 references 是否相等, 不是 object! 48 Exercise: Define the get method: /**get * returns the element at a specified index. * The worstTime(n) is O(n). * * @param index – the specified index. * @return – the element at index. * @throws IndexOutOfBoundsException – if index * is less than 0 or greater than size() – 1. * */ public E get (int index) 49 7.2.2 Iterating through a SinglyLinkedList Object Iterators 50 An iterator is an object that enables a user to loop through a collection without accessing the collection’s fields. iterator 是個 object 讓使用者可以 不存取collection的資 料欄位 而能直接對 collection 做迴圈 逐一存取. 51 public class SinglyLinkedList<E> implements List<E> extends AbstractCollection<E> { // We did this part earlier protected class Entry <E> {E element; Entry<E> next;} // Entry protected class SinglyLinkedListIterator implements Iterator<E> {protected Entry<E> next; … } // SinglyLinkedListIterator } // SinglyLinkedList 52 public SinglyLinkedListIterator( ) {next = head;} // default constructor 53 public boolean hasNext( ) {return next != null;} // hasNext 54 To motivate the definition of the next method, consider the following example: 為了激發 next method 的定義, 思考下列例子 55 head element next doe ray me null next 56 head element next doe ray me null next 57 Returned: “ray” So we need to: /*1*/ save next.element, /*2*/ advance next, and /*3*/ return the saved element in 1. 58 public E next( ) { /*1*/ E theElement = next.element; /*2*/ next = next.next; /*3*/ return theElement; } //next /* 2 */ above: The “next” field in the SinglyLinkedListIterator object is a reference to an Entry object that has a next field. 在 SinglyLinkedListIterator object 中, “next” 欄位 是指向有 next 欄位的 Entry object. 59 public E next( ) { /*1*/E theElement = next.element; /*2*/next = next.next; /*3*/return theElement; } // method next The next field in the SinglyListIterator object is a reference to an Entry object that has a next field. 60 Finally, we define an iterator method in the SinglyLinkedList class: 最後, 我們定義 SinglyLinkedList class 的 iterator method: /** iterator * returns a SinglyLinkedListIterator object * to iterate over this SinglyLinkedList object. */ public Iterator<E> iterator() {return new SinglyLinkedListIterator();} 61 What is returned? A reference to an object in the SinglyLinkedListIterator class, which implements the Iterator interface. 指向 實做 iterator interface 的 SinglyLinkedListIterator class 的 object 的 reference. 62 Example: Print each element of myLinked whose value is greater than 5.0: 例如: 印出 myLinked 中每個大於 5.0 的 element: Iterator<Double> itr = myLinked.iterator(); while (itr.hasNext()) {double d = itr.next(); if (d > 5.0) System.out.println (d);} 63 Exercise: In the preceding example, use an “enhanced for” statement instead of an iterator. ANS: for (Double d: myLinked) if d > 5.0 System.out.println (d) ; 64 7.3 Doubly Linked Lists previous element next 65 7.3.2 The LinkedList Class versus the ArrayList Class For the most part, the LinkedList class has the same method headings as the ArrayList class, 大多數情況下, LinkedList class 與 ArrayList class 有相同的 method headings, but those classes have different time estimates for some methods. 但 對於某些 methods 有不同的時間預估. 66 For example, for a LinkedList public E get (int index) public E set (int index, E element) worstTime(n) is linear in n versus constant for an ArrayList. 67 Sometimes LinkedList is faster: public boolean add (E element) The worstTime(n) is constant, versus linear in n for an ArrayList because of the possible re-sizing. 68 Basically, to get to a position in a LinkedList takes linear-in-n time, 基本上, 到達 LinkedList 的某位置需要 linear-in-n time, but once you get there, you can remove or insert in constant time. 但是一旦到達那裏 你移除或插入 只需要 constant time. 69 That magnifies the importance of iterators, 那彰顯了 iterators 的重要性, because once an iterator is positioned somewhere in the collection, 因為一旦 iterator 放在 collection 的某地方, you can insert or remove in constant time. 你就可在 constant 時間內 插入或移除. 70 Here are the method headings for all of the methods in the LinkedList class: 這裡是 LinkedList class 中全部 methods 的 method headings : 71 1. public 2. public LinkedList( ) LinkedList (Collection<? extends E> c ) 3. public boolean add (E element) 4. public void add (int index, E element) 5. public void addAll (Collection<? extends E> c) 6. public boolean addAll (int index, Collection c) 7. public boolean addFirst (E element) 8. public boolean addLast (E element) 9. public void clear( ) // worstTime(n) is constant 10. public Object clone( ) 11. public boolean contains (Object obj) 12. public boolean containsAll (Collection<?> c) 72 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. public boolean equals (Object obj) public E get (int index) public E getFirst ( ) public E getLast ( ) public int hashCode( ) public int indexOf (Object obj) public boolean isEmpty( ) public Iterator<E> iterator( ) public int lastIndexOf (Object obj) public ListIterator<E> listIterator( ) public ListIterator<E> listIterator (final int index) public boolean remove (Object obj) 73 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. public E remove (int index) public boolean removeAll (Collection<?> c) public E removeFirst() public E removeLast() public boolean retainAll (Collection<?> c) public E set (int index, E element) public int size( ) public List<E> subList (int fromIndex, int toIndex) public Object[ ] toArray( ) public <T> T[ ] toArray (T[ ] a) public String toString() 74 Example: Here is a processInput (String s) method that starts by converting s (EX: “10”) to int n and then 0. 1. 2. 3. 4. 5. Constructs a LinkedList of Double objects. public LinkedList( ) In a loop with i going from 0 to n – 1, appends new Double (i) to the LinkedList. public boolean add (E element) Inserts new Double (1.4) at index n / 3. public void add (int index, E element) Removes the element at index 2n / 3. public E remove (int index) Multiplies the middle element by 3.5. public E get (int index) public E set (int index, E element) Prints out the LinkedList; public String toString() 75 public void processInput (String s) { int n = Integer.parseInt (s); List<Double> myList = new LinkedList<Double>(); for (int i = 0; i < n; i++) myList.add (i + 0.0); myList.add (n / 3, 1.4); myList.remove (2 * n / 3); double d =(myList.get (n/2))*3.5; myList.set (n/2, d); System.out.println (myList) ; } Does this look familiar? Yes, we did the same in ArrayList. 76 The output, just as before, is 0.0, 1.0, 2.0, 1.4, 3.0, 14.0, 6.0, 7.0, 8.0, 9.0 77 7.3.3 LinkedList Iterators 78 public interface ListIterator extends Iterator 79 An iterator for lists allows the programmer to: 1) traverse the list in either direction, 2) modify the list during iteration, and 3) obtain the iterator's current position in the list. Lists 的 iterator 允許 programmer: 1) 往返 list 的任一方向, 2) 在此期間修改 list, 3) 獲得 iterator 在 list 的現在位置 80 • A ListIterator has no current element; its cursor position always lies between: the element that would be returned by a call to previous() and the element that would be returned by a call to next() ListIterator 沒有目前元素 ; 游標位置 總是位在 呼叫 previous() 回傳的element 及 呼叫 next() 回傳的element 之間. 81 The remove() and set(Object) methods are not defined in terms of the cursor position. remove( )和 set(Object) 非依游標位置 來定義 They are defined to operate on the last element returned by a call to next() or previous(). 他們是操作 呼叫 next() 或 previous() 後 回傳的 element. 82 Element(0) Element(1) ^ ^ 0 1 Cursor remove() set(Object) Element(2) Element(n-1) ^ ^ ^ 2 3 n Cursor 呼叫 remove() //remove Element(1) 呼叫 set(Object) next() //回傳 呼叫 // Element(1) set Element(1) 呼叫 previous() //回傳 Element(1) 83 Methods in the embedded ListItr class: IT1. public void add (E element)//add before cursor IT2. public boolean hasNext( ) IT3. public boolean hasPrevious( ) IT4. public E next( ) IT5. public int nextIndex( ) //we need it in the application IT6. public E previous( ) IT7. public int previousIndex( ) IT8. public void remove( ) IT9. public void set (E element) For each method, worstTime (n) is constant! 84 Linked list is a circular list The next slides show iterator location and its related insertions. 下面投影片 顯示 iterator 位置 和 相關的插入 Remember that linked list is a circular list, which helps understand how insertion works. 記住 linked list 是一種circular list, 有助於瞭解 如何執行插入動作. 85 Ex: ListIterator itr = list.listIterator() ;// list is empty header NULL 0 itr points to nextIndex 0 itr Ex: itr.add(“張三”) ; Same as above, itr points to nextIndex 1 header NULL 張三 0 1 itr 86 itr.next( ) returns header entry, itr.prervious( ) returns 張三 entry. So, 李四 entry will be added IN BETWEEN. next previous itr header 李四 2 itr 1 null 張三 0 87 Ex: ListIterator itr = list.listIterator() ; itr.add(“張三”) ; itr.add(“李四”) ; header NULL 張三 李四 88 itr.next( ) returns B itr.previous( ) returns A itr A itr.previous() B C itr.next() 89 /* listIterator 回傳 LinkedList 中位於 index 的 * ListIterator, * 如果 index = size() 則, * 拋出 IndexOutOfBoundsException 異常 * The worstTime(n) is O(n). * * @throws IndexOutOfBoundsException – * 如果 index 小於 0 或者大於 size(). */ public ListIterator<E> listIterator (final int index) 90 To print myList in reverse order: 以相反的順序印出 myList: itr = myList.listIterator (myList.size( )); while (itr.hasPrevious( )) System.out.println (itr.previous( )); 91 A ListIterator method: /** add 插入 element 到 LinkedList 中 * 於呼叫 next( ) 回傳的 element 之前 或 * 於呼叫 previous( )回傳的 element 之後 */ public void add (E element); 92 LinkedList<Double>myList = new LinkedList<Double>(); myList.add (0.0); myList.add (1.0); /*itr points to cursor before 0.0 */ ListIterator<Double> itr = myList.listIterator(); /* itr points to cursor before 1.0 */ itr.next(); /* add 0.8 between next() (1.0) and previous() (0.0) */ itr.add (0.8); 93 The LinkedList would now have: 0.0, 0.8, 1.0 94 A ListIterator method: /** * 移除最後回傳的 element. */ public void remove(); 95 LinkedList<String> myList = new LinkedList<String>(); myList.add ("A"); // [A] myList.add ("B"); // [A, B] myList.add ("C"); // [A, B, C] myList.add ("D"); // [A, B, C, D] ListIterator<String> itr = myList.listIterator(); itr.add ("E"); // [E, A, B, C, D] //cursor is at arrow itr.next(); // [E, A, B, C, D] // returned value is in red itr.add ("F"); // [E, A, F, B, C, D] itr.next(); // [E, A, F, B, C, D] itr.remove(); // [E, A, F, C, D] // remove what was just returned itr.previous(); // [E, A, F, C, D] itr.remove(); // [E, A, C, D] System.out.println (myList); 96 Result : [E, A, C, D] Partial example from last page: ListIterator<String> itr = myList.listIterator(); itr.add ("E"); // [E, A, B, C, D] itr.next(); // [E, A, B, C, D] 回傳 A itr.add ("F"); // [E, A, F, B, C, D] itr.next(); // [E, A, F, B, C, D] 回傳 B itr.remove(); // [E, A, F, C, D] 移除 B itr.previous(); // [E, A, F, C, D] 回傳 F itr.remove(); // [E, A, C, D] 移除 F A E itr A B itr C F B itr C B D itr C D itr D 97 User’s guide for choosing ArrayList or LinkedList: If the application entails a lot of accessing and/or modifying elements at widely varying indexes, an ArrayList will be much faster than a LinkedList. If a large part of the application consists of iterating through a list and making insertions and/or removals during the iterations, a LinkedList will be much faster than an ArrayList. 98 7.3.5 Fields and Heading of the LinkedList Class There are two fields of the LinkedList class: private transient int size = 0; private transient Entry<E> header = new Entry (null, null, null); 99 Fields and implementation of the LinkedList class: There are two fields (plus modCount, inherited) (modification count) Field not saved if object is serialized private transient int size = 0; private transient Entry header = new Entry (null, null, null); 100 private static class Entry<E> { E element; Entry<E> next; Entry<E> previous; Entry (E element, Entry<E> next, Entry<E> previous) {this.element = element; this.next = next; this.previous = previous; } // constructor } // Entry 101 7.3.6 Creating and Maintaining a LinkedList Object public LinkedList() // 看下一頁的圖 {header.next = header.previous = header;} For example, LinkedList<String> names = new LinkedList<String>(); 102 Empty LinkedList 103 LinkedList with one element 104 LinkedList with two elements index 0 index 1 105 The significance of the header entry is that: Header entry的重要性是: there is always an entry in back of and in front of any entry. 總是會有 entry 在任一個 entry 之前或之後. That simplifies insertions and removals. 那會簡化 插入或移除 的程式 106 7.3.7 Definition of the Two-Parameter add Method 107 Details of insertion into a LinkedList: names.add (1, “王五”); //before add, index 1 points to 李四 The method heading for this method is: public void add (int index, E element) This add method calls addBefore (element, entry (index)); and the heading for addBefore is private Entry<E> addBefore (E element, Entry<E> 108 e) So, “王五” will be inserted in front of the entry at index 1 with reference e (that is 李四) 所以, “王五”將被插入在 index 1, reference e 的entry之前(就是李四) 109 Start 110 Step 1 // insert newEntry in front of e that points to 李四 Entry<E> newEntry = new Entry(element, e, e.previous); // newEntry’s element is “王五” // newEntry’s next is “e” (“李四”) // new Entry’s previous is “e.previous” (“張三”) 111 Step 1 112 Step 2 // make newEntry follow its predecessor,張三 newEntry.previous.next = newEntry; 113 Step 2 114 Step 3 // make newEntry precede its successor, e (李四) newEntry.next.previous = newEntry; 115 Step 3 116 The same strategy works for names.add (0, “趙六”); // inserts between header entry // and entry at index 0 names.add (names.size(), “宋七”); // inserts between entry at index size() – 1 // and header entry 117 Group exercise: Determine the output from the following: 118 LinkedList<String> myList = new LinkedList<String>(); myList.add ("a");myList.add ("b");myList.add ("c"); myList.add ("d");myList.add ("e");myList.add (2, "r"); myList.remove (4); ListIterator<String> itr = myList.listIterator (3); itr.previous();itr.add ("x");itr.next();itr.remove(); itr = myList.listIterator (myList.size()); while (itr.hasPrevious()) System.out.print (itr.previous()); ANS: e c x b a 119 7.4 Application: A Line Editor 120 Line editor: A program that manipulates text, line by line. Line editor: 逐行地處理文件的 program. First line = line 0 One line is designated the current line with “>” at the beginning of the line. 以“>”在 line 的開頭來表示是 current line. Each editing command begins with $. 每一個 editing command 以 $ 起始. 121 For now, there are only four editing commands: 現在只有 4 道 editing commands: 122 1. $Insert Each subsequent line, up to the next editing command, 每一個後來的 line 到下一個 editing command 之前 is inserted into the text in front of the current line (at back of text if no current line) 被插入到 text 中在 current line 之前(如果沒有 current line 則插到 最後面). 123 Example: Suppose the text is empty $Insert 從前有隻狗, 狗的背上有長毛, Now the text is: 從前有隻狗, 狗的背上有長毛, > 124 Another example: Suppose the text is: 狗有很多種 有大狗、小狗 > 這是狗的一生 $Insert 從前有隻狗, 狗的背上有長毛, 125 Now the text is: 狗有很多種 有大狗、小狗 從前有隻狗, 狗的背上有長毛, > 這是狗的一生 126 2. $Delete m n Each line in the text between lines m and n, inclusive, will be deleted. 在 text 中, 介於 line m 到 n 之間的每一個 line (包含 m 與 n) 將被 deleted. The current line is now just after the last line deleted. 現在的 current line 剛好在 被 delete 的 last line 之後. 127 Example: Suppose the text is: 狗有很多種 有大狗、小狗 從前有隻狗, 狗的背上有長毛, > 這是狗的一生 $Delete 0 2 128 Now the text is: > 狗的背上有長毛, 這是狗的一生 129 Possible errors in the command line: Error: The first line number (m) is greater the second (n). Error: The first line number (m) is less than 0. Error: The 2nd line number (n) is greater than the last line number. Error: The command is not followed by two integers. 130 3. $Line m Line m becomes the current line in the text. Line m 變成 text 中的 current line. 131 Example: Suppose the text is: 狗有很多種 有大狗、小狗 從前有隻狗, 狗的背上有長毛, > 這是狗的一生 $Line 2 132 Now the text is: 狗有很多種 有大狗、小狗 > 從前有隻狗, 狗的背上有長毛, 這是狗的一生 133 Possible errors in the command line? Command line 可能的 errors 是? 134 4. $Done The text is printed and the execution of the editor is finished. 印出 text 並且結束編輯的工作. 135 7.4.1 Design of the Editor Class For flexibility, we will separate editing from input/output. 為了彈性, 我們將分離 editing 與 input/output. Then, for example, the input could come from the keyboard, or from a file. 例如, input 可以來自 keyboard 或是從 file. And that choice would not affect the editing. 而且此選擇不會影響 editing. 136 So we will create two classes: 所以我們將產生兩個 classes : EditorDriver: To handle input and output Editor: To handle editing 137 Error message will be thrown as exceptions. Error message 將以 exceptions 被丟出. For example, throw new RuntimeException (M_LESS_THAN_ZERO); 138 Error messages will be thrown in Editor methods and caught in EditorDriver methods. 139 For the Editor class, how do we start? 對於 Editor class , 我們要怎麼開始開發呢 ? Fields or methods? The chicken or the egg? 雞生蛋? 或蛋生雞? 140 Proceed as follows: Responsibilities of the class (what the class will provide to users) Method specifications Data Fields Method definitions 141 Responsibilities: To interpret the line for: 1) one of the 4 legal commands, 2) an illegal command, or 3) a line of text Then, carry out each of the four commands 142 interpret ( ) /** interpret 解讀給予的 line * * @param s – 要解讀的 line. * @return the resulting text (done command) * OR nothing (insert, delete, line commands) */ public String interpret (String s) 143 1. insert ( ) /* insert 插入 line 到text中 current line的前面. * * @param s – 要插入的 line. * @throws RuntimeException – 如果 s 多於 * MAX_LINE_LENGTH characters. */ protected void insert (String s) 144 2. delete ( ) /** delete * 從 text 中刪除以指定的兩個 indexes 為 range 的 lines. * * @param m – range 的第一的 index. * @param n – range 的最後的 index. * @throws RuntimeException – * 如果 1)m 小於 0 或是 * 2)m 大於 n 或是 * 3)n 大於或等於 text 中 lines 的數目. */ protected void delete (int m, int n) 145 3. line ( ) /* line 使指定的 line number成為 current line. * * @param m –指定的 line number * @throws RuntimeException * – 如果 m 小於 0 或是 * 大於text中 lines 的數目. */ protected void line (int m) 146 4. done ( ) /** done 終止 editor 並且回傳 text. * * @return the resulting text */ protected String done( ) 147 Data Fields? (Data Structure?) 148 Design sketch previous element next 從前有隻狗, 狗的背上有長毛, 149 // Data structure protected LinkedList<String> text; protected ListIterator<String> current; protected boolean inserting; // 何時想出 inserting? // 一開始想不到的 150 7.4.2 Method Definitions for the Editor Class public Editor( ) { text = new LinkedList<String>(); current = text.listIterator( ); inserting = false; } // default constructor 151 public String interpret (String s) { /* If the line doesn’t start with a $, * insert the line if inserting is true. * otherwise throw an exception. * * If the line does start with a $, * perform the appropriate command, * or throw an exception * if there is no such command. */ } // end of interpret 152 interpret ( ) public String interpret (String s) { /* if s 不是 $開頭, then if inserting is true insert s * else throw exception * if s 是 $開頭, 執行 command, * if 無此 command, throw exception */ 153 To insert a line: protected void insert (String s) { if (s.length( ) > MAX_LINE_LENGTH) throw new RuntimeException (LINE_TOO_LONG + MAX_LINE_LENGTH); current.add (s);//只 reuse LinkedList add 就搞定 insert 了 } // end of insert 154 protected void delete (int m, int n) { if (m > n) throw new RuntimeException (FIRST_GREATER); if (m < 0) throw new RuntimeException (FIRST_LESS_THAN_ZERO); if (n >= text.size( )) throw new RuntimeException (SECOND_TOO_LARGE); current = text.listIterator (m); for (int i = m; i <= n; i++) {current.next(); current.remove( ); } } // end of delete 155 protected void line (int m) { if (m < 0) throw new RuntimeException (M_LESS_THAN_ZERO); if (m > text.size()) throw new RuntimeException (M_TOO_LARGE); current = text.listIterator (m); } // end of line 156 protected String done( ) { //1. iterate through each line in the text, // 串接 each line 到 s, // // 2. return s } // end of done 157 done () 1.while (text 還有下一個 line) 串接 line 到 s current“>”在 text 中間 or 之後 2.return s 158 What about ‘>’? To determine whether itr is positioned at the current line (‘>’), we cannot check either 1) itr = = current or 2) itr.next( ).equals (current.next( ) ) Why not? (see next page) 159 1) itr == current won’t work because these are references to iterators, not to elements, nor even to entries. 160 2) itr.next( ).equals (current.next( )) won’t work because there may be multiple copies of the current element: 從前有隻狗, 狗的背上有長毛, current-> 從前有隻狗, itr -> 161 public String done ( ) { final String FINAL_TEXT_MESSAGE = "\n\nHere is the final text:\n"; String s = FINAL_TEXT_MESSAGE; ListIterator itr = text.listIterator( ); // 串接 each line 到 s // current“>”在 text 中間 while (itr.hasNext( )) if (itr.nextIndex( ) == current.nextIndex( )) s = s + "> " + itr.next() + '\n'; else s = s + " " + itr.next() + '\n'; // currrent“>”在 text 之後 if (!current.hasNext()) s = s + "> " + '\n'; return s;} // end done() 162 7.4.3 Design of the EditorDriver Class The EditorDriver class 163 The EditorDriver class has: openFiles() and editText() methods. EditorDriver class 有 openFiles() 和 editText() methods. These are virtually identical to the openFiles() and testVeryLongInt() methods from the VeryLongDriver class in Chapter 6. 這些實際上與 Chapter 6 中 VeryLongDriver class 裡的 OpenFiles()和 testVeryLongInt() method 相同的. 164 7.4.4 Implementation of the EditorDriver Class The editText() method reads in each line in the input file. editText() method 從 input file 讀取每一行. The line is interpreted, and exceptions are caught and printed. 每一行將被解讀, exceptions 會被 catch 並印出. For the $Done command, the text is printed. 對於$Done command, text 將被印出 165 public void editText(){ Editor anEditor = new Editor(); String line = new String(), result = new String(); // the resulting text while (true) { try { line = fileReader.readLine(); if (line == null) break; fileWriter.println (line); result = anEditor.interpret (line); } /*end try*/ catch (RuntimeException e) { fileWriter.println (e); } catch (IOException e) { System.out.println (e); } if (line.equals (Editor.DONE_COMMAND)) fileWriter.println (result); } /*end while*/ }// end of editText 166 Group exercise: In the previous slide, we had: if (line.equals (Editor.DONE_COMMAND)) What is the complete declaration of the identifier DONE_COMMAND in the Editor class? ANS: $Done 167