อะไรคือสิ่งที่ดีกว่ารายการ adjacency หรือเมทริกซ์ adjacency สำหรับปัญหากราฟใน C ++?


129

อะไรคือสิ่งที่ดีกว่ารายการ adjacency หรือเมทริกซ์ adjacency สำหรับปัญหากราฟใน C ++ ข้อดีข้อเสียแต่ละข้อเป็นอย่างไร?


21
โครงสร้างที่คุณใช้ไม่ได้ขึ้นอยู่กับภาษา แต่ขึ้นอยู่กับปัญหาที่คุณกำลังพยายามแก้ไข
avakar

1
ฉันหมายถึงการใช้งานทั่วไปเช่นอัลกอริทึม djikstra ฉันถามคำถามนี้เพราะฉันไม่รู้ว่าการติดตั้งรายการที่เชื่อมโยงนั้นคุ้มค่าที่จะพยายามทำให้โค้ดยากกว่าเมทริกซ์ adjacency
magiix

รายการใน C ++ นั้นง่ายพอ ๆ กับการพิมพ์std::list(หรือดีกว่าstd::vector)
avakar

1
@avakar: หรือstd::dequeหรือstd::set. ขึ้นอยู่กับวิธีที่กราฟจะเปลี่ยนไปตามเวลาและอัลกอริทึมใดที่คุณต้องการใช้
Alexandre C.

คำตอบ:


125

มันขึ้นอยู่กับปัญหา

เมทริกซ์ Adjacency

  • ใช้หน่วยความจำ O (n ^ 2)
  • มันรวดเร็วในการค้นหาและตรวจสอบว่ามีหรือไม่มีขอบเฉพาะ
    ระหว่างสองโหนดใด ๆ O (1)
  • มันช้าในการทำซ้ำทุกขอบ
  • การเพิ่ม / ลบโหนดทำได้ช้า การดำเนินการที่ซับซ้อน O (n ^ 2)
  • เพิ่มขอบใหม่ O (1) ได้อย่างรวดเร็ว

รายการ Adjacency

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

รายการที่เชื่อมโยงนั้นยากต่อการเขียนโค้ดคุณคิดว่าการใช้งานนั้นคุ้มค่าที่จะใช้เวลาเรียนรู้หรือไม่?
magiix

11
@magiix: ใช่ฉันคิดว่าคุณควรเข้าใจวิธีการเขียนโค้ดรายการที่เชื่อมโยงหากจำเป็น แต่สิ่งสำคัญก็คืออย่าสร้างวงล้อใหม่: cplusplus.com/reference/stl/list
Mark Byers

ใครสามารถให้ลิงค์ที่มีรหัสสะอาดสำหรับพูดว่าการค้นหาแรกกว้างในรูปแบบรายการที่เชื่อมโยง?
magiix


78

คำตอบนี้ไม่ได้มีไว้สำหรับ C ++ เท่านั้นเนื่องจากทุกสิ่งที่กล่าวถึงนั้นเกี่ยวกับโครงสร้างข้อมูลเองโดยไม่คำนึงถึงภาษา และคำตอบของฉันคือสมมติว่าคุณรู้โครงสร้างพื้นฐานของรายการผู้ช่วยและเมทริกซ์

หน่วยความจำ

หากหน่วยความจำเป็นข้อกังวลหลักของคุณคุณสามารถทำตามสูตรนี้สำหรับกราฟง่ายๆที่อนุญาตให้วนซ้ำ:

เมทริกซ์ถ้อยคำครอง n 2 /8 พื้นที่ไบต์ (หนึ่งบิตต่อรายการ)

รายการ adjacency ใช้พื้นที่ 8e โดยที่ e คือจำนวนขอบ (คอมพิวเตอร์ 32 บิต)

หากเรากำหนดความหนาแน่นของกราฟเป็น d = e / n 2 (จำนวนขอบหารด้วยจำนวนขอบสูงสุด) เราจะพบ "จุดพัก" ที่รายการใช้หน่วยความจำมากกว่าเมทริกซ์:

8e> n 2 /8 เมื่อ d> 1/64

ดังนั้นด้วยตัวเลขเหล่านี้ (ยังคงเฉพาะ 32 บิต) ดินแดนเบรกพอยต์ที่1/64 หากความหนาแน่น (e / n 2 ) มากกว่า 1/64 ดังนั้นควรใช้เมทริกซ์หากคุณต้องการบันทึกหน่วยความจำ

