Embed
Email

Data structure

Document Sample
Data structure
Shared by: HC111211053933
Categories
Tags
Stats
views:
21
posted:
12/10/2011
language:
pages:
129
Data structure

พื้นฐานโครงสร้างข้อมูล





คอมพิวเตอร์เป็นอุปกรณ์ที่สร้างขึ้นมาเพื่อใช้จัดการและเปลี่ยนแปลงข้อมูลข่

าวสาร (Information) ดังนั้น

จึงต้องมีการศึกษาถึงการควบคุมดูแลการทางานของคอมพิวเตอร์ที่ยุ่งเกี่ยวกับข้อมูลข่าว

สาร

เมื่อมีการเปลี่ยนแปลงแก้ไขหรือเพื่ออานวยประโยชน์ที่ต้องการการทางานเพื่อนแก้ไขปั

ญหาต่าง ๆ ด้วยระบบคอมพิวเตอร์จะประกอบด้วยส่วนต่าง ๆ ทางด้านฮาร์ดแวร์

(Hardware) เช่น ซีพียู (CPU) หน่วยความจา (Memory) อุปกรณ์รับส่งข้อมูล(Input/Output

Device)และซอฟแวร์(Software)ที่นามาใช้ควบคุมการทางานของฮาร์ดแวร์

เพื่อแก้ไขปัญหานั้น ๆ ในการแก้ไขปัญหาจึงต้องมีกระบวนการพัฒนาซอฟต์แวร์

(Software Development) ที่เป็นขั้นตอนมาใช้ดังนี้





ขั้นตอนการพัฒนาซอฟแวร์

การแยกแยะและวิเคราะห์ปัญหา

ในขั้นตอนแรกเป็นการแก้ไขปัญหาโดยการวิเคราะห์และแยกแยะ

สิ่งแรกที่ต้องพิจารณา คือ เอาต์พุต

ที่ต้องการและมีข้อมูลข่าวสารอะไรบ้างที่ทาที่ทาให้สามารถแก้ไขปัญหาได้หลังจากพิจาร

ณาเอ้าท์พุตก็คือพิจารณาอินพุต

และมีข้อมูลข่าวสารอะไรบ้างที่ทาให้สามารถแกไขปัญหาได้

หลังจากแยกแยะเอ้าท์พุตและอินพุต รวมถึงข้อมูลข่าวสารที่ต้องการเสร็จสิ้น

เป็นการพัฒนาเขียนอัลกอรึทึมและโปรแกรม

การออกแบบระบบ

เนื่องจากระบบคอมพิวเตอร์ไม่สามารถที่จะเข้าใจและแกไขปัญหาบางอย่างไ

ด้ จึงต้องมีวิธีการที่จะแก้ไขปัญหาโดยการออกแบบระบบ

ซึ่งเป็นการวางแผนออกแบบที่แยกแยะออกเป็นปัญหาย่อย

และพิจารณาสร้างชุดคาสั่งเพื่อแก้ไขปัญหาย่อยนั้น

จากนั้นมารวมกันเป็นระบบที่สามารถแก้ไขปัญหาทั้งหมด

มีลักษณะการวางแผนออกแบบจากบนลงล่าง (Top-down Design) ซึ่งประกอบด้วย 2

ส่วนหลัก ๆ คือ

1. โครงสร้างข้อมูล (Data Strutcure) ใช้ควบคุมและจัดการกับข้อมูลของปัญหานั้น ๆ

หรือที่เรียกว่าชนิดข้อมูลมีโครงสร้าง เรียกสั้น ๆ ว่าชนิดข้อมูล เช่น ชนิดข้อมูลอาร์เรย์

ชนิดข้อมูลสแตก และชนิดข้อมูลลิ้งค์ ลิสต์

การออกแบบระบบต้องเลือกใช้โครงสร้างข้อมูลอย่างเหมาะสมเพื่อจัดการกับข้อมูลที่ใช้ใ

นระบบ

2. การออกแบชุดคาสั่ง (Module Design)

ในการแก้ไขปัญหาจะต้องมีกระบวนการทางานเพื่อให้ได้มาซึ่งข้อมูลข่าวสารหรือเอ้าท์พุ

ต ที่ต้องการโดยชุดคาสั่งเป็นส่วนประกอบของระบบ

จึงต้องมีการออกแบบการทางานที่เป็นชุดคาสั่งหรือโมดุลนั้นๆ และเรียกว่า อัลกอรึทึม

ได้เป็น

โครงสร้างข้อมูล + อัลกอริทึม = โปรแกรม

การที่จะเลือกใช้โครงสร้างข้อมูลและอัลกอริทึมในการออกแบบให้การทางา

นอย่สงมีประสิทธิภาพ ซึ่งถือว่าเป็นหัวใจสาคัญของการออกแบบซอฟต์แวร์จะพิจารณาไ

ด้จากลักษณะดังต่อไปนี้

ความถูกต้อง

ระยะเวลาการทางาน

จานวนพื้นที่ใช้งาน

ความเรียบง่าย

ความเหมาะสมที่สุด

การเขียนคาสั่งและรวมกัน

การเขียนคาสั่ง (Coding) คือ การเขียนคาสั่งต่าง ๆ

ของโปรแกรมให้ทางานเป็นไปตามโครงสร้างข้อมูลและอัลกอริทึมด้วยภาษาเขียนโปรแก

รมภาหนึ่ง

ถ้าโครงสร้างข้อมูลและอัลกอริทึมถูกออกแบบไว้เป็นอย่างดีทาให้กระบวนการแปลงคาสั่

งจากภาษาเขียนให้เป็นภาษาเครื่องก็จะง่ายไม่ยุ่งยากลาบาก

การรวมกัน (Integration) เป็นกระบวนการนาคาสั่งต่าง ๆ

ที่เขียนเป็นแต่ละชุดคาสั่งมารวมกันและให้มีการทางานร่วมกันได้เป็นซอฟต์แวร์โปรแกร

มขึ้นมา

การเขียนโปรแกรมที่ดีนั้นจะต้องมีความถูกต้องในการทางาน

สามารถอ่านคาสั่งและทาความเข้าใจได้ง่าย จึงต้องมีโครงสร้างการเขียนโปรแกรมที่ดี

ซึ่งมีวิธีการเข้ามาช่วยเหลือในการเขียนโดยพิจารณาได้จากเรื่องต่อไปนี้

1. การเขียนโปรแกรมควรเป็นแบบบนลงล่าง (Top-Down)

โดยเฉพาะกับปัญหาที่มีขนาดใหญ่หรือมีความซับซ้อน

จึงควรแยกปัญหาใหญ่ออกเป็นปัญหาย่อย ๆ จากการเขียนคาสั่งทั้งหมดในโปรแกรม

ก็แยกเป็นชุดคาสั่งย่อย ๆ

2. ใช้โครงสร้างควบคุมการทางาน (Control Structure)

ในการเขียนโปรแกรมหรือชุดคาสั่ง เช่น การใช้เงื่อนไข IF การใช้วนลูปแบบต่าง ๆ

3. ควรใช้ตัวแปรที่เป็นแบบโลคอล (Local Variable)

และใช้กับชุดคาสั่งเพื่อแก้ปัญหาย่อย

4. ควรใช้ตัวแปรพารามิเตอร์ (Parameter) กับชุดคาสั่งเพื่อแก้ไขปัญหาย่อย

หลีกเลี่ยงที่จะใช้ตัวแปรที่เป็นแบบโกลบอล

และตัวพารามิเตอร์ควรมีการป้องกันหากมีการแก้ไขค่า

5. นาตัวแปรค่าคงที่ ( Constant Variable) มาใช้

จะช่วยให้การเขียนโปรแกรมมีความยืดหยุ่นมากขึ้นและอ่านเข้าใจง่าย

6. การเขียนโปรแกรมควรมีการจัดพื้นที่หรือบรรทัดว่างเพื่อให้อ่านสะดวก

มีการย่อหน้าเพื่อจัดระดับของคาสั่งและมีลักษณะที่เป็นกรอบ

ทดสอบความถูกต้อง

1. การตรวจคาสั่ง (Validation)

เป็นการตรวจสอบการเขียนโปรแกรมว่ามีความถูกต้องตามโครงสร้างของภาษาและทางา

นตรงตามที่ต้องการหรือไม่

2. การตรวจสอบความจริง (Verification)

เป็นการตรวจสอบขั้นตอนการทางานของโปรแกรมว่ามีความถูกต้องและสอดคล้องกันหรื

อไม่

3. การทดสอบ (Testing)

เป็นการทดสอบการทางานว่าในแต่ละส่วนหรือชุดคาสั่งและการทางานทั้งหมดในโปรแก

รมมีความถูกต้องหรือไม่ มีการทดสอบแต่ละยูนิต ทดสอบการรวมกันของยูนิต

การดูแลระบบ

หลังจากการพัฒนาซอฟต์แวร์เสร็จสมบูรณ์และนาไปใช้งาน หากมีความต้อ

งการที่จะเปลี่ยนแปลงแก้ไขเพื่อเติม หรือโปรแกรมมีปัญหาเกิดขึ้น จึงต้องมีการดูแลระ

บบ เพื่อนากลับมาปรับปรุงแก้ไขใหม่ให้เป็นไปตามความต้องการ

ความหมายโครงสร้างข้อมูล/ชนิดข้อมูล

การทางานของคอมพิวเตอร์จะมีการจัดการอย่างไรเพื่อให้ได้มาซึ่งข้อมูลข่าว

สาร และสามารถนามาใช้งานออกมาเป็นข้อมูลข่าวสารในรูปแบบต่าง

ๆ ที่ทาความเข้าใจได้ แต่เนื่องจากคอมพิวเตอร์เป็นเพียงเครื่องจักรที่ไม่สามารถเข้าใจ

ความหมายของข้อมูลข่าวสารได้เช่นเดียวกับคน จึงมีการกาหนดรูปแบบที่ใช้สื่อความห

มายของข้อมูลข้าวสารให้คอมพิวเตอร์กับผู้ใช้งานเข้าในตรงกันเรียกว่า

โครงสร้างข้อมูลหรือชนิดข้อมูล โดยแบ่งออกได้เป็นดังนี้

บิต (Bit)

เป็นหน่วยที่เล็กที่สุดในการทางานของคอมพิวเตอร์ที่แสดงเป็นสถานะได้ 2

สถานะ คือ เปิดกับปิด จึงกาหนดเป็นการเก็บค่าได้ 2 ค่า คือ 0 กับ 1 เรียกว่าไบนารี่ดิจิต

(Binary Digit)

ไบต์ (Byte)

เป็นการนาบิตหลาย ๆ บิตมาเรียงต่อรวมกันเพื่อกาหนดค่าได้มากขึ้น เช่น 3

บิต มาต่อเรียงกันจะทาให้เกิดสถานะที่ต่างกันคือ 000,001,010,100,011,010, และ 111

ก็จะได้เป็น 8 สถานะ เมื่อนาบิตมาเรียงต่อรวมกันเป็น 8 บิต เรียกว่าไบต์ มี 256 สถานะ

และกาหนดเป็นโครงสร้างข้อมูลที่มีขนาดเล็กที่สุดที่ใช้งานได้ มีค่าตั้งแต่ 0 – 255

(00000000 – 11111111)

เลขจานวนเต็ม (Integer)

เป็นการนาบิตหลาย ๆ บิตมาเรียงต่อรวมกันเพื่อกาหนดเป็นเลขจานวนเต็ม

ซึ่งได้เป็นระบบเลขฐานสอง โดยแต่ละบิตมีความหมายเป็นเลขยกกาลังสอง เช่น 20 = 1,

23 = 8 หรือ

21 + 22 +25 = 2+4+32 = 38 เลขที่ได้เป็นเลขจานวนเต็มบวก

ถ้าต้องการเป็นเลขจานวนเต็มลบ จะต้องใช้วิธีการเรียกว่า One-complement Notation

โดยการเปลี่ยนค่าของบิตที่เป็น 0 ให้เป็น 1 และค่าที่เป็น 1 ให้เป็น 0 เช่น 00100110 =

38 เมื่อสลับค่าจะได้บิต 11011001 = -38

ด้วยวิธีนี้ทาให้เก็บค่าได้ทั้งเลขจานวนเต็มบวกและเต็มลบ

ซึ่งมีบิตซ้ายสุดเป็นตัวกาหนดให้มีค่าบวกหรือลบเรียกว่า Sign Bit

เมื่อนาบิตมาเรียงต่อกัน 16 บิตได้เป็นเลขจานวนเต็มฐานสิบ มีอีกวิธีคือ Two-

complement Notation โดยการบวกค่า 1 เข้าไปกับค่าของ One-complement

Notation เช่นจาก 11011001 = -38 เมื่อบวก 1 จะได้ 11011010 = -38 เช่นกัน

ี้

แต่วิธีนจาทาให้เก็บค่าได้มากกว่า คือ มีตั้งแต่ -2n-1 ถึง 2n-1 -1 ดังต่อไปนี้

1000000000000000 = -32768 0000000000000000 = 0

1000000000000001 = -32767 0000000000000001 = 1

1000000000000010 = -32766 0000000000000010 = 2

1111111111111101 = -3 0111111111111101 = 32765

1111111111111110 = -2 0111111111111110 = 32766

1111111111111111 = -1 0111111111111111 = 32767





เลขจานวนจริง (Real Number)

เป็นรูปแบบของตัวเลขที่มีเลขทศนิยมเรียกว่า Floating – point Number

โดยทาการแบ่งบิตออกเป็นสองส่วน โดยบิตที่อยู่ด้านซ้ายเก็บค่าเป็นตัวเลขจานวนเต็ม

เรียกว่า แมนทิสสา (Mantissa) การเก็บค่าเป็นแบบเดียวกับตัวเลขจานวนเต็ม

ส่วนบิตที่อยู่ด้านขวาเก็บค้าเป็นจานวนหลักของ เลขทศนิยมเรียกว่า เอ็กซ์โพเนนท์

(Exponent) ในการเก็บจะใช้วิธี Two – complement Notation

ซึ่งได้มาจากเลขยกกาลังของ 10 เช่น .01 = 10-2, 6.25 x 10-2

การเก็บค่าเลขทศนิยมจะใช้บิตจานวน 32 บิต โดยแบ่งส่วนที่เป็นแมนทิสสาจานวน 24

บิต และส่วนที่เป็นเอ็กซ์โพเนนท์จานวน 8 บิต ดังนี้

00000000000000000000000000000000 = 0

00000000000000000000110000000011 = 12000

00000000000000000000010111111111 = 0.5

00000000000000000000010111111010 = 0.000005

11111111011010001001111111111110 = -387.53

ตัวอักษร (Character)

เป็นการเก็บค่าที่เป็นตัวอักษร

แต่เนื่องจากคอมพิวเตอร์ไม่สามารถเข้าใจจึงใช้เลขจานวนเต็มสื่อความหมายแทนโดยใช้

บิตจานวน 8 บิต เรียกว่า Bit String ซึ่งค่าตัวเลขที่ได้จะกาหนดเป็นตัวอกษรหนึ่งตัว

ดังนั้นจะได้ตัวอักษรทั้งหมด 256 ตัวที่เรียกว่าเอ็บซีดิก (EBCDIC) เช่น

ตัวอักษรA จะมีค่า 01000001 = 65 หรือ B มีค่า 01000010 = 66

ประกอบด้วยอักษรตัวเล็ก ตัวใหญ่ ตัวเลข และตัวอักษรพิเศษ และที่ใช้เพียง 7

บิตเรียกว่าวหัสแอสกี (ASCII Code) ใช้ครึ่งเดียวของเอ็บซีดิกแต่การทางานรวดเร็วกว่า

เมื่อใดที่นาตัวอักษรหลาย ๆ ตัวมาเรียงต่อกันก็จะได้เป็นข้อความ เช่น AB จะได้เป็น

0100000101000010

หากต้องการเก็บจานวนรูปแบบของตัวอักษรมากกว่านี้ก็สามารถทาได้โดยการเพิ่มจานว

นบิตเข้าไป ซึ่งขึ้นกับสถาปัตยกรรมของคอมพิวเตอร์จะรับได้หรือไม่ เช่นใช้ 10

บิตก็จะได้ตัวอักษร 1024 รูปแบบ

โครงสร้างข้อมูลเบื้องต้นและโครงสร้างข้อมูลนามธรรม

จากรูปแบบต่าง ๆ ของส่วนที่เป็นข้อมูลข่าวสาร

คอมพิวเตอร์ไม่สามารถจะให้ความหมายได้ว่าคืออะไร

แต่เมื่อนาการจัดการให้มีการทางานที่เป็นรูปแบบตามที่กาหนดก็จะสามารถสื่อความหม

ายขึ้นมาได้

ด้วยกระบวนการจัดการแบบนี้จะเรียกว่าโครงสร้างข้อมูลหรือชนิดข้อมูลและด้วยวิธีการ

ดังกล่าวจึงนาไปใช้ในการแก้ปัญหาต่าง ๆได้



โครงสร้างข้อมูลมีส่วนสาคัญในระบบคอมพิวเตอร์

ตัวแปรทุกตัวต้องมีการกาหนดชนิดข้อมูลซึ่งอาจเปิดเผยชัดเจน หรือปิดบังไว้

โครงสร้างข้อมูลเหล่านี้จึงมีลักษณะทางตรรกะ แต่ในทางกายภาพ

อาจมีความแตกต่างกัน โครงสร้างข้อมูลสามารถแบ่งออกเป็นแต่ละประเภทดังในรูปที่

1.1 ซึ่งแบ่งตามลักษณะวิธีการจัดเก็บข้อมูล

โครงสร้างข้อมูลซับซ้อน

โครงสร้างข้อมูล

โครงสร้างข้อมูลเบื้องต้น ไม่เป็นเชิงเส้น การจัดการแฟ้มข้อมูล

เรียบง่าย เชิงเส้น

ไบนารี N-อาร์เรย์

เลขจานวนเต็ม อาร์เรย์ สแตก ไบนารีทรี กราฟ แฟ้มข้อมูลลาดับ

เลขทศนิยม สตริง คิว ไบนารีเสิร์ชทรี ทรี แฟ้มข้อมูลโดยตรง

เสิร์ชทรี M- แฟ้มข้อมูลลาดับเชิงดัชนี

บูลีน เรคคอร์ด ลิ้งลิสต์

ทาง

ตัวอักษร บีทรี แฟ้มข้อมูลหลายคีย์

บี*-

ทรีมบีพลัว-

ทรี

ทราย

รูปที่ 1.1 ประเภทของโครงสร้างข้อมูล

1. โครงสร้างข้อมูลเบื้องต้น (Primitive Data Structure)

เป็นชนิดข้อมูลที่ไม่มีโครงสร้างข้อมูลอื่นมาเป็นส่วนประกอย

เมื่อต้องการเก็บค่าสามารถเรียกใช้งานได้ทันที บางครั้งเรียกว่าชนิดข้อมูลพื้นฐาน (Base

Type) หรือสร้างมาให้ใช้ด้วยภาษานั้น ๆ

ส่วนโครงสร้างข้อมูลแบบอื่น ๆ จะมีโครงสร้างข้อมูลอื่นเป็นส่วนประกอบ

เมื่อต้องการใช้จะต้องกาหนดรูปแบบรายละเอียดโครงสร้างขึ้นมาก่อนเรียกว่าข้อมูลชนิด

ผู้ใช้กาหนด

(Uses-defined Type) ดังนี้

2. โครงสร้างข้อมูลแบบเรียบง่าย (Simple Data Structure)

จะมีสมาชิกที่เป็นโครงสร้างข้อมูลอื่นเป็นส่วนประกอบ มีรูปแบบง่าย ๆ ไม่ซับซ้อน

สามารถทาความเข้าใจและสร้างขึ้นมาใช้งานได้ง่าย

3. โครงสร้างข้อมูลเชิงเส้น (Linear Data Structure)

เป็นโครงสร้างที่ความซับซ้อนมากขึ้น

ประกอบด้วยสมาชิกที่เป็นโครงสร้างข้อมูลอื่นจัดเรียงต่อกันเป็นแนวเส้น

4. โครงสร้างข้อมูลไม่เป็นเชิงเส้น (Nonlinear Data Structure)

เป็นโครงสร้างที่มีความซับซ้อนเช่นกัน

ประกอบด้วยสมาชิกที่เป็นโครงสร้างข้อมูลอื่นจัดเรียงกันในรูปแบบไบนารี่

ที่จัดเรียงสมาชิกมีการแยกออกเป็นสองทาง และแบบ N- อาร์เรย์

ที่จัดเรียงสมาชิกมีการแยกออกได้หลายทางหลายรูปแบบไม่แน่นอน

5. โครงสร้างการจัดการแฟ้มข้อมูล (File Organization)

เป็นโครงสร้างสาหรับนาข้อมูลเก็บไว้ในหน่วยความจาสารอง

โดยข้อมูลจะอยู่ในรูปแบบโครงสร้างข้อมูลอื่น

และมีวิธีการจัดการโดยการนาโครงสร้างข้อมูลอื่น ๆ มาช่วย

โครงสร้างข้อมูลต่าง

ๆที่กล่าวมาอาจต้องมีการควบคุมการทางานที่เกี่ยวข้องกับข้อมูลและส่วนที่มาเกี่ยวข้องใ

ห้เป็นไปตามที่ต้องการเรียกว่า โครงสร้างข้อมูลนามธรรม

ลักษณะโครงสร้างจะแบ่งออกเป็น 2 ส่วน คือ ส่วนข้อมูลและส่วนปฏิบัติการ

โดนภายในจะมีรายลเอียดการทางานต่าง ๆ

ประกอบด้วยโครงสร้างการจัดเก็บข้อมูลและอัลกอริทึม

เมื่อใดที่เรียกใช้งานโครงสร้างนามธรรมในส่วนรายละเอียดการทางานจะไม่ถูกเกี่ยวข้อง

หรือมีผลกระทบโดยถูกปิดบังไว้

จะเห็นว่าโครงสร้างข้อมูลซับซ้อนจะเป็นโครงสร้างข้อมูลนามธรรมที่ต้องมีส่วนการจัดเก็

บข้อมูลและส่วนปฏิบัติการ

โครงสร้างข้อมูลกับภาษาเขียนโปรแกรม

ภาษาเขียนโปรแกรม (Programming Language)

ช่วยให้ผู้เขียนโปรแกรมสามารถกาหนดโครงสร้างข้อมูลที่มีความหมายให้กับตาแปร

เนื่องจากตัวแปรเหล่านี้ต้องเก็บค่าตามลักษณะของโครงสร้างข้อมูลที่ได้กาหนดมาและส่

วนของการปฏิบัติการที่ช่วยให้การทางานกับโครงสร้างข้อมูลมีความถูกต้อง

ภาษาเขียนโปรแกรมหลายภาษาจะมีแนวทางที่แตกต่างกันในการกาหนดโครงสร้างข้อมู

ลมาให้ใช้ เช่น ภาษาซี(C)

อนุญาตให้โครงสร้างข้อมูลตัวอักษรกับเลขจานวนเต็มสามารถใช้ร่วมกันและคานวณได้

ภาษาปาสคาล (Pascal)

จะต้องประกาศตัวแปรอย่างชัดเจนว่ากาหนดโครงสร้างข้อมูลเป็นแบบใด

ขณะที่ภาษาฟอร์แทรน(Fortran)

เป็นการประกาศปิดบังไว้จึงไม่ต้องกาหนดโครงสร้างข้อมูลให้กับตัวแปร

โครงสร้างข้อมูลแบบแถวลาดับ

อาเรย์(Array)









1. โครงสร้างข้อมูลแบบอาเรย์ (Array)

โครงสร้างข้อมูลที่ภายในชื่อตัวแปรเดียวกันสามารถเก็บข้อมูล

ได้มากกว่า 1 ค่า

โดยที่ค่าที่เก็บไว้ภายในต้องเป็นข้อมูลชนิดเดียวกันและมีขนาดเท่ากัน

มีการจองพื้นที่ในหน่วยความจาให้อยู่แบบต่อเนื่องกัน

Virtual Address

 ตาแหน่งเสมือนเพื่อใช้ในการอ้างอิงถึงข้อมูล

เพื่อง่ายต่อการติดต่อว่าต้องการข้อมูลใน Array ที่ตาแหน่งหรือในช่องไหน

แต่ไม่ใช่ตาแหน่งจริงในหน่วยความจาหลัก

Physical Address ตาแหน่งจริงที่เก็บข้อมูลไว้ภายในหน่วยความจาหลัก









