อัลกอริทึมของ Prim

ในวิทยาการคอมพิวเตอร์อัลกอริทึมของ Primเป็นอัลกอริทึมแบบโลภ (greedy algorithm)ที่ใช้ค้นหาต้นไม้แผ่คลุมน้อยที่สุด (minimum spanning tree ) สำหรับกราฟแบบไม่มีทิศทาง ที่มีน้ำหนัก หมายความว่ามันจะค้นหาส่วนย่อยของขอบที่สร้างเป็นต้นไม้ซึ่งรวมทุกจุดยอดโดยที่น้ำหนักรวมของขอบ ทั้งหมด ในต้นไม้นั้นมีค่าน้อยที่สุด อัลกอริทึมนี้ทำงานโดยการสร้างต้นไม้นี้ทีละจุดยอด จากจุดยอดเริ่มต้นใดๆ ในแต่ละขั้นตอนจะเพิ่มการเชื่อมต่อที่ถูกที่สุดเท่าที่จะเป็นไปได้จากต้นไม้ไปยังจุดยอดอื่น
อัลกอริทึมนี้ได้รับการพัฒนาขึ้นในปี พ.ศ. 2473 โดยนักคณิตศาสตร์ชาว เช็ก Vojtěch Jarník [ 1 ]และต่อมาได้รับการค้นพบและเผยแพร่อีกครั้งโดย นัก วิทยาศาสตร์คอมพิวเตอร์Robert C. Primในปี พ.ศ. 2490 [ 2 ]และEdsger W. Dijkstraในปี พ.ศ. 2492 [ 3 ]ดังนั้นบางครั้งจึงเรียกว่าอัลกอริทึมของ Jarník [ 4 ]อัลกอริทึม Prim–Jarník [ 5 ]อัลกอริทึม Prim–Dijkstra [ 6 ] หรือ อั ลกอริทึม DJP [ 7 ]
อัลกอริทึมที่รู้จักกันดีอื่นๆ สำหรับปัญหานี้ ได้แก่อัลกอริทึมของ Kruskalและอัลกอริทึมของ Borůvka [ 8 ] อัลกอริทึมเหล่านี้ค้นหาป่าแผ่ขยายขั้นต่ำในกราฟที่อาจไม่เชื่อมต่อกัน ในทางตรงกันข้าม รูปแบบพื้นฐานที่สุดของอัลกอริทึมของ Prim จะค้นหาต้นไม้แผ่ขยายขั้นต่ำในกราฟที่เชื่อมต่อกันเท่านั้น อย่างไรก็ตาม การเรียกใช้อัลกอริทึมของ Prim แยกกันสำหรับแต่ละส่วนประกอบที่เชื่อมต่อกันของกราฟ ก็สามารถใช้เพื่อค้นหาป่าแผ่ขยายขั้นต่ำได้เช่นกัน[ 9 ]ในแง่ของความซับซ้อนของเวลา เชิงอะซิมโทติก อัลกอริทึมทั้งสามนี้มีความเร็วเท่ากันสำหรับกราฟแบบเบาบางแต่ช้ากว่าอัลกอริทึมที่ซับซ้อนกว่าอื่นๆ[ 7 ] [ 6 ] อย่างไรก็ตาม สำหรับกราฟที่มีความหนาแน่นเพียงพอ อัลกอริทึมของ Prim สามารถทำงานได้ในเวลาเชิงเส้นซึ่งตรงตามหรือปรับปรุงขอบเขตเวลาสำหรับอัลกอริทึมอื่นๆ[ 10 ]