คุณสามารถอ่านเกี่ยวกับสิ่งนี้ได้ที่wikipedia (บทความเกี่ยวกับเมทริกซ์ผู้ช่วย) และเว็บไซต์อื่น ๆ อีกมากมาย

หมายเหตุด้านข้าง : เราสามารถปรับปรุงประสิทธิภาพการใช้พื้นที่ของเมทริกซ์ adjacency ได้โดยใช้ตารางแฮชที่คีย์เป็นคู่ของจุดยอด (ไม่ได้กำหนดทิศทางเท่านั้น)

การทำซ้ำและการค้นหา

รายการ Adjacency เป็นวิธีที่กะทัดรัดในการแสดงเฉพาะขอบที่มีอยู่ อย่างไรก็ตามสิ่งนี้มาพร้อมกับค่าใช้จ่ายในการค้นหาขอบเฉพาะที่อาจช้า เนื่องจากแต่ละรายการมีความยาวเท่ากับระดับของจุดยอดเวลาค้นหากรณีที่เลวร้ายที่สุดในการตรวจสอบขอบเฉพาะอาจกลายเป็น O (n) ได้หากรายการไม่เรียงลำดับ อย่างไรก็ตามการค้นหาเพื่อนบ้านของจุดยอดจะกลายเป็นเรื่องเล็กน้อยและสำหรับกราฟที่เบาบางหรือมีขนาดเล็กค่าใช้จ่ายในการวนซ้ำผ่านรายการ adjacency อาจมีน้อยมาก

ในทางกลับกันเมทริกซ์ Adjacency จะใช้พื้นที่มากขึ้นเพื่อให้เวลาในการค้นหาคงที่ เนื่องจากทุกรายการที่เป็นไปได้มีอยู่คุณสามารถตรวจสอบการมีอยู่ของขอบในเวลาคงที่โดยใช้ดัชนี อย่างไรก็ตามการค้นหาเพื่อนบ้านใช้เวลา O (n) เนื่องจากคุณต้องตรวจสอบเพื่อนบ้านที่เป็นไปได้ทั้งหมด ข้อเสียของพื้นที่ที่เห็นได้ชัดคือสำหรับกราฟที่เบาบางจะมีการเพิ่มช่องว่างภายในจำนวนมาก ดูการอภิปรายเกี่ยวกับหน่วยความจำด้านบนสำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้

หากคุณยังไม่แน่ใจว่าควรใช้อะไร : ปัญหาในโลกแห่งความเป็นจริงส่วนใหญ่ทำให้เกิดกราฟที่เบาบางและ / หรือมีขนาดใหญ่ซึ่งเหมาะกว่าสำหรับการแสดงรายการผู้ช่วย อาจดูเหมือนยากที่จะนำไปใช้ แต่ฉันรับรองว่าไม่ใช่และเมื่อคุณเขียน BFS หรือ DFS และต้องการดึงข้อมูลเพื่อนบ้านทั้งหมดของโหนดออกไปก็จะอยู่ห่างจากโค้ดเพียงบรรทัดเดียว อย่างไรก็ตามโปรดทราบว่าฉันไม่ได้ส่งเสริมรายการผู้ช่วยโดยทั่วไป


9
+1 สำหรับข้อมูลเชิงลึก แต่สิ่งนี้จะต้องได้รับการแก้ไขโดยโครงสร้างข้อมูลจริงที่ใช้ในการจัดเก็บรายการ adjacency คุณอาจต้องการจัดเก็บสำหรับจุดยอดแต่ละรายการเป็นแผนที่หรือเวกเตอร์ซึ่งในกรณีนี้จะต้องอัปเดตตัวเลขจริงในสูตรของคุณ นอกจากนี้ยังสามารถใช้การคำนวณที่คล้ายกันเพื่อประเมินจุดคุ้มทุนสำหรับความซับซ้อนของเวลาของอัลกอริทึมเฉพาะ
Alexandre C.

3
ใช่สูตรนี้มีไว้สำหรับสถานการณ์เฉพาะ หากคุณต้องการคำตอบคร่าวๆให้ใช้สูตรนี้ต่อไปหรือปรับเปลี่ยนตามข้อกำหนดของคุณตามต้องการ (เช่นคนส่วนใหญ่มีคอมพิวเตอร์ 64 บิตในปัจจุบัน :))
keyser

1
สำหรับผู้ที่สนใจสูตรสำหรับจุดแตกหัก (จำนวนสูงสุดของขอบเฉลี่ยในกราฟของต่อมน้ำ n ก) e = n / sที่sมีขนาดตัวชี้
deceleratedcaviar

33

เอาล่ะฉันรวบรวมความซับซ้อนของเวลาและอวกาศของการดำเนินการพื้นฐานบนกราฟแล้ว
รูปภาพด้านล่างควรอธิบายได้ด้วยตนเอง
สังเกตว่า Adjacency Matrix เป็นที่นิยมมากกว่าเมื่อเราคาดว่ากราฟจะมีความหนาแน่นและรายการ Adjacency จะดีกว่าอย่างไรเมื่อเราคาดว่ากราฟจะเบาบาง
ฉันได้ตั้งสมมติฐานบางอย่าง ถามฉันว่าความซับซ้อน (เวลาหรืออวกาศ) ต้องการคำชี้แจงหรือไม่ (ตัวอย่างเช่นสำหรับกราฟแบบกระจัดกระจายฉันได้กำหนดให้ En เป็นค่าคงที่ขนาดเล็กเนื่องจากฉันได้สันนิษฐานว่าการเพิ่มจุดยอดใหม่จะเพิ่มขอบเพียงไม่กี่เส้นเนื่องจากเราคาดว่ากราฟจะยังคงเบาบางแม้ว่าจะเพิ่มแล้วก็ตาม จุดสุดยอด.)

กรุณาแจ้งว่ามีข้อผิดพลาดประการใด

ใส่คำอธิบายภาพที่นี่


ในกรณีที่ไม่ทราบว่ากราฟเป็นกราฟหนาแน่นหรือเบาบางมันจะถูกต้องหรือไม่ที่จะบอกว่าความซับซ้อนของปริภูมิสำหรับรายการ adjacency จะเป็น O (v + e)

สำหรับอัลกอริธึมที่ใช้งานได้จริงส่วนใหญ่การดำเนินการที่สำคัญที่สุดอย่างหนึ่งคือการวนซ้ำผ่านขอบทั้งหมดออกจากจุดยอดที่กำหนด คุณอาจต้องการเพิ่มลงในรายการของคุณนั่นคือ O (องศา) สำหรับ AL และ O (V) สำหรับ AM
สูงสุด

@johnred ไม่ดีกว่าที่จะบอกว่าการเพิ่มจุดยอด (เวลา) สำหรับ AL คือ O (1) เพราะแทนที่จะเป็น O (en) เพราะเราไม่ได้เพิ่มขอบในการเพิ่มจุดยอด การเพิ่มขอบสามารถทำได้โดยแยกจากกัน สำหรับ AM เป็นเรื่องที่ควรพิจารณา แต่ถึงอย่างนั้นเราก็ต้องเริ่มต้นแถวและคอลัมน์ที่เกี่ยวข้องของจุดยอดใหม่เป็นศูนย์ การเพิ่มขอบแม้กระทั่งสำหรับ AM สามารถคิดแยกกันได้
Usman

การเพิ่มจุดยอดให้กับ AL O (V) เป็นอย่างไร? เราต้องสร้างเมทริกซ์ใหม่คัดลอกค่าก่อนหน้าลงไป ควรเป็น O (v ^ 2)
Alex_ban

19

ขึ้นอยู่กับสิ่งที่คุณกำลังมองหา

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

ในทางกลับกันด้วยรายการ adjacencyจะเป็นการยากที่จะตรวจสอบว่าขอบที่กำหนดอยู่ในกราฟหรือไม่เนื่องจากคุณต้องค้นหารายการที่เหมาะสมเพื่อค้นหาขอบ แต่มีพื้นที่ที่มีประสิทธิภาพมากกว่า

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


จะเกิดอะไรขึ้นถ้าคุณใช้พจนานุกรมเพื่อจัดเก็บรายการผู้ช่วยนั่นจะทำให้คุณมีขอบในเวลาตัดจำหน่าย O (1)
Rohith Yeravothula

10

สมมติว่าเรามีกราฟที่มีnจำนวนโหนดและจำนวนขอบm

ตัวอย่างกราฟ
ใส่คำอธิบายภาพที่นี่

ถ้อยคำเมทริกซ์: เรากำลังสร้างเมทริกซ์ที่มีnจำนวนแถวและคอลัมน์อื่น ๆ ในหน่วยความจำก็จะใช้พื้นที่ที่เป็นสัดส่วนกับ n 2 การตรวจสอบว่าโหนดสองโหนดที่มีชื่อว่าuและvมีขอบระหว่างกันหรือไม่จะใช้เวลาΘ (1) ครั้ง ตัวอย่างเช่นการตรวจสอบสำหรับ (1, 2) คือขอบจะมีลักษณะดังนี้ในโค้ด:

