อะไรคือความแตกต่างระหว่างคอนเทนเนอร์ deque และ list STL?


98

อะไรคือความแตกต่างระหว่างทั้งสอง? ฉันหมายถึงวิธีการทั้งหมดเหมือนกัน ดังนั้นสำหรับผู้ใช้พวกเขาทำงานเหมือนกัน

ถูกต้องหรือไม่ ??


1
ฉันสนใจประสิทธิภาพการทำซ้ำ .. อะไรจะเร็วกว่าที่จะกล่าวถึงจากการขอทานจนจบ
nkint

คำตอบ:


62

จาก (ลงวันที่ แต่ยังมีประโยชน์มาก) สรุปSGI STLของdeque:

Deque เป็นเหมือนเวกเตอร์มากเช่นเวกเตอร์เป็นลำดับที่สนับสนุนการเข้าถึงองค์ประกอบแบบสุ่มการแทรกเวลาคงที่และการลบองค์ประกอบเมื่อสิ้นสุดลำดับและการแทรกเวลาเชิงเส้นและการลบองค์ประกอบที่อยู่ตรงกลาง

วิธีหลักที่ deque แตกต่างจากเวกเตอร์คือ deque ยังสนับสนุนการแทรกเวลาคงที่และการลบองค์ประกอบที่จุดเริ่มต้นของลำดับ นอกจากนี้ deque ยังไม่มีฟังก์ชันสมาชิกใด ๆ ที่คล้ายคลึงกับความจุของเวกเตอร์ () และ reserve () และไม่ได้ให้การรับประกันใด ๆ เกี่ยวกับความถูกต้องของตัววนซ้ำที่เกี่ยวข้องกับฟังก์ชันสมาชิกเหล่านั้น

นี่คือบทสรุปlistจากไซต์เดียวกัน:

รายการคือรายการที่เชื่อมโยงแบบทวีคูณ นั่นคือมันเป็นลำดับที่รองรับการส่งผ่านทั้งไปข้างหน้าและข้างหลังและ (ตัดจำหน่าย) การแทรกเวลาคงที่และการกำจัดองค์ประกอบที่จุดเริ่มต้นหรือจุดสิ้นสุดหรือตรงกลาง รายการมีคุณสมบัติที่สำคัญที่การแทรกและการต่อเชือกไม่ทำให้ตัววนซ้ำในรายการองค์ประกอบเป็นโมฆะและแม้กระทั่งการลบจะทำให้เฉพาะตัวทำซ้ำที่ชี้ไปยังองค์ประกอบที่ถูกลบ ลำดับของตัววนซ้ำอาจมีการเปลี่ยนแปลง (นั่นคือ list :: iterator อาจมีบรรพบุรุษหรือตัวต่อที่แตกต่างกันหลังจากการดำเนินการรายการมากกว่าที่เคยทำมาก่อน) แต่ตัวทำซ้ำเองจะไม่ถูกทำให้เป็นโมฆะหรือทำให้ชี้ไปยังองค์ประกอบอื่นเว้นแต่จะเป็นโมฆะนั้น หรือการกลายพันธุ์มีความชัดเจน

ในการสรุปภาชนะที่ใช้ร่วมกันอาจจะมีการปฏิบัติ แต่การค้ำประกันเวลาสำหรับการปฏิบัติเหล่านั้นแตกต่างจากภาชนะบรรจุภาชนะ สิ่งนี้สำคัญมากเมื่อพิจารณาว่าคอนเทนเนอร์ใดที่จะใช้สำหรับงาน: คำนึงถึงวิธีการใช้คอนเทนเนอร์บ่อยที่สุด (เช่นการค้นหามากกว่าการแทรก / การลบ) จะช่วยนำทางคุณไปยังคอนเทนเนอร์ที่เหมาะสม .


2
std :: list ยังมีวิธี 'splice' ซึ่งให้คุณรวมสองรายการเข้าด้วยกัน
Rick

25
จริงๆแล้วการรับประกันเวลาเป็นคุณสมบัติที่สำคัญอันดับสองของรายการ ที่สุดคุณลักษณะที่สำคัญของรายการคือการที่คุณสามารถเพิ่มและลบองค์ประกอบและได้ทำให้ iterators ของคุณ! ใน (เกือบ?) คอนเทนเนอร์ STL อื่น ๆ การดำเนินการแก้ไขทุกครั้งจะทำให้ตัววนซ้ำทั้งหมดของคุณเป็นโมฆะดังนั้นในการ "ลบรายการที่ตรงกัน" คุณจะต้องรวบรวมรายการที่ตรงกันในการดำเนินการเดียวจากนั้นจึงลบออกในอีกรายการหนึ่ง ในรายการคุณสามารถเดินผ่านลบและเพิ่มได้ตามที่คุณต้องการและไม่ต้องคำนวณตัววนซ้ำ
Tom Swirly

2
สิ่งเหล่านี้คือความแตกต่างที่เป็นนามธรรมดังนั้นจงวัดความเป็นจริงสำหรับกรณีของคุณ! ทั้ง list และ deque มีการแทรก / ลบ O (1) แต่อย่าลืมว่าหมายถึง k * O (1) และ k มีค่าต่างกันสำหรับ list และ deque ในกรณีของฉันการเพิ่มวัตถุในรายการใช้เวลานานกว่า deque ถึงสิบเท่าเนื่องจากรายการต้องการการเรียกใหม่ / ลบมากกว่า เห็นได้ชัดว่าจะแตกต่างกันไปตามการใช้งาน STL ที่คุณมี
Andy Krouwel

131