2. การประกาศตัวแปรอาเรย์

ชนิดของข้อมูล ชื่อตัวแปร[ช่องเริ่มต้น . . ช่องสุดท้าย]

เช่น

Int A[1 . . 10] ;

Char NAME[1 . . 35] ;

Boolean GRADE[1 . . 5] ;

Index  ตัวที่ทาการชี้ช่อง

ชื่อตัวแปร[Index] เช่น A[6]

Index

ช่องที่ 6

ตัวแปร

A



A[10]

A[9]

A[8]

A[7]

A[6]

A[5]

A[4]

A[3]

A[2]

A[1]

Int A[1 . . 10];

กาหนดให้ 1 ตัวแปรใช้พื้นที่ 4 Byte

1

4

8

12

16

20

24

28

32

36

40

Virtual Address :

A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[8], A[9], A[10]

Physical Address :

1-4, 5-8, 9-12, … , 37-40









แบบฝึกหัด

จงแจกแจงสมาชิกพร้อมทั้งระบุ Virtual Address และ Physical Addressของ Array

ต่อไปนี้

Char NAME[1 . . 7] ;

กาหนดให้ 1 ตัวแปรใช้พื้นที่ 3 Byte

2. Boolean GRADE[1 . . 5] ;

กาหนดให้ 1 ตัวแปรใช้พื้นที่ 3 Byte









การประกาศตัวแปรในภาษาคอมพิวเตอร์

Fortran : REAL DATA(6)



PL/1 : DECLARE DATA(6) FLOAT;



PASCAL: VAR DATA : ARRAY[1…6]

OF REAL





3. ชนิดของอาเรย์

3.1 อาเรย์ 1 มิติ

(One dimensional array)

3.2 อาเรย์ 2 มิติ

(Two dimensional array)

3.3 อาเรย์ 3 มิติ

(Three dimensional array)









3.1 อาเรย์ 1 มิติ

(One dimensional array)





รูปแบบ

A[l . . u]

A  ชื่อของอาเรย์

l  ค่าต่าสุด

u  ค่าสูงสุด









การกาหนดค่า



A[i] = N

N คือค่าของข้อมูล









ตัวอย่าง

จงเขียนอาเรย์ เมื่อกาหนดให้อาเรย์ A มีช่องเก็บข้อมูล 5 ช่อง โดยตาแหน่งที่ 4

มีค่าเป็น 10

การกาหนดค่า

รูปแบบอาเรย์ที่เป็นตาราง

A[4] = 10

10

A

1

2

3

4

5





การคานวณ

การหาความยาวของอาเรย์ A (จานวนช่อง)



การหาตาแหน่งของ A[i]

ความยาวของอาเรย์ (Length)

ความยาว (Length), ขนาด (Size)

 จานวนอิลิเมนท์ของอาเรย์ทั้งหมด

UB(Upper Bound) = ขอบบนของอาเรย์, ตัวชี้สูงสุด = u

LB(Lower Bound) = ขอบล่างของอาเรย์, ตัวชี้ต่าสุด = l





Length = UB - LB + 1

=u–l+1









ITEM[56…100]

NAME[25…75]

DATA[4…10]

B[1…6]

Length

Array

A[5 . . 10]  u = 10, l = 5

Length = u – l + 1

= 10 - 5 + 1

= 6

6

7

51

45

ตัวอย่าง

กาหนด DATA เป็นอาร์เรย์ของเลขจานวนเต็ม

จานวน 6 อิลิเมนท์ ดังนี้

DATA[1] = 247 DATA[2] = 56

DATA[3] = 429 DATA[4] = 135

DATA[5] = 87 DATA[6] = 156

156

87

135

429

56

247

DATA

1

2

3

4

5

6

156

87

135

429

56

247

DATA

1

2

3

4

5

6

บริษัทรถยนต์ใช้อาเรย์ AUTO ในการเก็บจานวนของรถที่ขายแต่ละปี ตั้งแต่ 1932 ถึง

1984



AUTO[i] = จานวนรถที่ขายในปี i

Array  AUTO[1932 . . 1984]

l = 1932

u = 1984

Length = u – l + 1

Length = 1984 – 1932 + 1 = 53



ตัวอย่าง









ตาแหน่งของอิลิเมนท์ในอาเรย์

LOC(A[i]) = ตาแหน่งของอิลิเมนท์ A[i] ของอาเรย์ A

Base(A) = ตาแหน่งอิลิเมนท์แรกของ A = L



ตาแหน่งของอิลิเมนท์ใดๆ ของอาเรย์ A 

LOC(A[i]) = L + w(i – l)

W = จานวนช่องของหน่วยความจาต่อข้อมูล 1 อิลิเมนท์



สิ่งที่ Computer เก็บ









AUTO[1932 . . 1965]

Base(AUTO) = L = 200

W=4

LOC(AUTO[1932]) = 200 + 4(1932 - 1932) = 200

LOC(AUTO[1933]) = 200 + 4(1933 - 1932) = 204

LOC(AUTO[1934]) = 200 + 4(1934 - 1932) = 208

LOC(AUTO[1965]) = 200 + 4(1965 - 1932) = 332









ตาแหน่งของอิลิเมนท์ในอาเรย์

:

LOC(A[i]) = L + w(i – l)









200

201

202

203

204

205

206

207

AUTO[1932]

AUTO[1933]

208

209

210

211

AUTO[1934]

หน่วยความจาของคอมพิวเตอร์

4.2 อาเรย์ 2 มิติ

(Two dimensional array)





Array 2 Dimension

(อาเรย์ 2 มิติ)



เป็นแบบที่การอ้างอิงหรือการเข้าถึงสมาชิกตัวใด จะใช้ตัวบอกลาดับ 2 ตัว

สามารถมองในลักษณะของ เมตริก (Metrix) หรือ ตาราง (Table)

สมาชิกแต่ละตัวจัดเรียงให้อยู่เป็น

แถว (Row)

หลัก (Column)









Array 2 มิติ (A) ที่มี 3 แถว 4 หลัก

หลักที่ 1 หลักที่ 2 หลักที่ 3 หลักที่ 4

แถวที่ 1 A[1,1] A[1,2] A[1,3] A[1,4]

แถวที่ 2 A[2,1] A[2,2] A[2,3] A[2,4]

แถวที่ 3 A[3,1] A[3,2] A[3,3] A[3,4]





A[i, j]  แถวที่ i หลักที่ j









แถว

หลัก





รูปแบบ

A[ l1..u1, l2..u2 ]

A  ชื่ออาเรย์

l1  ค่าต่าสุดของมิติที่ 1

u1  ค่าสูงสุดของมิติที่ 1

l2  ค่าต่าสุดของมิติที่ 2

u2  ค่าสูงสุดของมิติที่ 2









B[5..7, 6..9]









การหาจานวนหลักและจานวนแถว

A[ l1..u1, l2..u2 ]

A  Array 2 มิติ

แถว  u1 - l1 + 1 แถว

หลัก  u2 – l2 + 1 หลัก









A[-1..2, 2..4]

หลักที่ 1 หลักที่ 2 หลักที่ 3

แถวที่ 1

แถวที่ 2

แถวที่ 3

แถวที่ 4









A[-1, 2]

A[-1, 3]

A[-1, 4]

A[0, 2]

A[0, 3]

A[0, 4]

A[1, 2]

A[1, 3]

A[1, 4]

A[2, 2]

A[2, 3]

A[2, 4]

u1 - l1 + 1 = 2 – (-1) + 1 = 4 แถว

u2 – l2 + 1 = 4 – 2 + 1 = 3 หลัก



u1

l1

u2

l2





การคานวณหาจานวนสมาชิก

จานวนสมาชิก = M x N

M  จานวนแถว

N  จานวนหลัก









การแทนที่หน่วยความจา

Column Major

จัดเรียงหน่วยความจาเรียงกันไปทีละหลัก

2. Row Major

จัดเรียงหน่วยความจาเรียงกันไปทีละแถว

(1, 1)

(2, 1)

(3, 1)

(1, 2)

(2, 2)

(3, 2)

(1, 3)

(2, 3)

(3, 3)

(1, 4)

(2, 4)

(3, 4)

Column 1

Column 2

Column 3

Column 4

(1, 1)

(1, 2)

(1, 3)

(1, 4)

(2, 1)

(2, 2)

(2, 3)

(2, 4)

(3, 1)

(3, 2)

(3, 3)

(3, 4)

Row 1

Row 2

Row 3

Column Major

Row Major









การหาตาแหน่ง

แบบ column major

LOC(A[i, j]) = L + w(u1-l1+1)(j- l2) + w(i- l1)

แบบ row major

LOC(A[i, j]) = L + w(u2-l2+1) (i- l1) + w (j- l2)









แบบฝึกหัด

กาหนด Array A[-3..5, 3..8] จองที่ในหน่วยความจา โดยสมาชิกแต่ละตัว ใช้เนื้อที่ 4 Byte

และ loc(A[-3,3]) = 4836 จงหาที่อยู่ของ A[4,5] ทั้งแบบ Column Major และ Row Major









3.3 อาเรย์ 3 มิติ

(Three dimensional array)









Array 3 Dimension

(อาเรย์ 3 มิติ)

A[i, j, k]

ใช้แถวลาดับ 3 ตัว

เมตริกซ์ หรือตารางหลายชั้น

ตัวแรก  ชั้น

ตัวที่สอง  แถว

ตัวที่สาม  หลัก









A[2, 4, 3]

A[1, 1, 1] A[1, 1, 2] A[1, 1, 3]

A[1, 2, 1] A[1, 2, 2] A[1, 2, 3]

A[1, 3, 1] A[1, 3, 2] A[1, 3, 3]

A[1, 4, 1] A[1, 4, 2] A[1, 4, 3]

A[2, 1, 1] A[2, 1, 2] A[2, 1, 3]

A[2, 2, 1] A[2, 2, 2] A[2, 2, 3]

A[2, 3, 1] A[2, 3, 2] A[2, 3, 3]

A[2, 4, 1] A[2, 4, 2] A[2, 4, 3]

ชั้นที่ 1

ชั้นที่ 2









รูปแบบ

A[ l1..u1, l2..u2, l3..u3]

A  ชื่ออาเรย์

จานวนชั้น (P) = u1 - l1 + 1

จานวนแถว (M) = u2 – l2 + 1

จานวนหลัก (N) = u3 – l3 + 1









จานวนสมาชิก

(u1 - l1 + 1)*(u2 – l2 + 1)*(u3 – l3 + 1)

P*M*N

การคานวณหาจานวนสมาชิก





การแทนที่หน่วยความจา



A[1..2, 1..4, 1..3]









(1, 1, 1)

(2, 1, 1)

(1, 2, 1)

(2, 2, 1)

(1, 3, 1)

(2, 3, 1)

Column Major

Row Major

(1, 4, 3)

(2, 4, 3)

(1, 1, 1)

(1, 1, 2)

(1, 1, 3)

(1, 2, 1)

(1, 2, 2)

(2, 4, 2)

(2, 4, 3)









การหาตาแหน่ง

แบบ row major

LOC(A[i, j, k]) =

L + w(u1-l1+1) (u2-l2+1)(k- l3) + w(u1-l1+1) (j- l2) + w(i- l1)

แบบ column major

LOC(A[i, j, k]) =

L + w(u2-l2+1) (u3-l3+1)(i- l1) + w(u3-l3+1) (j- l2) + w(k- l3)









แบบฝึกหัด

กาหนด Array A[-2..5, 3..5, 1..2] อยู่ในหน่วยความจา โดยที่ loc(A[2,4,2]) = 4168

และใช้เนื้อที่ 2 Byte จงหาที่อยู่เริ่มต้น ของแถวลาดับ A เมื่อ A ถูกจัดเรียงแบบ Column

Major









4. การเข้าถึงอาเรย์ในหน่วยความจา

การชี้ตาแหน่ง

การเข้าถึง

การแทรกและการลบ

การเรียงลาดับ

การค้นหา

ลิเนียร์

ไบนารี









4.1 การชี้ตาแหน่ง (Indexing)

หน่วยความจาของคอมพิวเตอร์

1000

1001

1002

1003

:

ตาแหน่งของอิลิเมนท์ในอาเรย์

LOC(LA[K]) = ตาแหน่งของอิลิเมนท์ LA[K] ของอาร์เรย์ LA

Base(LA) = ตาแหน่งอิลิเมนท์แรกของ LA



ตาแหน่งของอิลิเมนท์ใดๆ ของอาเรย์ LA 

LOC(LA[K]) = Base(LA) + w(K – lower bound)

W = จานวนช่องของหน่วยความจาต่อข้อมูล 1 อิลิเมนท์



สิ่งที่ Computer เก็บ









Base(AUTO) = 200

W=4



LOC(AUTO[1932]) = 200 + 4(1932 - 1932) = 200

LOC(AUTO[1933]) = 200 + 4(1933 - 1932) = 204

LOC(AUTO[1934]) = 200 + 4(1934 - 1932) = 208

LOC(AUTO[1965]) = 200 + 4(1965 - 1932) = 332









ตาแหน่งของอิลิเมนท์ในอาเรย์









200

201

202

203

204

205

206

207

AUTO[1932]

AUTO[1933]

208

209

210

211

AUTO[1934]

หน่วยความจาของคอมพิวเตอร์





4.2 การเข้าถึงข้อมูลในอาเรย์

(Traversing Linear Array)

ให้ A เป็นอิลิเมนท์ที่เก็บอยู่ในหน่วยความจา

พิมพ์รายการของแต่ละอิลิเมนท์

นับจานวนอิลิเมนท์



ต้องใช้การเข้าถึงข้อมูล คือการเข้าไปติดต่อกับข้อมูล

ในแต่ละอิลิเมนท์









Algorithm 1

LA is a linear array with lower bound LB and upper bound UB. This algorithm traverses

LA applying an operation PROCESS to each element of LA.



[Initialize counter.] Set K := LB.

Repeat Steps 3 and 4 while K 300, then : Set NUM = NUM + 1

[End of loop]

3. Return

Algorithm 2









พิมพ์ปีและจานวนขายทั้งหมด



1. Repeat for K = 1932 to 1984 :

Write : K, AUTO[K]

[End of loop]

2. Return

Algorithm 3









4.3 การแทรกและการลบ

(Inserting and Deleting)

การแทรก  การเพิ่มข้อความ 1 อิลิเมนท์เข้าใน

อาเรย์ A

การลบ  การเอาข้อมูล 1 อิลิเมนท์ออกจากอาเรย์ A









การกาหนดค่าให้กับอิลิเมนท์ในอาเรย์

กาหนด TEST เป็นอาเรย์ขนาด 5 อิลิเมนท์ แต่มีข้อมูลเก็บอยู่เพียง TEST[1], TEST[2],

TEST[3] ถ้า X เป็นค่าอิลิเมนท์ต่อไปของ TEST เราสามารถเพิ่ม X

ลงในอาเรย์ได้โดยใช้การกาหนดค่า

TEST[4] := X

เราสามารถเพิ่ม Y โดยใช้การกาหนดค่า

TEST[5] := Y









ตัวอย่าง

Tom

Smith

John

Davis

Brown

John

Smith

Tom

Brown

Davis

Ford

John

Smith

Taylor

Brown

Davis

Tom

Ford

Ford

John

Smith

Taylor

Tom

Brown

NAME

NAME

NAME

NAME

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

ลบ Davis

เพิ่ม Taylor

เพิ่ม Ford









INSERT(LA, N, K, ITEM)

LA is a linear array with N elements and K is a positive integer such that K= K.

[Move Jth element downward.] Set LA[J+1] := LA[J].

[Decrease counter.] Set J := J-1.

[End of Step 2 loop.]

[Insert element.] Set LA[K] := ITEM.

[Reset N.] Set N := N+1.

Exit.









DELETE(LA, N, K, ITEM)

LA is a linear array with N elements and K is a positive integer such that K = array[l..u] of

Var = array[l..u] of



l  ขอบเขตล่าง

u  ขอบเขตบน



ตัวเลข

ตัวแปรที่กาหนดค่าแล้ว

อักขระ

รูปแบบข้อมูลที่กาหนด









ตัวอย่าง 1

Const min = 1; max = 7;

Type weekday = (mon, tue, wed, thu, fri );

list = array[1..100] of real;

Var week = array[1..5] of weekday;

a = array[0..100] of real;

b = array[min..max] of integer;

c = array[weekday] of 6..8;

ตัวอย่าง 1

list มีสมาชิกคือ

list[1], list[2],…, list[100] เก็บข้อมูลจานวนจริง เช่น list[50] := 45.34

week มีสมาชิกคือ

week[1], week[2],…,week[5] เก็บข้อมูลเดียวกับ weekday เช่น week[3] := wed









ตัวอย่าง 1

a มีสมาชิกคือ a[0], a[1],…,a[100] เก็บข้อมูลเป็นจานวนจริง



b มีสมาชิกคือ b[1], b[2],…,b[7] เก็บข้อมูลเป็นจานวนเต็ม



c มีสมาชิกคือ c[mon], c[tue],…,c[fri] เก็บข้อมูลเป็นเลข 6, 7 หรือ 8 เช่น c[wed] := 7









การกาหนดอาเรย์

5.2 Array 2 มิติ

Type = array[l..u, m..n] of

Var = array[l..u, m..n] of

l และ u เป็นขอบเขตล่างและบนของดัชนนีตัวแรก

m และ n เป็นขอบเขตล่างและบนของดัชนนีตัวที่สอง









ตัวอย่าง 2

Const min = 1; max = 7;

Type weekday = (mon, tue, wed, thu, fri);

list = array[1..2,1..100] of real;

Var a : array[1..7,min..max] of integer;

b : array[min..max,weekday] of real;





ตัวอย่าง 2

list มีสมาชิกคือ

list[1, 1], list[1, 2],…, list[1, 100]

list[2, 1], list[2, 2],…, list[2, 100]

a มีสมาชิกคือ

a[1, 1], a[1, 2],…, a[1, 7]

a[2, 1], a[2, 2],…, a[2, 7]

a[7, 1], a[7, 2],…, a[7, 7]









ตัวอย่าง 2

b มีสมาชิกคือ

b[1, mon], b[1, tue],…, b[1, fri]

b[2, mon], b[2, tue],…, b[2, fri]

b[7, mon], b[7, tue],…, b[7, fri]





ตัวอย่าง 3

Type

Sexno = Array [1..2] of integer;

Year = Array [1..4] of Sexno;

Var a[i, j] ใดๆ สามารถเขียนแทนด้วย a[i][j]

กาหนดให้ a[1, 1] := 30; a[1, 2] := 45;

a[2, 1] := 20; a[2, 2] := 25;

a[3, 1] := 20; a[3, 2] := 22;

a[4, 1] := 18; a[4, 2] := 20;

ตัวอย่าง 3

อาเรย์ 2 มิติแสดงได้ดังนี้









Type Year = APPARR[1..4, 1..2] of integer;

Var a : Year;

30

45

20

25

20

22

18

20









การกาหนดตัวแปรสาหรับข้อความ

Var name : array[1..30] of char;

หรือ

Var name : string[30]









ตัวอย่าง 4

โปรแกรมหาผลรวมแต่ละแถว แต่ละหลักของเมตริกซ์ขนาด 5 * 5

Program row_col_sum(input, output);

Type matrix = array[1..5,1..5] of integer;

Var a : matrix

row,col : array[1..5] of integer;

i, j : integer;









Begin for i = 1 to 5 do begin row[i] := 0;

col[i] := 0 end;

writeln(‘input matrix A’);

for i := 1 to 5 do

for j := 1 to 5 do readln(a[i, j]);

for i := 1 to 5 do

for j := 1 to 5 do row[i] := row[i]+a[i,j];

for j := 1 to 5 do

for i := 1 to 5 do col[j] := col[j]+a[i,j];

for i := 1 to 5 do

begin for j := 1 to 5 do write(a[i, j]);

writeln(row[i])

end;

for j := 1 to 5 do write(col[j], ‘ ‘)

End.









The END









โค

รงสร้างข้อมูลและขั้นตอนวิธี

บทที่ 3

โครงสร้างข้อมูลสตริงและเรคคอร์ด

โครงสร้างข้อมูลสตริง





สตริงเป็นโครงสร้างข้อมูลที่เป็นการรวบรวมโครงสร้างข้อมูลคาร์แรคเตอร์

(Character) ซึ่งเป็นตัวอักษรและสัญลักษณ์ (Symbol) ต่าง

ๆ เป็นชนิดข้อมูลที่ถูกใช้งานมากชนิดหนึ่ง ภาษาเขียนโปรแกรมหลายภาษาจะกาหนดใ

ห้มาใช้งานได้ทันที เช่น ภาษาปาสคาล แต่บางภาษาไม่มีมาให้ เช่น ภาษาซี

จะต้องสร้างขึ้นมาด้วยผู้เขียนโปรแกรม

โดยนาโครงสร้างอาร์เรย์มาใช้และสมาชิกทุกตัวมีโครงสร้างข้อมูลคาร์แรคเตอร์ได้ชนิดเดี

ยว ดังในรูปที่ 3.1 เป็นสตริงที่มีตัวอักษรต่อเป็นข้อความ



D a t a S t r u c t u r e s &

รูปที่ 3.1 ตัวอย่างโครงสร้างข้อมูลสตริงในรูปแบบของอาร์เรย์



การกาหนดสตริง

รูปแบบการกาหนดสตริงเป็นการนาเอาอักษรพยัญชนะ (Alphabet) มรารว

บรวม ดังนี้

S = ‘a1a2 . . . aN’



โดยตัวอักษร a1 เป็นสมาชิกของอักษรพยัญชนะ และ 1 ≤ i≤ N

เป็นการสร้างสตริงชื่อ S ที่มีความยาวเท่ากับ N ตัวอักษร

และการกาหนดค่าให้แต่ละสมาชิกจะเป็นแบบเดียวกับการใช้ในอาร์เรย์ ทาให้การใช้งา

นไม่สะดวกเมื่อต้องใช้งานบ่อย ๆ จึงมีการกาหนดชุดปฏิบัติการพื้นฐาน (Operator) เ

พื่อจัดการกับสตริง ดังนี้



ความยาวสตริง (String Length) เป็นการบอกให้ทราบว่าสตริงตัวนั้นมีตัวอักษรหรือ คว

ามยาวเท่าไร จะกาหนดเป็นฟังก์ชัน Length ที่ส่งค่าความยาวกลับมาให้ ดังนี้

N = Length (S) ;



ค่าที่ส่งกลับมาเท่ากับ N

รวมสตริง (String Concatenation) เป็นการนา 2 สตริงมารวมกันเป็นสตริงเดีย

ว โดยนาตัวอักษรทั้งหมดของสตริงตัวหลังไปต่อท้ายสตริงตัวแรก กาหนดเป็นฟังก์ชัน

Concate ดังนี้



Concate (S, S1);



โดย S1 = ‘b1b2 . . . bN’ จะได้ S = ‘a1a2 . . . aNb1b2 . . . bN’

สตริงย่อย (Substring) เป็นการคัดลอกตัวอักษรที่อยู่ติดกับบางส่วนของสตริงตัว

ที่สองให้กับสตริงตัวแรก

แต่ต้องทราบว่าสตริงย่อยที่ต้องการคัดลอกมีตาแหน่งเริ่มต้นและสิ้นสุดที่ไหน โดยกาหน

ดเป็นฟังก์ชัน SubStr ดังนี้



Substr (S , S1 , i , j);



โดย i ตาแหน่งเริ่มต้น และ o

#include

int Length( char * s) {

int i ;

for( i = 0; s[i] ; i++ );

return i ;

}

void Concate( char* ds, char* ss ) {

int i , j ;

for( i = 0; ds[i]; i++ );

for( j = 0; ss[j]; j++ )

ds [i++] = ss[j];

ds[i] = ‘\0’;

}

