อะไรคือความแตกต่างระหว่างทั้งสอง? ฉันหมายถึงวิธีการทั้งหมดเหมือนกัน ดังนั้นสำหรับผู้ใช้พวกเขาทำงานเหมือนกัน
ถูกต้องหรือไม่ ??
อะไรคือความแตกต่างระหว่างทั้งสอง? ฉันหมายถึงวิธีการทั้งหมดเหมือนกัน ดังนั้นสำหรับผู้ใช้พวกเขาทำงานเหมือนกัน
ถูกต้องหรือไม่ ??
คำตอบ:
จาก (ลงวันที่ แต่ยังมีประโยชน์มาก) สรุปSGI STLของdeque
:
Deque เป็นเหมือนเวกเตอร์มากเช่นเวกเตอร์เป็นลำดับที่สนับสนุนการเข้าถึงองค์ประกอบแบบสุ่มการแทรกเวลาคงที่และการลบองค์ประกอบเมื่อสิ้นสุดลำดับและการแทรกเวลาเชิงเส้นและการลบองค์ประกอบที่อยู่ตรงกลาง
วิธีหลักที่ deque แตกต่างจากเวกเตอร์คือ deque ยังสนับสนุนการแทรกเวลาคงที่และการลบองค์ประกอบที่จุดเริ่มต้นของลำดับ นอกจากนี้ deque ยังไม่มีฟังก์ชันสมาชิกใด ๆ ที่คล้ายคลึงกับความจุของเวกเตอร์ () และ reserve () และไม่ได้ให้การรับประกันใด ๆ เกี่ยวกับความถูกต้องของตัววนซ้ำที่เกี่ยวข้องกับฟังก์ชันสมาชิกเหล่านั้น
นี่คือบทสรุปlist
จากไซต์เดียวกัน:
รายการคือรายการที่เชื่อมโยงแบบทวีคูณ นั่นคือมันเป็นลำดับที่รองรับการส่งผ่านทั้งไปข้างหน้าและข้างหลังและ (ตัดจำหน่าย) การแทรกเวลาคงที่และการกำจัดองค์ประกอบที่จุดเริ่มต้นหรือจุดสิ้นสุดหรือตรงกลาง รายการมีคุณสมบัติที่สำคัญที่การแทรกและการต่อเชือกไม่ทำให้ตัววนซ้ำในรายการองค์ประกอบเป็นโมฆะและแม้กระทั่งการลบจะทำให้เฉพาะตัวทำซ้ำที่ชี้ไปยังองค์ประกอบที่ถูกลบ ลำดับของตัววนซ้ำอาจมีการเปลี่ยนแปลง (นั่นคือ list :: iterator อาจมีบรรพบุรุษหรือตัวต่อที่แตกต่างกันหลังจากการดำเนินการรายการมากกว่าที่เคยทำมาก่อน) แต่ตัวทำซ้ำเองจะไม่ถูกทำให้เป็นโมฆะหรือทำให้ชี้ไปยังองค์ประกอบอื่นเว้นแต่จะเป็นโมฆะนั้น หรือการกลายพันธุ์มีความชัดเจน
ในการสรุปภาชนะที่ใช้ร่วมกันอาจจะมีการปฏิบัติ แต่การค้ำประกันเวลาสำหรับการปฏิบัติเหล่านั้นแตกต่างจากภาชนะบรรจุภาชนะ สิ่งนี้สำคัญมากเมื่อพิจารณาว่าคอนเทนเนอร์ใดที่จะใช้สำหรับงาน: คำนึงถึงวิธีการใช้คอนเทนเนอร์บ่อยที่สุด (เช่นการค้นหามากกว่าการแทรก / การลบ) จะช่วยนำทางคุณไปยังคอนเทนเนอร์ที่เหมาะสม .
ให้ฉันระบุความแตกต่าง:
ความซับซ้อน
Insert/erase at the beginning in middle at the end
Deque: Amortized constant Linear Amortized constant
List: Constant Constant Constant
constant
และamortized constant
?
std::list
โดยพื้นฐานแล้วจะเป็นรายการที่เชื่อมโยงแบบทวีคูณ
std::deque
บนมืออื่น ๆ std::vector
ที่มีการใช้งานมากขึ้นเช่น มีเวลาในการเข้าถึงโดยดัชนีคงที่ตลอดจนการแทรกและการลบที่จุดเริ่มต้นและจุดสิ้นสุดซึ่งให้ลักษณะการทำงานที่แตกต่างจากรายการ
การรับประกันที่สำคัญอีกประการหนึ่งคือวิธีที่แต่ละคอนเทนเนอร์เก็บข้อมูลไว้ในหน่วยความจำ:
โปรดทราบว่า deque ได้รับการออกแบบมาเพื่อพยายามสร้างความสมดุลระหว่างข้อดีของทั้งเวกเตอร์และรายการโดยไม่มีข้อเสียตามลำดับ เป็นคอนเทนเนอร์ที่น่าสนใจเป็นพิเศษในแพลตฟอร์มที่ จำกัด หน่วยความจำตัวอย่างเช่นไมโครคอนโทรลเลอร์
กลยุทธ์การจัดเก็บหน่วยความจำมักถูกมองข้ามอย่างไรก็ตามบ่อยครั้งเป็นหนึ่งในเหตุผลที่สำคัญที่สุดในการเลือกคอนเทนเนอร์ที่เหมาะสมที่สุดสำหรับแอปพลิเคชันบางอย่าง
ไม่ A deque รองรับการแทรกและการลบ O (1) ที่ด้านหน้าและด้านหลังเท่านั้น ตัวอย่างเช่นอาจนำไปใช้ในเวกเตอร์ที่มีการห่อหุ้ม เนื่องจากมันรับประกันการเข้าถึงแบบสุ่ม O (1) ด้วยคุณจึงมั่นใจได้ว่าไม่ได้ใช้ (แค่) รายการที่เชื่อมโยงแบบทวีคูณ
ความแตกต่างของประสิทธิภาพได้รับการอธิบายอย่างดีจากผู้อื่น ฉันแค่อยากจะเพิ่มว่าอินเทอร์เฟซที่เหมือนกันหรือเหมือนกันเป็นเรื่องปกติในการเขียนโปรแกรมเชิงวัตถุซึ่งเป็นส่วนหนึ่งของวิธีการทั่วไปในการเขียนซอฟต์แวร์เชิงวัตถุ คุณไม่ควรคิดว่าสองคลาสทำงานในลักษณะเดียวกันเพียงเพราะใช้อินเทอร์เฟซเดียวกันมากกว่าที่คุณควรคิดว่าม้าทำงานเหมือนสุนัขเพราะทั้งคู่ใช้การโจมตี () และ make_noise ()
นี่คือการใช้รหัสพิสูจน์แนวคิดของรายการแผนที่ที่ไม่มีการเรียงลำดับซึ่งให้การค้นหา O (1) และการบำรุงรักษา LRU ที่แน่นอน O (1) ต้องการตัวทำซ้ำ (ไม่ถูกลบ) เพื่อให้สามารถดำเนินการลบได้ วางแผนที่จะใช้ใน O (1) ซอฟต์แวร์ที่มีการจัดการแคชขนาดใหญ่โดยพลการสำหรับตัวชี้ CPU บนหน่วยความจำ GPU พยักหน้าให้กับตัวกำหนดตารางเวลา Linux O (1) (LRU <-> รันคิวต่อโปรเซสเซอร์) unordered_map มีการเข้าถึงเวลาคงที่ผ่านตารางแฮช
#include <iostream>
#include <list>
#include <unordered_map>
using namespace std;
struct MapEntry {
list<uint64_t>::iterator LRU_entry;
uint64_t CpuPtr;
};
typedef unordered_map<uint64_t,MapEntry> Table;
typedef list<uint64_t> FIFO;
FIFO LRU; // LRU list at a given priority
Table DeviceBuffer; // Table of device buffers
void Print(void){
for (FIFO::iterator l = LRU.begin(); l != LRU.end(); l++) {
std::cout<< "LRU entry "<< *l << " : " ;
std::cout<< "Buffer entry "<< DeviceBuffer[*l].CpuPtr <<endl;
}
}
int main()
{
LRU.push_back(0);
LRU.push_back(1);
LRU.push_back(2);
LRU.push_back(3);
LRU.push_back(4);
for (FIFO::iterator i = LRU.begin(); i != LRU.end(); i++) {
MapEntry ME = { i, *i};
DeviceBuffer[*i] = ME;
}
std::cout<< "************ Initial set of CpuPtrs" <<endl;
Print();
{
// Suppose evict an entry - find it via "key - memory address uin64_t" and remove from
// cache "tag" table AND LRU list with O(1) operations
uint64_t key=2;
LRU.erase(DeviceBuffer[2].LRU_entry);
DeviceBuffer.erase(2);
}
std::cout<< "************ Remove item 2 " <<endl;
Print();
{
// Insert a new allocation in both tag table, and LRU ordering wiith O(1) operations
uint64_t key=9;
LRU.push_front(key);
MapEntry ME = { LRU.begin(), key };
DeviceBuffer[key]=ME;
}
std::cout<< "************ Add item 9 " <<endl;
Print();
std::cout << "Victim "<<LRU.back()<<endl;
}
ท่ามกลางความแตกต่างที่โดดเด่นระหว่างdeque
และlist
สำหรับ deque
:
รายการที่จัดเก็บไว้เคียงข้างกัน
เหมาะสำหรับการเพิ่มข้อมูลจากสองด้าน (ด้านหน้าด้านหลัง)
องค์ประกอบที่จัดทำดัชนีโดยตัวเลข (จำนวนเต็ม)
สามารถเรียกดูได้โดยตัววนซ้ำและแม้กระทั่งดัชนีขององค์ประกอบ
เวลาเข้าถึงข้อมูลเร็วขึ้น
สำหรับ list
รายการที่จัดเก็บ "แบบสุ่ม" ในหน่วยความจำ
สามารถเรียกดูได้โดยตัววนซ้ำเท่านั้น
เหมาะสำหรับการใส่และถอดตรงกลาง
เวลาในการเข้าถึงข้อมูลช้าลงทำซ้ำได้ช้าเนื่องจากพื้นที่เชิงพื้นที่ไม่ดีมาก
จัดการองค์ประกอบขนาดใหญ่ได้เป็นอย่างดี
คุณสามารถตรวจสอบลิงก์ต่อไปนี้ซึ่งเปรียบเทียบประสิทธิภาพระหว่างคอนเทนเนอร์ STL ทั้งสอง (ด้วย std :: vector)
หวังว่าฉันจะแบ่งปันข้อมูลที่เป็นประโยชน์