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