2016-07-14 4 views
2

Ich bin neu in C++ und könnte hier etwas sehr Grundlegendes fehlt aber ich versuche, einen Vektor von Vektoren zu erstellenVerwendung von Vektoren von Vektoren in C++ & push_back()

#include <iostream> 
#include <stack> 
#include <string> 
#include <map> 
#include <vector> 
#include <algorithm> 


using namespace std; 

class Solution { 
public: 
    vector<vector<string>> groupAnagrams(vector<string>& strs) 
    { 
     vector<vector<string>> result; 
     map<string,vector<string>> myMap; 

     if(strs.size() == 0) 
     { 
      return result; 
     } 

     for(string s : strs) 
     { 
      string temp = s; 
      sort(temp.begin(),temp.end()); 
      auto it = myMap.find(temp); 
      if(it != myMap.end()) 
      { 
       it->second.push_back(s); 
      } 
      else 
      { 
       vector<string> newVector; 
       newVector.push_back(s); 
       myMap.insert(pair<string,vector<string>>(temp,newVector)); 
       result.push_back(newVector); 
      } 
     } 
     cout<< myMap["abt"].size() <<endl; 
     return result; 
    } 
}; 


int main(int argc, const char * argv[]) 
{ 
    Solution mySolution; 
    vector<string> myStrings {"eat", "tea", "tan", "ate", "nat", "bat"}; 
    auto result = mySolution.groupAnagrams(myStrings); 

    for(vector<string> v: result) 
    { 
     //cout << v.size() << endl; 
     for(string s: v) 
     { 
      cout << s << " "; 
     } 
     cout << endl; 
    } 
    return 0; 
} 

ich einen Ausgang erwarte die sieht aus wie dieses

[ 
    ["ate", "eat","tea"], 
    ["nat","tan"], 
    ["bat"] 
] 

wenn ich versuche, den Vektor der Vektoren in main() ich die ganze Größe der Vektoren als 1.

Gut erhalten zu drucken, wenn ich die Größen der Vektoren in der Karte drucken , die Größen lo ok ok für mich da. Was fehlt mir hier?

UPDATE -

es Feste mit unter Änderung

for(string s : strs) 
{ 
    string temp = s; 
    sort(temp.begin(),temp.end()); 
    auto it = myMap.find(temp); 
    if(it != myMap.end()) 
    { 
     it->second.push_back(s); 
    } 
    else 
    { 
     vector<string> newVector; 
     newVector.push_back(s); 
     myMap.insert(pair<string,vector<string>>(temp,newVector)); 
    } 
} 
for(auto it: myMap) 
{ 
    result.push_back(it.second); 
} 

ich immer noch daran interessiert wäre, zu wissen, ob es einen Weg gibt, durch die Karte am Ende zu vermeiden, Looping und erreichen etwas, was ich anfangs gedacht machen?

+1

Beachten Sie, dass 'for (string s: strs)' eine Kopie jeder Zeichenfolge in 'strs' erstellt. – kfsone

+1

"... wenn es eine Möglichkeit gibt, das Durchlaufen der Karte am Ende zu vermeiden" - Ich möchte nicht in diese Richtung antworten, nur weil es leicht ist, falsch zu liegen (sehr falsch), wenn man in 'Vektor kommt &> Territorium. Selbst für meine eigenen Zwecke versuche ich, Containers mit Referenztypen zu umgehen, da es eine Quelle für schlechtes Speichermanagement ist, wenn Sie die Werte gleichzeitig erzeugen und sie nur an "äußere" Bereiche übergeben. Sie können auch Zeiger verwenden, und es sollte offensichtlich sein, warum das gefährlich ist. –

Antwort

5

Es ist dieser Teil:

{ 
    vector<string> newVector; 
    newVector.push_back(s); 
    myMap.insert(pair<string,vector<string>>(temp,newVector)); 
    result.push_back(newVector); 
} 

Jedes Mal result einen neuen Vektor gegeben wird, die ein Element aufweist. Der Grund dafür, dass die Änderungen am Vektor der Karte funktionieren und nicht am Vektor der Vektoren, liegt darin, dass vector::push_back jedes Mal eine Kopie erstellt.


Um dies zu lösen, gibt es zwei Möglichkeiten.

  1. Sie können versuchen, das Ergebnis zur gleichen Zeit wie die Karte zu aktualisieren, und erhalten Sie den Vektor, um einen Verweis auf die Kopie der Karte zu speichern.
  2. Da Sie result nicht für den Verarbeitungsschritt verwenden, nur für Ergebnisse, können Sie den Vektor kompilieren, nachdem Sie mit der Karte fertig sind.

Ich bevorzuge Methode # 2 für diese, da Sie nie die Karte selbst zurückgeben. Darüber hinaus gibt es eine Kunst, von einem Containertyp zum nächsten zu wechseln, zB gibt this question einige Ideen zu dem, was involviert ist.

+1

Der Teil, der das Problem verursacht, ist, dass die Zeile "it-> second.push_back (s)" nur in die Map und nicht in den "result" -Vektor drückt, da sie separate Dinge sind (obwohl sie beide aus 'newVector kopiert wurden) ') –

+0

