การ Implement Algorithms ของ ArrayList
แนะนำใหม่| English | ความหมาย |
|---|---|
| shift/ʃɪft/ | การเลื่อน |
| delete/dɪˈliːt/ | ลบ |
| insert/ˈɪnsɜːt/ | แทรก |
การลบที่อยู่ติดกันเผยให้เห็นปัญหาการข้ามองค์ประกอบ
- เริ่มจาก
[0, 0, 5]ลบดัชนี 0 แล้วเพิ่ม i ตัวเลขศูนย์ที่สองจะเลื่อนเข้ามาอยู่ในดัชนี 0 ดังนั้นลูปไปข้างหน้าจึงข้ามมันไปและเหลือ[0, 5] - สำหรับ while-loop แบบไปข้างหน้าที่สอนในที่นี้ ให้อยู่ที่ดัชนีเดิมหลังจากลบและ_advance เฉพาะเมื่อต้องการเก็บองค์ประกอบไว้ มันจะลบตัวเลขศูนย์ทั้งสองออกและจบลงด้วย
[5]
รักษาดัชนีไปข้างหน้าปัจจุบันหลังจากลบ
- หลังจาก
remove(i)ทุกองค์ประกอบถัดไปจะเลื่อนไปทางซ้ายหนึ่งตำแหน่ง หากมีองค์ประกอบใดอยู่ใน i ในตอนนี้它还未被检查; ตรวจสอบ它在下一次迭代中。 - ลูปด้านล่างรับลิสต์ของ Integer ที่ไม่เป็น null และไม่มีความยาวเป็นศูนย์ แล้วลบเลข 0 ทั้งหมดออกในตำแหน่งเดิม โดยใช้ขนาดปัจจุบันในแต่ละรอบและไม่ได้เรียกใช้ get กับลิสต์ที่เป็นว่าง
import java.util.ArrayList;
public class RemoveZeros {
public static void removeZeros(ArrayList<Integer> list) {
int i = 0;
while (i < list.size()) {
if (list.get(i) == 0) {
list.remove(i);
} else {
i++;
}
}
}
}
อธิบายว่าทำไมลูปนี้จึงหยุดทำงาน
- ในแต่ละรอบจะทำการลบองค์ประกอบหนึ่งออกและลดขนาดลง หรือเก็บไว้แล้วเพิ่มค่า i ดังนั้น
size() - iจำนวนตำแหน่งที่ยังต้องตรวจสอบ จะลดลงหนึ่งทุกครั้งที่วนลูป - เริ่มจาก
[0, 0, 5]สถานะคือ[0, 5]ที่ i=0,[5]ที่ i=0, จากนั้น[5]ที่ i=1. เงื่อนไขสุดท้ายเป็นเท็จ ดังนั้นจึงไม่มีการเข้าถึงข้อมูลนอกขอบเขตของอาร์เรย์
ลูปย้อนกลับปฏิบัติตามกฎที่แตกต่างออกไป
- การวนลูปย้อนกลับเริ่มต้นที่ดัชนีสุดท้ายที่มีอยู่จริง:
for (int i = list.size() - 1; i >= 0; i--)ลบองค์ประกอบที่ตรงกันด้วยremove(i); ค่า i ถัดไปจะเป็นค่าน้อยลงเสมอหนึ่ง - การลบที่ตำแหน่ง i จะทำให้เฉพาะดัชนีถัดไปเลื่อนตำแหน่ง ซึ่งได้ผ่านการตรวจสอบแล้ว องค์ประกอบที่ยังไม่ได้ตรวจสอบด้านหน้าจะคงดัชนีเดิมไว้ ดังนั้นการลดค่า i หลังการลบจึงถูกต้องในกรณีนี้; คำว่า "ห้ามเพิ่มค่าหลังการลบ" ไม่ใช่กฎสากล
เลือกการอัปเดตดัชนีให้สอดคล้องกับทิศทางการ遍历. ใน while-loop แบบไปข้างหน้า ให้หยุดอยู่หรือเพิ่มค่าหลังการลบ; ใน for-loop แบบย้อนหลัง ให้ลดค่าต่อ. การเปลี่ยนแปลงโครงสร้างโดยตรงระหว่าง enhanced loop เป็นรูปแบบที่ไม่ปลอดภัยแยกต่างหาก แม้จะไม่เกิด fail-fast exception ก็ตาม
ใน while-loop แบบ forward ที่แสดง在這裡 advancement i ก็ต่อเมื่อคุณ...
Difficulty 1/5 · 100 coins + a small bonus on first completion today
หลัง remove(i), องค์ประกอบถัดไปจะ-shift เข้ามาอยู่ใน i — อย่าข้ามมัน
ลูปแบบ naive แบบ forward บน [0, 0, 5] ที่ลบที่ i=0 แล้วเพิ่ม i จะข้ามศูนย์ถัดไป
Difficulty 1/5 · 100 coins + a small bonus on first completion today
ค่าศูนย์ที่เหลือจะย้ายเข้าสู่ดัชนี 0 แต่การทดสอบถัดไปจะดำเนินการที่ดัชนี 1. การวนลูปแบบย้อนกลับใช้กฎดัชนีที่ถูกต้องแตกต่างกัน
ทางเลือกอื่นของการลบแบบใน-place ที่หลีกเลี่ยงการเลื่อนตำแหน่งคือ...
Difficulty 1/5 · 100 coins + a small bonus on first completion today
Adding keepers to a fresh list sidesteps shifting
ArrayList algorithms reuse array patterns via...
Difficulty 1/5 · 100 coins + a small bonus on first completion today
Swap array [] and length for get(i) and size()
The resizable nature of an ArrayList lets you insert and delete elements, unlike a fixed array
Difficulty 1/5 · 100 coins + a small bonus on first completion today
add and remove change the list's size
วงลูปลบแบบย้อนกลับที่เริ่มต้นจาก size()-1 ต้องคงอยู่ที่ดัชนีเดิมหลังจากการลบทุกครั้ง
Difficulty 1/5 · 100 coins + a small bonus on first completion today
ผิด: องค์ประกอบที่ยังไม่ตรวจสอบก่อนหน้าจะยังคงรักษาดัชนีไว้ ดังนั้นวงลูปย้อนกลับจึงลดค่าลงตามปกติ
สร้างลิสต์ใหม่เมื่อต้องรักษาลิสต์เดิมไว้
- เพื่อรักษาลิสต์เดิมไว้ ให้สร้างผลลัพธ์ใหม่และ append ทุกองค์ประกอบที่ไม่ใช่ศูนย์ขณะอ่านจาก lisitเดิม วิธีนี้จะรักษาลำดับและขนาดของlisitเดิมไว้โดยไม่เปลี่ยน; แต่ต้องใช้พื้นที่จัดเก็บ lisit เพิ่มเติม
- สำหรับ lisit ของวัตถุแบบ mutable การคัดลอกการอ้างอิงที่คงไว้จะไม่ clone วัตถุนั้นๆ โครงสร้าง lisitใหม่อาจยังแบ่งปันวัตถุองค์ประกอบเดียวกับ lisitเดิม; ต้องแยกแยะเอกลักษณ์ของ lisit ออกจากเอกลักษณ์ขององค์ประกอบ
การลบแบบ forward จะคงดัชนีหลังจากการลบไว้
ศูนย์สองตัวที่อยู่ติดกันจะถูกตรวจสอบที่ดัชนี 0 ก่อนที่จะรักษา 5 ไว้
ตรวจสอบกรณีที่จะเปิดเผยอัลกอริทึม
- ทดสอบ lisitว่าง, ศูนย์ทั้งหมด, ไม่มีศูนย์, ศูนย์ติดกัน และศูนย์ที่ดัชนีสุดท้าย. สำหรับการลบแบบ in-place, การอ้างอิงอื่นไปยัง lisitเดียวกันจะสังเกตเห็นการเปลี่ยนแปลง; ผลลัพธ์ใหม่จะทำให้โครงสร้างเดิมคงอยู่
- ArrayList สามารถ insert หรือ delete องค์ประกอบ; การดำเนินการเหล่านี้สามารถ shift ดัชนีถัดไป. การค้นหาอาจคืนค่าดัชนีที่พบหรือ -1 เมื่อไม่มี; การหาค่าสูงสุดต้องการนโยบาย lisitว่างอย่างชัดเจน. การใช้รูปแบบ array ผ่าน get/size ช่วยได้ แต่แต่ละอัลกอริทึมยังคงต้องมีขอบเขตและสัญญาของตนเอง
การลบทำให้ดัชนีเลื่อน. อธิบายว่าองค์ประกอบ哪些ที่ยังไม่ได้ตรวจสอบและเลือกดัชนีถัดไป accordingly. Forward stay-or-increment และ backward decrement เป็นทั้งสองรูปแบบที่ถูกต้อง; lisitใหม่ของผู้คงไว้จะรักษาโครงสร้างเดิมแต่อาจแบ่งปันวัตถุ
Order the states for the corrected removal loop on [0, 0, 5].
Difficulty 3/5 · 200 coins + a small bonus on first completion today
Each removal rechecks the shifted value; keeping 5 finally advances the index.
วิธี removeZeros แบบไปข้างหน้าที่แสดงอยู่มีการเรียกใช้ get_calls จำนวนเท่าใดเมื่อทำงานกับรายการว่าง?
Difficulty 2/5 · 140 coins + a small bonus on first completion today
เงื่อนไขเริ่มต้น 0 < 0 เป็นเท็จ จึงไม่มีการเรียกใช้ get