void SubStr( char* ds, char* ss, int pos, int len ) {

int i = 0;

pos - -;

for( ; i

#include

#include

struct Enployee {

int ID;

char Name[80];

char Phone[80];

float Salary;

};

void printRecord( struct Employee e ) {

printf( ‚ID-number Number Phone Salary\n‛ );

printf( ‚%-10d %-20s %-12s %-8.2f\n‛, e.ID, e.Name, e.Phone, e.Salary );

}

main() {

struct Employee emp1;

int id;

char name[80];

char phone[80];

float salary;

printf( ‚Employee Records: \n‛ );

printf( ‚Enter ID-number: ‚ );

scanf( ‚%d‛ , &id );

emp1.ID = id;

getchar();

printf( ‚Enter name: ‚);

gets( name );

strcpy(emp1.Name,name);



printf( ‚Enter phone: ‚);

scanf( ‚%s‛, phone );

strcpy( emp1.Phone,phone );

printf( ‚Enter salary: ‚);

scanf( ‚%f‛, &salary );

emp1.Salary = salary;

printf( ‚\nValue in record is\n‛ );

printRecord( emp1 );

getch();



เป็นการเก็บข้อมูลพนักงานในรูปแบบเรคคอร์ดที่ชื่อ emp1 โดยมีการกาหนดชนิดของเ

รคคอร์ดที่จะใช้งาน ซึ่งประกอบด้วยเขตข้อมูลที่เก็บค่ารหัส ชื่อ หมายเลขโทรศัพท์ แ

ละเงินเดือน ดังนี้

Struct Employee {

Int ID;

char Name[80];

char Phone[80];

float Salary;

};

ภาษาซีใช้คา Struct หมายถึง โครงสร้างข้อมูลเรคคอร์ด ตามด้วยชื่อของโ

ครงสร้างข้อมูล จากนั้นตามด้วยชื่อสมาชิกแต่ละตัวพร้อมกับกาหนดโครงสร้างข้อมูลให้

แต่ละตัว เมื่อใช้งานต้องประกาศสร้างตัวแปรเรคคอร์ด emp1 ดังนี้

Struct Employee emp1;

เมื่อใดที่ต้องการเก็บข้อมูลหรือดึงข้อมูลมาใช้งานจะเป็นดังนี้

emp1.ID

emp1.Name

emp1.Phone

emp1.Salary



จากตัวอย่างมีการเขียนฟังก์ชัน printRecord เป็นตัวปฏิบัติการของเรคคอร์

ด ทาหน้าที่ในการแสดงผลทางจอภาพเป็นแบบตาราง เมื่อใดที่มีการประกาศตัวแปรเร

คคอร์ดใหม่มาใช้งาน ตัวแปรทุกตัวก็สามารถใช้ตัวปฏิบัติการร่วมกันได้

โดยทั่วไปการใช้โครงสร้างข้อมูลเรคคอร์ดจะไม่ใช้เพียงเรคคอร์ดเดียว แต่จ

ะใช้หลาย ๆ เรคคอร์ดเพื่อเก็บข้อมูลที่มีลักษณะแบบเดียวกันเป็นจานวนมาก

ๆ ที่เรียกว่าฐานข้อมูล (Database) วิธีการหนึ่งที่นามาใช้คือ กาหนดเป็นอาร์เรย์ให้แต่

ละสมาชิกมีโครงสร้างข้อมูลเรคคอร์ด แต่มีข้อจากัดี่จานนสมาชิกคงที่เปลี่ยนแปลงไม่ได้

มีอีกวิธีการหนึ่ง คือ กาหนดเป็นแบบไดนามิก (Dynamic) โดยการขอพื้นที่ในหน่วยค

วามจาให้กับโครงสร้างข้อมูลเรคคอร์ดเมื่อต้องการใช้งาน

และไม่จากัดจานวนเรคคอร์ดจนกว่าหน่วยความจาเต็ม แต่การเขียนโปรแกรมก็จะซับซ้

อนมากขึ้น ดังตารางที่ 3.3 เป็นตัวอย่างโปรแกรม Record2.c



ตารางที่ 3.3 ตัวอย่างโปรแกรม Record2.c

#include

#include

#include

#include

struct employee {

int ID;

char Name[80];

char Phone[80];

floar Salary;

};

typedef struct employee Employee;

typedef Employee* Employees;

Employees createEmployee() {

Employees e = malloc( sizeof (Employee) );

Return e;

}

void printEmployee( Employees e ) {

printf( ‚%-10d %-20s %-12s %-8.2f\n‛, e-›ID, e-›Name, e-›Phone, e-›Salary );

}

main() {

Employees emp1 = createEmployee();

Employees emp2 = createEmployee();

emp1 -›ID = 1101;

strcpy( emp1-›Name, ‚Sinsamut‛ );

strcpy( emp1-›Phone, ‚123456789‛ );

emp1 -›Salary = 12345.00;

emp2 -›ID = 2041;

strcpy( emp2-›Name, ‚Sudsakorn‛ );

strcpu( emp2-›Phone, ‚987654321‛);

emp2-›Salary = (float)54321.975;

printf( ‚Employee Records\n‛ );

printf( ‚ID – number Name Phone Salary\n‛ );

printEmployee( emp1 );

printEmployee( emp2 );

getch();

}



จากตัวอย่าเป็นการกาหนดโครงสร้างข้อมูลชื่อใหม่ (Alias) คือ Employee แ

ละ Employees ที่เป็นพอยน์เตอร์โดยมีลักษณะเป็นโครงสร้างข้อมูลเรคคอร์ด ดังนี้

typedef struct employee Employee;

typedef struct Employee* Employees;

เมื่อต้องการใช้งานจะต้องขอพื้นที่หน่วยความจาใช้งานให้กับแต่ละเรคคอร์ดในฟั

งก์ชัน createEmployee ดังนี้

Eployees e = malloc ( sizeof (Employees) );



เนื่องจากการเก็บข้อมูลของเรคคอร์ดจะนาไปไว้ในพื้นที่หน่วยความจาที่ขอไว้ ใน

การอ้างแต่ละสมาชิกในแบบเดิมที่ใช้เครื่องหมายมหัพภาค จึงต้องเปลี่ยนมาเป็นเครื่อง

หมายลูกศร(->) ดังนี้

emp1 -› ID

emp1 -› Name

emp1 -› Phone

emp1 -› Salary

ในการกาหนดโครงสร้างข้อมูลที่เป็นแบบไดนามิกช่วยให้การเขียนโปรแกรม

มีความยืดหยุ่นสูง แต่มีความซับซ้อนขึ้นและผู้เขียนโปรแกรมจะต้องคอยจัดการด้วยตนเ

อง และเป็นรูปแบบพื้นฐานที่จะนาไปใช้กับโครงสร้างข้อมูลแบบอื่น ๆ ต่อไป

โครงสร้างข้อมูลและขั้นตอนวิธี

บทที่ 4

โครงสร้างข้อมูลสแตก

โครงสร้างสแตก





โครงสร้างสแตกข้อมูลที่รู้จักและนามาใช้งานชนิดหนึ่งก็คือ สแตก (Stack)

มีลักษณะเป็นรายการในแนวเชิงเส้น (Linear List) รูปแบบหนึ่ง

และมีข้อกาหนดให้ชุดปฏิบัติการ สามารถเพิ่มและลบรายการเพียงด้านเดียว

ซึ่งเป็นด้านบนสุดของสแตก (Top of Stack)

เรียกว่าตัวชี้สแตก (Stack Pointer) มีรูปแบบเป็น

(Top)(S)โดยสแตกมีการกาหนดเป็นรูปแบบดังนี้

S = [s1 ,S2, … ,ST]

ด้านบนสุดของสแตกจะอยู่ที่ Top (S) =ST และมีจานวนสมาชิกในสแตกเท่ากับ T

ดังในรูปที่ 4.1



ST



S2

S1 รูปที่ 4.1 ตัวอย่างลักษณะสแตกที่มีสมาชิกเท่ากับ T มีตัวชี้สแตก Top

สแตกมีลักษณะเดียวกับที่วางจานหรือถาดในร้านอาหาร ดังในรูปที่ 4.2

ที่มีสปริงอยู่ด้านล่างและมีจานวางซ้อนเป็นขั้น ๆ จะมีเพียงจานที่อยู่บนหยิบออกไปได้

สแตกถูกนามาใช้แก้ไขปัญหาต่าง ๆ ดังต่อไปนี้



รูปที่ 4.2 ลักษณะที่วางจานหรือถาดที่เป็นแบบเดียวกับสแตก





ปัญหาที่ 1 เนืองจากคอมพิวเตอร์ทางานในรูปแบบของเลขฐาน 2

แต่ในส่วนของผู้ใช้งานจะเป็นเลขฐาน 10 จึงต้องแปลงค่าจากเลขฐาน 10 ไปเป็นเลขฐาน

2 เช่น เปลี่ยนจาก 26 เป็น 11010

ปัญหาที่ 2 คอมไพเลอร์ (Compiler) จะต้องคานวณนิพจน์ (Expression)

ทางคณิตศาสตร์ที่มีเครี่องหมายวงเล็บเปิดและปิดเข้ามาเกี่ยวข้อง

ปัญหาที่ 3 โปรแกรมเกมเล่นไพ่ (Card Game)

จะมีที่วางกองไพ่และการแจกไพ่ได้เฉพาะใบที่อยู่บนสุด

ปัญหาที่ 4 รูปแบบปัญหาการทางานบางอย่าง เช่น การทางานของ Switching Box

ของเครือข่าย หรือรูปแบบการสลับตู้รถไฟบนราง ดังในรูปที่ 4.3



รูปที่ 4.3 ตัวอย่างการใช้สแตกแก้ปัญหาการสลับตู้รถไฟบนราง

ปัญหาต่าง

ๆ เหล่านี้สามารถแก้ไขโดยใช้โครงสร้างสแตก ซึ่งมีลักษณะการทางานในรูปแบบที่เรียก

ว่าเข้าทีหลังออกก่อน (Last-In-First-Out, LIFO)

เมื่อมีค่าใหม่เข้ามาก็จะใส่ลงในสแตกซ้อนทับค่าเดิมที่เก็บอยู่ลงไปอยู่ด้านล่างไปเรื่อย ๆ

ในลักษณะแบบนี้

การปฏิบัติการของสแตก

จากลักษณะดังที่กล่างมาของสแตก จะต้องมีการปฏิบัติการเข้ามาช่วยการ

ทางานของสแตกให้มีความถูกต้อง

CreateStack( ) ใช้สร้างสแตกใหม่ขึ้นมาใช้งานและกาหนดค่าเริ่มต้นต่าง ๆ

Push(value, stack) ใช้เพิ่มค่าใหม่เก็บลงในสแตกที่ใช้งานอยู่ มีอัลกอริทึมการทางานเป็

นดังในตารางที่ 4.1

ตารางที่ 4.1 อัลกอริทึมการเพิ่มค่าใหม่เก็บลงในสแตก

1. ตรวจสอบสแตกว่าจะมีสมาชิกอยู่เต็มหรือไม่ โดยเปรียบเทียบค่า Top กับขนาดอาร์เรย์

2. ถ้าสแตกไม่เต็ม

2.1 เพิ่มค่าให้กับ Top โดยการบวก 1

2.2 ทาการนาค่าที่ได้มาเก็บลงในสแตกในตาแหน่ง Top

ไม่เช่นนั้นแจ้งกลับมาว่าสแตกเต็ม

3. Pop(stack) ใช้ดึงค่าออกจากสแตกที่ใช้งานอยู่และส่งค่า value กลับมาให้

มีอัลกอริทึมการ ทางานเป็นดังในตารางที่ 4.2





ตารางที่ 4.2 อัลกอริทึมดึงค่าออกจากสแตก

1. ตรวจสอบว่าสแตกว่างหรือไม่ โดยเปรียบเทียบค่า Top กับขนาดอาร์เรย์

2. ถ้าสแตกไม่ว่าง

1. ทาการดึงค่าในตาแหน่ง Top ออกมาให้

2. ลดค่าของ Top โดยการลบ 1 ไม่เช่นนั้นแจ้งกลับมาว่าสแตกว่าง



3. isEmpty(stack) ใช้ตรวจสอบว่าสแตกที่ใช้งานอยู่ว่างหรือไม่ ถ้าไม่มีค่าเก็บไว้เลยจะส่งค่าจริงกลับให้

เมื่อนาสแตกมาใช้งานตามลาดับดังในรูป (a) ถึง (g)

มีการทางานโดยใช้ชุดปฏิบัติการ Push และ Pop ดังนี้

เริ่มต้นสร้างสแตก S ขึ้นมาทางานจะได้เป็นสแตกว่าง ไม่มีสมาชิกโดยตัวชึ้สแตก Top

ยังไม่มีค่า



นาค่า A เข้ามาเก็บเป็นตัวแรกโดยใช้ Push(A) สแตก S = [A] ตัวชี้สแตก Top = A



นาค่า B เก็บต่อโดยใช้ Push(B) สแตก S = [A,B] ตัวชี้สแตก Top = B



(d)นาค่า C เก็บต่อโดยใช้ Push(C) สแตก S = [A,B,C]ตัวชี้สแตก Top =C



1 ต้องการดึงค่าออกมาโดยใช้ Pop( ) สแตก S = [A,B] ตัวชี้สแตกTop = B



(f) นาค่า D, E เก็บต่อโดยใช้ Push(D) และ Push(E) ตามลาดับ สแตก

S = [A,B,D,E] ตัวชี้สแตก Top = E

(g) ดึงค่าออกมา 3 ค่าโดยใช้ Pop( ) 3 ครั้งและเก็บค่า F โดยใช้ Push(F) สแตก S =

[A,F] ตัวชี้สแตก Top = F

จะเห็นว่าการทางานของสแตกเมื่อมีค่าใดส่งเข้ามาเก็บเป็นตัวสุดท้ายก็จะอยู่บนสุ

ด ค่าที่ใส่ลงมาก่อนหน้านี้ก็จะถูกซ้อนทับตามลาดับ หากมีการดึงค่าออกมาใช้ค่าที่อยู่บ

นสุดจะถูกดึงออกมาก่อน ลักษณะที่ได้จึงเป็นการกลับกันของลาดับการใช้งานและเรียก

ว่าเข้าทีหลังออกก่อน



ตัวอย่างการใช้สแตก

จากปัญหาในตอนต้นกล่าวถึงปัญหาการเปลี่ยนเลขฐาน 10 เป็นเลขฐาน 2

เนื่องจากการคานวณเป็นการหารเลขฐาน 10 เศษที่เหลือจะได้เป็นเลขฐาน 2 เมื่อ

นามาแสดงผลจะเป็นตัวเลขจากซ้ายไปขวา แต่เลขฐาน 2 เป็นตัวเลขจากขวาไปซ้ายจึง

เกิดการสลับด้านกัน จึงนาสแตกมาช่วยแก้ปัญหานี้ ดังในตารางที่ 4.3 คือ โปรแกรม

Stack.c

ตารางที่ 4.3 ตัวอย่างโปรแกรม Stack.c



เป็นการสร้างสแตกขึ้นมาโดยใช้โครงสร้างข้อมูลเรคคอร์ด และสร้างชุดปฏิ

บัติการให้กับสแตกขึ้นมาสาหนับเรียกใช้งานเพื่อแก้ใขการเปลี่ยนเลขฐาน 10 เป็นเลขฐ

าน 2 จากค่าที่ได้รับเข้าทางคีย์บอร์ด สแตกทีได้เป็นแบบไดนามิกคือขอใช้พื้นที่หน่วยค

วามจาให้กับสแตกตอนที่โปรแกรมทางาน ทาให้มีสแตกได้หลายตัวมาใช้งานพร้อมกันโ

ดยที่ใช้ชุดปฏิบัติการเดียวกันจากตัวอย่างจะใช้สแตกเพียวตัวเดียว

การใช้สแตกแก้ปัญหาการแปลงนิพจน์คณิตศาสตร์

คอมไพเลอร์จะแปลงคาสั่งจากภาษาระดับสูง (High-

level Language) ไปเป็นภาษาเครื่อง (Machine Language)

ส่วนหนึ่งที่ต้องแปลงคือนิพจน์คณิตศาสตร์ เช่น X = A * B + C

ซึ่งมีลักษณะที่เรียกว่า Infix Notation มีเครื่องหมายคานวณอยู่ระหว่างโอเปอแร้น

(Operand) โดยแปลงไปเป็นนิพจน์แบบ Postfix Notation

มีเครื่องหมายคานวณนาหน้าโอเปอแร้น แต่เนื่องจากนิพจน์แบบ Infix

มีการนาเครื่องหมายวงเล็บเข้ามาใช้ทาให้ทิศทางการคานวณเปลี่ยนไป ดังในตารางที่

4.4 เป็นตัวอย่างของการคานวณแบบเดียวกัน



ตารางที่ 4.4 ลักษณะนิพจน์แบบ Infix, Postfix, และ Prefix Notation

Postfix Prefix

Infix

A+(B*C) ABC*+ +A*BC

(A+B)*C AB+C* *+ABC

A+B-C AB+C- -+ABC

(A+B)*(C-D) AB+CD-* *+AB-CD

(A+B)*C-(D-E) ) $ (F+G) AB+C*DE—FG+$ $-*+ABC-DE+FG

การแปลงนิพจน์แบบ Infix เป็นแบบ Postfix

เมื่อพิจารณาการแปลงนิพจน์แบบ Infix เป็นแบบ Postfix

เป็นขั้นตอนการแปลงโดยเริ่มต้นจากสแกนนิพจน์ Infix

ทีละตัว หากพบวงเล็บก็จะทาส่วนที่อยู่ในวงเล็บให้เสร็จก่อนเป็นนิพจน์ย่อย

(Subexpression) ซึ่งจะได้เป็นอัลกอริทึมดังในตารางที่ 4.5

ตารางที่ 4.5 อัลกอริทึมการแปลงนิพจน์แบบ Infix เป็นแบบ Postfix

1. สร้างสแตกที่ว่างเปล่ายังไม่มีการเก็บค่า

2. ถ้าค่าในนิพจน์ Infix ยังไม่หมด หรือเกิดข้อผิดพลาด ให้ทาดังนี้



1. รับค่า (Token) ตัวถัดไปในนิพจน์ Infix (ประกอบด้วย ค่าคงที่ ตัวแปร

เครื่องหมายคานวณ วงเล็บเปิดและปิด

2. ค่าที่รับเข้ามา ถ้าเป็น



b.1 โอเปอแร้น (ค่าคงที่,ตัวแปร) นาไปแสดงทางจอภาพ

b.2 วงเล็บเปิด ให้นาใส่ลงในสแตก (Push)

b.3 วงเล็บปิด ดึงค่าออกจากสแตก (Pop)

และนาไปแสดงทาง จอภาพ ทาจนกว่าจะพบวงเล็บเปิด

b.4 เครื่องหมายคานวณ ถ้าสแตกว่าง หรือค่าที่รับมามี

Precedence สูงกว่าค่าบนสแตกให้นาใส่ลงในสแตก (Push) ถ้าหากค่าที่รับมามี Precedence

น้อยกว่าค่าบนสแตกให้ดึงค่าออกจากสแตก (Pop)

3. เมื่อทาจนค่าในนิพจน์ Infix หมด ให้ดึงค่าออกจากสแตก (Pop)

แสดงทางจอภาพตามลาดับ จนกว่าสแตกว่าง

จากอัลกอริทึมดังกล่าวเมื่อนามาใช้กับตัวอย่างนิพจน์ 7*8-(2+3)

จะได้เป็นลาดับขั้นตอนดังในรูปที่ 4.4 หรือเขียนเป็นแบบตารางได้ดังในตารางที่ 4.6









ตารางที่ 4.6 การแปลงนิพจน์ 7*8-(2+3) เป็นนิพจน์ Postfix

สแตก นิพจน์ Postfix

นิพจน์ Infix

7*8-(2+3) 7

*8-(2+3)

8-(2+3) * 78

-(2+3) 78*

-

(2+3)

-( 7 8 *2

2+3)

+3) 1. ( + 7 8 *2 3

3)

/ 8 *2 3 +

)

78*23+-

-

การหาค่าคาตอบจากการคานวณนิพจน์ Postfix

จากการแปลงนิพจน์แบบ Infix เป็นแบบ Postfix

ี่

ทาให้นิพจน์ทได้ไม่มีเครื่องหมายวงเล็บ ต่อจากนั้นจะทาการหาค่าคาตอบโดยสแกนนิพ

จน์ Postfix ทีละตัวจากซ้ายไปขวา

เมื่อใดที่พบโอเปอแร้นก็นาเก็บลงในสแตก สุดท้ายคาตอบที่ได้จะอยู่ในสแตกเพียงค่าเดี

ยวซึ่งจะได้เป็นอัลกอริทึมดังในตารางที่ 4.7

ตารางที่ 4.7 อัลกอริทึมการหาค่าคาตอบจากนิพจน์ Postfix

1. สร้างสแตกที่ว่างเปล่ายังไม่มีการเก็บค่า

2. ทางานต่อไปนี้ซ้าจนกว่าถึงจุดสิ้นสุดของนิพจน์

1. รับค่า (Token) ตัวถัดไปในนิพจน์ RPN

(ประกอยด้วย ค่าคงที่ ตัวแปร เครื่องหมายคานวณ)

2. ค่าที่รับเข้ามา ถ้าเป็นโอเปอแร้น ให้นาใส่ลงในสแตก (Push)

แต่ถ้าเป็นเครื่องหมายคานวณให้ทาดังนี้



b.1 ดึงค่าออกจากสแตก (Pop) สองค่า ถ้าไม่ครบให้แจ้งเกิดข้อผิดพลาด

b.2 นาเครื่องหมายคานวณทาการประมวลผลกับค่าทั้งสอง

b.3 นาผลลัพธ์ที่ได้ใส่กลับลงในสแตก (Push)

3. เมื่อถึงจุดสิ้นสุดของนิพจน์ ค่าที่เป็นคาตอบจะอยู่บนสแตก

ซึ่งมีเพียงค่าเดียวเท่านั้น

จากอัลกอริทึมดังกล่างเมื่อนามาใช้กับตัวอย่างนิพจน์ 2 4 *9 5 + -

จะเป็นตามลาดับขั้นตอนดังในรูปที่ 4.5 หรือเขียนเป็ฯแบบตารางได้ดังในตารางที่ 4.8





ตารางที่ 4.8 การหาค่าคาตอบจากนิพจน์

ค่าที่ได้ สแตก

นิพจน์ Postfix

24*95+- 2

4+95+- 24

*95+- 2*4=8 8

95+- 89

5+- 895

+- 9 + 5 = 14 8 14

- 8 – 14 = -6 -6

-6

บทที่ 5



โครงสร้างข้อมูลแบบคิว (Queue)







คิวเป็นโครงสร้างข้อมูลแบบหนึ่งซึ่งมีลักษณะที่ว่า

ข้อมูลที่นาเข้าไปเก็บก่อนจะถูกนาออกมาทางานก่อน

ส่วนข้อมูลที่เข้าไปเก็บทีหลังก็จะถูกนาออกมาใช้งานทีหลัง ขึ้นอยู่กับลาดับการเก็บข้อมูล

จะเรียกลักษณะการทางานแบบนี้ว่า เข้าก่อนออกก่อน หรือ First In First Out (FIFO)

โครงสร้างข้อมูลแบบนี้เป็นโครงสร้างที่ปรากฏอยู่โดยทั่วๆ ไป

โดยเฉพาะอย่างยิ่งในระบบปฏิบัติการคอมพิวเตอร์ ในระบบคมนาคม

รวมทั้งในระบบการทดลองดาวเทียมด้วย

ลักษณะของโครงสร้างแบบคิวจะเหมือนกับการเข้าแถวรอคอย

ไม่ว่าจะเป็นการรอคอยอะไรก็ตาม หรือจะเรียกสั้นๆ ว่า เข้าคิวก็ได้

ด้วยคุณสมบัติที่เด่นชัดของการทางานของโครงสร้างข้อมูลแบบคิวนี้

ว่าสิ่งใดที่เข้าก่อนย่อมต้องได้รับการทางานก่อน เช่น การสั่งพิมพ์งานพร้อมกันหลายๆ

คน โดยใช้เครื่องพิมพ์เครื่องเดียวกัน

ทาให้ระบบจะต้องมีการจัดระบบให้มีการเข้าคิวรอคอยการทางาน

ถ้าใครสั่งพิมพ์ก่อนก็จะเข้าคิวไปรอการพิมพ์ในลาดับแรก

ใครสั่งเป็นคนต่อไปก็จะต้องเข้าคิวรอจนกว่างานแรกจะทาการพิมพ์เสร็จ

จึงจะมาทางานกับคิวที่รออยู่ต่อไป

การนาข้อมูลสู่คิว จะเหมือนกับการยืนต่อแถวคอยอยู่

5 4 8 9 1 2 3 6 0



154 254 854 621 854 265 168



78 48 54 68 11 99 14 67 89



การสร้างคิว (Queue)

คิวที่อยู่ในคอมพิวเตอร์สามารถจัดเก็บได้หลายลักษณะ

แต่โดยทั่วไปแล้วจะใช้การจัดเก็บแบบลิงค์ลิสท์เดี่ยวหรือจัดเก็บโดยใช้อาร์เรย์

ก่อนที่จะทาการสร้างคิวจะต้องทาความเข้าใจถึงโครงสร้างของคิว ซึ่งประกอบไปด้วย

ตัวคิว ซึ่งในที่นี้ขอแทนด้วยอาร์เรย์ และจะต้องมีตัวชี้อีก 2 ตัว ได้แก่ ตัวชี้ F (Front

Pointer) ชี้ไปที่สมาชิกตัวแรก และตัวชี้ R (Rear Pointer) ชี้ไปที่สมาชิกตัวสุดท้ายของคิว

โดยที่เวลาข้อมูลจะเข้าสู่คิวจะเข้าทาง R ส่วนเวลาที่ข้อมูลจะออกจากคิวจะออกทาง F

5 4 8 9 1 2 3 6 0



154 254 854 621 854 265 168



78 48 54 68 11 99 14 67 89





F (Front Pointer) R (Rear Pointer)



เมื่อเริ่มต้นสร้างคิว คิวนั้นไม่มีค่าใดๆ ยังว่างเปล่า F และ R จะมีค่าเป็น 0 ทั้งคู่

คือไม่ได้ชี้ไปที่สมาชิกตัวใด การนาข้อมูลเข้าสู่คิวเรียกว่า การ Insertion

ส่วนการนาข้อมูลออกจากคิวเรียกว่า การ Deletion

การ Insertion

เป็นการนาข้อมูลเข้าสู่คิว โดยการที่จะนาข้อมูลเข้าสู่คิวนั้นจะแบ่งออกเป็น 2 กรณี

คือ

1. การนาข้อมูลเข้าไปในคิวว่าง โดยจะต้องดาเนินการให้พอยน์เตอร์ทั้ง 2 คือ F และ

R ชี้ไปยังช่องแรกหรือตาแหน่งที่จะเก็บข้อมูลแรก

2. การนาข้อมูลเข้าไปในคิวต่อจากข้อมูลเดิม จะต้องจัดการให้พอยน์เตอร์ R

ชี้ไปยังช่องหรือตาแหน่งของข้อมูลที่นาเข้าไป ส่วนพอยน์เตอร์ F

ยังคงชี้ไปยังช่องหรือตาแหน่งของข้อมูลที่นาเข้าไปเป็นข้อมูลแรก

จากการ Insertion ข้อมูลเข้าไปในคิวแล้ว ถ้าหากทาการ Insertion

ข้อมูลจนพอยน์เตอร์ R อยู่ที่ช่องสุดท้ายแล้ว จะไม่สามารถทาการ Insertion

ข้อมูลลงคิวได้อีก เนื่องจากตัวที่เก็บข้อมูลคิวเต็มทาให้ไม่สามารถที่จะรับข้อมูลอื่นๆ

อีกได้ ฉะนั้นจะเกิด Error ขึ้น ซึ่ง Error นี้เรียกว่า Overflow ขึ้น เช่น ถ้าจอง Array ขนาด 3

ช่องชื่อ Q

1. เมื่อคิวว่าง (Empty Queue)



0 1 2 3

F=0 R=0



0 1 2 3



2. INSERT (Q , A)







A



F=1 R=1



3. INSERT (Q , A)



0 1 2 3







A B



F=1 R=2



0 1 2 3



4. INSERT (Q , C)







A B C



F=1 R=3



หลังจากนี้จะเพิ่มข้อมูลเข้าคิวอีกไม่ได้ เนื่องจากคิวเต็มคือ R = 3

ALGORITHM QINSERT

ใช้ในการแทรกข้อมูลเข้าคิว โดยที่

F แทน ตัวชี้ต้นคิว

R แทน ตัวชี้ท้ายคิว

N แทน ขนาดของคิว

X แทน ข้อมูลที่จะแทรก

1. [ ตรวจสอบ Overflow ]



IF R = N THEN



PRINT ‚QUEUE OVERFLOW‛



EXIT



ENDIF



2. [ เพิ่มค่า R ]



R = R+1



3. [ แทรกข้อมูลเข้าคิว ]



Q( R ) = X



4. [ กรณีเป็นสมาชิกตัวแรก ]



IF F = 0 THEN



F = 1



ENDIF



5. [ จบการทางาน ]



EXIT

การ Deletion

เป็นการนาข้อมูลที่เก็บอยู่ในคิวออกจากคิว โดยการเมื่อทาการ Deletion

ข้อมูลนั้นออกจากคิวแล้ว จะต้องมีการจัดการให้ตัวชี้คิว F

ชี้ไปยังช่องหรือตาแหน่งต่อจากข้อมูลที่จะได้ทาการ Deletion ไปแล้ว ส่วนพอยน์เตอร์ R

ชี้ไปยังช่องข้อมูลสุดท้ายเหมือนเดิม

การ Deletion

ข้อมูลนี้จะทาการนาข้อมูลในส่วนของข้อมูลตัวแรกสุดที่เข้าสู่คิวออกไปทางานตามต้องก

าร แต่การ Deletion ข้อมูลนี้จะไม่สามารถ Deletion

ข้อมูลออกจากคิวที่ว่างเปล่าหรือไม่มีข้อมูลได้ (F = 0) ถ้าเกิดกรณีเช่นนี้จะเกิด Error

ที่เรียกว่า Underflow ขึ้น ฉะนั้นก่อนที่จะทาการ Deletion

ควรที่จะต้องมีการตรวจสอบว่าคิวว่างหรือไม่ เพื่อไม่ให้เกิด Error นี้ขึ้น



จากตัวอย่างข้างบน เมื่อทาการ Deletion



5. DELETE (Q)



0 1 2 3







B C



F=2 R=3



6. DELETE (Q)



0 1 2 3



C



F=3 R=3



7. DELETE (Q)



0 1 2 3

F=0 R=0



หลังจากนี้จะทา DELETE (Q) อีกไม่ได้ เนื่องจาก Q ว่าง คือ F = 0

พิจารณาจากขั้นตอนทั้ง 7 ขั้นต้น สรุปได้ว่า



1. การเพิ่มข้อมูลเข้า ซึ่งต้องเข้าที่ REAR ของคิว ต้องเพิ่มค่า R

ที่เป็นตัวชี้สมาชิกตัวสุดท้ายของคิวอีก 1 เพื่อให้ชี้เนื้อที่ถัดไป

สาหรับเตรียมให้นาข้อมูลมาใช้

2. การนาข้อมูลออกจากคิว ทาที่ FRONT ของคิว ซึ่ง F

ชี้สมาชิกตัวแรกของคิวอยู่แล้ว ดังนั้น จึงนาข้อมูลที่ F ชี้อยู่ออกได้เลย

หลังจากนั้นเปลี่ยนให้ F ไปชี้สมาชิกตัวถัดไป โดยเพิ่มค่า F อีก 1

จากข้อสรุป 2 ข้อนี้ เป็นเพียงข้อสรุปที่เป็นกรณีทั่ว ๆ ไป ยังมีกรณีพิเศษอีก 2

กรณี คือ

3. (ให้พิจาณาขั้นตอนที่ 1 และ 2) คือเมื่อเพิ่มข้อมูลเข้าคิวที่ว่างอยู่ต้องเซตค่า

FRONT ที่แต่เดิมชี้ที่ศูนย์ ให้ชี้ที่ 1 ด้วย เพื่อให้ F ชี้ที่สมาชิกแรกของคิว

4. (ให้พิจาณาขั้นตอนที่ 6 และ 7)

คือเมื่อทาการนาข้อมูลออกจากคิวในขณะที่ในคิวนั้นมีสมาชิกเดียว

หลังจากนาข้อมูลออกแล้วก็หมายความว่าคิวต้องว่าง ดังนั้นจึงต้องเซตค่า F

ให้ไปชี้ที่ศูนย์

ALGORITHM QDELETE

ใช้ในการลบข้อมูลออกจากคิว โดยที่

F แทน ตัวชี้ต้นคิว

R แทน ตัวชี้ท้ายคิว

Y แทน เก็บค่าข้อมูลที่จะลบออกจากคิว



1. [ ตรวจสอบ Underflow ]



IF F = 0 THEN



PRINT ‚QUEUE UNDERFLOW‛



EXIT



ENDIF

2. [ เก็บข้อมูลตัวที่จะลบไว้ที่ Y ]



Y = Q(F)



3. [ ปรับค่า F หรือ R ]



IF F = R THEN



F = R = 0



ELSE



F = F+1



ENDIF



4. [ จบการทางาน ]



EXIT





เซอร์คูล่าคิว (Circular Queue)



1 N



C



F R



จากรูปข้างต้น ในคิวมีเพียงสมาชิกเดียว แต่ R ชี้เนื้อที่สุดท้ายของคิว

ในลักษณะนี้ถ้าจะทาการเพิ่มข้อมูลเข้าในคิวอีกย่อมทาไม่ได้ เนื่องจาก ถ้า Q = R

แล้วแสดงว่าคิวเต็ม แม้ว่ายังมีเนื้อที่เหลือด้านหน้าก็ตาม ทาให้การใช้เนื้อที่ไม่เต็มที่

ทางแก้ไขก็คือยอมให้เนื้อที่ส่วนหน้าถูกใช้บรรจุข้อมูลได้

โดยให้ส่วนท้ายของคิวที่ตาแหน่ง Q(N) ไปต่อกับส่วนหน้าที่ตาแหน่ง Q(1)

โครงสร้างคิวแบบนี้เรียกว่า เซอร์คูล่าคิว (Circular Queue) ในคิวแบบธรรมดา เมื่อ R = N

จะหมายความว่าคิวนั้นเต็ม แต่คิวแบบ Circular เมื่อ R = N เราจะปรับให้ R = 1

1 N

R F



เซอร์คูล่าคิวนี้สามารถเพิ่มข้อมูลเข้าได้เรื่อยๆ จนเป็นดังรูปข้างล่าง

จึงจะไม่สามารถเพิ่มได้อีกซึ่งหมายถึงคิวเต็ม

1 N-1 N



R F

ในกรณีนาข้อมูลออกจากเซอร์คูล่าคิว จุดที่ต้องพิจารณาคือขณะที่ F ชี้ที่ N

(เนื้อที่สุดท้ายของคิว) โดยที่คิวมีสมาชิกมากกว่าหนึ่ง หรือ F กับ R

ไม่ได้ชี้ตาแหน่งเดียวกัน

1 N-1 N



R F

ในกรณีนี้หลังจากนาข้อมูลที่ F ออกแล้วต้องเซตค่า F ให้ชี้ที่สมาชิกตัวแรกของคิว

คือ F ชี้ที่ตาแหน่ง 1

และถ้าก่อนนาข้อมูลออกโดยที่ในคิวมีสมาชิกเพียงสมาชิกเดียว ดังรูป หลังจากนาข้อมู

ลออกไปแล้ว ให้เซตค่า F และ R ให้เป็นศูนย์ เพื่อแสดงว่าคิวว่าง

1 N



R F

ALGORITHM CQINSERT

ใช้ในการแทรกข้อมูลเข้าคิวแบบวงกลม โดยที่

F แทน ตัวชี้ต้นคิว

R แทน ตัวชี้ท้ายคิว

N แทน ขนาดของคิว

X แทน ข้อมูลที่จะแทรก

TEMP แทน ตัวเก็บค่าชั่วคราว

[ปรับค่า R]

TEMP = R

IF R = N THEN

R = 1

ELSE

R = R + 1

ENDIF

[ตรวจสอบ Overflow]

IF F = R THEN

PRINT ‚QUEUE OVERFLOW‛

R = TEMP

EXIT

ENDIF

[แทรกข้อมูลเข้าคิว]

Q (R) = X

[กรณีเป็นสมาชิกตัวแรก]

IF F = 0 THEN

F = 1

ENDIF

[จบการทางาน]

EXIT

ALGORITHM CQDELETE

ใช้ในการลบข้อมูลออกจากคิวแบบวงกลม โดยที่

F แทน ตัวชี้ต้นคิว

R แทน ตัวชี้ท้ายคิว

Y แทน เก็บค่าข้อมูลที่จะลบออกจากคิว



[ตรวจสอบ Underfolw]

IF F = 0 THEN

PRINT ‚QUEUE UNDERFLOW‛

EXIT

ENDIF

[เก็บข้อมูลตัวที่จะลบไว้ที่ Y]

Y = Q(F)

[กรณีที่คิวมีสมาชิกตัวเดียว]

IF F = R THEN

F = R = 0

ENDIF

[ปรับค่าของ F]

IF F = N THEN

F = 1

ELSE

F = F + 1

ENDIF

[จบการทางาน]

EXIT

การประยุกต์ใช้งานคิวในการจาลองแบบ

การจาลองแบบ (Simulation) หมายถึง การใช้ระบบหนึ่งเพื่อเลียนแบบพฤติกรรมข

องอีกระบบหนึ่ง ใช้งานเมื่อการทดลองด้วยระบบจริงๆ มีค่าใช้จ่ายสูง หรือเสี่ยงต่ออัน

ตราย การจาลองแบบของคอมพิวเตอร์ จะใช้ขั้นตอนการทางานของโปรแกรม เพื่อการ

เลียนแบบพฤติกรรมของระบบที่เราต้องการศึกษา

การจาลองแบบของระบบแบ่งกันใช้เวลา

ระบบคอมพิวเตอร์ที่มีการทางานแบบแบ่งกันใช้เวลา เป็นระบบที่มีผู้ใช้เครื่องคอม



พิวเตอร์พร้อมกันในเวลาเดียวกัน โดยระบบมีหน่วยผลกลาง (ซีพีย) และหน่วยความ



จาหลักเพียงอย่างละ 1 เท่านัน ผู้ใช้หลายๆ คนนี้ จะต้องมีการใช้หน่วยความจาหลักแ

ละหน่วยประมวลผลกลางร่วมกัน ซึ่งอนุญาติให้ผู้ใช้แต่ละคนประมวลผลโปรแกรม (ใช้

ทรัพยากรของระบบ) ในเวลาหนึ่งๆ แล้วก็จะให้ผู้ใช้คนต่อไปใช้จนกว่าจะวนกลับมายัง

ผู้ใช้คนแรกอีก วิธีการประมวลผลร่วมกันระหว่างผู้ใช้หลายๆ คน เราเรียกว่า

ระบบแบ่งกันใช้เวลา (Time sharing) ซึ่งลักษณะการใช้ซีพียูจะเป็นไปตามลาดับคือ ‚ม

าก่อนได้ก่อน‛ (first – come – first – serve) และมีลาดับการทางานดังนี้

เมื่อโปรแกรมขอใช้เวลาซีพียู โปรแกรมนั้นจะถูกนาไปต่อท้ายคิวประมวลผล



โปรแกรมทีอยู่ต้นคิวจะถูกส่งไปทางาน และยังคงอยู่ที่ต้นคิวจนกว่าจะใช้ซีพียูเสร็จ

เมื่อรันโปรแกรมทางานเสร็จตามเวลาการขอใช้ซีพียู ก็จะถูกนาออกจากคิว และจะไม่ถู

กนากลับมาอีก จนกว่าจะมีการขอใช้ซีพียูครั้งใหม่ (จึงจะกลับไปที่ข้อ 1. อีก)



การจาลองแบบสนามบิน

การเขียนโปรแกรมเพื่อจาลองแบบของสนามบิน จะใช้โครงสร้างข้อมูลแบบคิว แทนคิว

ของเครื่องบินที่จะรอขึ้นหรือรอลง แต่คอนข้างเป็นโปรแกรมที่ซับซ้อน ดังสภาพความเ

ป็นจริงที่ว่า สนามบินมีขนาดเล็กแต่มีเครื่องบินขึ้นลงจานวนมาก มีทางวิ่ง (runway) เ

พียงทางเดียว ดังนั้น ณ เวลาใด

ๆ เครื่องบิน จะต้องขึ้นหรือลงอย่างใดอย่างหนึ่งเท่านั้น และเพียงเครื่องเดียวด้วย ในเ

วลาที่เครื่องบินซึ่งพร้อมจะขึ้นหรือลงมาถึงสนามบิน สนามบินนั้นอาจจะว่างหรือมีเครื่อง

บินอื่นกาลังขึ้นหรือลงอยู่ก็ได้ และอาจจะมีเครื่องบินหลายลาที่รอขึ้นและรอลง จึงมีคิว

2 คิวเกิดขึ้น คือ คิวขึ้น (takeoff) และคิวลง (

landing) ในการรอนั้นบนพื้นจะดีกว่าบนอากาศ ดังนั้นจึงให้เครื่องบินขึ้นได้ก็ต่อเมื่อไม่มี

เครื่องบินลง หลักจากได้รับสัญญาณร้องขอจากเครื่องบินลาใหม่เพื่อจะลงหรือขึ้น โปร

แกรมการจาลองแบบจะให้บริการเครื่องบินที่อยู่ในตาแหน่งหัวคิวของคิวลงก่อน และถ้า

คิวลงว่าง จึงอนุญาตให้เครื่องบินในคิวขึ้นขึ้นได้ โปรแกรมจาลองแบบนี้สามารถจะทาง

านได้ตลอดเวลา









บทที่ 6

โครงสร้างข้อมูลลิงค์ลิสต์









โครงสร้างข้อมูลลิ้งค์ลิสต์

วิธีแก้ปัญหาในการย้ายข้อมูลที่พบในการจัดเก็บที่มีรูปแบบเรียงตามลาดับ(S

equential)เปลี่ยนมาใช้รูปแบบไม่เรียงตามลาดับ (Non-

sequential)ซึ่งรูปแบบการเรียงตามลาดับจะมีสมาชิกเรียงต่อเนื่องติดกันในทางตรรกะ

(Logical) และทางกายภาพ(Physical) เป็นแบบเดียวกัน

แต่รูปแบบไม่เรียงตามลาดับสมาชิกต่อเนื่องติดกันในทางตรรกะ

ส่วนทางกายภาพไม่จาเป็นต้องเหมือนกัน

โดยในทางตรรกะจะแสดงด้วยแต่ละสมาชิกมีการชี้ (Point) ต้อไปยังสมาชิกตัวถัดไป

สมาชิกทุกตัวในรายการจึงถูกเชื่อมต่อ (Link) เข้าด้วยกัน ดังรูปที่ 6.1

เป็นรายการเชื่อมต่อหรือเรียกว่าลิ้งค์ลิสต์ (Linked List) มีสมาชิก N ตัว

แต่ละสมาชิกเรียกว่าโหนด (Node)









จากรูปที่ 6.1 มีตัวแปรพอยน์เตอร์ First ชี้ไปยังโหนดแรกของรายการ

แต่ละโหมดมีตัวเชื่อมเป็นพอยน์เตอร์ที่ชี้ไปยังโหนดถัดไปโดยโหนดสุดท้ายมีค่าเป็น

NULL แสดงให้ทราบว่าไม่ได้ชี้ไปยังโหมดถัดไป

แต่ละโหนดเป็นโครงสร้างข้อมูลเรคคอร์ด ประกอบด้วยสองส่วน คือ

1.ส่วนเก็บข้อมูล (Info)

ใช้เก็บข้อมูลข่าวสารที่มีโครงสร้างข้อมูลเบื้องต้นหรือเรียบง่าย

2.ส่วนการเชื่อมต่อ (Next)

เป็นตัวชี้หรือพอยน์เตอร์เก็บค่าแอดเดรสใช้อ้างไปยังโหนดถัดไปในหน่วยความจา

สาหรับในทางกายภาพของลิ้งค์ลิสต์ แต่ละดหนดไม่จาเป็นต้องอยู่ติดกัน

อาจกระจัดกระจายไปยู่ส่วนไหนก็ได้ในหน่วยความจาโดยมีตัวเชื่อมชี้ไปยังตัวตาแหน่งขอ

งโหนดถัดไป

ดังที่กล่าวในตอนต้นโครงสร้างสแตกและคิวมีการใช้อาร์เรย์ในการเก็บค่า

สมาชิกทุกตัวจึงถูกจากัดให้เป็นชนิดเดียวกัน(Homogenous)

ซึ่งแก้ไขโดยเปลี่ยนมาใช้ลิ้งค์ลิสต์ที่มีโครงสร้างข้อมูลต่างกันได้

นอกจากนี้ยังมีผลดีในการปฏิบัติการแทรกข้อมูลหรือลบข้อมูล

เพียงแต่ย้ายการชี้ของตัวแปรพอยน์เตอร์เท่านั้น ทาให้สมาชิกอื่นไม่มีผลกระทบ

แต่ในกรณีค่าใช้จ่ายแล้วลิงค์ลิสต์จะสูงกว่าที่ต้องใช้พื้นที่เผิ่มมากขึ้นสาหรับส่วนการเชื่อม

ต่อเพื่อชี้ไปยังโหนดถัดไป

และการค้นหาโหนดที่ต้องการใช้เวลามากเนื่องจากเป็นการค้นหาเรียงตามลาดับ

(Sequential Search) ได้โหนดเดียวโดยเริ่มต้นที่โหนดแรกเสมอ



การปฏิบัติการพื้นฐานของลิงค์ลิสต์

สิ่งสาคัญอย่างหนึ่งในการใช้โครงสร้างข้อมูลลิงค์ลิสต์ คือ

ตัวแปรพอยน์เตอร์ (Pointer Variable) ซึ่งเก็บค่าเป็นตาแหน่งแอดเดรสในหน่วยความจา

(Memory Address)

ในการปฏิบัติการกับลิ้งค์ลิสต์และให้มีความถูกต้องจะใช้ตัวแปรพอยน์เตอร์ในการจัดการ

เรื่องต่อไปนี้

1.ใช้ทดสอบกับค่า NULL

2.ใช้ทดสอบว่ามีค่าเท่ากับตัวแปรพอยน์เตอร์อื่น

3.กาหนดให้มีค่าเป็น NULL

4.กาหนดให้ชี้ไปยังโหนด

ชุดปฏิบัติการของลิ้งค์ลิสต์ที่ทกวานร่วมกับตัวแปรพอยน์เตอร์ มีดังนี้

1.Node(P) ส่งโหนดที่ถูกชี้ด้วยต้วแปรพอยน์เตอร์ P กลับมาให้

2.INFO(P) ส่งค่าในส่วนเก็บข้อมูลของโหนดที่ถูกชี้ด้วยตัวแปรพอยน์เตอร์ P กลับมาให้

3.Next(P) ส่งพอยน์เตอร์ในส่วนการเชื่อมต่อขยองโหนดที่ถูกชี้ด้วยตัวแปรพอยน์เตอร์ P

กลับมาให้



การแทรกโหนดไว้ในลิ้งค์ลิสต์

อัลกอลิทึมในการแทรกโหนดใหม่เข้าไปไว้ในลิ้งค์ลิสต์ดังในตารางที่6.1



ตารางที่ 6.1 อัลกอริทึมการแทรกโหนดใหม่ลงในลิ้งค์ลิสสต์









ตัวอย่างการแทรกโหนดใหม่ไว้ในลิ้งค์ลิสต์ โดยเริ่มต้นสร้างเป็นโหนด I

ในหน่วยความจากาหนดส่วนเก็บข้อมูลมีค่า L ส่วนการเชื่อมต่อมี่ค่าเป็น NULL

ซึ่งมีตัวแปรพอยน์เตอร์ New ชี้อยู่ ดังในรูปที่ 6.2

และมีลิงค์ลิสต์ที่ต้องการแทรกโหนดใหม่เข้ามาระหว่างโหนด 2 เป็นโหนดก่อนหน้า

(Predecessor) และโหนด 3 เป็นโหนดถัดไป (Successor)

ดังนั้นจึงกาหนดให้ตัวแ

ปรพอยน์เตอร์ P

ชี้ไปยังโหนด 2

และขั้นตอนในการแทร

กประกอบด้วย









Next(New) =Next (P) กาหนดให้ตัวชี้ของโหนด I เปลี่ยนไปชี้ยังโหนด 3

ซึ่งเป็นส่วนหลังของการแทรกโหนดใหม่ ในรูปที่ 6.3









Next(P) =New กาหนดให้ตัวชี้ของโหนด 2 ที่มีตัวแปรพอยน์เตอร์ P

ชี้อยู่เปลี่ยนไปชี้ยังโหนด I ที่มีตัวแปรพอยน์เตอร์ New ชี้อยู่ ในรูปที่ 6.4









เมื่อการแทรกโหนดเสร็จสิ้น โหนด I

จะมาต่อจากโหนดก่อนหน้าและแทนที่ลาดับของโหนดถัดไป

การทางานดังกล่าวจะมีเพียง 2 โหนดที่เดี่ยวขอ้งคือโหนดใหม่ I

และโหนดที่ตัวแปรพอยน์เตอร์ P ชี้อยู่ ส่วนโหนดอื่นๆ

ไม่ถูกเรียกใช้งานเรือเปลี่ยนแปลง

การลบโหนดออกจากลิ้งค์ลิสต์

อัลกอริทึมในการลบโหนดออกจากลิ้งค์ลิสต์ดังในตารางที่ 6.2

ตารางที่ 6.2 อัลกอริทึมการลบโหนดออกจากลิ้งค์ลิสต์









พิจารณาจากตัวอย่างลิ้งค์ลิสต์ในรูปที่ 6.5 ต่อไปนี้

เป็นอัลกอริทึมในการลบโหนดออกจากลิ้งค์ลิสต์ โดยเริ่มต้นให้ตัวแปรพอยน์เตอร์ P

ชี้ไปโหนด 2 ซึ่งเป็นโหนดก่อนหน้าโหนด 3 ที่ต้องการลบ

และชั้นตอนในการลบประกอบด้วย









(a) Q = Next (P) เป็นการใช้ตัวแปรพอยน์เตอร์ Q เป็นตัวช่วย

กาหนดให้ชี้ไปยังโหนด 3 ที่ต้องการลบในรูปที่ 6.6









(b) Next(P) =Next (Q) กาหนดให้ตัวชี้ของโหนด 2 ที่มีตัวแปรพอยน์เตอร์ P

ชี้อยู่เปลี่ยนไปชี้ยังโหนด 4 ซึ่งเป็นโหนดถัดไปหลังโหนดที่ตัวแปรพอยน์เตอร์ Q ชี้อยู่

ในรูปที่ 6.7









(c) Free (Q) หลังจากนั้นจึงปลดปล่อยโหนดที่ต้องการลบซึ่งมีตัวพอยน์เตอร์ Q ชี้อยู่

เพื่อคืนพื้นที่หน่วยความจาของโหนดที่ลบไปและนาไปใช้กับงานอื่นได้ (Reuse)ได้เป็น

รูปที่ 6.8









ลาดับการทางานดังกล่าวจะเห็นว่ามีเพียง 2 โหนดเท่านั้นที่มาเกี่ยวข้อง คือ

โหนดที่ตัวแปรพอยน์เตอร์ P และ Q ชี้อยู่ ส่วนโหนดอื่นๆ

ไม่ถูกเรียกใช้งานหรือเปลี่ยนแปลง ยกเว้นในกรณีที่ตัวแปรพอยน์เตอร์ P

ชี้ไปยังโหนดสุดท้ายไม่สามารถลบโหนดถัดไปได้

ซึ่งต้องมีการไขอัลกอริทึมโดยตรวจสอบก่อนจะทาการลบ

ลิ้งค์ลิสต์ทางเดียว

โดยทั่งไปลิ้งค์ลิสต์จะมีโหนดที่มีส่วนการเชื่อมต่อชี้ไปยังโหนดถัดไปเพียงทางเดียว

(Unidirectional) ดังที่ผ่านมา เรียกว่าลิ้งค์ลิสต์ทางเดียว (Singly Linked List )

ซึ่งนอกจากจะมีชุดปฏิบัติการแทรกและลบโหนดแล้วยังมีอัลกอรึทึมในการจัดการลิงค์แบ

บอื่น ๆ ดังนี้

1.การค้นหาแต่ละโหนด

เป็นการเริ่มต้นที่โหนดแรกจากนั้นหาไปทีละโหนดตามลาดับที่เชื่อมต่อกันจนกว่าจะพบโ

หนดในลิงค์ลิสต์ดังในตารางที่ 6.3

ตารางที่ 6.3 อัลกอริทึมการวิ่งไปยังแต่ละโหนดในลิ้งค์ลิสต์









2.การแทรกโหนดที่ตอนต้นลิ้งค์ลิสต์

เป็นการสร้างโหนดใหม่ขึ้นมาและกาหนดเป็นโหนดแรกของลิ้งค์ลิสต์ โดยโหนดใหม่นี้

ถ้าหากให้การลบโหนดเป็นที่โหนดแรกเช่นกัน

ลักษณะการทางานจะเป็นแบบเดียวกับโครงสร้างข้อมูลสแตก ดังในรูปที่ 6.9

และจานวนค่าสมาชิกที่ใส่ลงไปก็ไม่จากัดเหมือนกับการใช้อาร์เรย์









3.การแทรกโหนดที่ตอนต้นลิงค์ลิสต์

เป็นการสร้างโหนดใหม่ขึ้นมาและนาไปต่อจากโหนดสุดท้ายของลิงค์ลิสต์ (Append)

โดยโหนดสุดท้ายเดิมจะชี้ไปยังโหนดใหม่ที่กลายเป็นโหนดสุดท้ายแทน

ถ้าให้การลบโหนดเป็นที่โหนดแรกทาให้ลักษณะการทางานจะเป็นแบบเดียวกับโครงสร้าง

ข้อมูลคิว ดังรูปที่ 6.10 โดยมีตัวแปรพอยน์เตอร์ Front ชี้ที่โหนดแรกและ Rear

ชี้ที่โหนดสุดท้าย จานวนค่าสมาชิกที่ใส่ลงไปก็ไม่จากัดเหมือนกับการใช้อาร์เรย์









4.การสลับด้านของรายการในลิ้งค์ลิสต์

เป็นการสร้างลิงค์ลิสต์ใหม่ให้รายการสลับด้านกับลิ้งค์ลิสต์ตัวเก่า

โดยให้โหนดสุดท้ายเปลี่ยนป็นโหนดแรก และให้โหนดแรกกลายเป็นโหนดสุดท้าย

นอกจากนี้ยังมีอัลกอรึทึมอื่น ๆ อีก เช่น

การรวมสองลิ้งค์ลิสต์เป็นลิ้งค์ลิต์เดียว หรือแยกลิ้งค์ลิสต์เดียวเป็นสองลิ้งค์ลิสต์



ลิ้งค์ลิสต์วงกลม

โดยปกติการใช้ลิ้งค์ลิสต์ เมื่อตัวแปรพอยน์เตอร์ P

ชี้ไปยังโหนดหนึ่งจะไม่สามารถชี้กลับไปยังโหนดก่อนหน้าน้าได้

วิธีการอย่างหนึ่งที่ทาให้สามารถวิ่งจากโหนดหนึ่งไปยังโหนดอื่น ๆ ได้ในลิงค์ลิสต์

โดยให้ตัวชี้ของโหนดสุดท้ายซึ่งเดิมเป็นค่า NULL ก็ให้ชี้กลับไปยังโหยดแรกแทน

ดังในรูปที่ 6.11 และเรียกว่าลิงค์ลิสต์วงกลม (Circular Linked List)









ปัญหาอย่างหนึ่งของการใช้ลิงค์ลิสต์วงกลมคือการวิ่งไปแต่ละโหนดจะเป็นกา

รวนลูปที่ไม่รู้จบ แนวทางหนึ่งในการแก้ปัญหาคือ การเพิ่มโหนดหัรายการ (Head Node)

เข้ามาในตอนต้นหรือตอนท้ายลิงค์ลิสต์วงกลม ดังในรูปที่ 6.12

ซึ่งมีความแตกต่างจากโหนดอื่น ๆ ที่มีข้อมูลพิเศษหรือค่าสัญลักษณ์ (Flag)

บอกให้ทราบว่าเป็นโหนดหัวรายการ









การวิ่งไปแต่ละโหนดจะทราบได้ว่าจุดสิ้นสุดอยู่ตรงไหนโดยใช้โหนดหัวรายก

าร นอกจากนี้การใช้โหนดหัวรายการ

กับลิงค์ลิสต์ทางเดียวช่วยการทางานมีประสิทธิภาพมากขึ้น เช่น ทุก ๆ

โหนดในลิงค์ลิสต์จะมีโหนดก่อนหน้าเสมอ

ทาให้อัลกอริทึมในการแทรกหรือลบโหนดมีความสะดวงและง่ายขึ้น

เมื่อลิงค์ลิสต์วงกลมว่าง (Empty Circular Linked Lidt)

จะมีเพียงโหนดหัวรายการเท่านั้นและมีพอยน์เตอร์ชี้กลับมาที่ตัวเอง ดังในรูปที่









6.13

ตัวอย่างการใช้ลิ้งค์ลิสต์วงกลม

ปัญหาโจเซฟ (Josephus Problem)

เป็นที่รู้จักกันมากและนาลิงค์ลิสต์วงกลมมาใช้ในการแก้ปัญหา เริ่มต้นเมื่อมีทหารกลุ่ม

หนึ่งถูกข้าศึกล้อมรอบอยู่ในเมืองซึ่งไม่สามารถต่อสูและหมดหวังที่จะชนะได้

แต่มีม้าเพียงตัวเดียวที่จะขี่พาหนีออกไปได้ กลุ่มทหารจึงตัดสินใจ

เลือกคนที่โชคดีขี่ม้าหนีไปโดยการให้ทุกคนนั่งเป็นวงกลม จากนั้นสุ่มเลือกชื่อทหารคนห

นึ่งเพื่อเริ่มต้นและนับทหารทีละคนในวงกลมจนเท่ากับ N ก็ให้ทหารคนนั้นออกจากวงก

ลม และเริ่มต้นนับแบบเดิมเมื่อถึงคนที่ N ก็ออกจากวงกลมไปเรื่อย ๆ

จนจานวนทหารลดลงเหลือเพียงคนสุดท้ายเป็นผู้ที่ได้ขี่ม้าหนีไป เช่น รูปที่ 6.14 มีทหา

รอยู่ 5 คนมีการนับเพื่อคัดออกเท่ากับ 4 จากรูป (a) จะได้คนสุดท้ายคือคนที่เริ่มต้น

นับในรูป (e)









ถ้าเราเป็นทหารคนหนึ่งควรจะยีนเป็นลาดับเท่าไรจึงจะเป็นคนสุดท้ายโดยมี

ทะหารทั้งหมด M คน และจานวนการนับเพื่อคัดออกเท่ากับ N

อัลกอริทึมในการปัญหาดังกล่าวจึงนาลิงค์ลิสต์วงกลมมาช่วยดังในตารางที่ 6.4 คือ

โปรแกรม Linklist.c

ตารางที่ 6.4 ตัวอย่างโปรแกรม

LinList.c

ลิ้งค์ลิสต์สองทาง

ในบางครั้งการทางานกับลิงค์ลิสต์อาจต้องการวิ่งไปยังโหนดต่าง ๆ

ในลิงค์ลิสต์โดยการถอยกลับไปยังโหนดก่อนหน้าหรือลบแต่ละโหนด

เพื่อห้เกิดประสิทธิภาพจึงนาลิงค์ลิสต์สองทาง (Doubly Linked List)

มาใช้แทนลิงค์ลิสต์ทางเดียว ดังในรูปที่ 6.15 ซึ่งแต่ละโหนดประกอบด้วย 3 ส่วน คือ

1.ส่วนเก็บข้อมูล (Info)

ใช้เก็บข้อมูลข่าวสารที่มีโครงสร้างข้อมูลเบื้องต้นหรือเรียบง่าย

2.ส่วนการเชื่อมต่อถัดไป (Next)

เป็นตัวชี้หรือพอยน์เตอร์เก็บค่าแอดเดรสใช้อ้างไปยังโหนดถัดไปในหน่วยความจา

3.ส่วนการเชื่อมต่อก่อนหน้า

เป็นตัวชี้หรือพอยน์เตอร์เก็บค่าแอดเดรสใช้อ้างกลับไปยังโหนดก่อนหน้าในหน่วยความ

จา









ลิงค์ลิสต์สองทางบางครั้งเรียกว่าลิงค์ลิสต์สมมาตร (Symmetrically Linked

List) เนื่องจากมีตัวชี้จากสองทิศทาง (Bidirectional) ทั้งด้านซ้ายและขวา

เมื่อนามาใช้เป็นลิงค์ลิสต์สองทางวงกลม (Circular Doubly Linked List) ได้ดังในรูปที่ 6.16

โดยอาจยกเลิกโหนดหัวรายการก็ได้









ในการปฏิบัติการจะชี้ไปยังโหนดถัดไปโดยใช้ Next(P)

และชี้กลับไปยังโหนดก่อนหน้าโดยใช้ Prior(P) ตัวชี้ทั้งสองมักจะเป็นพอยน์เตอร์ใช้ชื่อ

Right และ Left หรือใช้ s-link (Successor) และ p-link (Predecessor)

ดังนั้นเมื่อมีตัวแปรพอยน์เตอร์ p ชี้ไปยังโหนดใดจะได้ว่า

Next (Prior (P)) = P = Prior (Next (P))

การถอยกลับไปหนึ่งโหนดและไปข้างหน้าหนึ่งโหนดก็จะกลับมายังโหนดเดิม

หรือไปข้างหน้าหนึ่งโหนดและถอยกลับหนึ่งโหนดก็กลับมายังโหนดเดิมเช่นกัน

สาหรับลิงค์ลิสต์สองทางว่าง (Empty Doubly Linked List)

มีพอยน์เตอร์ทั้งสองชี้กลับมายังโหนดหัวรายการดังในรูปที่ 6.17

ซึ่งไม่มีโหนดอื่นอยู่ในลิงค์ลิสต์ จะได้ว่า

Prior (Head) = Head = Next (Head)









การแทรกโหนดไว้ในลิงค์ลิสต์สองทาง

การแทรกโหนดใหม่เข้าไปไว้ในลิงค์ลิสต์สองทางจะมีอัลกอริทึมดังในตาราง

ที่ 6.5

ตารางที่ 6.5 อัลกอริทึมการแทรกโหนดใหม่ลงในลิงค์ลิสต์สองทาง









ตัวอย่างที่ใช้จะเริ่มต้นโดยใช้โหนดใหม่ I ขึ้นในหน่วยความจา

กาหนดส่วนเก็บข้อมูลมีค่า L, ส่วนการเชื่อมต่อ Left และ Right มีค่าเป็น NULL

ซึ่งเป็นตัวแปรพอยน์เตอร์ New ชี้อยู่ดังในรูปที่ 6.18

และมีลิงค์ลิสต์สองทางที่มีการแทรกโหนดใหม่เข้ามาระหว่างโหนด 2

เป็นโหนดก่อนหน้าและโหนด 3 เป็นโหนดถัดไป จึงกาหนดให้ตัวแปรพอยน์เตอร์ P

ชี้ไปยังโหนด 2 และขั้นตอนในการแทรกประกอบด้วยดังต่อไปนี้









Next(New) = Next(P) กาหนดให้ตัวชี้ Right ของโหนด I เปลี่ยนไปชี้ยังโหนด 3

ซึ่งเป็นส่วนหลังของการแทรกโหนดใหม่ ในรูปที่ 6.19 และ Prior(New) = P

กาหนดให้ตัวชี้ Left ของโหนด I เปลี่ยนไปชี้ยังโหนด 2

ซึ่งเป็นส่วนก่อนหน้าของการแทรกโหนดใหม่









Next(P) = New กาหนดให้ตัวชี้ Right ของโหนด 2 ที่มีตัวแปรพอยน์เตอร์ P

ชี้อยู่เปลี่ยนไปชี้ที่โหนด I ที่มีตัวแปรพอยน์เตอร์ New ชี้อยู่ ในรูปที่ 6.20 และ Prior(P) =

New กาหนดให้ตัวชี้ Left ของโหนด 3 เปลี่ยนไปชี้ยังโหนด I เช่นกัน









เมื่อมีการแทรกโหนดเสร็จสิ้น โหนด I จะต่อจากโหนด 2

และแทนที่ลาดับของโหนด 3 ซึ่งจะกลายเป็นโหนดที่ 4 ในการทางานจะมี 3

โหนดที่เกี่ยวข้องคือ โหนดใหม่ I โหนดที่ตัวแปรพอยน์เตอร์ P ชี้อยู่ และโหนดถัดไป

ซึ่งต่างจากลิงค์ลิสต์ทางเดียวที่เกี่ยวข้องเพียง 2 โหนด



การลบโหนดออกจากลิงค์ลิสต์สองทาง

อัลกอริทึมที่นามาใช้ลบโหนดออกจากลิงค์ลิสต์ดังในตารางที่ 6.6

ตารางที่ 6.6 อัลกอริทึมการลบโหนดออกจากลิงค์ลิสต์สองทาง









พิจารณาจากตัวอย่างลิงค์ลิสต์สองทางในรูปที่ 6.21

เป็นอัลกอริทึมในการลบโหนดออกจากลิงค์ลิสต์สองทาง

โดยเริ่มต้นให้ตัวแปรพอยน์เตอร์ P ชี้ไปโหนด 2 ซึ่งเป็นโหนดที่ต้องการลบ

และขั้นตอนการลบประกอบด้วย









Next(Prior(P)) = Next(P) เป็นการใช้ตัวชี้ left

ของโหนดที่ต้องการลบอ้างกลับไปยังโหนดก่อนหน้าเพื่อชี้ Right

ชี้ไปยังโหนดถัดไปต่อจากโหนดที่ต้องการลบ ในรูปที่ 6.22

Prior(Next(P)) = Prior(P) เป็นการใช้ตัวชี้ Right

ขอองโหนดที่ต้องการลบอ้างไปยังโหนดถัดไปเพื่อสร้างตัวชี้ Left

ชี้กลับไปยังโหนดก่อนหน้าโหนดที่ต้องการลบในรูปที่ 6.23









Free(P) หลังจากนั้นจึงปลดปล่อยโหนดที่ต้องการลบซึ่งมีตัวแปรพอยน์เตอร์ P ชี้อยู่

เพื่อคืนพื้นที่หน่วยความจาของโหนดที่ลบไปและนาไปใช้กับงานอื่นได้ (Reuse)

ได้เป็นรูปที่ 6.24









ลาดับการทางานจะมี 3 โหนดที่มาเกี่ยวข้อง คือ

โหนดที่ต้องการลงมีตัวแปรพอยน์เตอร์ P โหนดก่อนหน้าและโหนดถัดไป ส่วนโหนดอื่น

ๆ ไม่ถูกเรียกใช้งานหรือเปลี่ยนแปลง

ลิ้งค์ลิสต์หลายทาง

มีอยู่หลายกรณีที่นาลิงค์ลิสต์มาใช้งานตามความเหมาะสมซึ่งแต่ละโหนดจะถู

กกาหนดให้ส่วนการเชื่อมต่อมีมากกว่าสองทางเรียกว่าลิงค์ลิสต์หลายทาง (Multi-linked

List) อย่างเช่นในรูปที่ 6.25

ที่แต่ละโหนดในลิงค์ลิสต์จะมีตัวชี้สามทางโดยมีพื้นฐานเป็นลิงค์ลิสต์สองทางซึ่งมีส่วนเก็

บข้อมูลคือ NameLength เก็บค่าความยาวของสตริง กับส่วนเชื่อมต่อที่เป็นตัวชี้ Right

และ Left และส่วนที่เชื่อมต่อที่สาม คือ ตัวชี้ NamePtr

ใช้ชี้ไปยังข้อมูลจริงอีกทีซึ่งมีโครงสร้างข้อมูลสตริงเก็บไว้ในหน่วยความจาที่ขอมาแทนกา

รเก็บไว้ภายในโหนด









ลิงค์ลิสต์หลายทางจะเป็นลักษณะพื้นฐานของโครงสร้างของข้อมูลอื่นที่จะกล่

าวในบทต่อ ๆ ไป เช่น ทรี (Tree) กราฟ (Graph) และนาไปใช้จัดการกับแฟ้มข้อมูล (File)

การค้นหาข้อมูล (searching)





การค้นหาคาตอบ

หรือการค้นหาข้อมูลในทางคอมพิวเตอร์มักจะกระทาบนโครงสร้างข้อมูลแบบต้นไม้

และกราฟ



ทั้งนีเพราะโครงสร้างข้อมูลในลักษณะนี้สามารถทาให้การค้นหาทาได้สะดวกและสามารถ

พลิกแพลงการค้นหาได้ง่าย ในความเป็นจริงแล้ว

การค้นหาข้อมูลบางครั้งสามารถกระทาบนโครงสร้างข้อมูลชนิดอื่นก็ได้เช่น อาเรย์ แสตก

และคิว แต่การจัดข้อมูลในโครงสร้างเช่นนี้ มีข้อจากัดในการค้นหาข้อมูลมาก

การค้นหาทาได้แบบเรียงลาดับ(Sequencial Search) เท่านั้น

ซึ่งใช้ได้กับข้อมูลที่มีขนาดเล็ก ดังนั้นในการค้นหาข้อมูลที่มีขนาดใหญ่ ก่อนการค้นหา

หรือระหว่างการค้นหา ข้อมูลที่จะถูกค้นจะต้องถูกจัดให้อยู่ในรูปแบบของต้นไม้

หรือกราฟเท่านั้น การค้นหาข้อมูลบนโครงสร้างต้นไม้และกราฟสามารถจ าแนกได้ 2

แบบคือ การค้นหาแบบไบล์ด(Blind Search) และการค้นหาแบบฮิวริสติก(Heuristic

Search)



การค้นหาแบบไบล์ด(Blind Search)



การค้นหาแบบไบล์ด(Blind search)

เป็นการค้นหาแบบที่เดินทางจากโหนดหนึ่งไปยังอีกโหนดหนึ่ง

โดยอาศัยทิศทางเป็นตัวกาหนดการค้นหา

ไม่ต้องมีข้อมูลอะไรมาช่วยเสริมการตัดสินใจว่าจะเดินทางต่อไปอย่างไร

หรือกล่าวอย่างง่าย ๆ คือการจะหยิบข้อมูลใดมาช่วยในการค้นหาต่อไป

ไม่ต้องอาศัยข้อมูลใด ๆ ทั้งสิ้น

นอกจากทิศทางซึ่งเป็นรูปแบบตายตัว การค้นหาแบบไบล์ดสามารถแบ่งย่อยได้ดังนี้ คือ

การค้นหาทั้หมด และการค้นหาบางส่วน

- การค้นหาทั้งหมด(exhaustive search) คือ การค้นหาทั้งหมดของปริภูมิสถานะ

- การค้นหาบางส่วน (partial search) การค้นหาเพียงบางส่วนของปริภูมิสถานะ

ซึ่งในความเป็นจริงการค้นหาส่วนมากใช้การค้นหาเฉพาะบางส่วนเท่านั้นเนื่องจากปริภูมิ

สถานะมักมีขนาดใหญ่ เท่าให้ไม่สามารถค้นหาได้ทั้งหมด

ดังนั้นจึงมีความเป็นไปได้ว่าคาตอบที่ได้อาจไม่ใช่คาตอบที่ดีที่สุด

การค้นหาแบบนี้สามารถแบ่งได้เป็น 2 ประเภทคือ การค้นหาแบบลึกก่อน(Depth first

search) และการค้นหาแบบกว้างก่อน (Breadth first search)





การค้นหาแบบลึกก่อน(Depth first search)

การค้นหาแบบลึกก่อนเป็นการค้นหาที่กาหนดทิศทางจากรูปของโครงสร้างต้นไม้

ที่เริ่มต้นจากโหนดราก(Root node) ที่อยู่บนสุด แล้วเดินลงมาให้ลึกที่สุด

เมื่อถึงโหนดล่างสุด(Terminal node)

ให้ย้อนขึ้นมาที่จุดสูงสุดของกิ่งเดี่ยวกันที่มีกิ่งแยกและยังไม่ได้เดินผ่าน

แล้วเริ่มเดินลงจนถึงโหนดลึกสุดอีก

ทาเช่นนี้สลับไปเรื่อยจนพบโหนดที่ต้องการหาหรือสารวจครบทุกโหนดแล้วตามรูปที่ 1

การค้นหาแบบลึกก่อนจะมีลาดับการเดินตามโหนดดังตัวเลขที่กากับไว้ในแต่ละโหนด



ดังที่ได้กล่าวมาแล้วว่า

โครงสร้างข้อมูลที่ใช้สาหรับการค้นหานี้สามารถใช้กับโครงสร้างกราฟได้ด้วย

โดยอาศัยหลักการเดียวกัน

แต่สาหรับการเดินทางบนกราฟนั้นจะไม่มีโหนดลึกสุดดังนั้นการเดินทางบนกราฟจะต้อง

ปรับวิธีการเป็นดังนี้ โดยเริ่มจาก

โหนดเริ่มต้น

จากนั้นให้นาโหนดที่อยู่ติดกับโหนดที่กาลังสารวจอยู่(ที่ยังไม่ได้ทาการสารวจและยังไม่ได้

อยู่ในแสต็กมาใส่แสต็ก) มาเก็บไว้ในสแต็กเมื่อสารวจโหนดนั้นเสร็จ ให้พอพ(pop)

ตัวบนสุดของโหนดออกมาทาการสารวจ

แล้วนาโหนดข้างเคียงทั้งหมดที่ยังไม่ได้สารวจมาต่อท้ายแสต็ก

แล้วพอพตัวบนสุดออกมาสารวจ ทาเช่นนี้เรื่อย ๆ จนกระทั้งพบโหนดที่ต้องการ

หรือสารวจครบทุดโหนด

การสารวจจะเริ่มต้นที่ A และนาโหนดข้างเคียง B และ C มาเก็บไว้ในแสต็ก เมื่อสารวจ

Aเสร็จพอพข้อมูลจากแสต็กออกมาได้ C ทาการสารวจ C และนาโหนดข้างเคียงกับ C

ที่ยังไม่ได้ทาการสารวจและยังไม่ได้อยู่ในแสต็กมาใส่แสต็ก D และ F

พุช(Push) ใส่แสต็ก ดังนั้นในแสต็กตอนนี้มี B D F อยู่ เมื่อสารวจ C เสร็จ พอพ F

ออกมาทาการสารวจ

แล้วนาโหนดข้างเคียงที่ยังไม่ได้สารวจและยังไม่ได้อยู่ในแสต็กมาใส่แสต็ก ซึ่งก็คือ G

ดังนั้นข้อมูลในแสต็กจะเป็น B D G ท าเช่นนี้ไปเรื่อย ๆ

จนจบการทางานก็จะได้ลาดับการส ารวจคือ (A C F G H E D B)

ในการค้นหาข้อมูลแบบนี้บนโครงสร้างของกราฟ มีข้อที่น่าสังเกตุคือ

โหนดที่เริ่มต้นการสารวจจะต้องมีการกาหนดมาให้ว่าโหนดใดเป็นโหนดเริ่มต้น

และข้อสังเกตุอีกประการหนึ่งคือวิธีการค้นหาแบบลึกก่อนที่ใช้สาหรับโครงสร้างข้อมูลแบ

บกราฟ สามารถใช้กับโครงสร้างข้อมูลแบบต้นไม้ได้ด้วย





การค้นหาแบบกว้างก่อน (Breadth first search)

การค้นหาแบบกว้างก่อนเป็นการกาหนดทิศทางการค้นหาแบบที่ละระดับของโครงส

ร้างต้นไม้โดยเริ่มจากโหนดราก(ระดับที่ 0) แล้วลงมาระดับที่ 1 จากซ้ายไปขวา

เมื่อเสร็จระดับที่ 1 ไประดับที่ 2จากซ้ายไปขวาเช่นกัน ทาเช่นนี้เรื่อย ๆ

จนพบโหนดที่ต้องการตามรูปที่ 3

ลาดับการเดินทางของโหนดเป็นไปตามหมายเลขที่กากับไว้บนโหนด





สาหรับการค้นหาแบบกว้างก่อนบนโครงสร้างต้นไม้

จะอาศัยโครงสร้างข้อมูลแบบคิว(Queue)มาช่วย

และด้วยวิธีการเช่นเดียวกับการค้นหาแบบลึกก่อนคือ ให้เริ่มต้นสารวจที่โหนดเริ่มต้น

แล้วนาโหนดข้างเคียงเก็บไว้ในคิว เมื่อสารวจโหนดเริ่มต้นเสร็จ

ให้นาข้อมูลในคิวออกมาสารวจ

แล้วนาโหนดข้างเคียงที่ยังไม่ได้สารวจและไม่ได้อยู่ในคิวใส่คิวไว้ ทาเช่นนี้ไปเรื่อย ๆ

จนพบโหนดที่ต้องการ หรือเมื่อสารวจครบทุกโหนด



การสารวจเริ่มต้นที่ A นาโหนดข้างเคียง B C ไว้ในคิว เมื่อสารวจ A เสร็จ นาข้อมูลในคิว

คือ Bออกมาสารวจ แล้วนาข้อมูลข้างเคียงคือ D E ใส่คิว ตอนนี้คิวจะมี B D E อยู่

แล้วนา B ออกมาสารวจทาเช่นนี้เรื่อย ๆ จะได้ลาดับการสารวจข้อมูลคือ (A B C D E F

G H)

เช่นเดียวกับการค้นหาแบบลึกก่อน

การค้นหาแบบกว้างก่อนโดยใช้โครงสร้างข้อมูลคิวมาช่วยต้องมีการกาหนดโหนดเริ่มต้น

และวิธีการนี้สามารถใช้ได้กับข้อมูลบนโครงสร้างแบบต้นไม้ด้วย



ตารางเปรียบเทียบ การค้นหาแนวลึกก่อนและแนวกว้างก่อน



การค้นหาแนวลึกก่อน การค้นหาแนวกว้างก่อน

1.ใช้หน่วยความจาน้อยกว่า 1.ใช้หน่วยความจามาก

เพราะว่าสถานะในเส้นทางค้นหาปัจจุบันเท่ เพราะต้องเก็บสถานะไว้ทุกตัวเพื่อหาเส้น

านั้นที่ถูกเก็บ(ในขณะใดๆ ทางจากสถานะเริ่มต้นไปหาคาตอบ

จะเก็บเส้นทางเดียว

พอจะไปเส้นทางอื่นเส้นทางที่ผ่านมาก็ไม่จา

เป็นต้องเก็บ)

2. 2. จาไม่ติดเส้นทางที่ลึกมาก ๆ

อาจจะติดเส้นทางที่ลึกมากโดยไม่พบคาตอ โดยไม่พบคาตอบ



เช่นในกรณีที่เส้นทางนั้นไม่มีคาตอบและเป็

นเส้นทางที่ยาวไม่สิ้นสุด

จะทาไม่สามารถไปเส้นทางอื่นได้

3. ถ้าคาตอบอยู่ในระดับ n+1 3. ถ้าคาตอบอยู่ในระดับ n+1

สถานะอื่นทุกตัวที่ระดับ 1ถึงระดับ n สถานะทุกตัวที่ระดับ 1ถึงระดับ n

ไม่จาเป็นต้องถูกกระจายจนหมด จะต้องถูกกระจายจนหมด

ทาให้มีสถานะที่ไม่จาเป็นในเส้นทางที่จะไ

ปสู่คาตอบถูกกระจายออกด้วย

4. 4.

เมื่อพบคาตอบไม่สามารถรับประกันได้ว่าเส้ ถ้ามีคาตอบจะรับประกันได้ว่าจะพบคาตอ

นที่ได้เป็นเส้นทางที่สั้นที่สุดหรือไม่ บแน่ ๆ และจะได้เส้นทางสั้นที่สุดด้วย









การค้นหาแบบฮิวริสติก(Heuristic Search)

การค้นหาคาตอบอาศัยวิธีการทางฮิวริสติก (heuristic search)

มีความความแตกต่างจากการค้นหาข้อมูลแบบธรรมดาและแบบฮิวริสติกนั้นอยู่ที่การค้น

หาข้อมูลธรรมดา ผู้ที่ทาการค้นข้อมูลจะต้องตรวจสอบข้อมูลทีละตัวทุกตัวจนครบ

แต่ฮิวริสติกจะไม่ลงไปดู ข้อมูลทุกตัว

วิธีการนี้จะเลือกได้คาตอบที่เหมาะสมให้กับการค้นหา ซึ่งมีข้อดีคือ สามารถทาการ

ค้นหาคาตอบจาก ข้อมูลที่มีขนาดใหญ่มาก ๆ ได้

แต่มีข้อเสียคือคาตอบที่ได้เป็นเพียงคาตอบที่ดี เท่านั้นไม่แน่ว่าจะดีที่สุด

แต่เนื่องจากว่าปัญหาในบางลักษณะนั้นใหญ่มาก และเป็นไปไม่ได้ที่จะทา

การค้นหาด้วยวิธี

ธรรมดากระบวนการของฮิวริสติกจึงเป็นสิ่งที่จาเป็นในเรื่องของฮิวริสติกนั้น

นอกจากจะมีการค้นหาแบบฮิวริสติกแล้ว ยังมีอีกสิ่งหนึ่งที่สาคัญคือ ฮิวริสติกฟังก์ชัน

(heuristic function) ซึ่งหมายถึงฟังก์ชันที่ทาหน้าที่ในการวัดขนาดของความเป็น

ไปได้ในการแก้ปัญหาซึ่งจะแสดงด้วยตัวเลข วิธีการดังกล่าวจะกระท

าได้โดยการพิจารณาถึงวิธีการ (aspects) ต่าง ๆ ที่ใช้ในการแก้ปัญหา

ณ สถานะหนึ่งว่าจะสามารถแก้ปัญหาได้ตามที่ต้องการหรือไม่

โดยกาหนดเป็นน้าหนักที่ให้กับการแก้ปัญหาของแต่ละวิธี

น้าหนักเหล่านี้จะถูกแสดงด้วยตัวเลขที่กากับไว้กับโหนดต่าง ๆ ในกระบวนการ ค้นหา

และค่าเหล่านี้จะเป็นตัวที่ใช้ในการประมาณความเป็นไปได้ว่าเส้นทางที่ผ่านโหนดนั้นจะมี

ความเป็นไปได้ในการนาไปสู่หนทางการแก้ปัญหาได้มากน้อยแค่ไหนจุดประสงค์ที่แท้จริง

ของฮิวริสติก ฟังก์ชันก็คือ การกากับทิศทางของกระบวนการค้นหา

เพื่อให้อยู่ในทิศทางที่ได้ประโยชน์สูงสุด

โดยการบอกว่าเราควรเลือกเดินเส้นทางไหนก่อน ในกรณีที่มีเส้น

ทางมากกว่าหนึ่งเส้นทางต้องเลือกกระบวนการค้นหาแบบฮิวริสติก

โดยปกติแล้วจะต้องอาศัยฮิวริสติกฟังก์ชัน ทาให้การแก้ปัญหาหนึ่ง ๆ จะดีหรือไม่

ก็ขึ้นอยู่กับฮิวริสติกฟังก์ชันดังนั้นการค้นหาแบบนี้จึงไม่มีอะไรเป็นหลักประกันว่าจะได้สิ่ง

ที่ไม่ดีออกมาด้วยเหตุนี้เอง เราจึงเรียกการ ค้นหาแบบฮิวริสติกนี้ว่า Weak Methods

หรือจะกล่าวอีกนัยหนึ่งคือ Weak Methods เป็นกระบวนการควบคุมโดยทั่วไป (general-

purpose control stategies) ซึ่งการค้นหาแบบนี้ สามารถแบ่งได้เป็น



การค้นหาแบบปีนเขา(Hill climbing)

ฟังก์ชันฮิวริสติกสามารถนามาช่วยในกระบวนการค้นหาเพื่อให้ได้คาตอบอย่างรวดเร็ว

และมีประสิทธิภาพ

วิธีการที่จะนาฟังก์ชันฮิวริสติกมาใช้มีหลายวิธีด้วยกันขึ้นอยู่กับว่าจะใช้ในลักษณะใด

เช่นเลือกสถานะที่มีค่าฮิวริสติกดีขึ้น

แล้วเดินไปยังสถานะนั้นเลยโดยไม่ต้องสนใจสถานะที่มีค่าฮิวริสติกแย่กว่าสถานะปัจจุบัน

หรือว่าจะเก็บสถานะทุกตัวไว้แม้ว่าค่าฮิวริสติกจะแย่ลงแล้วพิจารณาสถานะเหล่านี้ทีหลัง

เป็นต้น ในส่วนต่อไปนี้จะกล่าวถึงอัลกอริทึมต่าง ๆ

ที่นาฟังก์ชันฮิวริสติกมาช่วยในการค้นหาคาตอบ โดยเริ่มจากอัลกอริทึมปีนเข้า (Hill

climbing algorithm)





การค้นหาแบบฮิลไคลบิง(Hill climbing)

เป็นวิธีการค้นหาข้อมูลที่มีลักษณะคล้ายกับการปีนภูเขา

การที่นักปีนภูเขาจะเดินทางไปถึงยอดภูเขา นักปีนเขาจะต้องมองก่อนว่ายอดเขาอยู่ที่ใด

แล้วนักปีนเขาจะต้องพยายามไปจุดนั้นให้ได้

ลองนึกภาพของการปีนภูเขาโล้นที่มองเห็นแต่ยอด

และนักปีเขากาลังปีนภูเขาอยู่เบื้องล่างที่มีเส้นทางเต็มไปหมด

เพื่อที่จะเดินทางไปถึงยอดภูเขาโดยเร็วที่สุด นักปีน

เขาจะมองไปที่ยอดเขาแล้วสังเกตว่าทิศทางใดที่เมื่อปีนแล้วจะยิ่งใกล้ยอดเขา

และหลีกเลี่ยงทิศทางที่เมื่อไปแล้วจะทาให้ตัวเองห่างจากยอดเขา

นักปีนเขาจะต้องทาเช่นนี้ไปเรื่อย ๆ จนกระทั่งถึงยอดเขา





ตัวอย่างการใช้ฟังก์ชันฮิวริสติก โดยอัลกอริทึมปีนเขาอย่างง่ายโดยปัญหาโลกของ

บล๊อก





ตัวเลข h(i) ในรูปแสดงว่า สถานะที่ i มีค่าฮิวริสติกเท่ากับ h จากรู้จะเห็นได้ว่า

เริ่มต้นจากสถานะที่ 1 ที่มีค่าฮิวริสติกเท่ากับ -1

อัลกอริทึมปีนเขาใช้ตัวกระทาการเพื่อสร้างสถานะลูกตัวแรกของสถานะที่ 1

แล้ววัดค่าฮิวริสติกได้ 0 ซึ่งมีค่าดีขึ้น ถ้าสังเกตจากรูปที่ จะพบว่าสถานะที่ 1

มีสถานะลูกทั้งหมด 3 ตัว แต่ในกรณีของอัลกอริทึมปีนเขานี้

เมื่อได้สถานะลูกตัวแรกซึ่งมีค่าอิวริสติกดีขึ้น อัลกอริทึมจะไม่สร้างสถานะลูกที่เหลืออีก 2

ตัว และจะไม่มีการย้อนกลับมาที่สถานะลูกทั้ง 2 นี้

แม้ว่าหลังจากนี้อัลกอริทึมจะค้นไม่พบคาตอบกล่าวคือเป็นการตัดทางเลือกทิ้งไปเลย

ซึ่งการทาเช่นนี้แม้ว่าจะมีโอกาสไม่พบคาตอบแต่ก็มีข้อดีที่เป็นการช่วยลดเวลาและปริภูมิ

ที่ทาการค้นหาจะลดลงอย่างมากจากนั้นอัลกอริทึมมาสถานะที่ 2

แล้วเริ่มสร้างสถานะลูกได้สถานะที่ 3 ที่มีค่าฮิวริสติก -1 ซึ่งแย่ลงในกรณีที่แย่ลงเช่นนี้

อัลกอริทึมจะไม่ไปยังสถานะลูกตัวนี้และสร้างสถานะลูกตัวต่อไปโดยใช้ตัวกระทาการที่เห

ลือได้สถานะที่ 4 มีค่าฮิวริสติกเท่ากับ -1 ไม่ดีขึ้นเช่นกันจึงสร้างสถานะลูกตัวถัดไป

เป็นสถานะที่5 มีค่าฮิวริสติกเท่ากับ 1 เป็นค่าที่ดีขึ้น

อัลกอริทึมจะมายังสถานะนี้และค้นพบคาตอบในที่สุด

อัลกอริทึมปีนเขานี้จะมีประสิทธิภาพมากดังเช่นแสดงในตัวอย่างนี้ซึ่งกระจายสถ

านะทั้งสิ้นเพียง 6 ตัวแล้วพบคาตอบ

เปรียบเทียบกับอัลกอริทึมการค้นหาแนวกว้างก่อนซึ่งใช้สถานะทั้งสิ้นถึง 11 ตัว

อย่างไรก็ดีอัลกอริทึมนี้จะมีประสิทธิภาพมาก ถ้าใช้ฟังก์ชันฮิวริสติกที่ดีมาก ๆ

ในกรณีที่ฟังก์ชันฮิวริสติกไม่ดีนัก อัลกอริทึมนี้ก็อาจหลงเส้นทางได้

และอาจไม่พบคาตอบแม้ว่าปริภูมิที่กาลังค้นหามีคาตอบอยู่ด้วยก็ตาม

สาเหตุการหลงเส้นทางประการหนึ่งมาจากการเลือกสถานะลูก

ซึ่งอัลกอริทึมจะไม่ได้พิจารณาสถานะลูกทุกตัวโดยเมื่อพบสถานะลูกตัวใดตัวหนึ่งที่ดีขึ้นก็

จะเลือกเส้นทางนั้นทันที

อัลกอริทึมนี้สามารถดัดแปลงเล็กน้อยให้พิจารณาสถานะลูกทุกตัวให้ครบก่อน

แล้วเลือกสถานะลูกตัวที่มีค่าฮิวริสติกสูงสุด

เมื่อทาเช่นนี้ก็จะทาให้อัลกอริทึมได้พิจารณาเส้นทางที่ดีที่สุด ณ ขณะหนึ่ง ๆ

ได้ดีขึ้นเราเรียกอัลกอริทึมที่ดัดแปลงนี้ว่าอัลกอริทึมปีนเขาชันสุด (Steepest ascent hill

climbing)





การค้นหาดีสุดก่อน(Best-first search)

เป็นกระบวนการค้นหาข้อมูลที่ได้นาเอาข้อดีของทั้งการค้นหาแบบลึกก่อน(Depth

firstsearch) และการค้นหาแบบกว้างก่อน(Breadth first search)

มารวมกันเป็นวิธีการเดียว โดยที่แต่ละขั้นของการค้นหาในโหนดลูกนั้น

การค้นหาแบบดีที่ดีก่อนจะเลือกเอา โหนดที่ดีที่สุด (most

promising)และการที่จะทราบว่าโหนดใดดีที่สุดนี้สามารถทาได้โดยอาศัยฮิวริสติกฟังก์ชัน

ซึ่งฮิวริสติก ฟังก์ชันนี้จะทาหน้าที่เหมือนตัววัดผล

และให้ผลของการวัดนี้ออกมาเป็นคะแนน รูปที่ 2.7

เป็นตัวอย่างของการค้นหาแบบดีที่สุดก่อน ขั้นตอนนี้เริ่มจากตอน 1 สร้างโหนดราก(root

node) ในขั้นตอน 2 สร้างโหนดลูกB และ C แล้วตรวจสอบโหนด B และ C

ด้วยฮิวริสติกฟังก์ชัน ได้ผลออกมาเป็นคะแนนคือ 3 และ 1ตามล าดับ

จากนั้นให้เลือกโหนด C เป็นโหนดต่อไปที่เราสนใจ เพราะมีค่าน้อยกว่า (หมายเหตุ

ในการเลือกนี้จะเลือกค่ามากสุด หรือน้อยสุดก็ได้ ขึ้นอยู่กับลักษณะของปัญหา)

แล้วสร้างโหนด ลูกให้กับโหนด C ในขั้นตอน 3 ได้โหนด D และ E

แล้วตรวจสอบคะแนนได้ 4 และ 6 ตามล าดับ จากนั้นท

าการเปรียบเทียบค่าของโหนดท้ายสุด หรือเทอร์มินอล โหนด(terminal node) ทุกโหนด

ว่าโหนด ใดมีค่าดีที่สุด ในที่นี้จะต้องเลือกโหนด B เพราะมีคะแนนเพียง 3

(เลือกคะแนนต่าสุด) แล้วสร้างโหนด ลูกตามขั้นตอน 4 ได้ F และ G แล้วตรวจ

สอบคะแนนได้ 6 และ 5 คะแนนตามล าดับ ทาเช่นนี้เรื่อย ๆ

จนพบคาตอบหรือจนไม่สามารถ สร้างโหนดต่อไปได้อีก





อัลกอริธึม: การค้นหาแบบดีที่สุดก่อน

1. เริ่มด้วย OPEN ที่มีเพียงโหนดเริ่มต้น

2. ทาจนกว่าจะพบเป้าหมาย หรือว่าไม่มีโหนดเหลืออยู่ใน OPEN

�เลือกโหนดที่ดีที่สุดใน OPEN

�สร้างโหนดลูกให้กับโหนดที่ดีที่สุดนั้น

�สาหรับโหนดลูกแต่ละตัวให้ทาดังต่อไปนี้

i) ถ้าโหนดนั้นยังไม่เคยถูกสร้างมาก่อนหน้านั้น ให้ตรวจสอบค่าของมันโดย

