Ch 7 Linked Lists

advertisement
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
Download