c++實現雙端隊列


在使用c++容器的時候其底層如何實現  例如  vector 容器  :是一個內存可以二倍擴容的向量容器,使用方便但是對內存要求嚴格,弊端明顯    list  容器  : 雙向循環鏈表    deque  容器 :雙端隊列

deque容器是C++標准模版庫(STL,Standard Template Library)中的部分內容。deque容器類與vector類似,支持隨機訪問和快速插入刪除,它在容器中某一位置上的操作所花費的是線性時間。與vector不同的是,deque還支持從開始端插入數據:push_front()。

實際上雙端隊列是一個二維數組,但是實際存儲數據的部分並不是連續的,一維數組存放指針,指向二維申請出來的空間,如圖

 

 

首先申請一維空間存放指向二維的指針,例如一維空間長度為int len;則在len/4的位置先申請一塊二維空間,指向前的指針*_frist與指向后的指針*_last 位於二維空間的中間,前插數據則*_frist--,后插數據則*_last++;

如果前插到二維的0下標位置,若一維數組上一個位置指向的空間為空,此時會在一維上一個位置申請二維,*_frist指向二維尾部,例如上圖,會在*p   0 的位置申請二維,*_frist指向新開辟的二維的尾部,實現繼續前插,若上面的所有一維都申請了二維,但是下面還有一維數組還有空,則整體將數據往下挪,把一維0號下標的二維空出來,繼續前插,直到所有的一維都申請了二維並且數據放滿,此時需要擴容,將一維數組2倍擴大,然后將所有數據移到新的一維數組所指向的二維數組中,滿足數據位置為  :(新的一維數組長度/4)的位置。尾插同理  只是向下插方向相反。

下面是數據結構和基本函數

#define QUE_SIZE(T) 4096 / sizeof(T)
#define DEFAULT_QUE 2
class Deque
{
public:
  Deque();     //構造函數
  ~Deque();   // 析構函數
  Deque(const Deque &src);  // 左值引用參數構造拷貝函數 防止淺拷貝

  Deque(Deque &&src);        // 右值引用參數拷貝構造函數 防止臨時量對空間時間的浪費


  Deque& operator=(const Deque &src);    //  左值引用參數賦值構造函數

  
  Deque& operator=(Deque &&src);          //  帶右值引用參數的賦值構造函數

void push_back(int val); // 尾部入隊

  void pop_back();         // 尾部刪除

  void push_front(int val);  //  前插

  void pop_front();            //前刪

 
  int front();          //返回隊頭元素

  int back();         //  返回隊尾元素

  
  bool empty();   //   是否對空


  
private:
  int **mMapper;
  int *mFirst;
  int *mLast;
  int mMapperSize;
};

具體函數 封裝成類

#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
#define QUE_SIZE(T) 4096 / sizeof(T)
#define DEFAULT_QUE 2
class Deque
{
public:
  Deque()
  {
  mMapper=new int*[DEFAULT_QUE]();
  mMapperSize=DEFAULT_QUE;
  mMapper[DEFAULT_QUE/4]=new int[QUE_SIZE(int)];
  mFirst=mMapper[DEFAULT_QUE/4]+QUE_SIZE(int)/2;
  mLast=mFirst+1;
  }
  ~Deque()
  {
  int i=0;
  for(;i<mMapperSize;i++)
  {
    delete []mMapper[i];
    mMapper[i]=nullptr;
  }
  delete []mMapper;
  mMapper=nullptr;
  }
  
  Deque(const Deque &src)
  {
    mMapper=new int*[src.mMapperSize]();
    int mfirst=-1;
    int mlast=-1;
    bool sign=1;
    int i;
    for(i=0;i<src.mMapperSize;i++)
    {
       if(src.mMapper[i]==nullptr)
       {
          continue;
       }
       if(src.mMapper[i]!=nullptr)
       {

         if(sign)
         {
           mfirst=i;
           sign=0;
         }

      int j;
      mMapper[i]=new int[QUE_SIZE(int)];
      for(j=0;j<QUE_SIZE(int);j++)
      {
        *(mMapper[i]+j)=*(src.mMapper[i]+j);
      }
      mlast=i;
     }
    
    }
    mFirst=mMapper[mfirst]+(src.mFirst-src.mMapper[mfirst]);
    mLast=mMapper[mlast]+(src.mLast-src.mMapper[mlast]);
    mMapperSize=src.mMapperSize;
  }
  Deque(Deque &&src)
  {
    mMapper=src.mMapper;
    mMapperSize=src.mMapperSize;
    mFirst=src.mFirst;
    mLast=src.mLast;
    src.mMapper=nullptr;
  }

  Deque& operator=(const Deque &src)
  {
    if(this==&src)
    {
      return *this;
    }
    int i=0;
    for(;i<mMapperSize;i++)
    {
      delete[]mMapper[i];
    }
    delete []mMapper;
    mMapper=new int*[src.mMapperSize]();
    int mfirst=-1;
    int mlast=-1;
    bool sign=-1;
    for(i=0;i<src.mMapperSize;i++)
    {
       if(src.mMapper[i]==nullptr)
       {
          continue;
       }
       if(src.mMapper[i]!=nullptr)
       {
         if(sign)
         {
           mfirst=i;
           sign=0;
         }
      int j;
      mMapper[i]=new int[QUE_SIZE(int)];
      for(j=0;j<QUE_SIZE(int);j++)
      {
        *(mMapper[i]+j)=*(src.mMapper[i]+j);
      }
      mlast=i;
     }
    }
    mFirst=mMapper[mfirst]+(src.mFirst-src.mMapper[mfirst]);
    mLast=mMapper[mlast]+(src.mLast-src.mMapper[mlast]);
mMapperSize=src.mMapperSize;
    return *this;
  }
  