ใช้ฮิวริสติกฟังชัน แล้วเพิ่มเข้าไปใน OPEN แล้วบันทึกว่าเป็นโหนดแม่

ii) ถ้าโหนดนั้นถูกสร้างมาก่อนหน้านี้แล้ว ให้เปลี่ยนโหนดแม่ของมัน ถ้าเส้น

ทางใหม่ที่ได้ดีกว่าโหนดแม่ตัวเดิม ในกรณีนี้ ให้ปรับเปลี่ยนค่าตามเส้น

ทางที่อาจจะเกิดขึ้น





การค้นหาแบบ Greedy (Greedy Algorithm)

กรีดีอัลกอริธึม เป็นการค้นหาแบบดีที่สุดก่อน(Best first search) ที่ง่ายที่สุด

หลักการของการค้นหาแบบนี้คือ การเลือกโหนดที่ดีที่สุดตลอดเวลาอัลกอริธึม กรีดี

1. เลือกโหนดเริ่มต้นมาหนึ่งโหนด

2. ให้โหนดที่เลือกมานี้เป็นสถานะปัจจุบัน

3. ให้ทาตามขบวนการข้างล่างนี้จนกว่าจะไม่สามารถสร้างโหนดลูกได้อีก

3.1 สร้างสถานะใหม่ที่เป็นโหนดลูกที่เป็นไปได้ทั้งหมดจากสถานะปัจจุบัน