คำอธิบาย
โดยคร่าวๆ อาจอธิบายอัลกอริทึมนี้ได้ว่าดำเนินการตามขั้นตอนต่อไปนี้:
- เริ่มต้นสร้างต้นไม้ด้วยจุดยอดเพียงจุดเดียว ซึ่งเลือกมาโดยพลการจากกราฟ
- ขยายต้นไม้โดยใช้ขอบเพียงเส้นเดียว: ในบรรดาขอบที่เชื่อมต่อต้นไม้กับจุดยอดที่ยังไม่ได้อยู่ในต้นไม้ ให้หาขอบที่มีน้ำหนักน้อยที่สุด แล้วโอนขอบนั้นเข้าไปในต้นไม้
- ทำซ้ำขั้นตอนที่ 2 (จนกว่าจุดยอดทั้งหมดจะอยู่ในต้นไม้)
กล่าวโดยละเอียด สามารถนำไปใช้ได้ตามรหัสเทียมด้านล่างนี้
ฟังก์ชัน Prim(vertices, edges) คือสำหรับแต่ละจุดยอดใน vertices ให้ทำซ้ำ cheapestCost[vertex] ← ∞ cheapestEdge[vertex] ← null สำรวจ ← เซตว่าง ยังไม่ได้สำรวจ ← เซตที่ประกอบด้วยจุดยอดทั้งหมด startVertex ← องค์ประกอบใดๆ ของกลุ่มจุดยอด cheapestCost[startVertex] ← 0 ในขณะที่ยังไม่ได้สำรวจนั้นไม่ได้ว่างเปล่า // เลือกจุดยอดในพื้นที่ที่ยังไม่ได้สำรวจโดยใช้ต้นทุนต่ำสุด currentVertex ← vertex in unexplored with minimum cheapestCost[vertex] unexplored.remove(currentVertex) explored.add(currentVertex) สำหรับแต่ละขอบ (currentVertex, neighbor) ใน edges ให้ตรวจสอบว่า neighbor อยู่ใน unexplored และ weight(currentVertex, neighbor) < cheapestCost[neighbor] หรือไม่ cheapestCost[neighbor] ← weight(currentVertex, neighbor) cheapestEdge[neighbor] ← (currentVertex, neighbor) resultEdges ← รายการว่าง สำหรับแต่ละจุดยอดใน vertices ให้ทำดังนี้ถ้า cheapestEdge[vertex] ≠ null แล้ว resultEdges.append(cheapestEdge[vertex]) ผลลัพธ์ขอบ
ดังที่ได้อธิบายไว้ข้างต้น จุดเริ่มต้นของอัลกอริทึมจะถูกเลือกโดยพลการ เนื่องจากรอบแรกของลูปหลักของอัลกอริทึมจะมีชุดของจุดยอดในQที่มีน้ำหนักเท่ากันทั้งหมด และอัลกอริทึมจะเริ่มต้นต้นไม้ใหม่ในF โดยอัตโนมัติ เมื่อสร้างต้นไม้แผ่คลุมของแต่ละส่วนประกอบที่เชื่อมต่อกันของกราฟอินพุตเสร็จสมบูรณ์ อัลกอริทึมอาจถูกปรับเปลี่ยนให้เริ่มต้นด้วยจุดยอดs ใดๆ โดยการตั้งค่าC [ s ] ให้เป็นตัวเลขที่เล็กกว่าค่าอื่นๆ ของC (เช่น ศูนย์) และอาจถูกปรับเปลี่ยนให้ค้นหาต้นไม้แผ่คลุมเพียงต้นเดียวแทนที่จะเป็นป่าแผ่คลุมทั้งหมด (ซึ่งตรงกับคำอธิบายอย่างไม่เป็นทางการมากกว่า) โดยหยุดเมื่อใดก็ตามที่พบจุดยอดอื่นที่ถูกทำเครื่องหมายว่าไม่มีขอบที่เกี่ยวข้อง
อัลกอริทึมรูปแบบต่างๆ จะแตกต่างกันในวิธีการใช้งาน เซต Q : อาจเป็น รายการเชื่อมโยง แบบง่าย หรืออาร์เรย์ของจุดยอด หรืออาจเป็น โครงสร้างข้อมูล คิวลำดับความสำคัญ ที่ซับซ้อนกว่า การเลือกเช่นนี้ส่งผลให้ความซับซ้อนเชิงเวลาของอัลกอริทึมแตกต่างกัน โดยทั่วไปแล้ว คิวลำดับความสำคัญจะค้นหาจุดยอดvที่มีต้นทุนต่ำที่สุดได้เร็วกว่า แต่จะต้องมีการอัปเดตที่แพงกว่าเมื่อค่าของC [ w ] เปลี่ยนแปลง
ความซับซ้อนเชิงเวลา
ความซับซ้อนเชิงเวลาของอัลกอริทึมของ Prim ขึ้นอยู่กับโครงสร้างข้อมูลที่ใช้สำหรับกราฟและสำหรับการจัดลำดับขอบตามน้ำหนัก ซึ่งสามารถทำได้โดยใช้คิวลำดับความสำคัญตารางต่อไปนี้แสดงตัวเลือกทั่วไป:
| โครงสร้างข้อมูลน้ำหนักขอบขั้นต่ำ | ความซับซ้อนด้านเวลา (โดยรวม) |
|---|---|
| เมทริกซ์ประชิดการค้นหา | |
| ฮีปไบนารีและรายการความสัมพันธ์ | |
| กองฟิโบนาชี่และรายการความสัมพันธ์ |
การใช้งานวิธีของ Prim อย่างง่าย โดยใช้เมทริกซ์ประชิดหรือ การแสดงกราฟ รายการประชิดและการค้นหาน้ำหนักขั้นต่ำในอาร์เรย์ของน้ำหนักแบบเชิงเส้นเพื่อหาขอบที่มีน้ำหนักน้อยที่สุดที่จะเพิ่มเข้าไปนั้น ต้องใช้ เวลาในการทำงาน O ( | V | ² ) อย่างไรก็ตาม เวลาในการทำงานนี้สามารถปรับปรุงได้อย่างมากโดยใช้ฮีปในการค้นหาน้ำหนักขั้นต่ำในลูปภายในของอัลกอริทึม
เวอร์ชันปรับปรุงแรกใช้ฮีปเพื่อจัดเก็บขอบทั้งหมดของกราฟอินพุต โดยเรียงลำดับตามน้ำหนัก ซึ่งทำให้เวลาการทำงานในกรณีที่เลวร้ายที่สุดคือ O(|E| log |E|) แต่การจัดเก็บจุดยอดแทนขอบสามารถปรับปรุงให้ดียิ่งขึ้นไปอีก ฮีปควรเรียงลำดับจุดยอดตามน้ำหนักขอบที่น้อยที่สุดที่เชื่อมต่อกับจุดยอดใดๆ ในต้นไม้แผ่คลุมขั้นต่ำ (MST) ที่สร้างขึ้นบางส่วน (หรืออนันต์หากไม่มีขอบดังกล่าว) ทุกครั้งที่เลือกจุดยอดvและเพิ่มลงใน MST จะมีการดำเนินการลดค่าคีย์กับจุดยอดw ทั้งหมดที่ อยู่นอก MST บางส่วนซึ่งvเชื่อมต่อกับwโดยตั้งค่าคีย์เป็นค่าต่ำสุดของค่าก่อนหน้าและค่าใช้จ่ายของขอบของ ( v , w )
โดยใช้โครงสร้างข้อมูล ฮีปไบนารีแบบง่ายอัลกอริทึมของ Prim สามารถแสดงให้เห็นว่าทำงานในเวลาO ( | E | log | V | ) โดยที่| E |คือจำนวนขอบและ| V |คือจำนวนจุดยอด การใช้ฮีปฟิโบนาชชี ที่ซับซ้อนกว่า นี้ สามารถลดเวลาการทำงานลงเหลือO ( | E | + | V | log | V | ) ซึ่งเร็วกว่าในเชิง อะซิมโทติก เมื่อกราฟมีความหนาแน่นมากพอที่| E |คือω ( | V | ) และใช้เวลาเชิงเส้นเมื่อ |E| อย่างน้อย |V| log |V| สำหรับกราฟที่มีความหนาแน่นมากกว่า (มีขอบอย่างน้อย |V| cสำหรับc > 1 บางค่า) อัลกอริทึมของ Prim สามารถทำให้ทำงานในเวลาเชิงเส้นได้ง่ายยิ่งขึ้น โดยใช้ฮีปd -ary แทนฮีปฟิโบนาชชี[ 10 ] [ 11 ]

