1 / 92

อาร์เรย์ และ การจัดเรียงข้อมูล

อาร์เรย์ และ การจัดเรียงข้อมูล. a. 7. 6. 4. 5. 8. 9. a คือตัวแปรที่เป็นชื่อของอาร์เรย์นี้ ในภาษาจาวานั้น อาร์เรย์เป็น object ชนิดหนึ่ง เพราะฉะนั้น a ในที่นี้คือ object reference นั่นเอง พูดง่ายๆคือ a เป็นตัวลูกศรที่จะชี้ไปยังส่วนที่เก็บค่าต่างๆของอาร์เรย์นั่นเอง.

hazina
Download Presentation

อาร์เรย์ และ การจัดเรียงข้อมูล

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. อาร์เรย์ และ การจัดเรียงข้อมูล a 7 6 4 5 8 9 a คือตัวแปรที่เป็นชื่อของอาร์เรย์นี้ ในภาษาจาวานั้นอาร์เรย์เป็น object ชนิดหนึ่งเพราะฉะนั้น a ในที่นี้คือ object reference นั่นเองพูดง่ายๆคือ a เป็นตัวลูกศรที่จะชี้ไปยังส่วนที่เก็บค่าต่างๆของอาร์เรย์นั่นเอง อ.ดร.วิษณุ โคตรจรัส

  2. Index ของอาร์เรย์ • เราใช้ a[index] อ่านตำแหน่งต่างๆของอาร์เรย์จากรูปในหน้าที่แล้ว • a[0] จะหมายถึง 7 และ a[1] จะหมายถึง 6 • ค่า index จะเริ่มต้นที่ 0 (สำหรับภาษาจาวา) • ทุกค่า index จะต้องเป็นจำนวนเต็มเสมอรวมทั้งเป็น expression ที่คำนวณแล้วได้จำนวนเต็มก็ได้ • เช่นถ้า b=2 กับ c=3 แล้วa[b+c] ถือว่าเป็นการกล่าวถึงสมาชิกของอาร์เรย์ได้ถูกต้องตัว a[b+c] นี้ก็สามารถถูกนำไปใช้ได้เหมือนตัวแปรธรรมดาเช่น a[b+c] += 5; อ.ดร.วิษณุ โคตรจรัส

  3. ขนาดของอาร์เรย์ • ในจาวาเองทุกๆอาร์เรย์จะมีตัวแปร length • ที่จะถูกตั้งค่าไว้โดยอัตโนมัติตอนที่อาร์เรย์ถูกสร้างขึ้น • เราสามารถใช้ a.length หาขนาดของอาร์เรย์ a ได้ทันที อ.ดร.วิษณุ โคตรจรัส

  4. การสร้างอาร์เรย์ใน Java • ประกอบด้วยสองขั้นตอนใหญ่ๆคือ • Array Declaration: คือการนิยามตัวแปรอาร์เรย์ขึ้นมา • Array Allocation: คือการสร้างออบเจ็กต์ที่เป็นอาร์เรย์ขึ้นมาจริงๆแล้วใช้ assignment operator ทำให้ตัวแปรในข้อ 1 ชี้มายังตัวออบเจ็กต์นี้ อ.ดร.วิษณุ โคตรจรัส

  5. การสร้างอาร์เรย์ใน Java (ต่อ) int x[]; //Declaration –นี่คือการนิยามตัวแปร x ให้เป็นอาร์เรย์ของ //จำนวนเต็มแต่ยังไม่มีออบเจ็กต์จริงๆเกิดขึ้น x=new int[5]; //Allocation –นี่คือการสร้างอาร์เรย์ออบเจ็กต์ขนาด5 ช่อง // เมื่อทำแล้วจะได้อาร์เรย์ที่มีค่าในแต่ละช่องเป็นค่า default //ของข้อมูลชนิดนั้นในที่นี้จะมี 0 อยู่ทั้ง 5 ช่องจากนั้นเอา // x ชี้ไปที่ตัวอาร์เรย์ จะเห็นว่าต้องมีการกำหนดจำนวนช่องให้แน่นอนตอนสร้าง อ.ดร.วิษณุ โคตรจรัส

  6. การสร้างอาร์เรย์ใน Java โดยใช้ initializer list • เราสามารถสร้างอาร์เรย์ x ของจำนวนเต็ม 1 2 และ 3 ได้ด้วย int x[] = {1,2,3}; โดย {1,2,3}คือ initializer list นั่นเอง อ.ดร.วิษณุ โคตรจรัส

  7. null null null การสร้างอาร์เรย์ของ Object • ถ้ามีออบเจ็กต์ type MyObject เราก็สร้างอาร์เรย์ขนาด 3 ช่องของมันได้ MyObject a[] = new MyObject[3]; • โดยตัวอาร์เรย์ที่ถูกสร้างจะมีค่าเริ่มต้นของสมาชิกเป็นnull a อ.ดร.วิษณุ โคตรจรัส

  8. 0 0 0 0 0 0 0 0 0 อาร์เรย์ของอาร์เรย์ • int x[][] = new int[3][3]; a อ.ดร.วิษณุ โคตรจรัส

  9. x 5 6 1 2 3 4 อาร์เรย์ของอาร์เรย์ (ใช้ initializer list) • int x[] = {{1,2},{3,4},{5,6}}; อ.ดร.วิษณุ โคตรจรัส

  10. Matrix • สำหรับอาร์เรย์ 2 ชั้นนั้นเราสามารถดูให้เป็นเมตริกซ์ได้โดยให้index ตัวแรกแทนแถวและตัวที่ 2 แทนหลัก • อาร์เรย์จากหน้าที่แล้วจึงสามารถมองได้เป็น อ.ดร.วิษณุ โคตรจรัส

  11. การเว้นไม่ initialize ค่าในตอนสร้างอาร์เรย์ int y [][] = new int [2][]; • ตัว index ตัวหลังนั้นเราเว้นไว้ได้ • อาร์เรย์ในชั้นที่ 2 ก็จะเป็น null ไปก่อน • แต่อย่างไรก็ตามต้องมีการ initialize อาร์เรย์ชั้นนี้ให้เรียบร้อยก่อนที่จะมีการนำสมาชิกภายในไปใช้ • ในตัวอย่างนี้เราอาจทำการ initialize อาร์เรย์ย่อยได้ดังนี้ y[0] = new int[2]; y[1] = new int[3]; • จะเห็นได้ว่าอาร์เรย์ย่อยไม่จำเป็นต้องมีขนาดเท่ากัน อ.ดร.วิษณุ โคตรจรัส

  12. 5 2 4 3 1 Bubble Sort • เปรียบเทียบสองจำนวนแรกในอาร์เรย์ สลับที่สองจำนวนนี้ถ้าจำนวนขวามีค่าน้อยกว่าจำนวนซ้าย • ต่อจากนั้นก็มาเปรียบเทียบตัวเลขคู่ถัดมาในอาร์เรย์นั้น(ซึ่งตัวแรกอาจเคยถูกสลับที่มาแล้ว) แล้วทำการสลับที่ในกรณีเดียวกัน 2 5 4 3 1 • ทำไปเรื่อยๆจนถึงคู่สุดท้าย แล้วก็กลับมาเปรียบเทียบคู่แรกใหม่ ทำไปเรื่อยๆ อ.ดร.วิษณุ โคตรจรัส

  13. Running time ของ Bubble Sort • การสลับที่ต้องมีจำนวนครั้งที่เพียงพอที่จะเคลื่อนค่าที่ • มากที่สุดจากช่องซ้ายสุดของอาร์เรย์ไปยังช่องขวาสุด • น้อยที่สุดจากช่องขวาสุดของอาร์เรย์ไปยังช่องซ้ายสุด n จำนวน 5 2 4 3 1 Big O = O(n2) • n-1 ครั้งแรกจะเพียงพอทำให้ค่าที่อยู่ช่องซ้ายสุด (5) เคลื่อนไปยังช่องขวาสุดได้แต่ข้อมูลในช่องขวาสุด (1) นั้นจะเลื่อนมาได้เพียงหนึ่งช่องเท่านั้น • ดังนั้นต้องทำซ้ำอย่างนี้ไปอีก n-1 รอบ อ.ดร.วิษณุ โคตรจรัส

  14. 1: public static void bubblesort(int[] array){ 2: for (int pass = 1; pass<=array.length-1; pass++) 3: for(int element=0; element<= array.length –2; element++) 4: if(array[element] > array[element+1]) 5: swap(array, element, element +1); 6: } เปรียบเทียบและสลับ 1 คู่ } 1: public static void swap(int[] array, int a, int b){ 2: int temp = array[a]; 3: array[a]= array[b]; 4: array[b]= temp; 5:} อ.ดร.วิษณุ โคตรจรัส

  15. 4 4 3 4 3 4 5 3 3 4 3 2 2 3 5 4 2 2 3 1 2 4 3 5 1 1 5 1 2 2 2 4 5 5 1 1 5 1 1 5 Worst case ของ Bubble Sort (อาร์เรย์เรียงจากมากไปน้อย) ไม่ต้องสลับ ลูปแรกมีการเปรียบเทียบn-1ครั้งและมีการสลับที่n-1ครั้ง ลูปที่2 มีการเปรียบเทียบn-1ครั้งเหมือนเดิมแต่มีการสลับที่แค่n-2 ครั้ง อ.ดร.วิษณุ โคตรจรัส

  16. Worst case ของ Bubble Sort (ต่อ) • มีการเปรียบเทียบข้อมูลn-1 ครั้งในแต่ละลูปและโค้ดเรามีทั้งหมดn-1 ลูป • เพราะฉะนั้นจะมีการเปรียบเทียบข้อมูลในอาร์เรย์(n-1)2ครั้ง • มีการสลับที่ของข้อมูลในอาร์เรย์ (n-1) + (n-2) + (n-3) +…+ 1 = n(n-1)/2ครั้ง • bubble sort (worst case) = (n-1)2 + n(n-1)/2 * unit time ของการสลับที่ = (n-1)2 + n(n-1)/2 * 3 = (5n2– 7n +2) /2 อ.ดร.วิษณุ โคตรจรัส

  17. Selection Sort • เก็บค่า index ของสมาชิกตัวแรกของอาร์เรย์ a เอาไว้ในตัวแปร maxindex • ตรวจสอบสมาชิกของอาร์เรย์ที่ละตัวตามลำดับถ้าเจอตัวที่มีค่ามากกว่า a[maxindex] ก็ให้เปลี่ยนค่า maxindex ให้เก็บ index ค่าใหม่ตรวจจนหมดอาร์เรย์ • สลับที่สมาชิกตัวสุดท้ายของอาร์เรย์กับ a[maxindex] (ถ้าสองตัวนี้ไม่ใช่ตัวเดียวกัน) เพื่อให้ค่าที่มากที่สุดไปอยู่ขวาสุด • ทำข้อ 1 – 3 ใหม่กับสมาชิก n-1 ตัวที่เหลือแล้วทำต่อไปโดยสมาชิกจะลดลงเรื่อยๆ อ.ดร.วิษณุ โคตรจรัส

  18. maxindex =0 maxindex ยังคงเป็น 0 ตอนนี้ก็สลับที่a[maxindex] กับa[4] เริ่มใหม่ maxindex =0 maxindex กลายเป็น 1 แล้วสลับที่a[maxindex] กับa[3] 5 2 4 4 3 3 1 1 2 5 ตัวอย่าง Selection Sort เปรียบเทียบ n-1 ครั้ง สลับที่ 1 ครั้ง เปรียบเทียบ n-2 ครั้ง สลับที่ 1 ครั้ง อ.ดร.วิษณุ โคตรจรัส

  19. Big O = O(n2) Selection Sort (Code) ลดขนาดอาร์เรย์ลงเรื่อยๆ public static void selectionSort(int[] a){ int maxindex; //index of the largest value for(int unsorted= a.length; unsorted > 1; unsorted--){ maxindex = 0; for(int index= 1; index < unsorted; index++){ if(array[maxindex] < array[index]) maxindex = index; } if(a[maxindex] != a[unsorted -1]) swap(array, maxindex, unsorted -1); } } ไล่ตรวจอาร์เรย์ 1 รอบเพื่อ update maxindex สลับที่ถ้าไม่ใช่ค่าเดียวกัน อ.ดร.วิษณุ โคตรจรัส

  20. Selection Sort (worst case) • นับเวลาจากการเปรียบเทียบข้อมูลในอาร์เรย์และการ assign ข้อมูลเข้าหรือออกจากอาร์เรย์เท่านั้น • จะเกิดเมื่อมีการสลับที่ทุกรอบการใช้ลูป นั่นคือ ข้อมูลเกือบจะเรียงกัน แต่ตัวที่น้อยที่สุดอยู่ท้ายสุด เช่น 2,3,4,5,1 นับได้ดังนี้ • การเปรียบเทียบข้อมูลในอาร์เรย์ (n-1) + (n-2) + … + 1 ครั้ง • การเปรียบเทียบข้อมูลในอาร์เรย์เพื่อตัดสินการสลับที่ (n-1) ครั้ง • การสลับที่สมาชิกของอาร์เรย์ n-1 ครั้ง รวมได้ (n2 + 7n -8) /2 ซึ่งเร็วกว่า bubble sort เมื่อ n เป็น 3 ขึ้นไป อ.ดร.วิษณุ โคตรจรัส

  21. Insertion Sort • แบ่งอาร์เรย์เป็นข้างซ้ายและขวา ให้ข้างซ้ายเป็นข้างที่ถือว่าจัดเรียงแล้ว (แน่นอนว่าในตอนเริ่มต้องมีจำนวนสมาชิกในข้างนี้แค่ตัวเดียว) • ตรวจข้างขวาของอาร์เรย์โดยไล่ตรวจที่ละตัว ถ้าเจอตัวที่มีค่าน้อยกว่าตัวสุดท้ายของข้างซ้าย ให้เอาตัวนั้นไปใส่ในข้างซ้ายให้ถูกที่ • ทำซ้ำข้อ 1 โดยขยายขนาดของข้างซ้ายเพิ่มขึ้น 1 ตัว ทำไปเรื่อยๆ อ.ดร.วิษณุ โคตรจรัส

  22. 6 5 5 6 3 3 7 7 4 4 ตัวอย่าง Insertion Sort ด้านซ้ายนี่ถือว่าเรียงแล้ว ต้องเอา 5 ไปใส่ข้างหน้า (หรือเลื่อน 6 มาแล้วค่อยเอา 5 ใส่แทน) เลื่อน 5 กับ 6 อย่างละ 1 ช่อง แล้วเอา 3 ใส่ช่องแรก อ.ดร.วิษณุ โคตรจรัส

  23. 3 3 5 5 6 6 7 7 4 4 ไม่ต้องเลื่อนเพราะอยู่ถูกที่ เลื่อน 5,6,7 แล้วเอา 4 ใส่ช่องหลัง 3 ก็จะเสร็จ ตัวอย่าง Insertion Sort (ต่อ) อ.ดร.วิษณุ โคตรจรัส

  24. Big O = O(n2) 5 6 3 7 4 ตัวที่จะจับยัดเข้าด้านซ้าย public static void insertionSort(int[] a){ int index; for(int numSorted = 1; numSorted < a.length; numSorted++){ int temp = a[numSorted]; for(index = numSorted; index >0; index--){ if(temp< a[index-1]){ a[index] = a[index –1]; } else{ break; } } a[index] = temp; } } ไล่เปรียบเทียบกับ 6 และ 5 ตามลำดับ ทำให้ 6 เลื่อนขวา 1 ช่อง และ 5 ก็เลื่อนขวา 1 ช่อง พอไม่มีตัวไหนเลื่อนได้ก็ใส่ 3 ลงที่ที่ 5 เคยอยู่ อ.ดร.วิษณุ โคตรจรัส

  25. Insertion Sort (worst case) • Worst case เกิดเมื่อต้องมีการเลื่อนสมาชิกของอาร์เรย์มากที่สุด • นั่นคืออาร์เรย์ต้องเรียงจากมากไปน้อย • แต่ละรอบ ทุกสมาชิกของข้างซ้ายของอาร์เรย์จะต้องถูกเลื่อนไป 1 ตำแหน่ง อ.ดร.วิษณุ โคตรจรัส

  26. Insertion Sort (worst case ต่อ) • unit time ของ worst case insertion sort =(1+2+..+n-1)*2 + n-1 = n(n-1) + n-1 = (n+1)(n-1) = n2–1 เร็วกว่า selection sort เมื่อ n มีค่าไม่เกิน 6 เท่านั้น อ.ดร.วิษณุ โคตรจรัส

  27. Insertion Sort (กรณีเฉลี่ย) ถ้าเราอยู่ที่ลูปนอกสุดลูปที่ i • ถ้า a[i] อยู่ในที่ที่ไม่ต้องมีการเลื่อนจะเกิดการเปรียบเทียบ temp< a[index-1] เพียงครั้งเดียวเท่านั้น • ถ้า a[i] อยู่ในที่ที่ต้องมีการเลื่อนตำแหน่งจะมีการเปรียบเทียบเกิดขึ้นได้ตั้งแต่หนึ่งครั้งจนถึง i ครั้ง • เช่นถ้า i มีค่าเป็น 2 จะต้องมีการเปรียบเทียบ a[2] กับ a[1] (นี่นับเป็นครั้งที่หนึ่ง) • และจากนั้นถ้าเกิดการเลื่อน a[1] ไปใส่ a[2] จะต้องเปรียบเทียบค่าเดิมของ a[2] กับ a[0] ด้วย อ.ดร.วิษณุ โคตรจรัส

  28. Insertion Sort (กรณีเฉลี่ย ต่อ) • ฉะนั้นถ้าเราดูแต่จำนวนครั้งของการเปรียบเทียบจะได้ว่าในลูปที่ i มีจำนวนการเปรียบเทียบโดยเฉลี่ย ครั้ง • ดังนั้นถ้าคิดทุกลูปค่าจำนวนครั้งของการเปรียบเทียบที่เกิดขึ้นจะเป็น ครั้ง • ดังนั้นจึงสรุปได้ว่าค่าเวลาเฉลี่ยจะเข้าใกล้ค่าเวลาของworst case อ.ดร.วิษณุ โคตรจรัส

  29. Merge Sort • แบ่งอาร์เรย์เป็นสองส่วนไปจัดเรียงข้อมูลในแต่ละส่วนให้เรียบร้อย • (แต่ละอาร์เรย์ก็แบ่งสองส่วนได้อีกทำเป็นrecursion ได้) • รวมอาร์เรย์ที่จัดเรียงเรียบร้อยเข้าด้วยกัน อ.ดร.วิษณุ โคตรจรัส

  30. การรวมอาร์เรย์ใน merge sort (ขั้นที่ 1) • สมมติเราจะ รวมอาร์เรย์a (1,5,8,9) กับb (2,4,6,7) • ให้มีcounter อยู่ที่index แรกของอาร์เรย์ทั้งสองแล้วสร้างอาร์เรย์สำหรับเก็บผลการรวมขึ้นมา–ในที่นี้เราเรียกว่าอาร์เรย์ c b c a 1 5 8 9 2 4 6 7 indexB indexC indexA อ.ดร.วิษณุ โคตรจรัส

  31. การรวมอาร์เรย์ใน merge sort (ขั้นที่ 2) • เปรียบเทียบ a[indexA] กับ b[indexB] เอาค่าที่น้อยกว่า ใส่ c[indexC] แล้วเลื่อน counter ของตัวที่น้อยนั้นและของ c เพื่อเตรียมเปรียบเทียบครั้งต่อไป b c a 1 5 8 9 2 4 6 7 1 indexB indexA indexC อ.ดร.วิษณุ โคตรจรัส

  32. การรวมอาร์เรย์ใน merge sort (ขั้นที่ 3) • เปรียบเทียบ a[indexA] กับ b[indexB] แบบนี้ไปเรื่อยๆจนหมดหนึ่งอาร์เรย์ ในที่นี้ b จะหมดก่อน b c a 1 5 8 9 2 4 6 7 1 2 4 5 6 7 indexB indexC indexA • หลังจากนี้ก็แค่ก็อปปี้ส่วนที่เหลือของ a ใส่ c ให้หมด • ก็จะได้อาร์เรย์ผลลัพธ์ที่สมบูรณ์ อ.ดร.วิษณุ โคตรจรัส

  33. Worst case ของการรวมอาร์เรย์ • Worst case ของการรวมอาร์เรย์นี้ เกิดเมื่อต้องมีการเปรียบเทียบสมาชิกอาร์เรย์ทั้งสอง(a กับ b) ไปจนถึงสมาชิกตัวสุดท้ายของทั้งคู่ • ซึ่งจะมีการเปรียบเทียบทั้งหมด n-1 ครั้ง (n คือขนาดของอาร์เรย์ผลลัพธ์) เพราะฉะนั้น เวลาในการทำงานของการรวมอาร์เรย์จึงเป็น O(n) อ.ดร.วิษณุ โคตรจรัส

  34. โค้ดของการรวมอาร์เรย์โค้ดของการรวมอาร์เรย์ public static int[] merge(int[] a, int[] b){ int aIndex = 0; int bIndex = 0; int cIndex = 0; int aLength = a.length; int bLength = b.length; int cLength = aLength + bLength; int[] c = new int[cLength]; //ก่อนอื่นเปรียบเทียบ a กับ b แล้วเอาเลขออกใส่ c จนอาร์เรย์ตัวใดตัวหนึ่งหมด while((aIndex < aLength) && (bIndex < bLength){ if(a[aIndex]<=b[bIndex]){ c[cIndex] = a[aIndex]; aIndex++; }else{ c[cIndex] = b[bIndex]; bIndex++; } cIndex++; } มีต่อ อ.ดร.วิษณุ โคตรจรัส

  35. โค้ดของการรวมอาร์เรย์(ต่อ)โค้ดของการรวมอาร์เรย์(ต่อ) //ต่อไปก็ก็อปปี้อาร์เรย์ที่เหลือใส่ c ให้หมด if(aIndex == aLength){ //ถ้า a ถูกใช้หมดก่อน while(bIndex<bLength){ c[cIndex] = b[bIndex]; bIndex++; cIndex++; } }else{ //ถ้า b ถูกใช้หมดก่อน while(aIndex<aLength){ c[cIndex] = a[aIndex]; aIndex++; cIndex++; } } return c; } อ.ดร.วิษณุ โคตรจรัส

  36. การแบ่งอาร์เรย์เป็นส่วนๆการแบ่งอาร์เรย์เป็นส่วนๆ • ไม่ต้องมาจัดเรียงข้อมูลในตอนนี้เลยด้วยซ้ำ เพราะ • เมื่อเราแบ่งอาร์เรย์ไปเรื่อยๆ ผลสุดท้ายจะได้อาร์เรย์ที่มีขนาดเพียงหนึ่งมารวมกัน ตอนรวมอาร์เรย์ขนาดหนึ่งเข้าด้วยกันก็จะเป็นการจัดเรียงไปในตัวเลย • ฉะนั้น การรวมอาร์เรย์ที่ใหญ่ขึ้นมาก็จะมีการจัดเรียงอยู่แล้วโดยปริยาย อ.ดร.วิษณุ โคตรจรัส

  37. โค้ดของการแบ่งอาร์เรย์เป็นส่วนๆโค้ดของการแบ่งอาร์เรย์เป็นส่วนๆ 1: public static int[] mergeSort(int[] unsort, int left, int right){ 2: if(left == right){//ถ้าไม่เหลืออะไรให้จัดแล้วต้องตอบเป็นอาร์เรย์ขนาด 1 3: int[] x = new int[1]; 4: x[0] = unsort[left]; 5: return x; 6: } 7: else if(left<right){//ถ้ายังจัดได้ก็แบ่งอาร์เรย์ต่อไป 8: int center = (left+right)/2; 9: int[] result1 = mergeSort(unsort,left,center); 10: int[] result2 = mergeSort(unsort,center+1,right); 11: return merge(result1,result2); 12: } 13: } อ.ดร.วิษณุ โคตรจรัส

  38. เวลาในการทำงานของ merge sort • ถ้ามีสมาชิกตัวเดียวเราเห็นได้ชัดว่าเวลาที่ใช้นั้นคงที่ (ให้เป็น 1 ได้) • ส่วนถ้ามีสมาชิกหลายตัวเวลาที่ใช้จะเท่ากับเวลาที่ทำงานครึ่งซ้ายรวมกับครึ่งขวาแล้วรวมกับเวลาที่ใช้ในการรวมอาร์เรย์ทั้งสองอีกทีหนึ่ง (ซึ่งเป็นO(n)) อ.ดร.วิษณุ โคตรจรัส

  39. เวลาในการทำงานของ merge sort (ต่อ) • เอา n หารตลอดเราจะได้ (1) • เราเอามาเขียนเป็นชุดของสมการ โดยเปลี่ยนค่า n ไปเรื่อยๆ จะได้สมการชุดในหน้าถัดไป อ.ดร.วิษณุ โคตรจรัส

  40. เวลาในการทำงานของ merge sort (ต่อ 2) (2) (3) (x) อ.ดร.วิษณุ โคตรจรัส

  41. เวลาในการทำงานของ merge sort (ต่อ 3) • เอาสมการตั้งแต่ (1) ถึง (x) มาบวกกัน จะได้ • จะเห็นว่าmerge sort นั้นมีเวลาเร็วกว่าการจัดเรียงข้อมูลแบบอื่นๆที่กล่าวมา • แต่การจัดเรียงข้อมูลด้วยวิธีนี้มีข้อเสียคือต้องใช้พื้นที่ในการสร้างอาร์เรย์ที่เป็นผลรวมของสองอาร์เรย์ย่อย อ.ดร.วิษณุ โคตรจรัส

  42. Quick Sort 1. ถ้าไม่มีสมาชิกในอาร์เรย์หรือมีสมาชิกแค่ตัวเดียวให้ตอบเป็นอาร์เรย์นั้นเลยเพราะถือว่าแบบนี้ข้อมูลจัดเรียงในตัวเองอยู่แล้ว 2. เลือกตัวเลขใดตัวเลขหนึ่งในอาร์เรย์มาให้จำนวนนั้นเป็นจุดหลัก (ต่อไปนี้จะเรียกว่า pivot) 3. ใช้ pivot เป็นหลักเลื่อนสมาชิกทุกตัวที่น้อยกว่า pivot ไปอยู่ด้านซ้ายของ pivot และเลื่อนสมาชิกทุกตัวที่มากกว่า pivot ไปอยู่ด้านขวาของ pivot (ส่วนสมาชิกที่มีค่าเท่ากับpivot ก็แล้วแต่จะจัดการวิธีที่ดีที่สุดน่าจะเป็นการกระจายจำนวนเหล่านี้ไปยังทั้งสองข้างเท่าๆกัน) ขั้นตอนนี้เรียกว่าการ partition 4. ตอนนี้ตัว pivot ก็จะได้อยู่ในที่ที่ถูกต้องเรียบร้อยแล้วที่เราเหลือต้องทำก็คือทำquick sort กับอาร์เรย์ย่อยข้างซ้ายและข้างขวาของ pivot 5. คำตอบคืออาร์เรย์ที่เกิดจากการต่อ quicksort(ด้านซ้าย) กับ pivot กับ quicksort(ด้านขวา) อ.ดร.วิษณุ โคตรจรัส

  43. 3 3 5 1 6 4 1 5 6 4 ภาพหลักการทำ quick sort เลือกตัวนี้เป็น pivot ต่อไป แบ่งข้อมูลเป็นสองข้างของ 4 เอาไป quick sort เอาไป quick sort เอาผลมาต่อกัน จะได้คำตอบ อ.ดร.วิษณุ โคตรจรัส

  44. ขั้นที่ 1: เมื่ออาร์เรย์มีขนาดเล็ก • ถ้าไม่มีสมาชิกในอาร์เรย์หรือมีสมาชิกแค่ตัวเดียวให้ตอบเป็นอาร์เรย์นั้นเลยเพราะถือว่าแบบนี้ข้อมูลจัดเรียงในตัวเองอยู่แล้ว • แต่เราจะเห็นว่าจริงๆแล้วถ้าอาร์เรย์มีจำนวนสมาชิกน้อย(น้อยกว่า 20) ใช้ insertion sort จะเร็วกว่าซะอีกดังนั้นถ้าอาร์เรย์มีขนาดเล็กเราควรใช้วิธีจัดเรียงแบบอื่นแล้วค่อยเอาคำตอบจากวิธีนั้นมา อ.ดร.วิษณุ โคตรจรัส

  45. ขั้นที่ 2: การเลือก pivot • ห้ามใช้ตัวแรกของอาร์เรย์เป็นpivot เด็ดขาด • เพราะว่าถ้าอาร์เรย์นั้นจัดเรียงอยู่แล้ว(ไม่ว่าจะมากไปน้อยหรือน้อยไปมากก็ตาม) ตอนที่แบ่งข้างโดยใช้จุดหลักนี้จะพบว่าข้างหนึ่งเป็นอาร์เรย์ว่างเสมอทำให้ไร้ประสิทธิภาพ อ.ดร.วิษณุ โคตรจรัส

  46. 5 4 4 3 3 2 2 1 1 5 การเลือก pivot ที่ไม่ดี (ใช้ตัวแรกของสมาชิกอาร์เรย์) pivot ไม่มีด้านขวา สมาชิกจะไปกองอยู่ข้างเดียวหมด นั้นคือแทนที่จะลดขนาดของปัญหาลงได้ครึ่งหนึ่ง กลับลดลงได้แค่หนึ่งหน่วย อ.ดร.วิษณุ โคตรจรัส

  47. การเลือก pivot ที่ดี • เลือกpivotโดยใช้random number ส่วนใหญ่แล้วจะได้การแบ่งpartition สองข้างที่ดี • แต่ว่าวิธีนี้มีข้อเสียที่ว่าการสร้างrandom number นั้นเสียเวลาในตัวของมันเอง • ใช้ค่ามัธยฐานจากอาร์เรย์ช่องแรกกับช่องกลางและช่องสุดท้าย • จริงๆแล้วค่าpivot ที่จะทำให้แบ่งอาร์เรย์ได้เป็นสองข้างเท่ากันนั้นจะต้องเป็นค่ามัธยฐานจากทั้งอาร์เรย์ • แต่จะมานั่งคิดค่านี้มันก็จะเสียเวลาเกินไปดังนั้นจึงได้มีการลองใช้ค่ามัธยฐานจากอาร์เรย์ช่องแรกกับช่องกลางและช่องสุดท้ายพบว่าได้ผลดีเช่นกัน อ.ดร.วิษณุ โคตรจรัส

  48. โค้ดการเลือก pivot โดยหา median of 3 1: private static int pivotIndex(int[] a, int l, int r){ 2: int c = (l+r)/2; 3: if((a[l]<=a[r] && a[l]>=a[c]) || 4: (a[l]>=a[r] && a[l]<=a[c])) 5: return l; 6: if((a[c]<=a[l] && a[c]>=a[r]) || 7: (a[c]>=a[l] && a[c]<=a[r]) 8: return c; 9: return r; 10: } อ.ดร.วิษณุ โคตรจรัส

  49. ขั้นที่ 3: การแบ่ง partition • เอา pivot ที่เลือกได้แล้วออกไปให้พ้นทางโดยสลับที่กับสมาชิกตัวสุดท้ายของอาร์เรย์ • ให้ตัวแปร i เป็น index ของตำแหน่งแรกของอาร์เรย์และตัวแปร j เป็น index ของตำแหน่งรองสุดท้ายของอาร์เรย์ (อย่าลืมว่าตอนนี้เราใช้ตำแหน่งสุดท้ายเก็บ pivot ไปแล้ว) • ดูตำแหน่งของ i กับ jในอาร์เรย์เป็นหลักให้เลื่อน i ไปทางขวาเรื่อยๆข้ามสมาชิกในอาร์เรย์ที่มีค่าน้อยกว่าค่าของ pivot แต่ต้องหยุดเมื่อเจอสมาชิกในอาร์เรย์ที่มีค่ามากกว่าหรือเท่ากับค่าของ pivot • ในทำนองเดียวกันให้เลื่อน j ไปทางซ้ายเรื่อยๆข้ามสมาชิกที่มีค่ามากกว่าค่าของ pivot และหยุดเมื่อเจอสมาชิกในอาร์เรย์ที่มีค่าน้อยกว่าหรือเท่ากับค่าของ pivot อ.ดร.วิษณุ โคตรจรัส

  50. ถ้า i ยังอยู่ด้านซ้ายของ j อยู่ก็สลับที่สมาชิกในอาร์เรย์สองตำแหน่งนั้นเสียนี่เป็นการเอาค่าน้อย(เมื่อเทียบกับ pivot)ไปไว้ข้างซ้ายและค่ามากไปไว้ด้านขวาของอาร์เรย์ส่วนกรณีถ้า i ไม่อยู่ทางด้านซ้ายของ j ให้ข้ามไปทำข้อ 8 • เลื่อน i ไปทางขวาหนึ่งหน่วยและเลื่อน j ไปทางซ้ายหนึ่งหน่วยเพื่อหลบเลี่ยงช่องที่พึ่งมีการสลับที่สมาชิกไป • จากนั้นเริ่มทำจากข้อ 3 อีกครั้งหนึ่ง • ถ้ามาถึงขั้นตอนนี้ให้สลับที่สมาชิกที่อยู่ที่ตำแหน่ง i กับ pivot ก็จะได้อาร์เรย์ที่มี pivot อยู่ในตำแหน่งที่ถูกต้องด้านซ้ายจะมีสมาชิกที่มีค่าน้อยกว่าส่วนด้านขวาจะมีสมาชิกที่มีค่ามากกว่า อ.ดร.วิษณุ โคตรจรัส

More Related