1. 程式人生 > >c++中deque和list的基礎知識

c++中deque和list的基礎知識

STL中deque和vector的建構函式,assign基本相同,重點介紹deque的特性,deque和vector的主要區別如下:

  • deque是雙端佇列的資料結構,可以在隊首和隊尾高效的新增和刪除元素,這是相對於vector的優勢。

  • deque內部採用分段連續的記憶體空間來儲存元素,在插入元素的時候隨時都可以重新增加一段新的空間並連結起來,因此雖然提供了隨機訪問操作,但訪問速度和vector相比要慢。

  • deque並沒有data函式,因為deque的元素並沒有放在陣列中。

  • deque不提供capacity和reserve操作。

  • deque內部的插入和刪除元素要比list慢。
  • 由於deque在效能上並不是最高效的,有時候對deque元素進行排序,更高效的做法是,將deque的元素移到vector再進行排序,然後在移到回來。

  • deque為了實現整體連續的假象,導致其實現起來比較繁瑣,儘量少使用它。

  • deque
  • deque的初始化
    • deque的初始化,見如下程式碼。deque的初始化和vector完全相同
    • deque的assign函式,同樣有三種方式,初始化列表,賦值若干個相同的值,任意一個序列容器的範圍

      deque<int> v2;        // deque with 0 element
      deque<int> v3(20);   // deque with 20 elements whose value is 0
      deque<int> v4(20, 5);// deque with 20 elements whose value is 5
      deque<int> v5{ 20 }; // deque with 1 element whose value is 20 deque<int> v6(v4); // copy construct function deque<int> v7(v4.begin(), v4.end());//construct function deque<int> v8({ 1,2,3,4,5 });// construct a deque with initialize list deque<int> v9{ 1,2,3,4,5 };// construct a deque with initialize list
      deque<int> v10 = { 1,2,3,4,5 };// assignment construct function
  • deque的assign
    1. deque的assign有三種形式,assign

      deque<int> mydeque;
      deque<int> temp{ 1,2,4,5,6 };
      mydeque.assign(temp.begin(), temp.end());   //接受序列容器的範圍
      mydeque.assign(3, 5);      //變為3個值,每個值都是5
      mydeque.assign({ 1,2,3,4,5,6 });    //賦值一個初始化列表
  • deque的新增元素
    1. deque中新增元素,除了push_back和emplace_back之外,由於是雙端佇列,因此可以在隊首新增元素,deque中還有push_front和emplace_front等。
    deque<int> myDeque;
    myDeque.push_back(1);
    myDeque.push_front(2);
    myDeque.emplace_back(3);
    myDeque.emplace_front(6);
    copy(myDeque.begin(), myDeque.end(), ostream_iterator<double>(cout, " "));
  • list
  • list特點
    • list和deque的元素在記憶體的組織形式不同,以連結串列的形式儲存

    • list和deque相同,也可以在尾部和頭部加入元素,因此也支援push_back和push_front以及emplace_front和emplace_back

    • list可以高效的在內部插入元素而不需要移動元素,list是雙向連結串列

    • list的insert函式和emplace與vector,deque的方式完全相同

  • list的特有的一些函式
    1. list獨有的成員函式remove()可以移除和引數匹配的元素。例如如下程式碼:
    std::list<int> numbers{2,5,2,3,6,7,8,2,9};
    numbers.remove(2);// 刪除元素值為2的元素
    copy(numbers.begin(), numbers.end(), ostream_iterator<int>(cout, " "));
    1. 成員函式remove_if()期望傳入一個一元斷言作為引數,一元斷言接受一個和元素同類型的引數或引用,返回一個布林值。斷言返回true的元素都會被移除。斷言可以是一個函式,也可以是一個lambda表示式。
    std::list<int> numbers{2,5,2,3,6,7,8,2,9};
    auto f = [](const int& i)->bool {return i % 2 == 0; };
    numbers.remove_if(f);//刪除所有偶數
    copy(numbers.begin(), numbers.end(), ostream_iterator<int>(cout, " "));
    1. 成員函式unique,可以移除連續重複的元素 ,只留下一個,但是該函式不能刪除list中不連續的重複的元素。因此,如果需要刪除重複元素,則需要排序,排序之後再刪除重複元素。
      unique()函式過載形式兩種,一種沒有引數,有引數的版本接受一個二元斷言。斷言返回true的元素被認為是相等的。
    //沒有經過sort,直接unique
    numbers.assign({ 2,5,2,4,7,7,7,8});
    numbers.unique();// {2,5,2,4,7,8} 未刪除重複但不連續的元素
    copy(numbers.begin(), numbers.end(), ostream_iterator<int>(cout, " "));
    
    // sort 之後unique
    numbers.assign({ 2,5,2,4,7,7,7,8 });
    numbers.sort();// 2,2,4,5,7,7,7,8
    numbers.unique();// 2,4,5,7,8
    copy(numbers.begin(), numbers.end(), ostream_iterator<int>(cout, " "));
    
    
    //unique 的過載形式
    numbers.assign({ 2,5,2,4,7,7,7,8 });
    numbers.sort();// 2 2 4 5 7 7 7 8
    auto f1 = [](const int& a, const int& b)->bool {return a % 2 == b % 2; };
    numbers.unique(f1);// 2 5 8
    copy(numbers.begin(), numbers.end(), ostream_iterator<int>(cout, " "));
    1. sort()函式有兩個版本:無引數的sort()將所有元素升序排列,有引數版本的sort()函式接受一個函式物件或者lambda函式,用來表明排序依據。
    // 使用斷言
    numbers.assign({ 2,5,2,4,7,7,7,8 });
    numbers.sort(greater<>());// 2 2 4 5 7 7 7 8
    // 使用lambda函式
    numbers.assign({ 2,5,2,4,7,7,7,8 });
    auto f3 = [](const int&a, const int& b)->bool{return a>b;};
    numbers.sort(f3);// 2 2 4 5 7 7 7 8

    上述例子中使用了functional中的模板greater<T>斷言,這裡可以使用gerater<int>的形式,也可以使用greater<>的形式,後者是簡潔版本的函式物件,可以接受任何型別的引數,使用完美轉發(perfect forwarding)可以避免參數拷貝,被比較的引數會被移動而不是複製到函式中。