หลักฐานยืนยันความถูกต้อง
ให้Pเป็นกราฟ เชื่อมต่อที่มีน้ำหนัก ในแต่ละรอบของการทำงานของอัลกอริทึมของ Prim จะต้องหาเส้นเชื่อมที่เชื่อมจุดยอดในกราฟย่อยกับจุดยอดนอกกราฟย่อย เนื่องจาก Pเป็นกราฟเชื่อมต่อ จึงจะมีเส้นทางไปยังทุกจุดยอดเสมอ ผลลัพธ์Yของอัลกอริทึมของ Prim คือต้นไม้เพราะเส้นเชื่อมและจุดยอดที่เพิ่มเข้าไปในต้นไม้Yนั้นเชื่อมต่อกัน
ให้Y เป็นต้นไม้แผ่คลุมขั้นต่ำของกราฟ P ถ้าY = Yแล้วYเป็นต้นไม้แผ่คลุมขั้นต่ำ มิฉะนั้น ให้eเป็นขอบแรกที่เพิ่มเข้ามาในระหว่างการสร้างต้นไม้Yที่ไม่ได้อยู่ในต้นไม้Y และVเป็นเซตของจุดยอดที่เชื่อมต่อกันด้วยขอบที่เพิ่มเข้ามาก่อนขอบeดังนั้นจุดปลายด้านหนึ่งของขอบeอยู่ในเซตVและอีกด้านหนึ่งไม่อยู่ เนื่องจากต้นไม้Y เป็นต้นไม้แผ่คลุมของกราฟPจึงมีเส้นทางในต้นไม้Y ที่เชื่อมต่อจุดปลายทั้งสอง เมื่อเดินทางไปตามเส้นทางนั้น จะต้องพบขอบfที่เชื่อมต่อจุดยอดในเซตVกับจุดยอดที่ไม่ได้อยู่ในเซตVในการวนซ้ำเมื่อขอบeถูกเพิ่มเข้าไปในต้นไม้Yขอบfก็อาจถูกเพิ่มเข้าไปด้วย และจะถูกเพิ่มเข้าไปแทนขอบeถ้าค่าน้ำหนักของมันน้อยกว่าeและเนื่องจากขอบfไม่ได้ถูกเพิ่มเข้าไป เราจึงสรุปได้ว่า
ให้ต้นไม้Y2เป็นกราฟที่ได้จากการลบขอบf ออกจาก และเพิ่มขอบeเข้าไปในต้นไม้Y1 สามารถแสดงได้อย่างง่ายดายว่าต้นไม้Y2 เชื่อมต่อ มีจำนวนขอบเท่ากับต้นไม้Y1และน้ำหนักรวมของขอบทั้งหมดไม่เกินน้ำหนักรวมของขอบทั้งหมดของต้นไม้Y1 ดังนั้น ต้นไม้ จึงเป็นต้นไม้แผ่คลุมขั้นต่ำของกราฟPและประกอบด้วยขอบeและขอบทั้งหมดที่เพิ่มเข้ามาก่อนหน้านั้นในระหว่างการสร้างเซตVทำซ้ำขั้นตอนข้างต้นและในที่สุดเราจะได้ต้นไม้แผ่คลุมขั้นต่ำของกราฟPที่เหมือนกับต้นไม้Yซึ่งแสดงให้เห็นว่าYเป็นต้นไม้แผ่คลุมขั้นต่ำ ต้นไม้แผ่คลุมขั้นต่ำช่วยให้เซตย่อยแรกของบริเวณย่อยสามารถขยายออกเป็นเซตย่อยX ที่ใหญ่กว่า ซึ่งเราสมมติว่าเป็นเซตย่อยที่เล็กที่สุด
อัลกอริทึมแบบขนาน