  Deque& operator=(Deque &&src)
  {
    int i=0;
    for(;i<mMapperSize;i++)
    {
      delete []mMapper[i];
    }
    delete []mMapper;
    mMapper=src.mMapper;
    mMapperSize=src.mMapperSize;
    mLast=src.mLast;
    mFirst=src.mFirst;
    src.mMapper=nullptr;
    return *this;
  }
void push_back(int val) // 尾部入隊
  {
     int index = -1;
     for (int i = 0; i < mMapperSize; ++i)
     {
         if (mMapper[i] == nullptr)
         {
            index = i;
            continue;
         }
                
   // 表示last已經指向行的末尾了,需要擴容
        if (mMapper[i] + QUE_SIZE(int) == mLast)
        {
  // 說明下面還有空行,直接分配新的第二維數組
        if (i != mMapperSize - 1)
        {
           mMapper[i+1] = new int[QUE_SIZE(int)];
           mLast = mMapper[i + 1];
           break;
        }
                    
  // 說明last下面已經沒有空閑行了
        if (index != -1)
        {
  // 說明上面還有空閑行,整體往上挪一行,下面就有一個空閑行了
           for (int i = index; i < mMapperSize-1; ++i)
           {
               mMapper[i] = mMapper[i + 1];
           }
               mMapper[mMapperSize-1] = new int[QUE_SIZE(int)];
               mLast = mMapper[mMapperSize - 1];
               break;
        } 
        else 
        {
   // 說明上面沒有空閑行,一維需要開始擴容了
            int **tmpMapper = new int*[2* mMapperSize];
            int idx = 2 * mMapperSize / 4;
            for (int i = 0; i < mMapperSize; ++i)
            {
                tmpMapper[idx++] = mMapper[i];
            }
                   delete[]mMapper;
                        mMapper = tmpMapper;
                        mMapperSize *= 2;
                        
                        mMapper[idx] = new int[QUE_SIZE(int)];
                        mLast = mMapper[idx];
                        break;
                    }
                }
            }
            // 添加元素
            *mLast++ = val;
  }
  void pop_back()
  {
    int i;
    bool sign=1;
    for(i=0;i<mMapperSize;i++)
    {
      if(mMapper[i]==mLast)
      {
        mLast=mMapper[i-1]+QUE_SIZE(int);
        sign=0;
        break;
      }
    }
    if(sign)
    {
      mLast--;
    }
  }

  void push_front(int val)
  {

    // 遍歷第一維的數組,從下往上遍歷 與尾插方法一樣
     int index = -1;
     int i=mMapperSize-1;
     for (; i>=0; i--)
     {
        if (mMapper[i] == nullptr)
        {
             index = i;
             continue;
        }
                
       // 表示frist已經指向行首,需要擴容
       if (mMapper[i] ==mFirst)
         {
       // 說明上面還有空行,直接分配新的第二維數組
       if (i != 0)
       {
           mMapper[i-1] = new int[QUE_SIZE(int)];
           mFirst = mMapper[i-1]+QUE_SIZE(int);
             break;
       }
                    
     // 說明frist下面已經沒有空閑行了
       if (index != -1)
          
       {
     // 說明下面還有空閑行,整體往下挪一行,上面就有一個空閑行了
       for (i = index; i >0; i--)
       {
         mMapper[i] = mMapper[i-1];
       }
         mMapper[0] = new int[QUE_SIZE(int)];
         mFirst= mMapper[0]+QUE_SIZE(int);
          break;
        }
         else
        {
         // 說明下面沒有空閑行,一維需要開始擴容了
           int **tmpMapper = new int*[2* mMapperSize];
           int idx = 2 * mMapperSize / 4;
           for (int i = 0; i < mMapperSize; ++i)
           {
               tmpMapper[idx+i] = mMapper[i];
           }
               delete[]mMapper;
               mMapper = tmpMapper;
               mMapperSize *= 2;
                        
               mMapper[idx-1] = new int[QUE_SIZE(int)];
               mFirst = mMapper[idx-1]+QUE_SIZE(int);
               break;
                    }
                }
            }
            // 添加元素
            *mFirst-- = val;
  }
  void pop_front()
  {
    int i;
    bool sign=1;
    for(i=0;i<mMapperSize;i++)
    {
      if(mMapper[i]+QUE_SIZE(int)==mFirst)
      {
        mFirst=mMapper[i+1];
        sign=0;
        break;
      }
    }
    if(sign)
    {
      mFirst++;
    }

  }
  int front()
  {
    int i;
    for(i=0;i<mMapperSize;i++)
    {
      if(mMapper[i]+QUE_SIZE(int)==mFirst)
      {
        return *mMapper[i+1];
      }
    }
    return *(mFirst+1);

  }

  int back()
  {
    int i=0;
    for(;i<mMapperSize;i++)
    {
      if(mMapper[i]==mLast)
      {
        return *(mMapper[i-1]+QUE_SIZE(int));
      }
    }
    return *(mLast-1);

  }

  
  bool empty()
  {
    return mFirst+1==mLast;
  }
  

  
private:
  int **mMapper;
  int *mFirst;
  int *mLast;
  int mMapperSize;
};
int main()
{
     Deque s1;
     Deque s2;
     int i=0;
     for(;i<10000;i++)
     {
       s1.push_back(i);
     }
     s2=s1; 
     for(i=0;i<10000;i++)
     {
      cout<<s2.front()<<' ';
       s2.pop_front();
     }
    cout<<endl;
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM