ฉันสังเกตเห็นใน Effective STL
vector เป็นชนิดของลำดับที่ควรใช้เป็นค่าเริ่มต้น
มันหมายความว่าอะไร? ดูเหมือนว่าการเพิกเฉยต่อประสิทธิภาพvector
สามารถทำอะไรก็ได้
ใครช่วยเสนอสถานการณ์ที่vector
ไม่มีตัวเลือกที่เป็นไปได้ แต่list
ต้องใช้?
ฉันสังเกตเห็นใน Effective STL
vector เป็นชนิดของลำดับที่ควรใช้เป็นค่าเริ่มต้น
มันหมายความว่าอะไร? ดูเหมือนว่าการเพิกเฉยต่อประสิทธิภาพvector
สามารถทำอะไรก็ได้
ใครช่วยเสนอสถานการณ์ที่vector
ไม่มีตัวเลือกที่เป็นไปได้ แต่list
ต้องใช้?
คำตอบ:
สถานการณ์ที่คุณต้องการแทรกรายการจำนวนมากลงในที่ใดก็ได้ แต่จุดสิ้นสุดของลำดับซ้ำ ๆ
ตรวจสอบการรับประกันความซับซ้อนของคอนเทนเนอร์แต่ละประเภท:
list
ได้มีpush_front
เวกเตอร์:
รายการ:
โดยทั่วไปให้ใช้เวกเตอร์เมื่อคุณไม่สนใจประเภทของคอนเทนเนอร์ตามลำดับที่คุณใช้ แต่ถ้าคุณกำลังแทรกหรือลบหลาย ๆ อย่างจากที่ใดก็ได้ในที่อื่น ๆ นอกเหนือจากตอนจบคุณจะต้องการ เพื่อใช้รายการ หรือถ้าคุณต้องการเข้าถึงแบบสุ่มคุณจะต้องการเวกเตอร์ไม่ใช่รายการ นอกจากนั้นยังมีกรณีที่คุณจะต้องใช้อย่างใดอย่างหนึ่งตามธรรมชาติขึ้นอยู่กับใบสมัครของคุณ แต่โดยทั่วไปแล้วเป็นแนวทางที่ดี
reserve()
เพื่อลดรายการนั้นเป็น O (1) การเพิ่มรายการใหม่ลงในรายการ (เช่นไม่ใช่การต่อข้อมูล) ดำเนินการจัดสรรร้านค้าฟรี O (n)
list
หน่วยความจำเมื่อคุณลบองค์ประกอบ แต่vector
ไม่ A vector
ไม่ลดกำลังการผลิตเมื่อคุณลดขนาดยกเว้นว่าคุณใช้swap()
เคล็ดลับ
หากคุณไม่ต้องการแทรกองค์ประกอบบ่อยครั้งเวกเตอร์จะมีประสิทธิภาพมากขึ้น มันมีตำแหน่ง CPU แคชที่ดีกว่ารายการ ในคำอื่น ๆ ในการเข้าถึงองค์ประกอบหนึ่งที่ทำให้มันมากไปได้ว่าองค์ประกอบถัดไปอยู่ในแคชและสามารถเรียกดูได้โดยไม่ต้องอ่าน RAM ช้า
คำตอบส่วนใหญ่ที่นี่พลาดรายละเอียดที่สำคัญอย่างหนึ่ง: เพื่ออะไร
คุณต้องการเก็บไว้ในที่เก็บอะไร
หากเป็นคอลเล็กชันint
s ดังนั้นstd::list
จะสูญเสียในทุกสถานการณ์โดยไม่คำนึงว่าคุณสามารถจัดสรรใหม่ได้หรือไม่คุณจะลบออกจากด้านหน้าเท่านั้นเป็นต้นรายการจะช้ากว่าในการสำรวจการแทรกทุกครั้งจะทำให้คุณต้องเสียค่าใช้จ่าย มันจะยากมากที่จะเตรียมความพร้อมตัวอย่างที่เต้นlist<int>
vector<int>
และยิ่งกว่านั้นdeque<int>
อาจจะดีกว่าหรือใกล้กว่าไม่ใช่แค่เพียงการใช้รายการซึ่งจะมีค่าใช้จ่ายในหน่วยความจำมากขึ้น
อย่างไรก็ตามหากคุณกำลังจัดการกับข้อมูลขนาดใหญ่น่าเกลียด - และไม่กี่ของพวกเขา - คุณไม่ต้องการ overallocate เมื่อแทรกและคัดลอกเนื่องจากการจัดสรรใหม่จะเป็นภัยพิบัติ - แล้วคุณอาจจะดีกว่าด้วยกว่าlist<UglyBlob>
vector<UglyBlob>
ยังถ้าคุณเปลี่ยนเป็นvector<UglyBlob*>
หรือแม้กระทั่งvector<shared_ptr<UglyBlob> >
อีกครั้ง - รายการจะล้าหลัง
ดังนั้นรูปแบบการเข้าถึงจำนวนองค์ประกอบเป้าหมาย ฯลฯ ยังคงมีผลต่อการเปรียบเทียบ แต่ในมุมมองของฉัน - ขนาดองค์ประกอบ - ค่าใช้จ่ายในการคัดลอกเป็นต้น
list<T>
ความเป็นไปได้ที่จะsplice
อยู่ในO (1) หากคุณต้องการการต่อเวลาคงที่รายการอาจเป็นโครงสร้างของทางเลือก;)
UglyBlob
- แม้แต่วัตถุที่มีสมาชิกสตริงเพียงไม่กี่คนก็อาจมีราคาแพงในการคัดลอกได้อย่างง่ายดายดังนั้นการจัดสรรใหม่จะมีค่าใช้จ่าย นอกจากนี้: อย่าละเลยช่องว่างเหนือศีรษะการเติบโตแบบเอ็กซ์โปเนนเชียลของvector
วัตถุโฮลดิ้งที่มีขนาดไม่กี่สิบไบต์อาจทำให้เกิด (หากคุณไม่สามารถreserve
ล่วงหน้าได้)
vector<smart_ptr<Large>>
vs. list<Large>
- ฉันว่าถ้าคุณต้องการเข้าถึงองค์ประกอบแบบสุ่มvector
ความสมเหตุสมผล หากคุณไม่ต้องการเข้าถึงแบบสุ่มlist
ดูเหมือนจะง่ายกว่าและควรทำงานอย่างเท่าเทียมกัน
ความสามารถพิเศษอย่างหนึ่งของ std :: list คือการประกบกัน (การเชื่อมโยงหรือย้ายส่วนหนึ่งของหรือรายการทั้งหมดลงในรายการอื่น)
หรือบางทีถ้าเนื้อหาของคุณมีราคาแพงมากในการคัดลอก ในกรณีเช่นนี้อาจมีราคาถูกกว่าเช่นเรียงลำดับรายการด้วยรายการ
นอกจากนี้โปรดทราบว่าหากการรวบรวมมีขนาดเล็ก (และเนื้อหานั้นไม่แพงโดยเฉพาะการคัดลอก) เวกเตอร์อาจยังคงมีประสิทธิภาพสูงกว่ารายการแม้ว่าคุณจะแทรกและลบที่ใดก็ตาม รายการจะจัดสรรแต่ละโหนดแยกกันและอาจมีค่าใช้จ่ายสูงกว่าการย้ายวัตถุธรรมดาสองสามตัว
ฉันไม่คิดว่ามีกฎที่ยากมาก ขึ้นอยู่กับสิ่งที่คุณต้องการทำกับคอนเทนเนอร์เป็นส่วนใหญ่เช่นเดียวกับขนาดใหญ่ที่คุณคาดว่าภาชนะจะเป็นและประเภทที่มีอยู่ เวกเตอร์โดยทั่วไปสำคัญกว่ารายการเพราะมันจัดสรรเนื้อหาเป็นบล็อกที่ต่อเนื่องกัน (โดยทั่วไปจะเป็นอาร์เรย์ที่จัดสรรแบบไดนามิก
list::size
ไม่จำเป็นต้องเป็นเวลาคงที่ ดูstackoverflow.com/questions/228908/is-listsize-really-onและgcc.gnu.org/ml/libstdc++/2005-11/msg00219.html
splice
ระหว่างรายการต่าง ๆ ถูกระบุว่ามีความซับซ้อนเชิงเส้นและsize
คงที่โดยเฉพาะ ดังนั้นเพื่อรองรับสามเณรที่ทำซ้ำในsize
หรืออะไรก็ตามคลาสอัลกอริธึมทั้งหมดพ้นจาก STL หรือช่วงเวลาคอนเทนเนอร์ "ที่สอดคล้อง"
นักเรียนในชั้นเรียนของฉันดูเหมือนไม่สามารถอธิบายให้ฉันได้เมื่อมันมีประสิทธิภาพมากกว่าในการใช้เวกเตอร์ แต่พวกเขาดูมีความสุขมากเมื่อแนะนำฉันให้ใช้รายการ
นี่คือวิธีที่ฉันเข้าใจ
รายการ : แต่ละรายการมีที่อยู่ไปยังองค์ประกอบถัดไปหรือก่อนหน้าดังนั้นด้วยคุณสมบัตินี้คุณสามารถสุ่มรายการได้แม้ว่าจะไม่ได้เรียงลำดับก็ตามคำสั่งจะไม่เปลี่ยนแปลง: จะมีประสิทธิภาพหากหน่วยความจำของคุณมีการแยกส่วน แต่มันก็มีข้อได้เปรียบที่ใหญ่มาก ๆ เช่นคุณสามารถแทรก / ลบรายการได้ง่าย ๆ เพราะสิ่งเดียวที่คุณต้องทำคือเปลี่ยนพอยน์เตอร์ ข้อเสียเปรียบ: หากต้องการอ่านรายการเดียวแบบสุ่มคุณต้องข้ามจากรายการหนึ่งไปอีกรายการหนึ่งจนกว่าคุณจะพบที่อยู่ที่ถูกต้อง
เวกเตอร์ : เมื่อใช้เวกเตอร์หน่วยความจำจะถูกจัดระเบียบมากขึ้นเช่นอาร์เรย์ปกติ: รายการ n-th แต่ละรายการจะถูกจัดเก็บหลังรายการ (n-1) th และก่อน (n + 1) รายการ th ทำไมดีกว่ารายการ? เพราะอนุญาตให้เข้าถึงแบบสุ่มได้อย่างรวดเร็ว นี่คือวิธี: หากคุณทราบขนาดของรายการในเวกเตอร์และหากมีขนาดต่อเนื่องกันในหน่วยความจำคุณสามารถคาดการณ์ได้อย่างง่ายดายว่ารายการที่ n นั้นคืออะไร คุณไม่จำเป็นต้องเรียกดูรายการทั้งหมดของรายการเพื่ออ่านสิ่งที่คุณต้องการด้วยเวกเตอร์คุณสามารถอ่านได้โดยตรงด้วยรายการที่คุณไม่สามารถทำได้ ในทางตรงกันข้ามปรับเปลี่ยนอาร์เรย์เวกเตอร์หรือเปลี่ยนค่าช้ากว่ามาก
รายการมีความเหมาะสมในการติดตามวัตถุที่สามารถเพิ่ม / ลบในหน่วยความจำ เวกเตอร์มีความเหมาะสมมากกว่าเมื่อคุณต้องการเข้าถึงองค์ประกอบจากรายการจำนวนมาก
ฉันไม่ทราบวิธีเพิ่มประสิทธิภาพรายการ แต่คุณต้องรู้ว่าถ้าคุณต้องการเข้าถึงการอ่านอย่างรวดเร็วคุณควรใช้เวกเตอร์เพราะรายการดีเอชแอลของ STL นั้นดีแค่ไหนการเข้าถึงแบบอ่านจะไม่เร็วกว่าเวกเตอร์
vector
เกิดจากการเปลี่ยนขนาดสามารถช้าได้หรือไม่ ตกลงกันแล้ว แต่ในกรณีที่reserve()
สามารถใช้งานได้เพื่อหลีกเลี่ยงปัญหาเหล่านั้น
โดยทั่วไปเวกเตอร์เป็นอาร์เรย์ที่มีการจัดการหน่วยความจำอัตโนมัติ ข้อมูลอยู่ในหน่วยความจำต่อเนื่อง การพยายามแทรกข้อมูลที่อยู่ตรงกลางเป็นการดำเนินการที่มีค่าใช้จ่ายสูง
ในรายการข้อมูลจะถูกเก็บไว้ในตำแหน่งหน่วยความจำที่ไม่เกี่ยวข้อง การแทรกตรงกลางไม่เกี่ยวข้องกับการคัดลอกข้อมูลบางส่วนเพื่อให้มีที่ว่างสำหรับข้อมูลใหม่
เพื่อตอบคำถามของคุณโดยเฉพาะฉันจะเสนอราคาหน้านี้
เวกเตอร์โดยทั่วไปจะมีประสิทธิภาพมากที่สุดในเวลาสำหรับการเข้าถึงองค์ประกอบและเพื่อเพิ่มหรือลบองค์ประกอบจากจุดสิ้นสุดของลำดับ สำหรับการดำเนินการที่เกี่ยวข้องกับการแทรกหรือลบองค์ประกอบที่ตำแหน่งอื่น ๆ นอกเหนือจากจุดสิ้นสุดพวกเขาทำงานได้แย่กว่า deques และรายการและมีตัววนซ้ำและการอ้างอิงที่สอดคล้องกันน้อยกว่ารายการ
เมื่อใดก็ตามที่คุณไม่สามารถยกเลิกตัววนซ้ำได้
deque
พอหรือไม่
เมื่อคุณมีการแทรกหรือลบจำนวนมากในช่วงกลางของลำดับ เช่นผู้จัดการหน่วยความจำ
การรักษาความถูกต้องของตัววนซ้ำเป็นเหตุผลหนึ่งที่ใช้รายการ อีกอย่างหนึ่งคือเมื่อคุณไม่ต้องการให้เวกเตอร์จัดสรรใหม่เมื่อกดรายการ สิ่งนี้สามารถจัดการได้โดยการใช้การสงวน () อย่างชาญฉลาด แต่ในบางกรณีมันอาจจะง่ายกว่าหรือเป็นไปได้มากกว่าที่จะใช้รายการ
list::splice
เมื่อคุณต้องการที่จะย้ายวัตถุระหว่างภาชนะบรรจุที่คุณสามารถใช้
ตัวอย่างเช่นอัลกอริทึมการแบ่งกราฟอาจมีจำนวนวัตถุคงที่แบ่งซ้ำในจำนวนที่เพิ่มขึ้นของภาชนะบรรจุ วัตถุควรเริ่มต้นครั้งเดียวและยังคงอยู่ในตำแหน่งเดียวกันในหน่วยความจำเสมอ มันเร็วกว่ามากในการจัดเรียงใหม่โดยเชื่อมโยงใหม่กว่าด้วยการจัดสรรใหม่
แก้ไข:เมื่อไลบรารีเตรียมใช้ C ++ 0x กรณีทั่วไปของการต่อเรียงลำดับลงในรายการกำลังกลายเป็นความซับซ้อนเชิงเส้นด้วยความยาวของลำดับ นี่เป็นเพราะsplice
(ตอนนี้) จำเป็นต้องวนซ้ำลำดับเพื่อนับจำนวนองค์ประกอบในนั้น (เนื่องจากรายการต้องการบันทึกขนาดของมัน) เพียงแค่นับและเชื่อมโยงใหม่รายการก็ยังเร็วกว่าทางเลือกใด ๆ และการประกบทั้งรายการหรือองค์ประกอบเดียวเป็นกรณีพิเศษที่มีความซับซ้อนคงที่ แต่ถ้าคุณมีฉากต่อเนื่องที่ต่อเนื่องกันนานคุณอาจต้องขุดหาภาชนะที่ดีกว่าเก่าและไม่เข้ากัน
กฎฮาร์ดเดียวที่list
ต้องใช้คือที่ที่คุณต้องการกระจายพอยน์เตอร์ไปยังองค์ประกอบของคอนเทนเนอร์
แตกต่างกับvector
คุณรู้ว่าหน่วยความจำขององค์ประกอบที่จะไม่ได้รับการจัดสรร SEGFAULT
ถ้ามันอาจจะเป็นแล้วคุณอาจจะมีตัวชี้ไปยังหน่วยความจำที่ไม่ได้ใช้ซึ่งเป็นที่ที่ดีที่สุดใหญ่ไม่มีไม่มีและที่เลวร้ายที่สุด
(เทคนิคvector
ของ*_ptr
ก็จะทำงาน แต่ในกรณีที่คุณกำลังลอกเลียนแบบlist
เพื่อให้เป็นเพียงความหมาย.)
กฎอ่อนอื่น ๆ เกี่ยวข้องกับปัญหาประสิทธิภาพการทำงานที่เป็นไปได้ของการแทรกองค์ประกอบเข้าไปตรงกลางของคอนเทนเนอร์ซึ่งlist
จะเป็นที่นิยมมากกว่า
ทำให้มันง่าย -
ในตอนท้ายของวันที่คุณสับสนในการเลือกคอนเทนเนอร์ใน C ++ ใช้อิมเมจแผนภูมิผังงานนี้ (กล่าวขอบคุณฉัน): -
ป้อนคำอธิบายภาพที่นี่
เวกเตอร์ -
1. เวกเตอร์ขึ้นอยู่กับหน่วยความจำต่อเนื่อง
2. เวกเตอร์เป็นวิธีที่จะไปสำหรับชุดข้อมูลขนาดเล็ก
3. เวกเตอร์ทำงานได้เร็วที่สุดในขณะที่อยู่ในชุดข้อมูล
4. การลบการแทรกเวกเตอร์จะช้าในชุดข้อมูลขนาดใหญ่
รายการ -
1. รายการจะขึ้นอยู่กับหน่วยความจำฮีป
2. รายการเป็นวิธีที่จะไปสำหรับชุดข้อมูลขนาดใหญ่มาก
3. รายการค่อนข้างช้าในการข้ามชุดข้อมูลขนาดเล็ก แต่รวดเร็วที่ชุดข้อมูลขนาดใหญ่
4. การลบการแทรกรายการรวดเร็ว ชุดข้อมูลขนาดใหญ่ แต่ทำงานช้าลงสำหรับเครื่องที่เล็กกว่า
รายชื่อเป็นเพียงเสื้อคลุมสำหรับรายการที่เชื่อมโยงเป็นสองเท่าใน stl ดังนั้นจึงนำเสนอคุณลักษณะที่คุณอาจคาดหวังจาก d-linklist คือการแทรก O (1) และการลบ ในขณะที่เวกเตอร์เป็นลำดับข้อมูลติดต่อซึ่งทำงานเหมือนอาเรย์แบบไดนามิก PS- ง่ายต่อการสำรวจ
ในกรณีของเวกเตอร์และรายการความแตกต่างหลักที่ยื่นออกมาจากฉันมีดังต่อไปนี้:
เวกเตอร์
เวกเตอร์เก็บองค์ประกอบไว้ในหน่วยความจำต่อเนื่อง ดังนั้นการเข้าถึงแบบสุ่มสามารถทำได้ภายในเวกเตอร์ซึ่งหมายความว่าการเข้าถึงองค์ประกอบของเวกเตอร์นั้นเร็วมากเพราะเราสามารถคูณที่อยู่ฐานกับดัชนีรายการเพื่อเข้าถึงองค์ประกอบนั้นได้ ในความเป็นจริงมันใช้เวลาเพียง O (1) หรือเวลาคงที่สำหรับวัตถุประสงค์นี้
เนื่องจากเวกเตอร์นั้นล้อมอาร์เรย์ทุกครั้งที่คุณแทรกองค์ประกอบลงในเวกเตอร์ (ไดนามิกอาร์เรย์) มันจะต้องปรับขนาดตัวเองโดยการค้นหาบล็อกที่ต่อเนื่องกันใหม่ของหน่วยความจำเพื่อรองรับองค์ประกอบใหม่ที่มีราคาแพง
มันไม่ใช้หน่วยความจำเพิ่มเติมเพื่อเก็บพอยน์เตอร์ใด ๆ ไปยังองค์ประกอบอื่น ๆ ภายใน
รายการ
รายการจัดเก็บองค์ประกอบในหน่วยความจำที่ไม่ต่อเนื่อง ดังนั้นการเข้าถึงแบบสุ่มไม่สามารถทำได้ภายในรายการซึ่งหมายความว่าในการเข้าถึงองค์ประกอบเราต้องใช้พอยน์เตอร์และสำรวจรายการที่ช้ากว่าสัมพันธ์กับเวกเตอร์ ใช้เวลา O (n) หรือเวลาเชิงเส้นซึ่งช้ากว่า O (1)
เนื่องจากรายการใช้หน่วยความจำที่ไม่ต่อเนื่องกันเวลาที่ใช้ในการแทรกองค์ประกอบภายในรายการนั้นมีประสิทธิภาพมากกว่าในกรณีของเวกเตอร์ของมันเนื่องจากหลีกเลี่ยงการจัดสรรหน่วยความจำใหม่
มันใช้หน่วยความจำเพิ่มเติมเพื่อเก็บพอยน์เตอร์ไปยังองค์ประกอบก่อนและหลังองค์ประกอบเฉพาะ
ดังนั้นการรักษาความแตกต่างเหล่านี้ไว้ในใจเรามักจะพิจารณาถึงหน่วยความจำการเข้าถึงแบบสุ่มและการแทรกบ่อยครั้งเพื่อตัดสินผู้ชนะของรายการเวกเตอร์ vsในสถานการณ์ที่กำหนด
รายการนั้นเป็นรายการที่เชื่อมโยงเป็นทวีคูณจึงง่ายต่อการแทรกและลบองค์ประกอบ เราต้องเปลี่ยนพอยน์เตอร์ไม่กี่ตัวในขณะที่ในเวคเตอร์ถ้าเราต้องการแทรกองค์ประกอบตรงกลางแล้วแต่ละองค์ประกอบหลังจากนั้นต้องเลื่อนด้วยดัชนีหนึ่งอัน นอกจากนี้หากขนาดของเวกเตอร์เต็มคุณจะต้องเพิ่มขนาดของมันก่อน ดังนั้นจึงเป็นการดำเนินการที่มีราคาแพง ดังนั้นเมื่อใดก็ตามที่การแทรกและการลบจะต้องดำเนินการบ่อยขึ้นในรายการกรณีดังกล่าวควรจะใช้