ลูปหลักของอัลกอริทึมของ Prim นั้นเป็นแบบลำดับโดยเนื้อแท้และไม่สามารถขนานได้อย่างไรก็ตามลูปภายในซึ่งกำหนดขอบถัดไปที่มีน้ำหนักน้อยที่สุดที่ไม่ก่อให้เกิดวงจร สามารถขนานได้โดยการแบ่งจุดยอดและขอบระหว่างโปรเซสเซอร์ที่มีอยู่[ 12 ]รหัสเทียมต่อไปนี้แสดงให้เห็นสิ่งนี้
- กำหนดค่าให้กับโปรเซสเซอร์แต่ละตัวชุดหนึ่งของจุดยอดที่ต่อเนื่องกันซึ่งมีความยาว.
- สร้าง C, E, F และ Q ตามขั้นตอนวิธีแบบลำดับและแบ่ง C, E รวมถึงกราฟระหว่างโปรเซสเซอร์ทั้งหมด โดยที่โปรเซสเซอร์แต่ละตัวจะเก็บขอบขาเข้าของชุดจุดยอดของตนเอง,ระบุส่วนต่างๆ ของCและEที่จัดเก็บไว้บนโปรเซสเซอร์.
- ทำซ้ำขั้นตอนต่อไปนี้จนกว่าQจะว่างเปล่า:
- ในทุกโปรเซสเซอร์: ค้นหาจุดยอดมีค่าต่ำสุดใน[(วิธีแก้ปัญหาเฉพาะที่)
- ลดค่า ต่ำสุด ของคำตอบเฉพาะที่เพื่อหาจุดยอดvที่มีค่าC [ v ] น้อยที่สุดเท่าที่จะเป็นไปได้ (คำตอบโดยรวม)
- ส่งข้อมูลโหนดที่เลือกไปยังโปรเซสเซอร์ทุกตัว
- เพิ่มv ลง ในFและหากE [ v ] ไม่ใช่ค่าแฟล็กพิเศษ ให้เพิ่มE [ v ] ลงในFด้วย
- บนโปรเซสเซอร์ทุกตัว: อัปเดตและเช่นเดียวกับในอัลกอริธึมแบบลำดับ
- คืนค่าF
โดยทั่วไปแล้วอัลกอริธึมนี้สามารถนำไปใช้กับเครื่องกระจาย[ 12 ]เช่นเดียวกับเครื่องหน่วยความจำร่วม[ 13 ]เวลาในการทำงานคือโดยสมมติว่า การดำเนินการ ลดและกระจายสัญญาณสามารถทำได้ใน[ 12 ] ได้มีการสำรวจอัลกอริธึมของ Prim เวอร์ชันสำหรับเครื่องหน่วยความ จำร่วม ซึ่งอัลกอริธึมลำดับของ Prim จะทำงานแบบขนาน โดยเริ่มจากจุดยอดที่แตกต่างกัน[ 14 ]อย่างไรก็ตาม ควรสังเกตว่ามีอัลกอริธึมที่ซับซ้อนกว่านี้ในการแก้ ปัญหา ต้นไม้ครอบคลุมขั้นต่ำแบบกระจายได้อย่างมีประสิทธิภาพมากขึ้น
ดูเพิ่มเติม
- อัลกอริทึมของไดจ์กสตราเป็นอัลกอริทึมที่คล้ายคลึงกันมากสำหรับปัญหาการหาเส้นทางที่สั้นที่สุด
- กรีดอยด์sนำเสนอวิธีการทั่วไปในการทำความเข้าใจความถูกต้องของอัลกอริทึมของ Prim