Sie sagen also, dass der Vektor, der in der Karte gespeichert ist und die im Ergebnis gespeichert ist, anders sind? Und alle Updates werden auf dem Vektor gemacht, der in der Karte gespeichert wird, aber nicht auf dem, der in Ergebnis ist, da sie unterschiedlich sind? – kimi

+0

@ghanta_engineer genau, ja. Ihre Map wird aktualisiert, und Sie ändern den in der Map gespeicherten Vektor direkt. Das Ergebnis nimmt jedoch nur eine Kopie mit einem Element auf und wird nie wieder aufgerufen. –

0

Das Problem ist mit diesem Teil des Codes:

vector<string> newVector; 
newVector.push_back(s); 
myMap.insert(pair<string,vector<string>>(temp,newVector)); 
result.push_back(newVector); 

Gegliedert:

vector<string> newVector; 

Erstellt einen neuen, lokalen, temporären Vektor.

newVector.push_back(s); 

ordnet Platz für ein string auf der Rückseite der newVector und Kopien s hinein.

myMap.insert(pair<string,vector<string>>(temp,newVector)); 

Erstellt ein std :: pair eine Kopie der temporären und eine Kopie von newVector enthält - wie ordnet dann Platz für ein passendes Paar in der Karte und kopiert die temporäre Paar (dh Kopien der Zeichenfolge und der Vektor, wieder) hinein.

result.push_back(newVector); 

Dieser ordnet Platz für einen neuen Vektor auf der Rückseite des Ergebnisses und Kopien newVector hinein.

result und myMap enthalten zu diesem Zeitpunkt unabhängige Snapshots von newVector. Der Rest Ihres Codes aktualisiert den Vektor in myMap, aber das Ergebnis ist unverändert.

Sie können dieses Problem beheben, indem sie nicht result on the fly bauen, sondern bauen es nur, wenn alle Arbeit getan ist:

// take a reference to each string in the vector, 
    // const indicates it will be immutable 
    for(const string& s : strs) 
    { 
     string temp = s; 
     sort(temp.begin(),temp.end()); 
     std::vector<string>& dest = myMap[temp]; 
     dest.emplace_back(s); 
    } 

    cout<< myMap["abt"].size() <<endl; 

    for (auto& kv : myMap) // kv: key value 
    { 
     // std::move tells 'emplace_back' it can steal the 
     // vector's data right out of kv.second. 
     result.emplace_back(std::move(kv.second)); 
    } 

Der resultierende Code wird hier gezeigt: http://ideone.com/eofloM

#include <iostream> 
#include <stack> 
#include <string> 
#include <map> 
#include <vector> 
#include <algorithm> 


using namespace std; 

class Solution { 
public: 
    vector<vector<string>> groupAnagrams(vector<string>& strs) 
    { 
     vector<vector<string>> result; 
     map<string,vector<string>> myMap; 

     if(strs.size() == 0) 
     { 
      return result; 
     } 

     for(const string& s : strs) 
     { 
      string temp = s; 
      sort(temp.begin(),temp.end()); 
      std::vector<string>& dest = myMap[temp]; 
      dest.emplace_back(s); 
     } 

     cout<< myMap["abt"].size() <<endl; 

     for (auto& kv : myMap) // kv: key value 
     { 
      result.emplace_back(std::move(kv.second)); 
     } 

     return result; 
    } 
}; 


int main(int argc, const char * argv[]) 
{ 
    Solution mySolution; 
    vector<string> myStrings {"eat", "tea", "tan", "ate", "nat", "bat"}; 
    auto result = mySolution.groupAnagrams(myStrings); 

    for(vector<string> v: result) 
    { 
     //cout << v.size() << endl; 
     for(string s: v) 
     { 
      cout << s << " "; 
     } 
     cout << endl; 
    } 
    return 0; 
}  
0

Ich wäre immer noch interessiert zu wissen, ob es einen Weg gibt, die Endlosschleife zu umgehen und etwas zu erreichen, was ich ursprünglich tun wollte?

class Solution { 

private: 
     vector<vector<string>*> result; 
     map<string,vector<string>> myMap; 

public: 
    vector<vector<string>*> groupAnagrams(vector<string>& strs) 
    { 
//  vector<vector<string>*> result; 
//  map<string,vector<string>> myMap; 

einfach das Ergebnis machen und die Mitglieder der Klasse zuzuordnen. Sehen Sie sich den Typ an, der in den Vektor der Zeiger des Vektors geändert wurde.

 else 
     { 
      vector<string> newVector; 
      newVector.push_back(s); 
      auto p = myMap.insert(pair<string,vector<string>>(temp,newVector)); 

      //p is pair<iterator, bool> 
      //where iterator is pointing to the inserted element 
      //so p.first->second is the new vector 

      result.push_back(&(p.first->second)); 
     } 

notieren wir hier Adresse des Vektors in der Karte.

for(vector<string>* v: result) 
{ 
    for(string s: *v) 
    { 
     cout << s << " "; 
    } 
    cout << endl; 
} 

den Vektor iteriert und den Zeigertypen unter Berücksichtigung gibt das Ergebnis als:

eat tea ate 
tan nat 
bat 

Dies nimmt die zweite Schleife entfernt und benötigt weniger Platz, sondern macht den Code ein wenig kompliziert.