3.2 จากสถานะใหม่ที่สร้างขึ้นมาทั้งหมด ให้เลือกสถานะ หรือ โหนดลูก

ที่ดีที่สุดออกมาเพียงโหนดเดียว

4. กลับไปที่ขึ้นตอนที่ 2

ตัวอย่าง จากเรื่องการเดินทางของเซลแมนที่จะต้องเดินทางไปยังเมือง A B C D

ซึ่งมีระยะทางตามตารางที่ 3 เราจะแก้ปัญหานี้ด้วยวิธีการของกรีดีบ้าง





การแก้ปัญหาเริ่มจาก การเลือก A เป็นเมืองเริ่มแรก จากนั้นทาการสร้างโหนดลูกB C

และ D หารระยะทางระหว่าง A ถึงเมืองเหล่านี้ได้ 20 30 และ 50 ตามลาดับ เลือก B

เป็นเมืองที่จะเดินทางต่อมา จากนั้นสร้างโหนดลูกของ B ได้ C และ D

และได้ระยะทางเท่ากับ 15 และ 20 ตามลาดับ เลือก C เป็นเมืองที่จะเดินทางต่อไป

จากนั้นสร้างโหนดลูกให้ C ได้ D มีค่าเท่ากับ 10 เลือกเดินมาที่ D