if(matrix[1][2] == 1)

หากคุณต้องการระบุขอบทั้งหมดคุณต้องวนซ้ำบนเมทริกซ์ซึ่งจะต้องใช้ลูปซ้อนกันสองวงและจะใช้เวลาΘ (n 2 ) (คุณสามารถใช้ส่วนสามเหลี่ยมด้านบนของเมทริกซ์เพื่อกำหนดขอบทั้งหมด แต่จะเป็นอีกครั้งΘ (n 2 ))

Adjacency List: เรากำลังสร้างรายการที่แต่ละโหนดชี้ไปที่รายการอื่นด้วย รายการของคุณจะมีnองค์ประกอบและแต่ละองค์ประกอบจะชี้ไปที่รายการที่มีจำนวนรายการที่เท่ากับจำนวนเพื่อนบ้านของโหนดนี้ (ดูภาพเพื่อการแสดงภาพที่ดีขึ้น) ดังนั้นมันจะใช้พื้นที่ในหน่วยความจำที่เป็นสัดส่วนกับn + m การตรวจสอบว่า (u, v) เป็นขอบจะใช้เวลา O (deg (u)) ซึ่ง deg (u) เท่ากับจำนวนเพื่อนบ้านของ u เพราะอย่างที่สุดคุณต้องวนซ้ำรายการที่ชี้โดย u การระบุขอบทั้งหมดจะใช้เวลาΘ (n + m)

รายการ Adjacency ของกราฟตัวอย่าง

ใส่คำอธิบายภาพที่นี่
คุณควรตัดสินใจเลือกตามความต้องการของคุณ เนื่องจากชื่อเสียงของฉันฉันไม่สามารถใส่ภาพของเมทริกซ์ได้ขออภัยด้วย


7

หากคุณกำลังดูการวิเคราะห์กราฟใน C ++ สิ่งแรกที่จะเริ่มต้นคือไลบรารีกราฟเพิ่มประสิทธิภาพซึ่งใช้อัลกอริทึมจำนวนมากรวมถึง BFS

แก้ไข

คำถามก่อนหน้านี้เกี่ยวกับ SO อาจช่วยได้:

วิธีการสร้าง ac-boost-undirected-graph-and-traverse-it-in-depth-first-Searc h


ขอบคุณฉันจะตรวจสอบห้องสมุดนี้
magiix

+1 สำหรับกราฟเพิ่ม นี่คือวิธีที่จะไป (ยกเว้นแน่นอนหากเป็นเพื่อการศึกษา)
Tristram Gräbener

5

นี่คือคำตอบที่ดีที่สุดพร้อมตัวอย่าง

คิดว่าฟลอยด์-Warshallตัวอย่างเช่น เราต้องใช้เมทริกซ์ adjacency ไม่เช่นนั้นอัลกอริทึมจะช้าลงอย่างไม่มีอาการ

หรือถ้าเป็นกราฟหนาแน่นบนจุดยอด 30,000 จุด? จากนั้นเมทริกซ์ adjacency อาจจะสมเหตุสมผลเนื่องจากคุณจะจัดเก็บ 1 บิตต่อคู่ของจุดยอดแทนที่จะเป็น 16 บิตต่อขอบ (ขั้นต่ำที่คุณต้องการสำหรับรายการผู้ช่วย) นั่นคือ 107 MB แทนที่จะเป็น 1.7 GB

แต่สำหรับอัลกอริทึมเช่น DFS, BFS (และที่ใช้เช่น Edmonds-Karp), Priority-first search (Dijkstra, Prim, A *) เป็นต้นรายการ adjacency จะดีพอ ๆ กับเมทริกซ์ เมทริกซ์อาจมีขอบเล็กน้อยเมื่อกราฟมีความหนาแน่น แต่เกิดจากค่าคงที่ที่ไม่ได้มาตรฐานเท่านั้น (เท่าไหร่มันเป็นเรื่องของการทดลอง)


2
สำหรับอัลกอริทึมเช่น DFS และ BFS หากคุณใช้เมทริกซ์คุณจะต้องตรวจสอบทั้งแถวทุกครั้งที่คุณต้องการค้นหาโหนดที่อยู่ติดกันในขณะที่คุณมีโหนดที่อยู่ติดกันอยู่แล้วในรายการที่อยู่ติดกัน ทำไมคุณถึงคิดว่าan adjacency list is as good as a matrixในกรณีเหล่านั้น?
realUser404

