2015-05-10 16 views
-1

我有一個問題,我想創建一個類似於C++中的R風格列表的數據結構。結構就像一個可以容納可變大小行的矩陣。這是一個C++任務,所以我實際上無法在R本身執行此操作。如何破解C++中的R風格列表?

我想了解這個這種方式:

  • 各個「級別」的列表是炭的C++矢量
  • 有指針的矢量,每一個都指向不同的電平的列表的。

我知道如何單獨創建每個級別矢量,但不知道如何將它們連接到指針矢量,以便可以訪問它們。此外,我將使用什麼C++語法來訪問關卡中的特定元素,例如如果我想訪問第二層的第三個元素,那麼在R中它就像Levels [[2]] $ elements [3]一樣。這是如何在C++中完成的?

+6

這將是一種學習C++的痛苦方式。獲取一本C++書,學習語言。那麼你將會更好地瞭解如何用一種語言表達用不同語言表達的概念。 – DavidO

+0

如何...''#include typedef std :: vector Row_t; typedef std :: vector RLikeSomething_t;''?你可以像這樣訪問:''RLikeSomething_t東西; .... something [row] [column] ='x';'' – BitTickler

回答

2

下面是我用RCPP 只是爲了緩解例子彙編的例子:所有的數據類型是STL類型(雖然我們用隱式轉換來獲取列表回):

#include <Rcpp.h> 

// [[Rcpp::export]] 

std::list<std::vector<double> > ex(std::vector<double> a, 
            std::vector<double> b) { 

    std::list<std::vector<double> > l; 
    l.push_back(a); 
    l.push_back(b); 

    return l; 
} 

/*** R 
v <- sqrt(1:5) 
w <- log(3:5) 
ex(v, w) 
***/ 

可以輸出直接成R此將它編譯,然後加載,以及具有在端部的示例運行

R> Rcpp::sourceCpp("/tmp/ex.cpp") 

R> v <- sqrt(1:5) 

R> w <- log(3:5) 

R> ex(v, w) 
[[1]] 
[1] 1.00000 1.41421 1.73205 2.00000 2.23607 

[[2]] 
[1] 1.09861 1.38629 1.60944 

R> 

所以這應該通過你的要求,因爲列表容器在兩個不同長度的向量上。

您可能會發現Rcpp documentation有助於在R和C++之間來回切換---但我第二次評論DavidO,您還需要學習C++本身。

0

爲了分配的目的,模擬一堆積木的堆積和堆積(謝天謝地),下面是我最終想到的(見下文)。樁的水平由chars的矢量表示,而樁的不同水平則由指向PileLevel的指針向量處理。這花了我一些時間,但我終於明白,像任何其他數據類型一樣,可以在容器類上推送指針。

第一類定義和一堆的一級處理操作:

#include <iostream> 
#include <vector> 

using namespace std; 

class PileLevel 
{ 

public: 
    vector<char> elements; 

    char GetLevelElement(int i); 
    void SetLevelElement(int i, char newelt); 
    void PushLevelElement(char newelt); 
    char PopLevelElement(); 
    int GetLevelSize(); 
    void PrintLevel(); 
    void ClearLevel(); 
    bool isLevelEmpty(); 
}; 

char PileLevel::GetLevelElement(int i) 
{ 
    return elements.at(i); 
} 

void PileLevel::SetLevelElement(int i, char newelt) 
{ 
    elements.at(i) = newelt; 
} 

void PileLevel::PushLevelElement(char newelt) 
{ 
    elements.push_back(newelt); 
} 

int PileLevel::GetLevelSize() 
{ 
    return elements.size(); 
} 

char PileLevel::PopLevelElement() 
{ 
    int lst = GetLevelSize(); 
    //cout << lst << endl; 
    char eltToRet = elements[lst-1]; 
    //cout << eltToRet << endl; 
    elements.pop_back(); 
    return eltToRet; 
} 

void PileLevel::PrintLevel() 
{ 
    int ctr=0; 
    for (ctr = 0; ctr < GetLevelSize(); ctr++) 
    { 
     cout << elements.at(ctr) << " " ; 
    } 
    cout << endl; 
} 

