2016-05-18 142 views
1

我試圖實現深度優先搜索作爲一個函數,它接受一個圖形並輸出DFS。如何在不違反封裝的情況下合法訪問和修改私有字段矢量和地圖?

class Graph 
{ 
private: 
    int V; 
    int timestamp; 
    std:: vector<std:: list<int> > graph; 
    std:: map<int, vertex> nodemap; 
public: 
    Graph(int V); 
    int Size(); 

    void addEdge(int u, int v); 
    void printEdges(); 
    void printVertices(); 
}; 

以上是我爲圖形所做的類。我正在嘗試創建一個函數,該函數返回指向專用矢量和地圖的指針,以便我可以執行的循環對圖的鄰接列表和Map數據結構的操作。但是,我知道直接操作數據結構是對封裝的違反,我想維護我的程序的面向對象的規範。如何在不違反封裝的情況下這樣做?

PS:我不期待使用朋友函數,因爲我不想讓該函數成爲例外。我想找到一個由程序員普遍使用的主流解決方案,並且是一個有紀律的解決方案。如果需要,我可以更改我的Class字段/可訪問性。

謝謝你的時間!

+0

你能有一個'public'函數返回'map'和'vector'的副本?假設調用者不需要修改元素,那麼這樣做不應該有問題。 – Tas

+0

您可以將(const)迭代器返回到每個序列的begin()和end(),這將允許迭代,但不允許插入或刪除。不幸的是,它不提供'std :: map'的查找。 –

+0

調用者確實需要修改元素。 –

回答

0

如果您需要遍歷鄰接圖的迭代器,那麼您添加了一個允許您這樣做的成員函數。

你有兩個明顯的選擇:

  1. 定義自己的AdjacencyMapIterator類,並提供begin()/end()返回那些實例。
  2. 提供一個函數來獲取一個函數,其中函子在鄰接圖中的每個條目上被調用。

首先應該是這樣的:

for(auto it = graph.adjacency_begin() ; it!=graph.adjacency_end(); ++it) { 
    vertex& v1 = it->v1; 
    vertex& v2 = it->v2; 
    ... 
} 

第二個看起來像

graph.for_each_adjacency(
    [](vertex& v1, vertex &v2) { .... } 
); 

最大的問題是要找出如何迭代期間處理更改您的圖形結構。我所見過的大多數實現都明確地禁止了這個(通過拋出一個異常,或者說明這樣做是未定義的行爲),或者在內部副本上操作迭代。如果你需要不同的東西 - 期待它將來成爲一個痛點。

如果你想要做一個循環的一些更新,其中內環路更新

是不允許的,只是循環存儲需要更新某個地方,然後循環完成後應用所有的更新:

std::vector<UpdateInfo> updates; 
graph.for_each_adjacency([&updates](const vertex& v1, const vertex& v2) { 
    updates.push_back(calculateUpdate(v1,v2)); 
}); 

foreach(updates, [&graph](const UdpateInfo &update) { 
    applyUpdate(update, graph); 
}); 
1

你應該決定你是否是「面向對象」的。如果沒有,那麼你剛剛有一個結構(又名錄音),所以讓你的領域公開和派對。但是如果你是O-O,那麼有幾條路要走。您可以提供Graph上的訪問器,例如,給定頂點的訪問器返回邊(或相鄰頂點)。然後你在圖形外部編寫遍歷算法。或者,您提供您的遍歷算法作爲Graph的方法,並且可以直接訪問私有成員。

+0

是的,這就是我正在做的事情(你提供你的遍歷算法作爲Graph的一種方法,它可以直接訪問私有成員),但是我有一種令人沮喪的感覺,那是不正確的。只是問是否有什麼法律上的錯誤?無論如何,它是否違反了OOP? –

+0

@DanishAmjadAlvi不,它絕對是O-O。很多時候,你會在班級內部找到算法,特別是在需要緊密耦合的地方。在某些情況下,儘管將它們分開是有好處的。例如,假設你想編碼幾種算法 - 遍歷,最大連接等。然後_假設你想要不同的_representations_ - 例如,你現在有鄰接表,關聯矩陣或其他東西。您可能更喜歡將算法分開。 – davidbak

相關問題