ฉันกำลังวนซ้ำเวกเตอร์และต้องการดัชนีที่ตัววนซ้ำกำลังชี้ไปที่ AFAIK สามารถทำได้สองวิธี:
it - vec.begin()
std::distance(vec.begin(), it)
อะไรคือข้อดีข้อเสียของวิธีการเหล่านี้?
ฉันกำลังวนซ้ำเวกเตอร์และต้องการดัชนีที่ตัววนซ้ำกำลังชี้ไปที่ AFAIK สามารถทำได้สองวิธี:
it - vec.begin()
std::distance(vec.begin(), it)
อะไรคือข้อดีข้อเสียของวิธีการเหล่านี้?
คำตอบ:
ฉันอยากit - vec.begin()
ได้อย่างแม่นยำด้วยเหตุผลตรงข้ามที่ Naveen ให้ไว้: ดังนั้นมันจะไม่รวบรวมถ้าคุณเปลี่ยนเวกเตอร์เป็นรายการ หากคุณทำสิ่งนี้ในระหว่างการทำซ้ำทุกครั้งคุณสามารถเปลี่ยนอัลกอริทึม O (n) เป็นอัลกอริทึม O (n ^ 2) ได้อย่างง่ายดาย
ตัวเลือกอื่นถ้าคุณไม่ข้ามไปมาในคอนเทนเนอร์ระหว่างการวนซ้ำจะเป็นการเก็บดัชนีเป็นตัวนับลูปที่สอง
หมายเหตุ: it
เป็นชื่อสามัญสำหรับ iterator std::container_type::iterator it;
คอนเทนเนอร์
it
อะไร
std::container_type::iterator it;
std::list
ไม่ได้มีการเข้าถึงโดยตรงไปยังองค์ประกอบโดยตำแหน่งของพวกเขาดังนั้นหากคุณไม่สามารถทำคุณไม่ควรจะสามารถที่จะทำlist[5]
list.begin() + 5
ฉันต้องการstd::distance(vec.begin(), it)
จะให้ฉันเปลี่ยนคอนเทนเนอร์ได้โดยไม่ต้องเปลี่ยนรหัสใด ๆ ตัวอย่างเช่นหากคุณตัดสินใจที่จะใช้std::list
แทนที่จะstd::vector
ไม่มีตัววนซ้ำการเข้าถึงแบบสุ่มรหัสของคุณจะยังคงรวบรวม เนื่องจาก std :: distance เลือกวิธีที่ดีที่สุดขึ้นอยู่กับลักษณะของตัววนซ้ำคุณจะไม่ทำให้ประสิทธิภาพลดลงเช่นกัน
vec
ข่าวร้าย หากรหัสถูกเขียนใหม่ให้เป็นแบบทั่วไปโดยใช้ประเภทคอนเทนเนอร์เป็นพารามิเตอร์เทมเพลตนั่นคือเมื่อเราสามารถ (และควร) พูดคุยเกี่ยวกับการจัดการตัววนซ้ำแบบไม่เข้าถึง ;-)
vec
เป็นข่าวร้ายเช่นกัน
ตามที่ลุงและเบ็นแสดงให้เห็นแล้วก็มีเหตุผลที่ดีสำหรับทั้งคู่ สิ่งใดที่ "ดีกว่า" ขึ้นอยู่กับพฤติกรรมที่คุณต้องการ: คุณต้องการรับประกันพฤติกรรมที่มีเวลาคงที่หรือคุณต้องการให้มันถอยกลับไปเป็นเส้นตรงเมื่อจำเป็นหรือไม่
it - vec.begin()
ใช้เวลาคงที่ แต่operator -
มีการกำหนดไว้เฉพาะในตัววนซ้ำการเข้าถึงแบบสุ่มดังนั้นโค้ดจะไม่คอมไพล์เลยด้วยตัววนซ้ำรายการตัวอย่างเช่น
std::distance(vec.begin(), it)
ใช้งานได้กับตัววนซ้ำทุกประเภท แต่จะเป็นการดำเนินการแบบคงที่เวลาหากใช้กับตัววนซ้ำการเข้าถึงแบบสุ่ม
ไม่มีอย่างใดอย่างหนึ่งคือ "ดีกว่า" ใช้สิ่งที่คุณต้องการ
ฉันชอบอันนี้: it - vec.begin()
เพราะสำหรับฉันมันชัดเจนว่า "ระยะทางจากจุดเริ่มต้น" ด้วยตัววนซ้ำเราใช้ความคิดในแง่ของเลขคณิตดังนั้น-
เครื่องหมายจึงเป็นตัวบ่งชี้ที่ชัดเจนที่สุดที่นี่
distance
?
it++
และไม่ชอบstd::increment(it)
อะไรใช่ไหม นั่นจะไม่นับรวมว่าชัดเจนน้อยลงหรือไม่
++
ดำเนินการถูกกำหนดเป็นส่วนหนึ่งของลำดับ STL เป็นวิธีที่เราเพิ่มตัววนซ้ำ std::distance
คำนวณจำนวนขององค์ประกอบระหว่างองค์ประกอบแรกและสุดท้าย ความจริงที่ว่า-
ผู้ปฏิบัติงานใช้งานเป็นเพียงเรื่องบังเอิญ
หากคุณถูก จำกัด / ฮาร์ดโค้ดอัลกอริทึมของคุณให้ใช้ a std::vector::iterator
และstd::vector::iterator
เพียงอย่างเดียวก็ไม่สำคัญว่าวิธีการใดที่คุณจะใช้ อัลกอริทึมของคุณได้รับการ concretized เกินกว่าจุดที่เลือกอย่างใดอย่างหนึ่งสามารถสร้างความแตกต่างใด ๆ พวกเขาทั้งสองทำสิ่งเดียวกัน มันเป็นเพียงเรื่องของการตั้งค่าส่วนตัว ฉันจะใช้การลบอย่างชัดเจนเป็นการส่วนตัว
หากในอีกทางหนึ่งคุณต้องการรักษาระดับทั่วไปในอัลกอริทึมของคุณให้สูงขึ้นเพื่อให้เป็นไปได้ว่าบางวันในอนาคตมันอาจถูกนำไปใช้กับประเภท iterator อื่น ๆ วิธีที่ดีที่สุดขึ้นอยู่กับเจตนาของคุณ . ขึ้นอยู่กับว่าคุณต้องการเข้มงวดกับประเภทตัววนซ้ำที่สามารถใช้ที่นี่ได้อย่างไร
หากคุณใช้การลบอย่างชัดเจนอัลกอริทึมของคุณจะถูก จำกัด ให้อยู่ในระดับที่ค่อนข้างแคบของตัววนซ้ำ: ตัววนซ้ำการเข้าถึงแบบสุ่ม (นี่คือสิ่งที่คุณได้รับตอนนี้std::vector
)
หากคุณใช้distance
อัลกอริทึมของคุณจะสนับสนุนคลาสตัววนซ้ำที่กว้างขึ้น: อินพุตตัววนซ้ำ
แน่นอนว่าการคำนวณdistance
สำหรับตัววนซ้ำที่ไม่ได้เข้าถึงแบบสุ่มนั้นโดยทั่วไปแล้วเป็นการดำเนินการที่ไม่มีประสิทธิภาพ (ในขณะที่อีกครั้งสำหรับตัวที่เข้าถึงแบบสุ่มจะมีประสิทธิภาพเท่ากับการลบ) มันขึ้นอยู่กับคุณที่จะตัดสินใจว่าอัลกอริทึมของคุณเหมาะสมกับการวนซ้ำแบบไม่สุ่มหรือเข้าถึงได้หรือไม่ การสูญเสียผลลัพธ์อย่างมีประสิทธิภาพกำลังทำลายล้างจุดที่ทำให้อัลกอริทึมของคุณไร้ประโยชน์อย่างสมบูรณ์จากนั้นคุณควรติดกับการลบดังนั้นห้ามการใช้งานที่ไม่มีประสิทธิภาพและบังคับให้ผู้ใช้ค้นหาวิธีการอื่น ๆ หากประสิทธิภาพของตัววนซ้ำที่ไม่ได้เข้าถึงยังอยู่ในช่วงที่ใช้งานได้คุณควรใช้distance
และจัดทำเอกสารเกี่ยวกับความจริงที่ว่าอัลกอริทึมทำงานได้ดีขึ้นกับตัววนซ้ำการเข้าถึงแบบสุ่ม
ตามhttp://www.cplusplus.com/reference/std/iterator/distance/เนื่องจากvec.begin()
เป็นตัววนซ้ำการเข้าถึงแบบสุ่มวิธีระยะทางจะใช้-
โอเปอเรเตอร์
ดังนั้นคำตอบคือจากมุมมองของประสิทธิภาพมันเหมือนกัน แต่บางทีการใช้อาจdistance()
จะง่ายกว่าที่จะเข้าใจถ้าใครจะต้องอ่านและเข้าใจโค้ดของคุณ
ฉันใช้-
ตัวแปรstd::vector
เพียงอย่างเดียว - มันค่อนข้างชัดเจนว่ามีความหมายอะไรและความเรียบง่ายของการดำเนินการ (ซึ่งไม่มากกว่าการลบตัวชี้) แสดงโดยไวยากรณ์ ( distance
ในอีกด้านหนึ่งดูเหมือนว่าพีทาโกรัสบน อ่านครั้งแรกใช่ไหม?) เป็นจุด UncleBen ออก-
ยังทำหน้าที่เป็นยืนยันคงที่ในกรณีที่มีการเปลี่ยนแปลงไปvector
accidentiallylist
นอกจากนี้ฉันคิดว่ามันเป็นเรื่องธรรมดามาก - ไม่มีตัวเลขที่จะพิสูจน์ได้ อาร์กิวเมนต์หลัก: it - vec.begin()
สั้นกว่าในซอร์สโค้ด - งานพิมพ์น้อยลงใช้พื้นที่น้อยลง ในขณะที่มันเป็นที่ชัดเจนว่าคำตอบที่เหมาะสมสำหรับคำถามของคุณเดือดลงไปเป็นเรื่องของรสชาตินี้จะยังเป็นอาร์กิวเมนต์ที่ถูกต้อง
นี่คือตัวอย่างเพื่อค้นหาเหตุการณ์ "ทั้งหมด" 10 รายการพร้อมกับดัชนี คิดว่านี่จะช่วยได้บ้าง
void _find_all_test()
{
vector<int> ints;
int val;
while(cin >> val) ints.push_back(val);
vector<int>::iterator it;
it = ints.begin();
int count = ints.size();
do
{
it = find(it,ints.end(), 10);//assuming 10 as search element
cout << *it << " found at index " << count -(ints.end() - it) << endl;
}while(++it != ints.end());
}