簡體   English   中英

如何在C ++中跟蹤訪問點

[英]How to keep track of visited points in C++

我在c ++中遇到問題,必須跟蹤遍歷中訪問的點。 重點是

struct Point {
  int x;
  int y;
};

我首先想解決類似問題的方法是使用類似

std::set<Point> visited_points;

或者可能

std::map<Point, bool> visited_points;

但是,我是C ++的初學者,我意識到您必須實現一個Compare,但我不知道該怎么做。 當我問時,有人告訴我說在這樣的問題中使用地圖是“過分殺傷”的。 他說更好的解決方案是做類似的事情

std::vector<std::vector<bool>> visited_points;

他說std::map並不是最好的解決方案,因為使用向量更快。

我想知道為什么使用雙精度矢量在樣式和性能方面更好。 是因為很難實現比較功能? 雙重向量對我來說很討厭,我也認為它比使用集合或地圖更難看。 確實是解決此問題的最佳方法,還是有我不知道的更好的解決方案?

如果有人抽象地問您“跟蹤我訪問過的對象的最佳方法是什么?”,那么您會得到答復“使用std::unordered_set<Object> ”(通常稱為哈希表)是可以原諒的適用於C ++以外的語言)。 這是一個很好的簡單答案,如果您根本不了解對象,這通常是正確的。 畢竟,哈希查找是(預期的)O(1),實際上通常是相當快的。

有一些警告,最大的警告是您將需要能夠為每個對象計算哈希值。 C ++標准庫尚未(尚未提供)用於計算任意對象甚至POD的哈希值並將對象呈現為字符串以便能夠利用std::hash<std::basic_string>的框架。通常是太多的工作(當然,除非對象已經是字符串)。

如果您不知道如何為對象編寫哈希函數,則可以考慮使用有序關聯容器(又稱平衡BST)。 但是,這不是一個好主意。 不是因為很難編寫比較函數。 編寫比較功能通常很簡單,尤其是對於POD。 您可以利用以下事實: std::tuple為元素類型都可比較的每個元std::tuple實現比較功能。

有序關聯容器的真正問題在於它們的開銷很高。 元素訪問很慢:O(log n),而不是O(1),並且常數也不小。 而且,維護平衡樹所需的簿記數據遠大於兩指針哈希表節點(對於小對象來說,甚至是相當大的)。 因此,有序的關聯容器僅在您需要能夠按順序遍歷它們時才有意義。 通常,“訪問過”的地圖根本不需要遍歷-它們僅用於查找。

有序和無序容器都有另一個問題:容器中的對象是單獨的動態內存分配(API要求對容器中對象的引用必須是穩定的),因此隨着時間的流逝,各個對象最終會分散在動態內存中,導致很多緩存未命中。

但是,實際上,即使在開始考慮對對象進行哈希處理以使其保持在哈希集中的難度(或難度)之前,您仍應考慮所跟蹤對象的性質。 特別是,是否可以使用小(-ish)整數輕松索引它們? 如果是這樣,您可以只使用一個位向量,每個可能的對象一個位。 對於訪問速度(絕對為O(1))和空間而言,這都是一種有效的表示方式,並且它對於內存緩存是最佳的。

如果您的對象易於編號,則位向量將是一個有吸引力的選擇。 每個對象一個位(從字面上看)比散列圖少兩個數量級的空間,因此,除非您希望訪問的圖非常稀疏(在需要訪問圖的算法中很少見),否則它將很大贏得。

對於您遇到的問題,我收集的信息與跟蹤矩形陣列(例如游戲板或圖像)中訪問的點有關,很明顯,位向量方法可以很好地解決問題。 確實,您需要兩個級別的索引編制(除非您將兩個索引縮減為一個整數,如果您知道維數就很容易了),但這並不會增加太多開銷。

盡管人們對它的主意有疑問,但C ++標准庫將std::vector<bool>特例實際用作向量。 這樣就不可能創建指向向量單個元素的本機指針(這就是為什么許多人認為std::vector<bool>是一種hack),並且在嘗試將其用作std::vector<bool>會產生一些其他奇怪的問題。向量。 但是,如果您想要的只是一個位掩碼(如訪問過的地圖),那么這是一個很好的解決方案。

C ++還提供了真正的位向量-std :: bitset-但不幸的是,這些需要在編譯時知道其大小。 Boost提供了dynamic_bitset ,這是一種事后看來的std::vector<bool> ,因此也值得一看。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM