Transcript ArrayList

ArrayList
คล้าย array แต่ไม่เหมือน




ใช้ index ในการเข้าถึงสมาชิกแต่ละตัวได้
จัดการขยายขนาดได้เองโดยอัตโนมัติ
มีเมธอดสาหรับใส่ ของในอาร์ เรย์ตรงไหนก็ได้
เมธอดนั้นเป็ นไปตาม List Interface แต่กม็ ีเมธอดของมันเองด้วย
 clone
 ensureCapacity
 trimToSize

ใส่ ได้แต่ Object เท่านั้น
ตัวอย่างเมธอด

public ArrayList(int initialCapacity)
IllegalArgumantException ถ้า
initialCapacity <0
 Throw
ArrayList<String>name = new
ArrayList<String>(100);
 ถ้าเราไม่บอกขนาด อาร์ เรย์ลิสต์ที่สร้างจะจุได้ 10 สมาชิก

คอนสตรัคเตอร์อีกแบบ

public ArrayList(Collection<? Extends E> c)
 เอาของจาก c
มาใส่ ในอาร์ เรย์ลิสต์ของเราที่สร้างใหม่
 ลาดับของสมาชิกก็เอาตามลาดับสมาชิกของ c
 อาร์ เรย์ลิสต์ที่สร้างจะมีขนาด 110% ของ c
 Worst time = O(n)
 ชนิ ดของสมาชิกจาก c ต้องเป็ นชนิ ดเดียวกับในอาร์ เรย์ลิสต์ หรื อไม่กต็ อ้ งเป็ นสับ
คลาส
ถ้าเรามี womanList ซึ่งจุของประเภท Woman ซึ่งเป็ นสับคลาสของ People
 เราสามารถสร้าง อาร์ เรย์ลิสต์ของ People ได้จาก womanList
 ArrayList<People> a = new
ArrayList<People>(womanList);



จริ งๆแล้วเป็ นการสร้างพอยต์เตอร์ไปยังของใน c เท่านั้น นี่ถือว่าเป็ น
shallow copy แบบหนึ่ง
อีกแบบคือใช้เมธอด clone()
 ArrayList<People> a
=
(ArrayList<People>)womanList.clone();

Shallow copy มี reference ต่างหากจากตัวต้นฉบับ แต่ถา้ ภายในมี
ออบเจ็กต์ พอยต์เตอร์ ของออบเจ็กต์น้ นั จะชี้ไปที่สิ่งเดียวกับต้นฉบับ
 จะไม่เหมือนกับการใช้ a
womanList เลย
= womanList; เพราะอันนี้จะให้ a ชี้ไปที่
Shallow copy
womanList
a
w1
w2
w3
Shallow copy (2)