เป็นเมืองสุดท้ายก่อนกลับไป A รวมระยะทางเท่ากับ 20 + 15 + 10 + 50 = 95



การค้นหาแบบ A*

การค้นหาแบบ A* เป็นอีกแบบของการค้นหาแบบดีที่สุดก่อน

วิธีการเลือกโหนดที่จะใช้ในการดาเนินการต่อจะพิจารณาจากโหนดที่ดีที่สุด

แต่ในกรณีของ A* นี้จะมีลักษณะพิเศษกว่าคือ ในส่วนของฮิวริสติกฟังก์ชัน

ในกรณีของการค้นหาแบบดีที่สุดก่อนนั้น ค่าที่ได้จากฮิวริสติก ฟังก์ชัน จะเป็นค่าที่วัดจาก

โหนดปัจจุบัน แต่ในกรณีของ A* ค่าของฮิวริสติก ฟังก์ชัน จะวัดจากค่า 2 ค่าคือ

ค่าที่วัดจากโหนดปัจจุบันไปยังโหนดราก และจากโหนดปัจจุบันไปยังโหนดเป้าหมาย

ถ้าเราให้ตัวแปร f แทนค่าของฮิวริสติก ฟังก์ชัน g เป็นฟังก์ชันที่ใช้วัดค่า cost