void PileLevel::ClearLevel() 
{ 
    elements.clear(); 
} 

bool PileLevel::isLevelEmpty() 
{ 
    if (elements.size() == 0) 
     return true; 
    else 
     return false; 
} 

接下來,一個類來處理業務爲堆:

#include <iostream> 
#include <vector> 

#include "PileLevel.h" 

using namespace std; 

class BlockPile 
{ 
public: 
    vector<PileLevel*> Levels; 
    int PileHeight; 

    //constructor and destructor 
    BlockPile(); 
    ~BlockPile(); 

    //helper functions 
    void PrintPile(); 
    int GetPileHeight(); 
    void AddLevel(); 
    void AddLevel(char newElt); 
    char PopLvlElt(int lvl); 
    void PopEntireLevel(int lvl); 
    void DeleteTopLevel(); 
    bool isPileEmpty(); 
    void PushLvlElt(char block, int lvl); 
    void TryStackOnNewTopLevel(char block); 
    void TryStackOnLowerLevel(char block, int lvl); 
    void unStackPile(); 

    //required functions 
    void clear(); 
    bool isEmpty(); 
    char unStack(); 
    char topBlock(); 
    void stack(char block); 
    int numBlocks(); 
}; 

//BlockPile::BlockPile() //test constructor to make sure basic push capabilities are working 
//{ 
// PileLevel* base = new PileLevel; 
// base->PushLevelElement('A'); 
// base->PushLevelElement('B'); 
// base->PushLevelElement('C'); 
// Levels.push_back(base); 
// PileLevel* L1 = new PileLevel; 
// L1->PushLevelElement('D'); 
// L1->PushLevelElement('E'); 
// L1->PushLevelElement('F'); 
// Levels.push_back(L1); 
//} 

BlockPile::BlockPile() 
{ 
    PileLevel* base = new PileLevel; 
    base->PushLevelElement('A'); 
    Levels.push_back(base); 
} 

BlockPile::~BlockPile() 
{ 
    while (! isPileEmpty()) 
    { 
     DeleteTopLevel(); 
    } 
} 


int BlockPile::GetPileHeight() 
{ 
    //cout << "Pile is: " << Levels.size() << " levels high." << endl; 
    return Levels.size(); 
} 

void BlockPile::PrintPile() 
{ 
    int ctr = 0; 
    int lim = GetPileHeight(); 
    //cout << lim << endl; 
    if (! isPileEmpty()) 
    { 
     for (ctr = 0; ctr < lim; ctr++) 
     { 
      Levels[ctr]->PrintLevel(); 
     } 
     cout << endl; 
    } 
    else 
     cout << "Can't print empty pile." << endl; 
} 

void BlockPile::AddLevel() //add an empty level 
{ 
    PileLevel* nuLevel = new PileLevel; 
    Levels.push_back(nuLevel); 
} 

void BlockPile::AddLevel(char newElt) //add a new level with one element pushed 
{ 
    PileLevel* nuLevel = new PileLevel; 
    nuLevel->PushLevelElement(newElt); 
    Levels.push_back(nuLevel); 
} 

void BlockPile::DeleteTopLevel() 
{ 
    PileLevel* delPtr; 
    int ht = GetPileHeight(); 

    if (! isPileEmpty()) 
    { 
     delPtr = Levels[ht-1]; //set a pointer to the top level 
     Levels[ht-1]->ClearLevel(); //clear any remaining data in the top level 
     Levels[ht-1] = NULL; //disconnect the level from the vector of levels 
     delete delPtr; //delete the level 
     Levels.pop_back(); //pop the pointer to the level 
    } 
    else 
     cout << "Pile is empty." << endl; 
} 

char BlockPile::PopLvlElt(int lvl) 
{ char eltToRet; 

    eltToRet = Levels[lvl]->PopLevelElement(); 
    //cout << Levels[lvl]->GetLevelSize() << endl; 

    //must take these steps to clean up the pile if element popped was the only item remaining on the level 
    if (Levels[lvl]->GetLevelSize() == 0) 
    { 
     vector<PileLevel*>::iterator ptVecIter = Levels.begin(); //need to declare this iterator and use .begin() because .erase() is defined to take iterator arguments 
     Levels.erase(Levels.begin() + (lvl)); 
    } 
    return eltToRet; 
} 