จากหน้าที่แล้ว ถ้าเราเรี ยกใช้
People(“MRS.X”)); กับ
 a.add(new People(“MR.A.J.”)) จะได้
 womanList.add(new
womanList
MRS.X
a
w1
w2
w3
MR.A.J.
new ArrayList<People>(womanList); กับ
 (ArrayList<People>)womanList.clone();
 จริ งๆจะต่างกันนิ ดนึ ง

 การโคลนจะได้จานวนช่องอาร์ เรย์เท่าเดิม
 แต่การใช้ copy
ของเดิม
constructor อาร์เรย์จะมีขนาด 110% เทียบกับ
อาร์เรย์ธรรมดาก็มีการก็อปปี้

System.arraycopy(array1, i, array2, i2, 3);
 ก็อปปี้ จาก array1
ที่ index i
 ไปที่ array2 โดยเริ่ มที่ index i2
 ก็อปปี้ ไป 3 ตัว
public boolean add(E element)

เอาของใส่ ทา้ ยอาร์เรย์ลิสต์
Worst time = O(n), Avg time = constant
 รี เทิร์น true เมื่อของได้ถูกใส่ จริ งๆ (แบบนี้ ก็ true ตลอด)

public E get(int index)
รี เทิร์นสมาชิก ณ ตาแหน่งที่บอก
 Throw indexOutOfBoundsException ถ้า
size()<=index, หรื อ index<0

public E set(int index, E element)
แทนที่สมาชิกตัวที่ index ด้วย element
 รี เทิร์นสมาชิกเก่าที่เก็บที่ index นี้
 Throw indexOutOfBoundsException ถ้า
size()<=index หรื อ index<0
 Worst time = constant

public void add(int index, E
element)
แทรก element เข้าไป ณ ตาแหน่ง index
 สมาชิกตัวอื่นต้องเลื่อนตาแหน่ งไป

Worst time = O(n)
 Throw indexOutOfBoundsException ถ้า
size()< index หรื อ index<0

public E remove(int index)
เอาสมาชิก ณ ตาแหน่ง index ออกไป
 สมาชิกข้างขวาต้องเลื่อนมาแทนที่
 รี เทิร์นสมาชิกตัวที่เอาออก
 Throw indexOutOfBoundsException ถ้า
size()<=index หรื อ index<0

public int indexOf(Object element)
หาค่าที่เหมือนกับ element ตัวแรกในอาร์เรย์ลิสต์
 รี เทิร์น ดัชนี ของค่านั้นในอาร์ เรย์ลิสต์ หรื อ -1 ถ้าหาไม่เจอ
 เทียบค่าว่าเหมือนหรื อไม่ดว้ ยเมธอด equals()


Worst time = O(n)
ArrayList class heading


public class ArrayList<E> extends
AbstractList<E> implements List<E>,
RandomAccess, Cloneable, java.io.Serializable
มีฟิลด์
 private

transient E[ ] elementData;
Transient หมายถึงไม่เซฟตัวอาร์เรย์ตอนทา serialization แต่เซฟสมาชิกนะ
 private
int size;
ตัวอย่างโค้ดภายในคอนสตรัคเตอร์
public ArrayList (int initialCapacity) {
elementData = new Object [initialCapacity];
}
public ArrayList ( ) {
this (10);
}
public ArrayList(Collection<? extends E> c) {
this((c.size()*110)/100); // โตขึ้น 10%
Iterator i = c.iterator( );
while (i.hasNext( ))
elementData[size++] = i.next();
}
ตัวอย่างโค้ดภายใน เมธอด add(E element)
public boolean add(E element){
ensureCapacity(size+1); //ขยายอาร์เรย์ถา้ จาเป็ น
elementData[size++] = element;
return true;
}
public void ensureCapacity(int min)
{ modcount++; //ดูหน้าถัดไป
int oldCapacity = elementData.length;
if(min>oldCapacity){ //ความจุใหม่ใหญ่กว่าเก่า
E oldData[] = elementData;
int newCapacity = (oldCapacity*3)/2+1; //ให้ขยาย 50%
if(newCapacity < minCapacity) //ถ้ายังขยายไม่พอ
newCapacity = min; // ก็ให้ขนาดตามอินพุตไปเลย
elementData = (E) new Object[newCapacity];
System.arrayCopy(oldData,0,elementData,0,size);
}
}
modCount


มีในแต่ละคลาส ArrayList, LinkedList, TreeMap, TreeSet,
HashMap, HashSet
ของ ArrayList นั้น inherit มาจาก AbstractList
 เปลี่ยนค่าเมื่อมีการเปลี่ยนแปลง

คือมีการ insert หรื อ remove จาก ArrayList นี้
อิเทอเรเตอร์ แต่ละตัวก็มี expectedModCount ต่างหาก
 เปลี่ยนค่าเมื่ออิเทอเรเตอร์ ตวั นั้นเปลี่ยนของในคอลเลคชัน
่ เช่น itr.remove()
 modCount

ก็จะเปลี่ยนด้วย
ถ้าสองฟิ ลด์น้ ีไม่เท่ากันเมื่อไร แสดงว่ามีการเปลี่ยนคอลเลคชัน่ ด้วยเมธอดที่ไม่ใช่
ของอิเทอเรเตอร์ ระหว่างที่อิเทอเรเตอร์ มีการใช้งานอยู่ เช่นเปลี่ยนโดยเทรดอื่น
 ทุกๆการเปลี่ยนแปลงของอิเทอเรเตอร์ เอง จะมีการเรี ยกใช้
Fail fast
if (modCount!=expectedModCount)
throw new ConcurrentModificationException();
modCount & expectedModCount
(ต่อ) ตัวอย่างการใช้อิเทอเรเตอร์ที่ไม่ดี
public ModCountDriver( ) {
ArrayList list = new ArrayList( );
list.add (“yes”);
สร้างอิเทอเรเตอร์
Iterator itr = list. iterator( );
modCount++, แต่ expectedModCount เท่าเดิม
list.add (“good”);
itr.next( ); // exception thrown at this point
}
next นี่จึงใช้ไม่ได้
เวลาของ ensureCapacity

Worst time = การก็อปปี้ อาร์เรย์ = O(n)

Avg time =
 ต้องเรี ยก add
ไป n/3 ครั้งก่อน ถึงจะมีการก็อปปี้ อาร์ เรย์
 ฉะนั้น ต้องเรี ยก add ไป (n/3)+1 ครั้ง จึงจะเกิดการก็อปปี้ n สมาชิก
 จานวนการก็อปปี้ ต่อการเรี ยก add หนึ่ งครั้งจึงเฉลี่ยเป็ น n/((n/3)+1)

ประมาณ 3 ครั้ง
 Avg
time = constant
โค้ดของเมธอดโคลน
public Object clone() {
try {
ArrayList v = (ArrayList)super.clone(); // copies size
v.elementData = new Object[size];
System.arraycopy(elementData, 0, v.elementData,
0, size);
v.modCount = 0;
return v;
}
catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
ตัวอย่างการใช้งาน สมมติเราต้องการทาอะไรต่างๆดังนี้
1.
2.
3.
4.
5.
6.
สร้าง ArrayList ซึ่งมี n สมาชิก
ลูป n ครั้ง ใส่ สมาชิกซึ่งเป็ น Double (i) โดย i เริ่ มจาก 0 ลงไปท้าย
ลิสต์
ใส่ new Double (7.8) ที่ index n/2
เอาสมาชิกที่ตาแหน่ง 2n / 3 ทิ้งไป
เอา 2.5 คูณกับสมาชิกตัวกลางของลิสต์
พริ้ นต์ค่าภายในลิสต์ท้ งั หมดออกมา
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
public void processInput (String s) {
1
int n = Integer.parseInt (s);
ArrayList myList = new ArrayList (n);
2
for (int i = 0; i < n; i++)
myList.add (new Double (i));
3
myList.add (n / 2, new Double (7.8));
myList.remove (2 * n / 3);
4
double d = ((Double)myList.get (n / 2)).doubleValue( )
* 2.5;
myList.set (n / 2, new Double (d));
5
gui.println (myList) ;
}
6
การใช้งาน ArrayList – VeryLongInt
ฟิ ลด์ในคลาส VeryLongInt

protected ArrayList<Integer> digits;
 แต่ละสมาชิกจะมีเลขหนึ่ งหลักเท่านั้น
การใช้งาน ArrayList –
VeryLongInt class

public VeryLongInt(String s)
 สร้าง VeryLongInt
ขึ้นมาจาก String
 Throw NullPointerException ถ้า s == null
VeryLongInt a = new VeryLongInt(“5629?3”);
 จะได้ค่า 56293 เก็บไว้ใน a

 Worst
time = O(string length)
ไม่ใช่เลขจึงทิ้งได้
โค้ดของ VeryLongInt(String s)

ลูปไปตามคาแร็ กเตอร์แต่ละตัว
 ถ้าคาแร็ กเตอร์ เป็ นตัวเลข ให้ลบด้วย ‘0’
 เอาเลขที่ได้ใส่ อาร์ เรย์ลิสต์
เพื่อให้ได้ค่าแท้จริ งออกมา
public VeryLongInt(String s){
final char LOWEST_DIGIT_CHAR = ‘0’;
digits = new ArrayList<Integer>(s.length());
char c;
int digit;
for(int i = 0; i<s.length(); i++){
c = s.charAt(i);
if(Character.isDigit(c)){
digit = c - LOWEST_DIGIT_CHAR;
digits.add(digit); // auto convert
}
Avg time = constant,
}
Worst time = constant เพราะไม่มีการเปลี่ยนขนาด
}
Avg time &
worst time =
O(n)

public String toString()
 Return

String ที่แทน VeryLongInt object นี้
56293 จะกลายเป็ น [5,6,2,9,3]
 Worst
time = O(จานวนหลักเลข)
public String toString(){
return digits.toString();//เรี ยกใช้เมธอดของอาร์เรย์ลิสต์
}

public void add(VeryLongInt
otherVeryLong)
 บวกสอง VeryLongInt
time = O(จานวนหลักเลขของตัวที่มีจานวนหลักมากที่สุด)
 Throw NullPointerException ถ้า otherVeryLong
== null
 Worst
โค้ดของ add(VeryLongInt
otherVeryLong)
บวกทีละหลัก เริ่ มจากหลักหน่วย (เหมือนบวกเลขปกติ) เอาผลที่บวกแต่
ละหลักนั้นใส่ อาร์เรย์ลิสต์อีกตัวที่ชื่อว่า sumDigits
 ถ้าเรามี 135 กับ 79 เราจะได้ผลใน sumDigits เป็ น 412
เพราะว่าหลักหน่วยถูกนาไปใส่ sumDigits เสี ยก่อน ดังนั้นต้องมี
การรี เวิร์สสมาชิกใน sumDigits

 จะได้ 214
เป็ นคาตอบที่แท้จริ ง
public void add(VeryLongInt otherVeryLong){
final int BASE = 10;
int largerSize, partialSum, carry = 0;
ArrayList<Integer>sumDigits= new ArrayList<Integer>();
if(digits.size()>otherVeryLong.digits.size())
largerSize = digits.size();
else
หลักที่ i เริ่ มจากหลักหน่วย
largerSize = otherVeryLong.digits.size();
for(int i=0; i<largerSize; i++){
partialSum = least(i) + otherVeryLong.least(i) + carry;
O(n)
carry = partialSum / BASE ;
sumDigits.add(partialSum % BASE);
}
Constant time
if(carry==1)
sumDigits.add(carry); //ไงๆหลักสูงสุดก็มี carry ได้ค่าเดียว
Collections.reverse(sumDigits);
digits = sumDigits;
}
protected int least(int i){
if(i>=digits.size())
return 0;
return digits.get(digits.size()-i-1);
}
Constant time