@ realUser404 แน่นอนการสแกนแถวเมทริกซ์ทั้งหมดเป็นการดำเนินการ O (n) รายการ Adjacency จะดีกว่าสำหรับกราฟแบบกระจัดกระจายเมื่อคุณต้องการสำรวจขอบขาออกทั้งหมดสามารถทำได้ใน O (d) (d: องศาของโหนด) เมทริกซ์มีประสิทธิภาพแคชที่ดีกว่ารายการผู้ช่วยเนื่องจากการเข้าถึงตามลำดับดังนั้นสำหรับกราฟที่ค่อนข้างหนาแน่นการสแกนเมทริกซ์จะมีความหมายมากกว่า
Jochem Kuijpers

3

เพื่อเพิ่มคำตอบของ keyser5053 เกี่ยวกับการใช้หน่วยความจำ

สำหรับกราฟกำกับใด ๆ เมทริกซ์ adjacency (ที่ 1 บิตต่อขอบ) จะใช้n^2 * (1)หน่วยความจำบิต

สำหรับกราฟที่สมบูรณ์รายการ adjacency (พร้อมตัวชี้ 64 บิต) จะใช้n * (n * 64)หน่วยความจำบิตโดยไม่รวมค่าใช้จ่ายในรายการ

สำหรับกราฟที่ไม่สมบูรณ์รายการ adjacency จะใช้0หน่วยความจำบิตโดยไม่รวมค่าใช้จ่ายในรายการ


สำหรับรายการ adjacency คุณสามารถใช้สูตรต่อไปนี้เพื่อกำหนดจำนวนขอบสูงสุด ( e) ก่อนที่เมทริกซ์ adjacency จะเหมาะสมที่สุดสำหรับหน่วยความจำ

edges = n^2 / sเพื่อกำหนดจำนวนขอบสูงสุดsขนาดตัวชี้ของแพลตฟอร์มอยู่ที่ใด

หากคุณกราฟกำลังมีการปรับปรุงแบบไดนามิกคุณสามารถรักษาประสิทธิภาพนี้กับนับขอบเฉลี่ย (ต่อโหนด) n / sของ


ตัวอย่างบางส่วนที่มีตัวชี้ 64 บิตและกราฟไดนามิก (กราฟไดนามิกจะอัปเดตวิธีแก้ปัญหาอย่างมีประสิทธิภาพหลังการเปลี่ยนแปลงแทนที่จะคำนวณใหม่ตั้งแต่ต้นทุกครั้งหลังจากทำการเปลี่ยนแปลง)

สำหรับกราฟกำกับโดยที่n300 จำนวนขอบที่เหมาะสมที่สุดต่อโหนดโดยใช้รายการ adjacency คือ:

= 300 / 64
= 4

หากเราเสียบสิ่งนี้เข้ากับสูตรของ keyser5053 d = e / n^2( eจำนวนขอบรวมอยู่ที่ใด) เราจะเห็นว่าเราอยู่ต่ำกว่าจุดพัก ( 1 / s):

d = (4 * 300) / (300 * 300)
d < 1/64
aka 0.0133 < 0.0156

อย่างไรก็ตาม 64 บิตสำหรับตัวชี้อาจมากเกินไป หากคุณใช้จำนวนเต็ม 16 บิตแทนตัวชี้ออฟเซ็ตเราสามารถใส่ขอบได้สูงสุด 18 ขอบก่อนจุดแตกหัก

= 300 / 16
= 18

d = ((18 * 300) / (300^2))
d < 1/16
aka 0.06 < 0.0625

แต่ละตัวอย่างเหล่านี้ไม่สนใจค่าใช้จ่ายของ adjacency แสดงรายการตัวเอง ( 64*2สำหรับเวกเตอร์และตัวชี้ 64 บิต)


ฉันไม่เข้าใจส่วนd = (4 * 300) / (300 * 300)นี้ไม่ควรd = 4 / (300 * 300)? d = e / n^2ตั้งแต่สูตรคือ
Saurabh

2

ทั้งนี้ขึ้นอยู่กับการนำ Adjacency Matrix ไปใช้ 'n' ของกราฟก่อนหน้านี้เพื่อการใช้งานที่มีประสิทธิภาพ ถ้ากราฟเป็นแบบไดนามิกเกินไปและต้องมีการขยายเมทริกซ์ทุก ๆ ครั้งก็นับเป็นข้อเสียได้เช่นกัน?