void BlockPile::PopEntireLevel(int lvl) 
{ 
    while (! Levels[lvl]->GetLevelSize() <= 0) 
    { 
     cout << Levels[lvl]->PopLevelElement() << " " ; 
    } 
    //must take these steps to clean up the pile if element popped was the only item remaining on the level 
    if (Levels[lvl]->GetLevelSize() == 0) 
    { 
     vector<PileLevel*>::iterator ptVecIter = Levels.begin(); //need to declare this iterator and use .begin() because .erase() is defined to take iterator arguments 
     Levels.erase(Levels.begin() + (lvl)); 
    } 
    cout << endl; 
} 

void BlockPile::PushLvlElt(char block, int lvl) 
{ 
    if (Levels[lvl]->GetLevelSize() >= 0) //if the current level exists and contains 0 or more elements 
     Levels[lvl]->PushLevelElement(block); 
    else if (Levels[lvl] == NULL) //if pointer to current level is NULL 
    { 
     Levels[lvl] = new PileLevel; 
     Levels[lvl]->PushLevelElement(block); 
    } 
    else if (lvl > GetPileHeight()) //if lvl is greater than current height of pile 
    { 
     AddLevel(block); //add a new level to the pile and push the block on it 
    } 
} 


bool BlockPile::isPileEmpty() 
{ 
    if (Levels.size() == 0) 
     return true; 
    else 
     return false; 
} 

void BlockPile::unStackPile() 
{ 
    int lim = GetPileHeight() - 1; 

    while (lim > -1) 
    { 
     PopEntireLevel(lim); 
     lim--; 
    } 
} 

void BlockPile::TryStackOnNewTopLevel(char block) 
{ 
    int oldTopLvl = GetPileHeight()-1; //get current top level of pile 

    AddLevel(); //add a dummy new level but don't push anything on it yet 
    int newTopLvl = GetPileHeight()-1; //get new top level after adding dummy level 

    int newTopLvlSize = Levels[newTopLvl]->GetLevelSize(); //should be 0 
    int oldTopLvlSize = Levels[oldTopLvl]->GetLevelSize(); //should be > 0 
    int sizeDiff = oldTopLvlSize - newTopLvlSize; 

    //cout << newTopLvlSize << " " << oldTopLvlSize << " " << sizeDiff << endl; 

    if (sizeDiff >=2) //if difference in size between dummy level and old top level is at least 2 
     Levels[newTopLvl]->PushLevelElement(block); //push the block on the new top level 
    else 
    { 
     DeleteTopLevel(); //remove the dummy level, not ready for it yet 
     TryStackOnLowerLevel(block,oldTopLvl); //try to push the block on the next lower level 
    } 
} 

void BlockPile::TryStackOnLowerLevel(char block, int lvl) 
{ 
    if (lvl == 0) //if at level 0, base of the pile, can't go lower than this 
    { 
     Levels[lvl]->PushLevelElement(block); //must push the block at the base 
    } 
    else //if not yet at base 
    { 
     int thisLvlSize = Levels[lvl]->GetLevelSize(); //get size of current level 
     int lowerLvlSize = Levels[lvl-1]->GetLevelSize(); //get size of next lower level 
     int sizeDiff = lowerLvlSize - thisLvlSize; //difference in size 

     //cout << thisLvlSize << " " << lowerLvlSize << " " << sizeDiff << endl; 

     if (sizeDiff >= 2) //if size difference is at least 2 
      Levels[lvl]->PushLevelElement(block); //push block on current level 
     else //if diff is smaller than 2 
      TryStackOnLowerLevel(block,lvl-1); //make recursive call and try to push it on a lower level 
    } 
} 

//required functions 
void BlockPile::clear() 
{ 
    int lim = GetPileHeight()-1; 

    while (lim > -1) 
    { 
     DeleteTopLevel(); 
     lim--; 
    } 
} 

bool BlockPile::isEmpty() 
{ 
    return isPileEmpty(); 
} 

char BlockPile::unStack() 
{ 
    int ht = GetPileHeight()-1; 

    return PopLvlElt(ht); 
} 

