Ich habe ein Raster aus Kacheln bekannter endlicher Größe, die eine Karte bilden. Einige der Kacheln auf der Karte werden in ein Gebiet gelegt. Dieses Gebiet ist verbunden, aber über seine Form ist nichts bekannt. Meistens war es ein ziemlich regelmäßiger Fleck, aber er konnte in eine Richtung sehr lang sein und möglicherweise sogar Löcher haben. Ich bin daran interessiert, die (äußere) Grenze des Territoriums zu finden.
Das heißt, ich möchte eine Liste aller Kacheln, die eine der Kacheln im Gebiet berühren, ohne sich selbst im Gebiet zu befinden. Was ist ein effizienter Weg, dies zu finden?
Für zusätzliche Schwierigkeiten kommt es vor, dass meine Kacheln hexadezimal sind, aber ich vermute, dass dies keinen allzu großen Unterschied macht. Jede Kachel ist immer noch mit einer ganzzahligen x- und y-Koordinate beschriftet, und bei einer gegebenen Kachel kann ich leicht ihre Nachbarn finden. Nachfolgend einige Beispiele: Das Schwarze ist das Territorium und das Blaue die Grenze, die ich finden möchte. Dies ist an sich kein schwieriges Problem. Ein einfacher Algorithmus hierfür ist in Pseudopython:
def find_border_of_territory(territory):
border = []
for tile in territory:
for neighbor in tile.neighbors():
if neighbor not in territory and neighbor not in border:
border.add(neighbor)
Dies ist jedoch langsam und ich hätte gerne etwas Besseres. Ich habe eine O (n) -Schleife über das Territorium, eine andere Schleife (eine kurze, aber immer noch) über alle Nachbarn, und dann muss ich die Mitgliedschaft über zwei Listen überprüfen, von denen eine die Größe n hat. Das ergibt eine schreckliche Skalierung von O (n ^ 2). Ich kann das auf O (n) reduzieren, indem ich Sets anstelle von Listen für Grenze und Territorium verwende, damit die Mitgliedschaft schnell überprüft werden kann, aber es ist immer noch nicht großartig. Ich gehe davon aus, dass es viele Fälle geben wird, in denen das Territorium groß ist, die Grenze jedoch aufgrund einer einfachen Skalierung zwischen Fläche und Linie klein. Wenn das Territorium beispielsweise ein Feld mit dem Radius 5 ist, hat es die Größe 91, der Rand jedoch nur die Größe 36.
Kann jemand etwas Besseres vorschlagen?
Bearbeiten:
Um einige der folgenden Fragen zu beantworten. Das Territorium kann eine Größe von etwa 20 bis 100 haben. Die Menge der Kacheln, die das Territorium bilden, ist ein Attribut eines Objekts, und für dieses Objekt ist eine Menge aller Randkacheln erforderlich.
Zunächst wird das Territorium als Block erstellt und erhält dann meist nacheinander Kacheln. In diesem Fall ist es wahr, dass der schnellste Weg darin besteht, nur einen Rahmen zu behalten und ihn nur auf dem gewonnenen Plättchen zu aktualisieren. Gelegentlich kann es zu einer großen Änderung des Gebiets kommen. Daher muss es dann vollständig neu berechnet werden.
Ich bin jetzt der Meinung, dass ein einfacher Grenzfindungsalgorithmus die beste Lösung ist. Die einzige zusätzliche Komplexität, die dadurch entsteht, besteht darin, sicherzustellen, dass die Grenze jedes Mal neu berechnet wird, wenn dies erforderlich ist, jedoch nicht mehr. Ich bin ziemlich zuversichtlich, dass dies in meinem aktuellen Framework zuverlässig möglich ist.
Was das Timing angeht, habe ich in meinem aktuellen Code einige Routinen, die jede Kachel des Gebiets überprüfen müssen. Nicht jede Runde, aber bei der Erstellung und gelegentlich danach. Das nimmt über 50% der Laufzeit meines Testcodes ein, obwohl es nur ein sehr kleiner Teil des gesamten Programms ist. Ich war daher bestrebt, alle Wiederholungen zu minimieren. JEDOCH beinhaltet der Testcode (natürlich) viel mehr Objekterstellung als ein normaler Programmablauf, daher ist mir klar, dass dies möglicherweise nicht sehr relevant ist.