1 / 83

418115: การโปรแกรมเชิงโครงสร้าง โครงสร้างข้อมูล 1

418115: การโปรแกรมเชิงโครงสร้าง โครงสร้างข้อมูล 1. ประมุข ขันเงิน. Abstract Data Type. Abstract Data Type. ชนิดข้อมูลนามธรรม (Abstract Data Type ย่อว่า ADT) ประกอบด้วย กลุ่มของข้อมูล วิธีการจัดการกับกลุ่มของข้อมูลนี้ เน้นว่าเรา สามารถทำอะไรได้กับกลุ่มข้อมูล ได้บ้าง

Download Presentation

418115: การโปรแกรมเชิงโครงสร้าง โครงสร้างข้อมูล 1

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. 418115: การโปรแกรมเชิงโครงสร้างโครงสร้างข้อมูล 1 ประมุข ขันเงิน

  2. Abstract Data Type

  3. Abstract Data Type • ชนิดข้อมูลนามธรรม(Abstract Data Type ย่อว่า ADT) ประกอบด้วย • กลุ่มของข้อมูล • วิธีการจัดการกับกลุ่มของข้อมูลนี้ • เน้นว่าเราสามารถทำอะไรได้กับกลุ่มข้อมูลได้บ้าง • ไม่ได้เน้นว่าเราจะเขียนโปรแกรมเพื่อให้จัดการข้อมูลนี้ได้อย่างไร

  4. ตัวอย่าง: เซต • สัญลักษณ์: S • ข้อมูลที่เก็บ: • ของชนิดเดียวกัน (int, float, char, ฯลฯ) หลายๆ ตัว • ข้อมูลที่แตกต่างกันมีได้เพียงตัวเดียว • ตัวอย่าง: {1, 2, 5} • ความสามารถ: • add(S, x): เพิ่ม x เข้าใน S • remove(S, x): ลบ x ออกจาก S • contains(S, x): ถามว่า x เป็นสมาชิกของ S หรือไม่?

  5. ตัวอย่าง: เซต • สมมติเราสนใจเซต S = {1,2,3} • contains(S, 3)  true • contains(S, 4)  false • add( S, 4) • ได้ S = {1,2,3,4} • add(S, 5) • ได้ S = {1,2,3,4,5} • remove(S, 2) • ได้ S = {1,3,4,5} • contains(S, 2) false

  6. ตัวอย่าง: ลิสต์ (List) • ใช้แทนลำดับ (a0, a1, a2, …, an-1) ของข้อมูล • สมาชิกลำดับสามารถซ้ำกันได้ • ความสามารถ: • get(L, i): คืนสมาชิกตัวที่ i • set(L, i, x): ทำให้สมาชิกตัวที่ iกลายเป็น x • find(L, x): หาตำแหน่งของ x ใน L ถ้าไม่เจอคืน -1 ถ้ามีหลายตัวคืนตัวหน้าสุด • insert(L, i, x): เพิ่ม x เข้าไปใน iโดยทำให้มันเป็นสมาชิกตัวที่ iหลังจากแทนเสร็จแล้ว • remove(i): ลบสมาชิกตัวที่ iออก

  7. ตัวอย่าง: ลิสต์ (List) • สมมติว่า L = (7,2,1,3,9) • get(L, 0)  7 และ get(L, 4)  9 • set(L, 1, 10) • ได้ L = (7, 10, 1, 3, 9) • insert(L, 2, 9) • ได้ L = (7, 10, 9, 1, 3, 9) • remove(L, 4) • ได้ L = (7, 10, 9, 1, 9) • find(L, 10)  1 และ find(L, 9)  2 และ find(L, 2)  -1

  8. ตัวอย่าง: สแตก (Stack) • ความสามารถ • push(S, x): ใส่ข้อมูลเข้าไปวางไว้บน “หัว” ของ stack • pop(S): เอาเข้ามูลที่อยู่ที่ “หัว” ออกมา • จำได้ไหม? • stack เป็นหน่วยความจำชนิดหนึ่ง (stack segment) • มีวิธีการจัดการข้อมูลเหมือนกับ stack เลย

  9. ตัวอย่าง: สแตก (Stack) • สมมติตอนแรก S = ()  stack ว่าง • push(S, 5) • ได้ S = (5) • push(S, 3) • ได้ S = (5, 3) • push(S, 7) • ได้ S = (5, 3, 7) • pop(S)  7 • ได้ S = (5, 3) • push(S, 20) • ได้ S = (5, 3, 20)

  10. ตัวอย่าง: คิว (Queue) • ความสามารถ • enqueue(Q, x): ใส่ข้อมูลเข้าไปวางไว้บน “ท้าย” ของ queue • dequeue(Q): เอาเข้ามูลที่อยู่ที่ “หัว” queue ออกมา • พบกันทั่วไปในชิวิตประจำวัน • แต่ไร้คุณค่าทางคณิตศาสตร์

  11. ตัวอย่าง: คิว (Queue) • สมมติ Q = ()  คิวว่าง • enqueue(Q, 5) • Q = (5) • enqueue(Q, 3) • Q = (5, 3) • enqueue(Q, 7) • Q = (5, 3, 7) • dequeue(Q)  5 • Q = (3, 7) • enqueue(Q, 20) • Q = (3, 7, 20) • dequeue(Q)  3 • Q = (7, 20)

  12. ทำไมเราต้องพูดถึง ADT? • เรามักจะเจอรูปแบบ(pattern) ในการจัดการข้อมูล • รูปแบบที่เจอบ่อยๆ เราจะสรุปมาเป็น ADT • ประโยชน์ • มีคำศัพท์เวลาเอาไปใช้คุยกับคนอื่น • เวลาอธิบายอัลกอริทึมจะได้อธิบายสั้นๆ • เปิดโอกาสให้เราเขียนโปรแกรมได้หลายๆ แบบ • เพราะ ADT ไม่พูดถึงวิธีการเขียนโปแกรม • เขียนยังไงก็ได้ให้มันทำงานได้ตามนั้นพอ

  13. โครงสร้างข้อมูล (Data Structure) • โครงสร้างข้อมูล คือ วิธีการเขียนโปรแกรมให้สอดคล้องกับความต้องการของ ADT • เวลาพูดถึงโครงสร้างข้อมูล เราจะพูดถึง • วิธีการก็บข้อมูลในหน่วยความจำ • วิธีการทำปฏิบัติการต่างๆ ของ ADT

  14. โครงสร้างข้อมูลและ ADT • ADT หนึ่งมีโครงสร้างข้อมูลหลายตัวที่ทำงานเป็นมันได้ • โครงสร้างข้อมูลหนึ่งก็สามารถทำงานเป็น ADT หลายตัวได้ • โครงสร้างข้อมูลแต่ละตัวมีความแตกต่างกัน • ความเร็วของปฏิบัติการต่างๆ • ขนาดหน่วยความจำที่ใช้

  15. อะเรย์และอะเรย์ปรับขนาดได้อะเรย์และอะเรย์ปรับขนาดได้

  16. อะเรย์ • อะเรย์ คือ ข้อมูลที่ถูกเรียงติดกันเป็นพืดๆ ในหน่วยความจำ • ในภาษา C เราเข้าถึงสมาชิกตัวที่ iของอะเรย์ A ด้วยนิพจน์ A[i] • การเข้าถึง A[i] ทำได้อย่างรวดเร็ว (เสียเวลาหนึ่งหน่วย) • ขนาดของอะเรย์ในภาษา C มักจะถูกกำหนดไว้ตายตัว

  17. อะเรย์ที่ปรับขนาดได้ • อะเรย์ที่เราใช้ที่ผ่านมาต้องกำหนดขนาดล่วงหน้าไว้ใน code • ไม่สามารถเปลี่ยนแปลงขนาดได้ตอนโปรแกรมรันไปแล้ว • ด้วย dynamic memory allocation เราสามารถสร้างอะเรย์ที่เราสามารถยืดหรือหดขนาดมันได้ • อย่างไรก็ดีการเข้าถึงสมาชิกต่างๆ ในอะเรย์ เราจะทำผ่านฟังก์ชัน • เข้าถึงตรงๆ ก็ได้ แต่ไม่ปลอดภัย

  18. IntArray • เราจะสร้างอะเรย์สำหรับเก็บค่าประเภท intที่เราสามารถกำหนดขนาดเองเวลาโปรแกรมรัน • อะเรย์นี้เก็บอยู่ใน structต่อไปนี้ typedefstruct{ intcapacity; int*data; }IntArray;

  19. IntArray • data คือ pointer ไปยังสมาชิกตัวแรกในอะเรย์ • capacity คือขนาดของอะเรย์ที่จองไว้ • ข้อมูลของอะเรย์จะอยู่ที่ data[0], data[1], …, data[capacity-1]

  20. IntArray Functions • voidIntArray_alloc(IntArray*a,intcapacity) • ทำให้อะเรย์มีขนาดเท่ากับ capacity • intIntArray_get(IntArray*a,inti) • คืนสมาชิกตัวที่ iของอะเรย์ a • voidIntArray_set(IntArray*a,inti,intx) • ทำให้สมาชิกตัวที่ i ของอะเรย์ a มีค่าเท่ากับ x • voidIntArray_clear(IntArray*a) • ยกเลิกการจองพื้นที่ใน heap ของอะเรย์ • voidIntArray_init(IntArray*a) • ตั้งแต่เริ่มต้นให้อะเรย์ a กล่าวคือเซตค่า size = capacity = 0 และ data = NULL

  21. IntArray_init voidIntArray_init(IntArray*a) { a->size=0; a->capacity=0; a->data=NULL; }

  22. IntArray_get intIntArray_get(IntArray*a,inti) { returna->data[i]; }

  23. IntArray_set voidIntArray_set(IntArray*a,inti,intx) { a->data[i]=x; }

  24. IntArray_alloc voidIntArray_alloc(IntArray*a,intcapacity) { if(capacity==0){ if(a->data!=NULL){ free(a->data); a->data=NULL; } a->capacity=0; } elseif(capacity>0){ int*new_data; if(a->data!=NULL) new_data=(int*)realloc(a->data,sizeof(int)*capacity); else new_data=(int*)malloc(sizeof(int)*capacity); if(new_data!=NULL) a->data=new_data; else exit(1); a->capacity=capacity; } }

  25. IntArray_set voidIntArray_clear(IntArray*a) { IntArray_alloc(a,0); }

  26. ตัวอย่างการใช้งาน intmain() { IntArrayA; IntArray_alloc(&A,3); IntArray_set(&A,1,5); IntArray_set(&A,1,3); IntArray_set(&A,1,7); printf("A[1] = %d\n",IntArray_get(&A,1)); IntArray_set(&A,1,10); printf("A[1] = %d\n",IntArray_get(&A,1)); IntArray_clear(&A); return0; }

  27. ใช้อะเรย์สร้างลิสต์

  28. ทวนความจำ: ลิสต์ • ใช้แทนลำดับ (a0, a1, a2, …, an-1) ของข้อมูล • สมาชิกลำดับสามารถซ้ำกันได้ • ความสามารถ: • get(L, i): คืนสมาชิกตัวที่ i • set(L, i, x): ทำให้สมาชิกตัวที่ iกลายเป็น x • find(L, x): หาตำแหน่งของ x ใน L ถ้าไม่เจอคืน -1 ถ้ามีหลายตัวคืนตัวหน้าสุด • insert(L, i, x): เพิ่ม x เข้าไปใน iโดยทำให้มันเป็นสมาชิกตัวที่ iหลังจากแทนเสร็จแล้ว • remove(i): ลบสมาชิกตัวที่ iออก

  29. ในภาษา C • ต้องการ user-defined data type ชื่อ IntListสำหรับเก็บ int • ต้องการฟังก์ชันต่อไปนี้ • intIntList_get(IntList*L,inti) • voidIntList_set(IntList*L,inti,intx) • intIntList_find(IntList*L,intx) • voidIntList_insert(IntList*L,inti,intx) • voidIntList_remove(IntList*L,inti) • voidIntList_clear(IntList*L) • ลบสมาชิกทั้งหมดและคืนหน่วยความจำที่จองไว้ให้ระบบ • voidIntList_init(IntList*L) • ตั้งค่าเริ่มต้นให้กับลิสต์

  30. ข้อมูลแบบ IntList • ข้างในมีอะเรย์ยืดหดได้อยู่หนึ่งตัว (แต่เราจะยืดอย่างเดียว) • มีฟีลด์ size เพื่อบอกว่าตอนนี้ array มีสมาชิกกี่ตัว • เวลาทำงาน เราจะทำให้ capacity ของอะเรย์ไม่น้อยกว่า size เสมอ • capacity = จำนวนสมาชิกที่สามารถเก็บได้ • size = สมาชิกที่เก็บไว้จริง typedefstruct { IntArrayarr; intsize; }IntList;

  31. กฎการเก็บข้อมูล (Representation Invariant) • เทคนิคหนึ่งที่ใช้ในการเขียนโครงสร้างข้อมูล • กำหนดข้อความหนึ่งที่จะเป็นจริงตลอดชีวิตการทำงานของโครงสร้างข้อมูล • แล้วใช้ข้อความนี้เป็นไกด์ในการเขียนฟังก์ชันต่างๆ • ในที่นี้เราจะตั้งกฎสองกฎ • ฟีลด์ size มีค่าเท่ากับจำนวนสมาชิกในลิสต์ • สมาชิกตัวที่ iในอะเรย์ arrคือสมาชิกตัวที่ iของลิสต์

  32. IntList_get • get(L, i): คืนสมาชิกตัวที่ i • กฎ: สมาชิกตัวที่ iในอะเรย์ arrคือสมาชิกตัวที่ iของลิสต์ • ใช้IntArray_getทำงาน intIntList_get(IntList*L,inti) { returnIntArray_get(&L->arr,i); }

  33. IntList_set • set(L, i, x): ทำให้สมาชิกตัวที่ iกลายเป็น x • กฎ: สมาชิกตัวที่ iในอะเรย์ arrคือสมาชิกตัวที่ iของลิสต์ • ก็ใช้ IntArray_setทำงานเช่นกัน voidIntList_set(IntList*L,inti,intx) { IntArray_set(&L->arr,i,x); }

  34. IntList_find • find(L, x): หาตำแหน่งของ x ใน L ถ้าไม่เจอคืน -1 ถ้ามีหลายตัวคืนตัวหน้าสุด • วนดูสมาชิกข้างในอะเรย์ทีละตัว แล้วตอบตำแหน่งของตัวแรกที่เจอ intIntList_find(IntList*L,intx) { inti; for(i=0;i<L->size;i++) if(x==IntArray_get(&L->arr,i)) returni; return-1; }

  35. IntList_insert • insert(L, i, x): เพิ่ม x เข้าไปใน iโดยทำให้มันเป็นสมาชิกตัวที่ iหลังจากแทนเสร็จแล้ว • กฎ: • ฟีลด์ size มีค่าเท่ากับจำนวนสมาชิกในลิสต์ • สมาชิกตัวที่ iในอะเรย์ arrคือสมาชิกตัวที่ iของลิสต์

  36. Before & After IntList IntArray L= size = 5 arr= capacity = 7 data= IntList_insert(&L, 2, 4) IntList IntArray L= size = 6 arr= capacity = 7 data=

  37. Before & After IntList IntArray L= size = 5 arr= capacity = 7 data= IntList_insert(&L, 2, 4) IntList IntArray L= size = 6 arr= capacity = 7 data=

  38. Before & After • จากกฎ เราต้อง • เลื่อนข้อมูลที่อยู่ทางด้านขวาของช่อง iไปทางขวาหนึ่งช่อง • เอาค่าใหม่ไปใส่ช่อง i • เพิ่ม size ขึ้น 1 IntList IntArray L= size = 5 arr= capacity = 7 data= IntList IntArray L= size = 6 arr= capacity = 7 data=

  39. กรณีอะเรย์เต็ม IntList IntArray L= size = 3 arr= capacity = 3 data= IntList_insert(&L, 0, 11) ???

  40. กรณีอะเรย์เต็ม • เราต้องเอาเลข 7 ไปใส่ช่องที่ 3 • แต่มันไม่มีช่องที่ 3 • ฉะนั้นเราต้องยึดอะเรย์ • แต่จะยืดเท่าไหร่ดี?

  41. กรณีอะเรย์เต็ม • ยืดเพิ่ม 1 ช่อง • หมายความว่าเพิ่มแต่ละครั้งต้องยืดหนึ่งครั้ง • แต่การยืดอะเรย์แต่ละครั้งจะมีการจองหน่วยความจำใหม่ • การจองหน่วยความจำใหม่เป็นปฏิบัติการที่ช้า • ยืดเพิ่ม 2 เท่าของขนาดเดิม • จองให้ capacity ใหม่เท่ากับ size*2 • ไม่ต้องจองหน่วยความจำบ่อยมาก • ถ้าข้อมูลใหญ่ นานๆ จะจองครั้งหนึ่ง  เร็ว • แต่เปลืองหน่วยความจำมากถึง 2 เท่า • ปัญหา: ถ้า size = 0 มันจะทำให้ capacity ใหม่เท่ากับ 0 • แทนที่จะมีช่องให้เก็บข้อมูลกลับไม่มี

  42. กรณีอะเรย์เต็ม • ยืดเป็น 2*size+1 • ใช้หน่วยความจำพอๆ กับการยืดสองเท่า • แต่ไม่มีปัญหากรณี size = 0 • ถ้า size = 0 จะจองให้ capacity = 1 • ถ้า size = 1 จะจองให้ capacity = 3 • ถ้า size = 3 จะจองให้ capacity = 7 • ถ้า size = 7 จะจองให้ capacity = 15 • เช่นนี้ไปเรื่อยๆ

  43. กรณีอะเรย์เต็ม IntList IntArray L= size = 3 arr= capacity = 3 data= IntList_insert(&L, 0, 11) IntList IntArray L= size = 4 arr= capacity = 7 data=

  44. IntList_insert voidIntList_insert(IntList*L,inti,intx) { intk; if(i<0||i>L->size) { fprintf(stderr,"index out of range!"); return; } if(L->size+1>L->arr.capacity) IntArray_alloc(&L->arr,(L->size)*2+1); for(k=L->size;k>i;k--) IntArray_set(&L->arr,k,IntArray_get(&L->arr,k-1)); IntArray_set(&L->arr,i,x); L->size++; }

  45. IntList_insert voidIntList_insert(IntList*L,inti,intx) { intk; if(i<0||i>L->size) { fprintf(stderr,"index out of range!"); return; } if(L->size+1>L->arr.capacity) IntArray_alloc(&L->arr,(L->size)*2+1); for(k=L->size;k>i;k--) IntArray_set(&L->arr,k,IntArray_get(&L->arr,k-1)); IntArray_set(&L->arr,i,x); L->size++; } เช็คว่า iอยู่ในช่วงที่ ถูกต้องหรือไม่

  46. IntList_insert voidIntList_insert(IntList*L,inti,intx) { intk; if(i<0||i>L->size) { fprintf(stderr,"index out of range!"); return; } if(L->size+1>L->arr.capacity) IntArray_alloc(&L->arr,(L->size)*2+1); for(k=L->size;k>i;k--) IntArray_set(&L->arr,k,IntArray_get(&L->arr,k-1)); IntArray_set(&L->arr,i,x); L->size++; } ยืดอะเรย์ถ้าเต็ม

  47. IntList_insert voidIntList_insert(IntList*L,inti,intx) { intk; if(i<0||i>L->size) { fprintf(stderr,"index out of range!"); return; } if(L->size+1>L->arr.capacity) IntArray_alloc(&L->arr,(L->size)*2+1); for(k=L->size;k>i;k--) IntArray_set(&L->arr,k,IntArray_get(&L->arr,k-1)); IntArray_set(&L->arr,i,x); L->size++; } เลื่อนสมาชิก

  48. IntList_insert voidIntList_insert(IntList*L,inti,intx) { intk; if(i<0||i>L->size) { fprintf(stderr,"index out of range!"); return; } if(L->size+1>L->arr.capacity) IntArray_alloc(&L->arr,(L->size)*2+1); for(k=L->size;k>i;k--) IntArray_set(&L->arr,k,IntArray_get(&L->arr,k-1)); IntArray_set(&L->arr,i,x); L->size++; } เอาค่าใหม่แทรก แล้วเพิ่ม size

  49. IntList_remove • remove(i): ลบสมาชิกตัวที่ iออก • กฎ: • ฟีลด์ size มีค่าเท่ากับจำนวนสมาชิกในลิสต์ • สมาชิกตัวที่ iในอะเรย์ arrคือสมาชิกตัวที่ iของลิสต์

  50. Before & After IntList IntArray L= size = 5 arr= capacity = 7 data= IntList_remove (&L, 1) IntList IntArray L= size = 4 arr= capacity = 7 data=

More Related