char BlockPile::topBlock() 
{ 
    int ht = GetPileHeight()-1; 

    int lsize = Levels[ht]->GetLevelSize() - 1; 

    return Levels[ht]->GetLevelElement(lsize); 
} 

void BlockPile::stack(char block) 
{ 
    TryStackOnNewTopLevel(block); 
} 

int BlockPile::numBlocks() 
{ 
    int acc = 0; 
    int ht = GetPileHeight(); 
    int ctr; 

    for(ctr = 0; ctr < ht; ctr++) 
    { 
     acc = acc + Levels[ctr]->GetLevelSize(); 
    } 
    return acc; 
} 

最後一個驅動程序:

#include <iostream> 
#include <array> 

#include "BlockPile.h" 

using namespace std; 

int main() 
{ 
    //PileLevel myLevel; 

    //myLevel.PushLevelElement('A'); 
    //myLevel.PushLevelElement('B'); 
    //myLevel.PushLevelElement('C'); 
    //myLevel.PushLevelElement('D'); 

    //myLevel.PrintLevel(); 
    //cout << myLevel.GetLevelSize() << endl; 
    //myLevel.PopLevelElement(); 
    //myLevel.PrintLevel(); 

    //BlockPile myPile; 
    //myPile.GetPileHeight(); 
    //myPile.PrintPile(); 
    //myPile.AddLevel('Z'); 
    //myPile.GetPileHeight(); 
    //myPile.PrintPile(); 
    //myPile.PushLvlElt('P', 2); 
    //myPile.PushLvlElt('Q', 1); 
    //myPile.PrintPile(); 
    //cout << myPile.PopLvlElt(2) << endl; 
    //cout << myPile.PopLvlElt(1) << endl; 
    //cout << myPile.PopLvlElt(0) << endl; 
    //myPile.PrintPile(); 
    //myPile.DeleteTopLevel(); 
    ////myPile.DeleteTopLevel(); 
    //myPile.PrintPile(); 
    //myPile.PushLvlElt('G',0); 
    //myPile.PushLvlElt('H',0); 
    //myPile.AddLevel('I'); 
    //myPile.PushLvlElt('J',2); 
    //myPile.AddLevel('K'); 
    //myPile.PrintPile(); 
    ////myPile.PopEntireLevel(3); 
    ////myPile.PopEntireLevel(2); 
    //myPile.unStackPile(); 
    //myPile.PrintPile(); 

    //BlockPile myPile2; 
    //myPile2.PrintPile(); 
    //myPile2.TryStackOnNewTopLevel('B'); 
    //myPile2.PrintPile(); 
    //myPile2.TryStackOnNewTopLevel('C'); 
    //myPile2.PrintPile(); 
    //myPile2.TryStackOnNewTopLevel('D'); 
    //myPile2.PrintPile(); 
    //myPile2.TryStackOnNewTopLevel('E'); 
    //myPile2.PrintPile(); 
    //myPile2.TryStackOnNewTopLevel('F'); 
    //myPile2.PrintPile(); 

    array<char,44> BlockSet = {'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '+', '-', '=', '/', '<', '>', '?', ',', '.'}; 
    int BSSize = BlockSet.size(); 
    int idx = 0; 

    BlockPile myPile3; 
    myPile3.PrintPile(); 
    //myPile3.clear(); 
    for (idx = 0; idx < BSSize; idx++) 
    { 
     myPile3.stack(BlockSet[idx]); 
     cout << "Number of blocks currently in pile: " << myPile3.numBlocks() << endl; 
     myPile3.PrintPile(); 
    } 

    cout << "Top block is: " << myPile3.topBlock() << endl; 
    cout << endl; 

    for (idx=0; idx < 5; idx++) 
    { 
     cout << "Unstacking block: " << myPile3.unStack() << endl; 
     cout << "Top block is now: " << myPile3.topBlock() << endl; 
     cout << "Number of blocks is now: " << myPile3.numBlocks() << endl; 
     cout << endl; 
    } 

    cout << endl; 

    cout << "Unstacking remainder of pile..." << endl; 
    myPile3.unStackPile(); 

    system("pause"); 
    return 0; 
} 

瞧。