ให้ฉันระบุความแตกต่าง:

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

  • Dequeให้การแทรกและการลบที่รวดเร็วทั้งในตอนท้ายและตอนต้น การแทรกและลบองค์ประกอบที่อยู่ตรงกลางนั้นค่อนข้างช้าเนื่องจากองค์ประกอบทั้งหมดที่ขึ้นไปถึงปลายทั้งสองข้างอาจถูกย้ายเพื่อให้มีที่ว่างหรือเติมเต็มช่องว่าง
  • ในรายการการแทรกและการลบองค์ประกอบทำได้อย่างรวดเร็วในแต่ละตำแหน่งรวมทั้งปลายทั้งสองด้าน

  • Deque : การแทรกหรือการลบองค์ประกอบใด ๆ นอกเหนือจากที่จุดเริ่มต้นหรือจุดสิ้นสุดจะทำให้ตัวชี้การอ้างอิงและตัววนซ้ำทั้งหมดที่อ้างถึงองค์ประกอบของ deque ไม่ถูกต้อง
  • รายการ : การแทรกและการลบองค์ประกอบไม่ทำให้ตัวชี้การอ้างอิงและตัวทำซ้ำไปยังองค์ประกอบอื่น ๆ ไม่ถูกต้อง

ความซับซ้อน

             Insert/erase at the beginning       in middle        at the end

Deque:       Amortized constant                  Linear           Amortized constant
List:        Constant                            Constant         Constant

6
@aJ: อะไรคือความแตกต่างระหว่างconstantและamortized constant?
Lazer

17
การปฏิบัติงานในระยะยาวปฏิบัติตามที่อธิบายไว้ อย่างไรก็ตามการดำเนินการเดียวอาจใช้เวลานานกว่าที่ระบุไว้ เช่นการแทรกองค์ประกอบลงในเวกเตอร์ที่มีความจุปัจจุบัน 10 และขนาดแล้ว 9 เป็นค่าคงที่โดยที่เวลาเป็นเส้นตรงถ้าความจุเป็น 10 และขนาดเป็น 10 ด้วยเนื่องจากต้องจัดสรรและคัดลอกองค์ประกอบทั้งหมดไปยังหน่วยความจำใหม่ .
aJ.

5
@aJ: deque ให้การเข้าถึงแบบสุ่มอย่างไร? โครงสร้างนี้ถูกนำไปใช้อย่างไร?

9

std::list โดยพื้นฐานแล้วจะเป็นรายการที่เชื่อมโยงแบบทวีคูณ

std::dequeบนมืออื่น ๆ std::vectorที่มีการใช้งานมากขึ้นเช่น มีเวลาในการเข้าถึงโดยดัชนีคงที่ตลอดจนการแทรกและการลบที่จุดเริ่มต้นและจุดสิ้นสุดซึ่งให้ลักษณะการทำงานที่แตกต่างจากรายการ


5

การรับประกันที่สำคัญอีกประการหนึ่งคือวิธีที่แต่ละคอนเทนเนอร์เก็บข้อมูลไว้ในหน่วยความจำ:

  • เวกเตอร์คือบล็อกหน่วยความจำที่ต่อเนื่องกัน
  • deque คือชุดของบล็อกหน่วยความจำที่เชื่อมโยงซึ่งมีองค์ประกอบมากกว่าหนึ่งรายการถูกเก็บไว้ในแต่ละบล็อกหน่วยความจำ
  • รายการคือชุดขององค์ประกอบที่กระจายอยู่ในหน่วยความจำกล่าวคือเก็บไว้เพียงหนึ่งองค์ประกอบต่อหน่วยความจำ "บล็อก"

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

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


4

ไม่ A deque รองรับการแทรกและการลบ O (1) ที่ด้านหน้าและด้านหลังเท่านั้น ตัวอย่างเช่นอาจนำไปใช้ในเวกเตอร์ที่มีการห่อหุ้ม เนื่องจากมันรับประกันการเข้าถึงแบบสุ่ม O (1) ด้วยคุณจึงมั่นใจได้ว่าไม่ได้ใช้ (แค่) รายการที่เชื่อมโยงแบบทวีคูณ


2

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


1

นี่คือการใช้รหัสพิสูจน์แนวคิดของรายการแผนที่ที่ไม่มีการเรียงลำดับซึ่งให้การค้นหา 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;
} 

คุณโพสต์ข้อความนี้ถูกที่หรือไม่ นี่ไม่ตอบคำถาม
Blastfurnace

1

ท่ามกลางความแตกต่างที่โดดเด่นระหว่างdequeและlist

  • สำหรับ deque :

    รายการที่จัดเก็บไว้เคียงข้างกัน

    เหมาะสำหรับการเพิ่มข้อมูลจากสองด้าน (ด้านหน้าด้านหลัง)

    องค์ประกอบที่จัดทำดัชนีโดยตัวเลข (จำนวนเต็ม)

    สามารถเรียกดูได้โดยตัววนซ้ำและแม้กระทั่งดัชนีขององค์ประกอบ

    เวลาเข้าถึงข้อมูลเร็วขึ้น

  • สำหรับ list

    รายการที่จัดเก็บ "แบบสุ่ม" ในหน่วยความจำ

    สามารถเรียกดูได้โดยตัววนซ้ำเท่านั้น

    เหมาะสำหรับการใส่และถอดตรงกลาง

    เวลาในการเข้าถึงข้อมูลช้าลงทำซ้ำได้ช้าเนื่องจากพื้นที่เชิงพื้นที่ไม่ดีมาก

    จัดการองค์ประกอบขนาดใหญ่ได้เป็นอย่างดี

คุณสามารถตรวจสอบลิงก์ต่อไปนี้ซึ่งเปรียบเทียบประสิทธิภาพระหว่างคอนเทนเนอร์ STL ทั้งสอง (ด้วย std :: vector)

หวังว่าฉันจะแบ่งปันข้อมูลที่เป็นประโยชน์

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