1

หากคุณใช้ตารางแฮชแทนเมทริกซ์การเสริมหรือรายการคุณจะได้เวลารันและพื้นที่ขนาดใหญ่ที่ดีกว่าหรือเท่ากันสำหรับการดำเนินการทั้งหมด (การตรวจสอบขอบคือO(1)การได้รับขอบที่ติดกันทั้งหมดO(degree)เป็นต้น)

มีค่าใช้จ่ายที่คงที่สำหรับทั้งรันไทม์และพื้นที่ (ตารางแฮชไม่เร็วเท่ากับรายการที่เชื่อมโยงหรือการค้นหาอาร์เรย์และใช้พื้นที่พิเศษในปริมาณที่เหมาะสมเพื่อลดการชนกัน)


1

ฉันกำลังจะสัมผัสกับการเอาชนะการแลกเปลี่ยนการเป็นตัวแทนรายชื่อผู้ช่วยปกติเนื่องจากคำตอบอื่น ๆ ได้ครอบคลุมแง่มุมอื่น ๆ

เป็นไปได้ที่จะแสดงกราฟในรายการ adjacency ด้วยแบบสอบถามEdgeExistsในเวลาคงที่ที่ตัดจำหน่ายโดยใช้ประโยชน์จากDictionaryและHashSetโครงสร้างข้อมูลแนวคิดคือการเก็บจุดยอดในพจนานุกรมและสำหรับจุดยอดแต่ละจุดเราจะเก็บชุดแฮชไว้อ้างอิงไปยังจุดยอดอื่น ๆ ที่มีขอบด้วย

การแลกเปลี่ยนเล็กน้อยในการใช้งานนี้คือจะมีความซับซ้อนของพื้นที่ O (V + 2E) แทนที่จะเป็น O (V + E) เช่นเดียวกับในรายการ adjacency ปกติเนื่องจากขอบจะแสดงสองครั้งที่นี่ (เนื่องจากจุดยอดแต่ละจุดมีชุดแฮชของตัวเอง ของขอบ) แต่การดำเนินการเช่นAddVertex , AddEdge , RemoveEdgeสามารถทำได้ในเวลาตัดจำหน่าย O (1) ด้วยการใช้งานนี้ยกเว้นRemoveVertexซึ่งใช้ O (V) เหมือนเมทริกซ์ adjacency นี่หมายความว่านอกเหนือจากความเรียบง่ายในการนำไปใช้งานเมทริกซ์ adjacency ไม่มีข้อได้เปรียบเฉพาะใด ๆ เราสามารถประหยัดเนื้อที่บนกราฟกระจัดกระจายโดยมีประสิทธิภาพเกือบเท่ากันในการใช้งานรายการผู้ช่วยนี้

ดูการใช้งานด้านล่างในที่เก็บ Github C # สำหรับรายละเอียด โปรดทราบว่าสำหรับกราฟถ่วงน้ำหนักจะใช้พจนานุกรมที่ซ้อนกันแทนการรวมชุดพจนานุกรม - แฮชเพื่อรองรับค่าน้ำหนัก ในทำนองเดียวกันสำหรับกราฟกำกับจะมีชุดแฮชแยกกันสำหรับขอบเข้าและออก

ขั้นสูงอัลกอริทึม

หมายเหตุ: ฉันเชื่อว่าการใช้การลบแบบขี้เกียจเราสามารถเพิ่มประสิทธิภาพการดำเนินการRemoveVertexเป็น O (1) ตัดจำหน่ายได้แม้ว่าฉันจะไม่ได้ทดสอบแนวคิดนั้นก็ตาม ตัวอย่างเช่นเมื่อลบเพียงแค่ทำเครื่องหมายจุดสุดยอดว่าถูกลบในพจนานุกรมจากนั้นจึงล้างขอบกำพร้าอย่างเกียจคร้านในระหว่างการดำเนินการอื่น ๆ


สำหรับเมทริกซ์ adjacency ลบจุดยอดจะใช้ O (V ^ 2) ไม่ใช่ O (V)
Saurabh

ใช่. แต่ถ้าคุณใช้พจนานุกรมเพื่อติดตามดัชนีอาร์เรย์มันจะลงไปที่ O (V) ดูการใช้งานRemoveVertexนี้
justcoding121
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.