จากสถานะเริ่มต้นจนถึงสถานะปัจจุบัน h' เป็นฟังก์ชันที่ใช้วัดค่า cost

จากสถานะปัจจุบันถึงสถานะเป้าหมาย ดังนั้น





f = g + h’









อัลกอริทึม A* (A*

Search) เป็นการขยายอัลกอริทึมดีสุดก่อนโดยพิจารณาเพิ่มเติมถึงต้นทุนจากสถานะเริ่ม

ต้นมายังสถานะปัจจุบันเพื่อใช้คานวณค่าฮิวริสติกด้วย ในกรณีของอัลกอริทึม A*

เราต้องการหาค่าต่าสุดของฟังก์ชัน f' ของสถานะ s นิยามดังนี้

f'(s)=g(s)+h'(s)

โดยที่ g คือฟังก์ชันที่คานวณต้นทุนจากสถานะเริ่มต้นมายังสถานะปัจจุบัน h'

คือฟังก์ชันที่ประมาณต้นทุนจากสถานะปัจจุบันไปยังคาตอบ ดังนั้น f'

จึงเป็นฟังก์ชันที่ประมาณต้นทุนจากสถานะเริ่มต้นไปยังคาตอบ (ยิ่งน้อยยิ่งดี)

เรามองได้ว่าฟังก์ชัน h' คือฟังก์ชันฮิวริสติกที่เราเคยใช้ในการค้นหาอื่น ๆ

ก่อนหน้านี้เช่นอัลกอริทึมปีนเขา อัลกอริทึมดีสุดก่อน เป็นต้น ในที่นี้เราใส่เครื่องหมาย '

เพื่อแสดงว่าฟังก์ชันนี้เป็นฟังก์ชันประมาณของฟังก์ชันจริงที่ไม่รู้ (เราทาได้แค่ประมาณว่า

h' คือต้นทุนจากสถานะปัจจุบันไปยังคาตอบ

เราจะรู้ต้นทุนจริงก็ต่อเมื่อเราได้ทาการค้นหาจริงจนไปถึงคาตอบแล้ว) ส่วน g

เป็นฟังก์ชันที่คานวณต้นทุนจริงจากสถานะเริ่มต้นมายังสถานะปัจจุบัน

(จึงไม่ได้ใส่เครื่องหมาย ' )

เพราะเราสามารถหาต้นทุนจริงได้เนื่องจากได้ค้นหาจากสถานะเริ่มต้นจนมาถึงสถานะปัจ

จุบันแล้ว ส่วน f' ก็เป็นเพียงแค่ฟังก์ชันประมาณโดยการรวมต้นทุนทั้งสอง คือ h' กับ g

อัลกอริทึม A* จะทาการค้นหาโดยวิธีเดียวกันกับอัลกอริทึมดีสุดก่อนทุกประการ

ยกเว้น ฟังก์ชันฮิวริสติกที่ใช้เปลี่ยนมาเป็น f' (ต่างจากอัลกอริทึมดีสุดก่อนที่ใช้ h')

โดยการใช้ f' อัลกอริทึม A* จึงให้ความสาคัญกับสถานะหนึ่ง ๆ 2 ประการ คือ (1)

สถานะที่ดีต้องมี h' ดีคือต้นทุนเพื่อจะนาไปสู่คาตอบหลังจากนี้ต้องน้อย และ (2)

ต้นทุนที่จ่ายไปแล้วกว่าจะถึงสถานะนี้ (g) ต้องน้อยด้วย เราจึงได้ว่า A*

จะค้นหาเส้นทางที่ให้ต้นทุนโดยรวมน้อยที่สุดตามค่า f' ซึ่งต่างจากอัลกอริทึมดีสุดก่อน

ที่เน้นความสาคัญของสถานะที่ต้นทุนหลังจากนี้ที่จะนาไปสู่คาตอบต้องน้อย

โดยไม่สนใจว่าต้นทุนที่จ่ายไปแล้วกว่าจะนามาถึงสถานะนี้ต้องเสียไปเท่าไหร่

โดยสมมติให้ต้นทุนหรือระยะห่างระหว่างสถานะพ่อแม่ไปยังสถานะลูกเท่ากับ 1 หน่วย

เช่นต้น ทุนจริง (g) จาก A ไปยัง B,C หรือ D มีค่าเท่ากับ 1 หน่วย



จากรูปจะเห็นได้ว่าในขั้นตอนที่ 4 สถานะ C จะถูกเลือกมากระจายโดยอัลกอริทึม A*

เนื่องจากมีค่า f' น้อยสุดเท่ากับ 3.5 ซึ่งน้อยกว่า E ที่มีค่าเท่ากับ 4 แม้ว่าค่า h' ของ E

จะน้อยกว่าซึ่งต่างจากการสร้างสถานะของอัลกอริทึมดีสุดก่อน

BUBBLE SORT

Sort เป็นแบบหนึ่งของ exchange sort หลักการมีอยู่ว่าว่าเราจะเปรียบเทียบค่า 2 ค่าที่ติดกัน

ถ้าไม่ได้อยู่ในลาดับที่เรากาหนด เช่น จากน้อยไปมาก ก็ให้แลกเปลี่ยนตาแหน่งของค่าทั้ง 2 ค่านั้น

แล้วเอาค่าน้อย (หรือค่ามาก ถ้าเป็นการเรียงจากค่ามากไปหาค่าน้อย)

เปรียบเทียบกับค่าถัดไปอีกเป็นเช่นนี้ตลอดไปจนกว่าอยู่ในลาดับที่ถูกต้อง

สมมติว่าเร Bubbleามีลิสต์ (5,1,2,8,9) เราจะเรียงโดยเทคนิคนี้ได้ดังรูปที่ 1

(โดยต้องการเรียงจากมากไปน้อยตามแนวบนลงล่าง









รูปการเรียงแบบ bubble sort

ขั้นแรกให้นาเอา 5 เปรียบเทียบกับ 1 ปรากฏว่า 5 และ1 เรียงลาดับตามที่เราต้องการอยู่แล้ว

จากนั้นให้นาเอา 1 เปรียบเทียบกับตัวถัดไปคือ 2 เนื่องจาก 2 มากกว่า 1 และ 2



อยูในตาแหน่งที่ผิดลาดับ จึงให้แลกที่กับ 1 หลังจากที่ 2 ไปอยู่ในตาแหน่งท่อยู่เดิมของ 1

(นั่นคือตาแหน่งที่ 2 )แล้วก็ให้ 2 เปรียบเทียบกับค่าในตาแหน่งที่ 1 คือ 5

ปรากฏอยู่ในลาดับที่ถูกต้อง ก็ไม่ต้องแลกที่กัน ต่อมานา 1 ไปเปรียบเทียบกับ 8

แล้วทาในลักษณะเดิม ค่า 8 จะค่อย ๆ ลอยขึ้นไปอยู่ในตาแหน่งที่ถูกต้อง ในที่สุดก็นา 1

ไปเปรียบเทียบกับ 9 เลข 9 จะค่อย ๆลอยขึ้นไปยังตาแหน่งที่ถูกต้อง )

สิ่งที่ต้องทาในการเรียงค่าคือ เปรียบเทียบ และแลกตาแหน่ง

เราจะพิจารณากรณีปลายสุด 2 กรณี คือ

1)ถ้าลิสต์นั้นเป็นลิสต์ที่เรียงเรียบร้อยแล้วจากมากไปน้อย

และเราบังเอิญต้องการเรียงจากมากไปน้อยโดยใช้ bubble sort

เราจะสามารถทาได้โดยไม่ต้องมีการแลกตาแหน่งเลยและต้องทาการเปรียบเทียบ เพียง n - 1

ครั้งเท่านั้น (ถ้ามีข้อมูล n ตัว)

(2)ถ้าลิสต์นั้นเป็นลิสต์ที่เรียงเรียบร้อยแล้วจากน้อยไปมากและเราต้องการเรียงมันจากมากไปน้อย

เราต้องทาการแลกเปลี่ยนและเปรียบเทียบเป็นจานวน 1 + 2 + 3 + … +(n - 1) ครั้งหรือเท่ากับ

n(n - 1) / 2 ครั้งนั่นเอง

จะเห็นได้ว่า bubble sort จะดีหรือเลวก็ขึ้นอยู่กับว่าลิสต์นั้นเกือบเรียง

ในลาดับที่เราต้องการจะเรียงมันหรือไม่ ถ้าค่าในลิสต์นั้นอยู่ในแบบ random

ก็จะต้องมีการแลกเปลี่ยนประมาณ n(n - 1)/4 ครั้ง การเรียงข้อมูลแบบนี้จึงจัดเป็นพวก O(n2)

ซิงเกิลตัน อาร์.ซี. (Singleton R.C. - Alogrithm 347 - CACM)พบว่าวิธีเรียงแบบ bubble

จะดีที่สุดถ้าลิสต์นั้นมีค่าเท่ากับหรือน้อยกว่า 11 ตัว

สรุปได้ว่าการเรียงข้อมูลแบบนี้ไม่เหมาะกับลิสต์ขนาดยาว ๆ

อย่างไรก็ดีวิธีเรียงแบบนี้สามารถจาได้ง่ายและโปรแกรมได้ง่ายขึ้น



INSERTION SORT

วิธีนี้ต้องใช้พื้นที่ความจาเพิ่มขึ้นอีก N ตาแหน่งสาหรับเก็บส่วนที่เรียงแล้ว นั่นคือถ้าเรามีลิสต์ A(1

: N) ที่ยังไม่ได้เรียง เราต้องใช้ลิสต์ B(1 : N) มาช่วย โดยที่เราจะดึงแต่ละค่าในลิสต์ A

ไปใส่ในตาแหน่งสัมพันธ์ที่ถูกต้องในลิสต์ B ในที่สุดลิสต์ B จะเป็นลิสต์ที่มีค่าต่าง ๆ

เรียงกันตามลาดับ

อย่างไรก็ดี เราก็มีวิธีที่จะ sort - in - place นั่นคือใช้พื้นที่ความจาเพียง N

ตาแหน่งเท่านั้นโดยไม่ต้องใช้พื้นที่ความจาเพิ่ม วิธีนี้เราจะนาตัวที่ I

จากส่วนที่ยังไม่ได้เรียงใส่เข้าไปในส่วนที่เรียงแล้ว ซึ่งมี J ตัว

สมมติให้ชุดตัวเลขที่เรียงเป็น 5,4,2,8,8,9,6 การเรียงจะมีลาดับดังนี้

HEAP SORT

การเรียงข้อมูลโดยอาศัยโครงสร้าง heap เป็นการเรียงข้อมูลแบบที่ดีที่สุด เพราะเป็น

อัลกอริทึมที่ประกันได้ว่าเวลาที่ใช้ไม่ว่าในกรณีใดจะเป็น O(log 2 n) เสมอ

โครงสร้าง Heap heap เป็นต้นไม้ไบนารีที่มีคุณสมบัติว่าโหนดใด ๆ

ในต้นไม้นั้นจะมีค่าคีย์ใหญ่กว่าค่าคีย์ที่อยู่ใน left son และ right son ของมัน (ถ้าโหนดนั้นมีลูก)

ตัวอย่างดังรูป(ก) เป็น heap ส่วนรูป(ข) ไม่ใช่ heap









รูป การเปรียบเทียบระหว่างโครงสร้าง heap กับโครงสร้างอื่น



จากนิยามของโครงสร้าง heap เราทราบว่ารูตโหนดของ heap

จะเป็นโหนดที่มีค่าคีย์ใหญ่กว่า ดังนั้นจากอันพุตที่กาหนดให้เราต้องสร้าง heap ขึ้นก่อน

แล้วทาการเอาต์พุตรูตโหนดก็จะได้ค่าแรก (ค่าใหญ่ที่สุด) ของชุดที่เรียงแล้ว

ในกรณีนี้จะเรียงจากมากไปน้อย(อัลกอริทึมที่เราอธิบายถึงจะได้ค่าที่เรียงแล้วจากน้อยไปมาก)

หลังจากที่เอาต์พุตค่ารูตโหนดไปแล้ว ต้นไม่ที่เหลืออยู่จะไม่เป็น heap

เราต้องมีวิธีการตกแต่งหรือปรับแต่งให้ต้นไม้ที่เหลืออยู่นั้นเป็น heap จะได้เอาต์พุตค่าถัดไปได้

ดังนั้นกระบวนการใหญ่ของการทา heap sort ประกอบด้วย 3 ขั้นตอนดังนี้



ขั้นที่ 1 สร้างโครงสร้าง heap

ขั้นที่ 2 เอาต์พุตคีย์ที่รูตโหนด

ขั้นที่ 3 ปรับแต่งต้นไม่ที่เหลือให้เป็น heap

การสร้างโครงสร้าง Heap จากชุดอินพุต อาร์เรย์ใด ๆ สามารถถูกตีความเป็นต้นไม้ไบนารีได้ เช่น

อาร์เรย์ที่มีค่าดังนี้ (ดูรูป¶Ñ´ä»)









ความสัมพันธ์ระหว่างโครงสร้างอาร์เรย์และโครงสร้าง heap

จะมีรูปเป็นต้นไม้ไบนารีดังรูปµèÍ仹Õé









รูปต้นไม้ไบนารีของอาร์เรย์

การสร้าง heap จะสร้างจากค่าอาร์เรย์ที่อ่านเข้ามาทีละค่าโดยจะสร้าง heap ขนาดที่มี I -1 โหนด

เมื่อรับอีกโหนดเข้ามาก็จะได้ heap ที่มีขนาด I ทาเรื่อย ๆ จนได้ heap ขนาด n

การอินพุตค่าใหม่เข้าไปใน heap ให้ถูกตาแหน่งค่าตามในต้นไม้ไบนารี หลักการมีดังนี้ (ให้ I

เป็นพอยน์เตอร์ชี้ไปยังโหนด Knew)

ขั้นที่ 1 ให้เปรียบเทียบโหนดที่เข้าใหม่กับโหนดที่เป็นพ่อ

IF Knew > K FATHER THEN แลกที่กัน เลื่อน I ไปชี้ยังตาแหน่ง FATHER (นั่นคือ I ติดตาม Knew

ขึ้นไป)

ขั้นที่ 2 ทาขั้นที่ 1 เรื่อย ๆ จนทาไม่ได้









ต้นไม้ที่เห็นระหว่างการสร้าง heap นั้น เป็นการตีความข้อมูลในอาร์เรย์

ส่วนความสัมพันธ์ระหว่างพ่อ - ลูก เป็นแบบที่กล่าวมาแล้วข้างต้น

หลังจากที่ข้อมูลเรียงในรูปโครงสร้าง heap แล้ว เราจะเอาเอาต์พุตค่ารูตโหนดซึ่งอยุ่ที่ตาแหน่งที่ 1

ในอาร์เรย์ การเอาต์พุตเราจะให้ค่าA(1) แลกที่กับค่าสุดท้ายของอาร์เรย์ A(8) การแทนในรูปต้นไม้

ค่าที่เอาต์พุตไปแล้วจะแทนโดยโหนดสี่เหลี่ยม ต้นไม้ที่ได้ (ไม่นับโหนดสี่เหลี่ยม) ไม่เป็นโครงสร้าง

heap จากนี้ต่อไปเราต้องใช้อัลกอริทึมปรับค่าคีย์ต่าง ๆ ในต้นไม้ให้คุณสมบัติ heap



การปรับต้นไม้ที่ได้จากการแลกค่าให้มีคุณสมบัติ Heap

การปรับแต่งทาได้โดยเลื่อนค่าที่รูตโหนดจากบนลงมาล่าง ดังนี้

ขั้นที่ 1 ให้ตั้งค่าพอยน์เตอร์ I ชี้ไปยังรูตโหนด

ขั้นที่ 2 ให้เลือกค่าที่ใหญ่ที่สุดระหว่าง left son และ right son ของโหนด I

เป็นค่าที่เลื่อนมาอยู่ที่ตาแหน่ง I ส่วนค่าคีย์ที่ตาแหน่ง I ก็เลื่อนไปอยู่ที่ตาแหน่ง left son และ right

son ของมันที่มีค่าใหญ่กว่า จากนั้นเลื่อนพอยน์เตอร์ I มาอยู่ที่ตาแหน่งใหม่นี้

ขั้นที่ 3 ทาขั้นที่ 2 จนกว่าจะทาไม่ได้

รูปการปรับต้นไม้ให้มีคุณสมบัติ heap



แสดงถึงการเลือนค่า 22 ลงไปยังตาแหน่งถูกต้องของมัน เพื่อที่ทาต้นไม้ที่ได้เป็น heap

เมื่อต้นไม้เป็นไปตามรูป (ค) ต้นไม้นั้นจะเป็น heap ซึ่งมีค่าสูงสุด 42 อยู่ที่รูตโหนด เราจะเอาต์พุต

42 ไปอยู่ที่ตาแหน่งสุดท้ายของอาร์เรย์ (ตาแหน่งก่อนค่า 90 ไป 1 ตาแหน่ง) ดังรูป(ก)



ส่วนค่าทีอยู่ที่ตาแหน่งนั้น (ค่า 27) ก็ไปอยู่ที่ตาแหน่ง A(1) หรือรูตโหนด

จากนั้นก็เริ่มต้นปรับแต่งต้นไม้ใหม่ให้เป็น heap ซึ่งเริ่มโดยตั้งค่า I ชี้ไปยังรูตโหน´



QUICK SORT

Quick Sort เป็นอีกวิธีที่เหมาะกับลิสต์ขนาดใหญ่

และเป็นวิธีเรียงข้อมูลที่ให้ค่าเฉลี่ยของเวลาที่ใช้น้อยที่สุดเท่าท ี่ค้นพบวิธีหนึ่ง

อย่างไรก็ดีเราต้องใช้สแตกขนาด log2n

สาหรับเป็นตาแหน่งของลิสต์ย่อยที่ยังไม่ได้เรียงและเวลาที่ใช้ในกรณีเลวร้ายที่สุด จะไม่ดีกว่าแบบ

O(n2)

สมมติ A(K1,K2,…,Kn) เป็นลิสต์ของค่าหรือเรคอร์ดที่ยังไม่ได้เรียง เราจะเลือก K1

จากนั้นจะแบ่งลิสต์ A นี้ออกเป็น 2 ลิสต์ย่อย S1 และ S2 โดยที่

S1 ประกอบด้วยเรคอร์ดที่มีค่าคีย์น้อยกว่า K1

S2 ประกอบด้วยเรคอร์ดที่มีค่าคีย์น้อยกว่า K1

นั่นคือเราสามารถเขียนลิสต์ A ได้ดังนี้ {

S1 } rhs ? lhs : rhs;

}

ฟังก์ชั่นช่วย

/**

* Internal method to insert into a subtree.

* @param x the item to insert.

* @param t the node that roots the tree.

* @return the new root.

*/

private AvlNode insert( Comparable x, AvlNode t )

{

if( t == null )

t = new AvlNode( x, null, null );

else if( x.compareTo( t.element ) 0 )

{

t.right = insert( x, t.right );

if( height( t.right ) - height( t.left ) == 2 )

if( x.compareTo( t.right.element ) > 0 )

t = rotateWithRightChild( t );

else

t = doubleWithRightChild( t );

}

else

; // Duplicate; do nothing

t.height = max( height( t.left ), height( t.right ) ) + 1;

return t;

}





t

/**

* Rotate binary tree node with left child.

* For AVL trees, this is a single rotation for case 1.

* Update heights, then return new root.

*/

private static AvlNode rotateWithLeftChild( AvlNode k2 )

{

AvlNode k1 = k2.left;

k2.left = k1.right;

k1.right = k2;

k2.height = max( height( k2.left ), height( k2.right ) ) + 1;

k1.height = max( height( k1.left ), k2.height ) + 1;

return k1;

}



k2

k1

k2

k1

/**

* Rotate binary tree node with right child.

* For AVL trees, this is a single rotation for case 4.

* Update heights, then return new root.

*/

private static AvlNode rotateWithRightChild( AvlNode k1 )

{

AvlNode k2 = k1.right;

k1.right = k2.left;

k2.left = k1;

k1.height = max( height( k1.left ), height( k1.right ) ) + 1;

k2.height = max( height( k2.right ), k1.height ) + 1;

return k2;

}



k1

k2

k1

k2

/**

* Double rotate binary tree node: first left child

* with its right child; then node k3 with new left child.

* For AVL trees, this is a double rotation for case 2.

* Update heights, then return new root.

*/

private static AvlNode doubleWithLeftChild( AvlNode k3 )

{

k3.left = rotateWithRightChild( k3.left );

return rotateWithLeftChild( k3 );

}



k2

k1

X

Y1

Y2

k3

Z

k2

k3

k1

X

Z

Y1

Y2

k2

k1

X

Y1

Y2

k3

Z

/**

* Double rotate binary tree node: first right child

* with its left child; then node k1 with new right child.

* For AVL trees, this is a double rotation for case 3.

* Update heights, then return new root.

*/

private static AvlNode doubleWithRightChild( AvlNode k1 )

{

k1.right = rotateWithLeftChild( k1.right );

return rotateWithRightChild( k1 );

}



k2

k1

k3

X

Z

Y1

Y2

k2

k3

X

Y1

Y2

k1

Z

k2

k3

X

Y1

Y2

k1

Z









โครงสร้างทรี



นิยามและแนวคิด



โครงสร้างข้อมูลแบบทรี ซึ่งเป็นโครงสร้างข้อมูลที่สาคัญอีกชนิดหนึ่ง

โดยในช่วงแรกจะแนะนาให้รู้จักกับแนวความคิดและ ทฤษฎีของกราฟกันก่อน

กราฟรูปต่าง ๆ



นิยามของกราฟ



นิยามว่า กราฟประกอบด้วยเซตของจุดที่เรียกว่า โหนด(node) หรือ จุดยอด(vertex)

และเซตของ เส้นเชื่อม(edge) ระหว่างจุด และโหนด 2 โหนดใดๆ ที่มีเส้นเชื่อม

เราเรียกว่า โหนดประชิด (adjacent nodes)

กราฟเส้นเชื่อมมีทิศทางจากโหนดหนึ่งไปยังอีกโหนดหนึ่ง เราเรียกว่า

เส้นเชื่อมแบบมีทิศทาง(directed edge) กราฟเส้นเชื่อมไม่มีทิศทางแน่นอน เราเรียกว่า

กราฟแบบไม่มีทิศทาง (undirected edge) กราฟที่เส้นเชื่อมทุกเส้นมีทิศทางที่แน่นอน

เราเรียกว่า กราฟแบบมีทิศทาง (directed graph) หรือ ไดกราฟ (digraph)

กราฟที่เส้นเชื่อมทุกเส้นไม่มีทิศทางแน่นอน (undirected

graph)กราฟมีทั้งเส้นเชื่อมแบบมีทิศทาง และเส้นเชื่อมแบบไม่มีทิศทาง เราเรียกว่า

กราฟผสม (mixed graph) ซึ่งบางครั้งก็มีเส้นเชื่อมเชื่อมระหว่างโหนด 2 โหนดใดๆ

มากกว่า 1 เส้น ดังรูป เส้นเชื่อมขนานและห่วง ซึ่งมีลักษณะนี้เราเรียกว่า

เส้นเชื่อมขนานและห่วง (parallel edge) โดยในรูปมีเส้นเชื่อมขนาน 2 เส้น

เชื่อมระหว่างโหนด 1 กับโหนด 2 และมีเส้นเชื่อมขนาน 3 เส้น เชื่อมระหว่างโหนด 2 กับ

โหนด 3 ส่วนที่มีเส้นเชื่อมเชื่อมโหนดตัวมันเองเรียกว่า ห่วง (loop , sling)

เราจะไม่สนใจทิศทางห่วง ว่าจะเป็นเส้นเชื่อมแบบมีทิศทาง

หรือเส้นเชื่อมแบบไม่มีทิศทาง



โครงสร้างทรี

ทรีเป็นกราฟแบบมีทิศทาง ที่มีโครงสร้างแบบลาดับชั้น

ทิศทางของกราฟที่แทนทรีจะมีทิศทางจากบนลงล่าง ดังนั้นการกวาดทรี

