DFS ส่วนใหญ่ใช้เพื่อค้นหาวัฏจักรในกราฟไม่ใช่ BFS เหตุผลใด? ทั้งสองสามารถค้นหาได้ว่ามีการเยี่ยมชมโหนดแล้วหรือไม่ในขณะที่ข้ามต้นไม้ / กราฟ
DFS ส่วนใหญ่ใช้เพื่อค้นหาวัฏจักรในกราฟไม่ใช่ BFS เหตุผลใด? ทั้งสองสามารถค้นหาได้ว่ามีการเยี่ยมชมโหนดแล้วหรือไม่ในขณะที่ข้ามต้นไม้ / กราฟ
คำตอบ:
การค้นหาครั้งแรกเชิงลึกจะมีประสิทธิภาพในการจำมากกว่าการค้นหาครั้งแรกแบบกว้างเนื่องจากคุณสามารถย้อนกลับได้เร็ว นอกจากนี้ยังง่ายต่อการใช้งานหากคุณใช้ call stack แต่ต้องอาศัยพา ธ ที่ยาวที่สุดไม่ล้นสแต็ก
นอกจากนี้หากกราฟของคุณถูกนำทางคุณจะต้องไม่เพียง แต่จำไว้ว่าคุณเคยไปที่โหนดหรือไม่ แต่ยังรวมถึงวิธีที่คุณไปที่นั่นด้วย มิฉะนั้นคุณอาจคิดว่าคุณได้พบกับวัฏจักร แต่ในความเป็นจริงสิ่งที่คุณมีคือสองเส้นทางที่แยกจากกัน A-> B แต่นั่นไม่ได้หมายความว่ามีเส้นทาง B-> A ตัวอย่างเช่น,
หากคุณทำ BFS โดยเริ่มจาก0
จะตรวจพบว่ามีวงจรอยู่ แต่จริงๆแล้วไม่มีวงจร
ด้วยการค้นหาครั้งแรกในเชิงลึกคุณสามารถทำเครื่องหมายโหนดว่าเยี่ยมชมแล้วเมื่อคุณลงมาและยกเลิกการทำเครื่องหมายเมื่อคุณย้อนกลับ ดูความคิดเห็นสำหรับการปรับปรุงประสิทธิภาพของอัลกอริทึมนี้
สำหรับขั้นตอนวิธีการที่ดีที่สุดสำหรับการตรวจสอบรอบในกราฟที่คุณสามารถดูขั้นตอนวิธีการ Tarjan ของ
BFS อาจสมเหตุสมผลหากไม่มีการกำหนดทิศทางของกราฟ (โปรดเป็นแขกของฉันในการแสดงอัลกอริทึมที่มีประสิทธิภาพโดยใช้ BFS ที่จะรายงานรอบในกราฟกำกับ!) โดยที่ "cross edge" แต่ละอันจะกำหนดวัฏจักร ถ้าครอสเอดจ์คือ{v1, v2}
และรูท (ในทรี BFS) ที่มีโหนดเหล่านั้นอยู่r
ดังนั้นวัฏจักรคือr ~ v1 - v2 ~ r
( ~
คือพา ธ-
ขอบเดียว) ซึ่งสามารถรายงานได้เกือบจะง่ายเหมือนใน DFS
เหตุผลเดียวที่จะใช้ BFS คือถ้าคุณรู้ว่ากราฟ (ไม่ได้บอกทิศทาง) ของคุณจะมีเส้นทางยาวและมีเส้นทางเล็ก ๆ (กล่าวอีกนัยหนึ่งคือลึกและแคบ) ในกรณีนั้น BFS จะต้องใช้หน่วยความจำสำหรับคิวน้อยกว่าตามสัดส่วนของ DFS 'stack (แน่นอนว่าทั้งคู่ยังคงเป็นเส้นตรง)
ในกรณีอื่น ๆ DFS เป็นผู้ชนะอย่างชัดเจน มันทำงานบนกราฟทั้งแบบกำหนดทิศทางและแบบไม่บอกทิศทางและเป็นเรื่องเล็กน้อยที่จะรายงานวัฏจักร - เพียงต่อขอบด้านหลังใด ๆ เข้ากับเส้นทางจากบรรพบุรุษไปยังลูกหลานและคุณจะได้รับวงจร สรุปแล้วดีกว่าและใช้งานได้จริงกว่า BFS สำหรับปัญหานี้
BFS จะไม่ทำงานสำหรับกราฟที่กำหนดทิศทางในการค้นหารอบ พิจารณา A-> B และ A-> C-> B เป็นเส้นทางจาก A ถึง B ในกราฟ BFS จะบอกว่าหลังจากเดินไปตามหนึ่งในเส้นทางที่ B ไปเยี่ยม เมื่อเดินทางต่อไปในเส้นทางถัดไปจะบอกว่ามีการพบโหนด B อีกครั้งดังนั้นจึงมีวงจรอยู่ที่นั่น เห็นได้ชัดว่าไม่มีวงจรที่นี่
ฉันไม่รู้ว่าทำไมคำถามเก่า ๆ ถึงโผล่ขึ้นมาในฟีดของฉัน แต่คำตอบก่อนหน้านี้ทั้งหมดไม่ดีดังนั้น ...
DFS ใช้เพื่อค้นหารอบในกราฟกำกับเพราะมันใช้งานได้
ใน DFS ทุกจุดยอดคือ "เยี่ยม" ซึ่งการเยี่ยมชมจุดยอดหมายถึง:
มีการเยี่ยมชมย่อหน้าย่อยที่เข้าถึงได้จากจุดยอดนั้น ซึ่งรวมถึงการติดตามขอบที่ไม่มีการติดตามทั้งหมดที่สามารถเข้าถึงได้จากจุดยอดนั้นและการเยี่ยมชมจุดยอดที่ไม่สามารถเข้าถึงได้ทั้งหมด
จุดยอดเสร็จสิ้น
คุณลักษณะที่สำคัญคือขอบทั้งหมดที่เข้าถึงได้จากจุดยอดจะถูกตรวจสอบก่อนจุดยอดจะเสร็จสิ้น นี่เป็นคุณสมบัติของ DFS แต่ไม่ใช่ BFS อันที่จริงนี่คือคำจำกัดความของ DFS
เนื่องจากคุณสมบัตินี้เรารู้ว่าเมื่อจุดยอดแรกในวงจรเริ่มต้น:
ดังนั้นหากมีวัฏจักรเรารับประกันว่าจะพบขอบของจุดยอดเริ่มต้น แต่ยังไม่เสร็จ (2) และหากเราพบขอบดังกล่าวเราจะรับประกันได้ว่ามีวัฏจักร (3)
นั่นเป็นเหตุผลที่ DFS ใช้เพื่อค้นหารอบในกราฟกำกับ
BFS ไม่มีการรับประกันดังกล่าวดังนั้นจึงไม่ได้ผล (แม้ว่าอัลกอริธึมการค้นหาวงจรที่ดีอย่างสมบูรณ์แบบซึ่งรวม BFS หรือคล้ายกันเป็นโพรซีเดอร์ย่อย)
ในทางกลับกันกราฟที่ไม่ได้บอกทิศทางมีวัฏจักรเมื่อใดก็ตามที่มีสองเส้นทางระหว่างจุดยอดคู่ใด ๆ กล่าวคือเมื่อมันไม่ใช่ต้นไม้ สิ่งนี้ง่ายต่อการตรวจจับระหว่าง BFS หรือ DFS - ขอบที่โยงไปถึงจุดยอดใหม่จะก่อตัวเป็นต้นไม้และขอบอื่น ๆ บ่งบอกถึงวัฏจักร
หากคุณวางวงรอบไว้ที่จุดสุ่มบนต้นไม้ DFS จะมีแนวโน้มที่จะชนวงจรเมื่อมันปกคลุมต้นไม้ประมาณครึ่งหนึ่งและครึ่งหนึ่งของเวลาที่มันจะเคลื่อนที่ไปตามที่ที่วัฏจักรไปแล้วและครึ่งหนึ่งของเวลาจะไม่ ( และจะพบโดยเฉลี่ยในครึ่งหนึ่งของต้นไม้ที่เหลือ) ดังนั้นจะประเมินโดยเฉลี่ยประมาณ 0.5 * 0.5 + 0.5 * 0.75 = 0.625 ของต้นไม้
หากคุณวางวงรอบไว้ที่จุดสุ่มในต้นไม้ BFS จะมีแนวโน้มที่จะเข้าสู่วงจรก็ต่อเมื่อมีการประเมินเลเยอร์ของต้นไม้ที่ความลึกนั้น ดังนั้นคุณมักจะต้องประเมินใบไม้ของต้นไม้ไบนารีที่สมดุลซึ่งโดยทั่วไปจะส่งผลให้มีการประเมินต้นไม้มากขึ้น โดยเฉพาะอย่างยิ่ง 3/4 ของเวลาอย่างน้อยหนึ่งในสองลิงก์จะปรากฏในใบไม้ของต้นไม้และในกรณีเหล่านั้นคุณต้องประเมินโดยเฉลี่ย 3/4 ของต้นไม้ (หากมีลิงก์เดียว) หรือ 7 / 8 ของต้นไม้ (ถ้ามีสองอัน) ดังนั้นคุณถึงคาดหวังที่จะค้นหา 1/2 * 3/4 + 1/4 * 7/8 = (7 + 12) / 32 = 21/32 = 0.656 ... ของต้นไม้โดยไม่ต้องเพิ่มค่าใช้จ่ายในการค้นหาต้นไม้ด้วยวัฏจักรที่เพิ่มออกไปจากโหนดใบไม้
นอกจากนี้ DFS ยังใช้งานได้ง่ายกว่า BFS ดังนั้นจึงเป็นสิ่งที่จะใช้เว้นแต่คุณจะรู้บางอย่างเกี่ยวกับวัฏจักรของคุณ (เช่นวัฏจักรมีแนวโน้มที่จะอยู่ใกล้รูทที่คุณค้นหาซึ่งจุดนั้น BFS จะให้ข้อได้เปรียบแก่คุณ)
ในการพิสูจน์ว่ากราฟเป็นวัฏจักรคุณเพียงแค่ต้องพิสูจน์ว่ามันมีหนึ่งรอบ (ขอบชี้เข้าหาตัวเองไม่ว่าทางตรงหรือทางอ้อม)
ใน DFS เราใช้จุดยอดหนึ่งครั้งและตรวจสอบว่ามีวัฏจักรหรือไม่ ทันทีที่พบวัฏจักรเราสามารถละเว้นการตรวจสอบจุดยอดอื่น ๆ ได้
ใน BFS เราจำเป็นต้องติดตามขอบจุดยอดจำนวนมากพร้อมกันและบ่อยครั้งกว่าที่คุณจะพบว่ามันมีวัฏจักรหรือไม่ในตอนท้าย เนื่องจากขนาดของกราฟเติบโตขึ้น BFS ต้องใช้พื้นที่มากขึ้นการคำนวณและเวลาเมื่อเทียบกับ DFS
ขึ้นอยู่กับว่าคุณกำลังพูดถึงการใช้งานแบบวนซ้ำหรือแบบวนซ้ำ
Recursive-DFS เข้าชมทุกโหนดสองครั้ง Iterative-BFS เข้าชมทุกโหนดหนึ่งครั้ง
หากคุณต้องการตรวจจับวงจรคุณต้องตรวจสอบโหนดทั้งก่อนและหลังที่คุณเพิ่ม adjacencies ทั้งเมื่อคุณ "เริ่ม" บนโหนดและเมื่อคุณ "เสร็จสิ้น" ด้วยโหนด
สิ่งนี้ต้องการการทำงานมากขึ้นใน Iterative-BFS ดังนั้นคนส่วนใหญ่จึงเลือก Recursive-DFS
โปรดทราบว่าการใช้งาน Iterative-DFS แบบง่ายๆด้วยเช่น std :: stack มีปัญหาเช่นเดียวกับ Iterative-BFS ในกรณีนี้คุณต้องวางองค์ประกอบจำลองลงในสแต็กเพื่อติดตามเมื่อคุณ "เสร็จสิ้น" ในการทำงานบนโหนด
ดูคำตอบนี้สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับวิธีที่ Iterative-DFS ต้องการงานเพิ่มเติมเพื่อพิจารณาว่าเมื่อใดที่คุณ "เสร็จสิ้น" กับโหนด (ตอบในบริบทของ TopoSort):
การเรียงลำดับโทโพโลยีโดยใช้ DFS โดยไม่มีการเรียกซ้ำ
หวังว่าจะอธิบายได้ว่าทำไมผู้คนถึงนิยม Recursive-DFS สำหรับปัญหาที่คุณต้องพิจารณาเมื่อคุณ "เสร็จสิ้น" การประมวลผลโหนด
คุณจะต้องใช้BFS
เมื่อคุณต้องการค้นหารอบที่สั้นที่สุดที่มีโหนดที่กำหนดในกราฟกำกับ
ถ้าโหนดที่กำหนดคือ 2 มีสามรอบที่มันเป็นส่วนหนึ่งของ - [2,3,4]
, &[2,3,4,5,6,7,8,9]
[2,5,6,7,8,9]
สั้นที่สุดคือ[2,3,4]
สำหรับการนำสิ่งนี้ไปใช้โดยใช้ BFS คุณต้องดูแลรักษาประวัติของโหนดที่เยี่ยมชมอย่างชัดเจนโดยใช้โครงสร้างข้อมูลที่เหมาะสม
แต่เพื่อวัตถุประสงค์อื่น ๆ ทั้งหมด (เช่นค้นหาเส้นทางที่เป็นวัฏจักรหรือเพื่อตรวจสอบว่ามีรอบหรือไม่) DFS
เป็นทางเลือกที่ชัดเจนสำหรับเหตุผลที่ผู้อื่นกล่าว