เราจึงไม่นิยมแสดงทิศทางของเส้นเชื่อม









นิยามทรี



จากรูปโครงสร้างทรี เราให้นิยามทรีในรูปแบบอื่นๆ ได้อีก เช่น

การให้นิยามในรูปของการเรียกซ้าซึ่งสอดคล้องกับลักษณะธรรมชาติ ของทรี ดังนี้ คือ

ทรีประกอบด้วยโหนด R ซึ่งเรียกว่า โหนดราก (root) และ ทรีย่อย (subtree) จานวนศูนย์

หรือมากกว่าศูนย์ ได้แก่ T1,T2,...,Tk ซึ่งแต่ละทรีย่อยจะเชื่อมกับโหนดราก

(R)โดยตรงด้วยเส้นเชื่อม



การเรียกชื่อองค์ประกอบของทรี



โหนดที่อยู่ระดับบนสุดของทรี เรียกว่า โหนด R ,โหนดราก, พ่อ (father)

โหนดรากของทรีย่อยของ R เรียกว่า ลูก (child) ของ R

โหนดที่ไม่มีโหนดลูก เรียกว่า โหนดใบ (leaf node)

เส้นเชื่อมโหนดทรี เรียกว่า กิ่ง (branch)

โหนดที่มีทั้งพ่อทั้งลูก เรียกว่า โหนดกิ่ง (branch node)

โหนดที่มีพ่อเดียวกัน เรียกว่า โหนดพี่น้อง (sibling) และยังอาจนิยามโหนดว่าเป็น โหนดปู่

(grandfather) หรือ โหนดหลาน (gtrandchild) ได้ในลักษณะเดียวกัน

เส้นทาง (path) จากโหนด n1 ไปยังโหนด nk ใดๆ จะเป็นลาดับของโหนด n1,n2,...,nk

ความยาว (length) ของเส้นทางจะเป็นจานวนของเส้นเชื่อมที่อยู่ในเส้นทาง ซึ่งเท่ากับ k-1

เส้นทาง จากโหนดใดๆ ไปยังตัวเองจะมีความยาวเป็ยศูนย์ และในทรีแต่ละทรี

จะมีเส้นทางหนึ่งเส้นเท่านั้นจากโหนดรากไปยัง โหนดใดๆ ความลึก (depth) เป็น

ความยาวของเส้นทางจากโหนดรากไปยังโหนด n โซึ่งมีเส้นทางเดียวที่ไม่ซ้ากัน) ความสูง

(height) เป็น เส้นทางทีสุดจากโหนด n ไปยังโหนดใบถ้ามีเส้นทางจาดโหนด n1

ไปยังโหนด n2 จะเป็น บรรพบุรุษ (ancestor) ของ n2 และ n2 จะเป็น ลูกหลาน

(descendant) ของ n1 ถ้า n1 != n2 ดังนั้น n1 จะเป็น บรรพบุรุษที่แท้จริง (proper

ascestor) ของ n1 และ n2 ลูกหลานที่แท้จริง (proper descendant)



ทรีแบบลาดับ



ทรีแบบราก (rooted tree ) เป็นทรีที่สามารถวาดได้อิสระ โดยเชื่อมโหนดในระดับต่าลงไป

และมีโหนด ใบอยู่ในระดับล่าง มีโครงสร้างไม่เหมาะสมก่การใช้งาน

เนื่องจากวิธีการเรียกชื่อโหนดจากลาดับซ้ายไปขวา "ทรีแบบลาดับ (ordered tree)" คือ

ทรีแบบรากที่โหนดลูกของแต่ละโหนดถูกกาหนดลาดับดังรูป

ถ้าต้องการจะใช้ทรีแบบลาดับเป็นโครงสร้างข้อมูล

ในแต่ละโหนดจะต้องมีจานวนเขตข้อมูลมากพอๆ กับจานวน ของโหนดนั้น

ดังนั้นถ้ามีบางโหนดในทรีมีจานวนทรีมากกว่า 10 ทรีย่อย

จะต้องมีเขตข้อมูลสาหรับลิงค์ของ แต่ละโหนดถึง 10 เขต ซึ่งแต่ละเขตลิงค์ต่างๆ

เหล่านี้ส่วนใหญ่จะมีค่าเป็น NULL ซึ่งทาให้เนื้อที่จานวนมาก ไม่ได้ใช้งาน



ตัวอย่างทรี





ไบนารีทรี



ี่

นิยามว่า ไบนารีทรี เป็น ทรีว่าง หรือทรีทประกอบด้วยโหนดรากที่เรียกว่า ราก กับ

ไบนารีทรี 2 ทรี เรียกว่า ทรีย่อยทางซ้าย (left subtree) และ ทรีย่อยทางขวา (right

subtree) ของราก การสร้างไบนารีทรี ที่มีโหนดเดียว

สามารถสร้างโหนดนั้นเป็นโหนดรากที่มีทรีย่อยทางซ้าย และทรีทางขวาเป็นทรีว่าง

จะเห็นว่าไบนารีทรีแตก ต่างจากทรีทั่วไป เนื่องจากในไบนารีทรี ความหมายของคาว่า

ซ้าย หรือ ขวา มีความสาคัญ ไบนารีทรี 2 โหนด

ดังนั้นไบนารีทรีสามรถได้มาจากทรีแบบลาดับที่เหมาะสมกัน

โดยการแยกกิ่งทางซ้ายออกจากกิ่งทางขวา



การเปลี่ยนทรีทั่วไปเป็นไบนารีทรี



ไบนารีทรีเป็นโครงสร้างข้อมูลที่มีประสิทธิภาพ แต่มีข้อจากัดว่า

แต่ละโหนดมีลูกได้ไม่เกิน 2 และในการประยุกต์ ใช้งานส่วนใหญ่

โครงสร้างข้อมูลเป็นจานวนใดๆ ได้ตามใจ การเปลี่ยนทรีทั่วไปเป็นไบนารีทรี

เริ่มต้นจะเชื่อมโหนด แต่ละโหนดกับโหนดลูกซ้ายสุดของโหนดนั้น ซึ่งเรียกว่าโหนดแรก

ต่อมาเชื่อมแต่ละโหนดยกเว้นโหนดรากกับโหนดถัดไป ที่มีพ่อเดียวกัน(พี่น้อง)

ซึ่งเรียกว่าเชื่อมโหนดลูกถัดไป



เพื่อให้โครงสร้างของไบนารีทรีที่ดีกว่านี้ จะต้องหมุนทรีเล็กน้อยตามเข็มนาฬิกา

ซึ่งจะทาให้เส้นเชื่อมที่ชี้ลงล่าง ชี้ลงไปทางซ้าย และเส้นเชื่อมที่ชี้ตามแนวนอน

ชี้ลงไปข้างล่างทางขวา



ป่าและสวน



ป่า (forest) หมายถึงของทรีที่เป็นทรีแบบรก และ สวน (orchard) หมายถึง

ชุดของทรีแบบลาดับ แต่โดยทั่วไป แล้วป่ากับสวนมีความหมายเดียวกัน คือ

ชุดของทรีทั่วไป



สามารถสร้างป่าหรือสวนได้ โดยการขจัดรากออกไปจากทรีแบบราก

หรือแบบลาดับและทานองเดียวกัน สามารถแปลง จากป่าแสวนไปเป็นไบนารีทรีได้



มีขั้นตอนดังต่อไปนี้

ขจัดเส้นเชื่อมเดิมออก

แปลงทรีแต่ละต้นให้เป็นไบนารีทรี

เชื่อมโหนดรากของทรีเขาด้วยกัน ในแนวนอนโดยใช้ความสัมพันธ์พี่น้อง

หมุนทรีที่ได้ 45 องศาตามเข็มนาฬิกา

ซึ่งจะทาให้เส้นเชื่อมในแนวตั้งกลายเป็นเส้นเชื่อมทางซ้าย

และเส้นเชื่อมในแนวนอนกลายเป็นเส้นเชื่อมทางขวา



การท่องไบนารีทรี (traversal of binary tree)



เป็นการเคลื่อนที่ไปยังโหนดทุกโหนดของไบนารีของทรี

หรือการเยี่ยมโหนดทุกโหนดของทรี ในข้อมูลแบบทรีโหนด

ทุกโหนดที่จะท่องมีลาดับแตกต่างกัน ที่โหนดใด ไๆที่กาหนดให้จะต้องมีการกระทา 3

อย่าง ในลาดับใดๆ คือ

เยี่ยมโหนดนั้น

ท่องไปยังทรีย่อยทางซ้ายของโหนดนั้น

ท่องไปยังทรีย่อยทางขวาของโหนดนั้น

จุดสาคัญของของการท่องไบนารีทรีคือ จะเยี่ยมททรีย่อยก่อนการท่องทรีย่อยที่มีอยู่

หรือจะเยี่ยมโหนดนั้นใน ระหว่างการท่องทรีย่อยของโหนดนั้น

หรือจะเยี่ยมดหนดนั้นในระหว่างการท่องทรีย่อยภายหลังจากการท่องทรีย่อย

ทั้งสองของโหนดนั้นเสร็จเรียบร้อยแล้ว



ถ้าเรากาหนดให้การเยี่ยมโหนด เป็นงาน V การท่องทรีย่อยทางซ้ายเป็น L

การท่องทรีย่อยทางขวาเป็น R จึงจะ ได้วิธีการท่องทรีทั้งหมด 6 วิธี



VLR LVR LRV VRL RVL RLV

การท่องทรีทั้ง 6 วิธีดังกล่าวเราจะลดเหลือ 3 วิธี

ที่มีการท่องทรีย่อยทางซ้ายก่อนการท่องทรีย่อยทางขวา ส่วนอีก 3 วิธีที่เหลือ

ก็เหมือนกับเป็นภาพกระจกเงาของ 3 วิธี

ดังกล่าววิธีการท่องทรีย่อยทางซ้ายก่อนทรีย่อยทางขวา 3 วิธีดังกล่าว

เรามีชื่อเรียกเฉพาะดังนี้

แบบ VLR เรียกว่า พรีออร์เดอร์ (preoder)

แบบ LVR เรียกว่า อินออร์เดอร์ (inorder)

แบบ LRV เรียกว่า โพสต์ออร์เดอร์(postorder)

การเรียกชื่อ 3 วิธีดังกล่าว จะเรียกตามลาดับการเยี่ยมโหนด V



นันคือการท่องแบบพรีออร์เดอร์จะเยี่ยมโหนด V ก่อนการเยี่ยมทรีย่อยทาง

ซ้ายและทางขวา การท่องแบบอินออร์เดอร์จะเยี่ยมโหนด V

ในระหว่างการท่องทรีย่อยทางซ้าย และทรีย่อยทางขวา

และการท่องแบบโพสต์ออร์เดอร์ โหนด V

จะถูกเยี่ยมหลังจากท่องทรีย่อยทางซ้ายและทางขวา มาแล้ว



การท่องแบบพรีออร์เดอร์ โหนดรากจะต้องถูกเยี่ยมเป็นอันดับแรก

จากนั้นจะเคลื่อนไปท่องยังทรีย่อยทางซ้าย

และจากนั้นก็จะเคลื่อนไปเยี่ยมทรีย่อยทางขวาของโหนดราก



การท่องแบบอินออร์เดอร์ ก่อนที่จะมีการเยี่ยมโหนดราก

จะท่องทรีย่อยทางซ้ายของโหนดรากก่อน จากนั้นจะเคลื่อน ไปเยี่ยมโหนดราก

และสุดท้ายก็จะเยี่ยมโหนดทางขวาของโหนดราก



การท่องแบบโพสต์ออร์เดอร์

จะท่องทรีย่อยทางซ้ายและทางขวาก่อนที่จะเยี่ยมโหนดราก

การประยุกต์ใช้ ไบนารีทรีกับนิพจน์ ก็สามารถจะกระทาได้

ถ้าประยุกต์ใช้แบบอินออร์เดอร์ จะได้ นิพจน์อินฟิกส์

ถ้าประยุกต์ใช้แบบโพสออร์เดอร์

จะได้นิพจน์โพสต์ฟิกส์ถ้าประยุกต์ใช้แบบพรีออร์เดอร์ จะได้นิพจน์พรีฟิกส์



ไบนารีแบบเทรด



การท่องไบนารีแบบทรีดังข้างต้น จะมีขั้นตอนการทางานแบบเรียกซ้า

จึงต้องมีการใช้สแตกมาช่วย คือในขณะที่ ทาการท่องไบนารีทรี

จะเก็บตาแหน่งต่าง ๆ ที่มีการเคลื่อนที่ผ่านไปไว้ในสแตก

และเมื่อต้องการย้อนกลับไปทางเดิมก็จะทา

การพ็อพสแตกเพื่อนาตาแหน่งต่าง ๆออกมา



วิธีการที่ประสิทธิภาพในการท่องไบนารี

โดยการให้ลิงค์ทางขวาของแต่ละโหนดที่เป็น NULL เก็บลิงค์พิเศษ

ที่ชี้ไปยังโหนดที่มาตามหลังโหนดนั้นๆ ในการท่องไบนารีทรี

และเรียกลิงค์พิเศษนี้ว่า "เทรดทางขวา"(right tread)

การใช้เทรดทาให้การท่องทาได้ง่ายขึ้น

เพราะเพียงแต่เดินตามลิงค์ธรามดา หรือเดินตามเทรดเพื่อหาโหนดถัดไป

และต่อมาเมื่อสร้างเทรดทางซ้าย (left tread) ด้วยโดย

ให้โหนดที่เป็นลิงค์ทางซ้ายเป็น NULL

เก็บลิงค์พิเศษที่ชี้ไปยังโหนดที่มาก่อน

ซึ่งจะทาให้ได้ไบนารีเทรดแบบสมบูรณ์(Fully threaded binary tree)

และในทานองเดียวกันก็สมารถสร้างเทรดแบบพรีออร์เดอร์

และโพสต์ออร์เดอร์ ได้ โดยการให้ลิงค์ทางซ้ายแทนค่าNULL

ชี้ไปยังโหนดที่มาก่อนแบบพรีออร์เดอร์หรือโพสต์ออร์เดอร์และลิงค์ทางข

วามีค่าเป็น NULL ชี้ไปยังโหนดที่มาทีหลัง แบบพรีออร์เดอร์ หรือ

โพสต์ออร์เดอร์ ในการเขียนโปรแกรม

ต้องมีวิธีการบางอย่างที่จะบอกว่าลิงค์แต่ละตัวเป็นลิงค์ที่ชี้ไปยังทรีย่อยป

กติหรือเป็นเทรดที่ชี้



ไปยังโหนดอื่น ๆใน ทรี จึงมีการออกแบบกันให้มีลักษณะดังนี้



LTAG Llink Information Rlink RTAG



โดยที่ LTAG และ RTAG มีขนาด 1 บิท เก็บข้อมูล 0 หรือ 1 (จริงหรือเท็จ)

ถ้า LTAG = 1 หมายถึงลิงค์ทางซ้ายชี้ไปยังทรีย่อยทางซ้ายแบบปกติ

ถ้า LTAG = 0

หมายถึงลิงค์ทางซ้ายเป็นเทรดที่ชี้ไปยังโหนดที่ชี้ไปยังโหนดที่มาก่อน

ถ้า RTAG = 1 หมายถึงลิงค์ทางขวาชี้ไปยังทรีย่อยทางขวาปกติ

ถ้า RTAG = 0 หมายถึงลิงค์ทางขวาชี้ไปยังโหนดที่มาทีหลัง



วิธีการท่องแบบเทรดนี้จึงเป็นวิธี ที่ทาให้เราสามารถท่องทรีได้โดยไม่ต้องใช้สแตกมาช่วย









โครงสร้างข้อมูลแบบกราฟ

(Graph Structure)





โครงสร้างกราฟ (Graph Structure)



กราฟ เป็นโครงสร้างข้อมูลที่มีโครงสร้างประกอบไปด้วยโหนด (Vertices)

และการเชื่อมต่อ(Edge)

ลักษณะการเชื่อมต่อจะแตกต่างจากโครงสร้างข้อมูลแบบอื่น ๆ คือ

สามารถที่จะเชื่อมต่อแต่ละโหนดได้หลากหลาย และทิศทางของการเดินทางสามารถเชื่อ

มต่อได้หลากหลายเช่นกัน



 สัญลักษณ์แทนกลุ่มโหนดและเส้นทางการเชื่อมต่อ

o G แทนกราฟ



o V แทนโหนด



o B แทนเส้นของการเชื่อมต่อ

ลักษณะของกราฟ





กราฟเป็นโครงสร้างข้อมูลเชิงตาข่าย (Network Structure)

มีการเชื่อมต่อความสัมพันธ์ระหว่างโหนดต่าง ๆ แบบหลากหลาย

โครงสร้างกราฟ เป็นแบบไม่ตายตัว (Dynamic Structure)

สามารถเพิ่มหรือลดโหนดได้ครั้งละหนึ่งหน่วยบนโครงสร้าง



 การเข้าถึงข้อมูลเป็นแบบลาดับ (Ordered traversal)

โดยเริ่มจากโหนดที่กาหนดเป็นโหนดเริ่มต้น

แล้วเข้าถึงโหนดต่อไปตามการเชื่อมต่อ









Abstract Data Type ของกราฟ



รูปแบบข้อมูล (Element): ข้อมูลที่จัดเก็บต้องเป็นชนิดเดียวกัน

เนื่องจากใช้อธิบายรูปแบบความสัมพันธ์ของโหนดกับการเชื่อมต่อ

รูปแบบโครงสร้าง (Srtucture): ความสัมพันธ์ระหว่างโหนดและการเชื่อมต่อ เป็นลักษณะ

หนึ่งต่อหนึ่ง (one to one) คือ

หนึ่งคู่ของการเชื่อมต่อจะต้องเชื่อมต่อด้วยเส้นเชื่อมต่อเพียงหนึ่งเส้น

การดาเนินงาน (Operation):

มีการดาเนินการพื้นฐานที่ใช้กับโหนดและการเชื่อมต่อพร้อมทั้งการค้นหาโหนดที่ต้องการ

5 การดาเนินการดังนี้

Abstract Data Type ของกราฟ





 การดาเนินการเพิ่มโหนด

 การดาเนินการลบโหนด

 การดาเนินการเพิ่มเส้นเชื่อมต่อ

 การดาเนินการลบเส้นเชื่อมต่อ

 การดาเนินการค้นหาโหนด









ทฤษฎีด้านการดาเนินการ





1.การดาเนินการเพิ่มโหนด



ก่อนดาเนินการ โหนดข้อมูลใหม่ที่ยังไม่มีการเชื่อมต่อ

หลังการดาเนินการโหนดถูกเพิ่มเข้ามายังโครงสร้างซึ่งไม่มีเส้น

เชื่อมต่อ









ทฤษฎีด้านการดาเนินการ





2.การดาเนินการลบโหนด



ก่อนดำเนินกำร เลือกโหนด

หลังกำรดำเนินกำรลบโหนดที่เลือกออกจากโครงสร้างพร้อมทั้ง



เส้นการเชื่อมต่อ









ทฤษฎีด้านการดาเนินการ





3.การดาเนินการเพิ่มเส้นเชื่อมต่อ



ก่อนดำเนินกำร ตรวจสอบโหนดที่จะทาการเพิ่มเส้นเชื่อมต่อทั้งคู่



ว่ายังไม่มีเส้นเชื่อมต่อ



หลังกำรดำเนินกำร เพิ่มเส้นเชื่อมต่อโหนดทั้งคู่







ทฤษฎีด้านการดาเนินการ





4.การดาเนินการลบเส้นเชื่อมต่อ



ก่อนดำเนินกำร เลือกเส้นเชื่อมต่อที่ต้องการลบ



หลังกำรดำเนินกำร เส้นเชื่อมต่อที่เลือกถูกลบออกจากคู่โหนด









ทฤษฎีด้านการดาเนินการ

5.การดาเนินการค้นหาโหนด



ก่อนดำเนินกำร -



หลังกำรดำเนินกำร ค้นพบโหนดที่ต้องการแล้วส่งค่าตาแหน่งของโหนดคืน

ถ้าไม่พบให้ส่งค่าผิดพลาด









การแทนที่กราฟด้วยเมตริกซ์ (Adjacency Matrix)



 เป็นโครงสร้างที่ประกอบไปด้วยโหนดและเส้นเชื่อมต่อที่บอกถึงเส้นทางของการเ

ดินทาง หรือความสัมพันธ์ในทิศทางซึ่งสามารถนามาแทนความสัมพันธ์นั้นด้วยก

ารกาหนดเมตริกซ์ n x n





การท่องเข้าไปในกราฟ (Traversal)





มีรูปแบบของการดาเนินการ 3 รูปแบบ



 Breadth First Search (BFS)

 Depth First Search (DFS)

 Priority First Search (PFS)









การท่องเข้าไปในกราฟ (Traversal)





 Breadth First Search (BFS)

เป็นการท่องเข้าไปในกราฟโดยเข้าเยี่ยมโหนดตัวแรก

และดาเนินการ หากมีโหนดใกล้เคียงจะดาเนินการกับโหนดที่อยู่ด้านซ้ายก่อน





การท่องเข้าไปในกราฟ (Traversal)





 Depth First Search (DFS)



เป็นลักษณะการท่องเข้าไปยังโหนดเริ่มต้น แล้วให้โหนดใกล้เคียงเป็นโหนดเริ่มต้น เ

ข้าเยี่ยมโหนด ทาต่อไปจนกระทั่งไม่มีโหนดใกล้เคียงจึงย้อนกลับมายังโหนดก่อนหน้า แ

ละเข้าเยี่ยมโหนดอีกด้านด้วยรูปแบบเดียวกันจนครบ

เทียบได้กับการท่องเข้าไปในทรีแบบพรีออเดอร์





การท่องเข้าไปในกราฟ (Traversal)



Priority First Search (PFS)

มีรูปแบบของการท่องเข้าไปเยี่ยม (Visit) โหนดต่าง ๆ

ด้วยรูปแบบของคิวที่มีลาดับความสาคัญ (Priority Queues)

แทนที่โครงสร้างสแตกหรือคิวแบบทั่วไป คือมีการเพิ่มคิวเข้ามาโดยพิจารณาและดาเนิน

การในลาดับที่สาคัญก่อน









ระบบข่ายงาน (Network)







อัลกอริทึมคานวณระยะทางในข่ายงาน



1. Minimum Spanning Tree



o เป็นรูปแบบของการค้นหาโดยกาหนดเรียกใช้โหนดทุกโหนดและทุกเส้นก

ารเชื่อมต่อ มาลาดับความสาคัญของน้าหนักโดยเริ่มจากค่าน้อยที่สุดในข่

ายงาน ทาการเชื่อมต่อคู่โหนดนั้น และดาเนินการต่อไปในค่าน้าหนักที่ต่

อกัน แต่ถ้าโหนดใดมีการเชื่อมต่อคู่โหนดแล้วจะไม่เชื่อมต่ออีก



อัลกอริทึมคานวณระยะทางในข่ายงาน



2. Shortest Path Algorithm



o เป็นอัลกอริทึมที่ใช้ในการหาระยะทางที่สั้นที่สุดเช่นเดียวกับ MST

แต่จะเปลี่ยนจากการหาเส้นทางจากโหนดแรกไปยังโหนดปลายทางของข่

ายงาน เป็นโหนดที่กาหนดเป็นโหนดต้นทางไปยังโหนดต่าง ๆ

โดยหาระยะทางสั้นที่สุดแต่ละเส้นทาง



ตัวอย่างเช่น กาหนดการเดินทางจากบ้านยังจังหวัดต่าง ๆ

ด้วยการเดินทางด้วยเครื่องบิน จะต้องมีการวางแผนว่าจะใช้สายการบินเส้นทางใดไป


Related docs
Other docs by HC111211053933
Activity 2
Views: 0  |  Downloads: 0
Year 3 and 4 Medium Term Planning � Block A
Views: 0  |  Downloads: 0
Document
Views: 3  |  Downloads: 0
DEPARTMENT OF
Views: 0  |  Downloads: 0
Description
Views: 1  |  Downloads: 0
FEDERAL COURT OF AUSTRALIA
Views: 0  |  Downloads: 0
PG Seminars 07
Views: 1  |  Downloads: 0
CIVIL WAR TRIVIA
Views: 2  |  Downloads: 0
OPERATIONALIZING VARIABLES
Views: 0  |  Downloads: 0
By registering with docstoc.com you agree to our
privacy policy

You are almost ready to download!

You are almost ready to download!