Datenstruktur zum Testen aller Teilmengen einer Abfrage auf Mitgliedschaft

7

Gibt es eine Datenstruktur, die die folgenden Vorgänge effizient unterstützt?

  1. Set hinzufügen
  2. Fragen Sie ab, ob eine Teilmenge einer Menge hinzugefügt wurde.

Dies könnte mit linearem Overhead implementiert werden, indem jeder hinzugefügte Satz während jeder Abfrage getestet wird. Kann es effizienter umgesetzt werden? Kleine Wahrscheinlichkeiten für falsch positive / negative Ergebnisse sind akzeptabel (z. B. Bloom-Filter-Stil).

Elliot Gorokhovsky
quelle
Ist es überhaupt möglich, schneller als o (n) zu überprüfen, ob ein Satz hinzugefügt wurde, wobei n die Anzahl der hinzugefügten Sätze ist? Wie?
Albert Hendriks
@alberthendriks Wenn alle Sätze Singleton sind, können Sie es in der Protokollzeit tun, also frage ich mich, ob es in dieser allgemeineren Einstellung effizienter gemacht werden kann
Elliot Gorokhovsky
Lassen Sie uns diese Diskussion im Chat fortsetzen .
Albert Hendriks
1
Können Sie weitere Details zu Ihren Sets angeben? Sind sie ganze Zahlen? Wenn nicht, haben sie zumindest eine schwache Ordnung?
Orlp
1
@ RenéG Sind diese ganzen Zahlen begrenzt oder nicht? Wenn ja, wie hoch ist die Grenze? Unabhängig davon bearbeiten Sie diese Informationen bitte in der Frage.
Orlp

Antworten:

2

Angenommen, alle Ihre Mengen sind endliche Teilmengen von N. LassenSP(N) bezeichnen Ihre Menge von Mengen.

Sie möchten zwei Operationen:

  • O1(S,s): Für jeden sN, hinzufügen s zu S

  • O2(S,s): Für jeden sN, gibt es einige sS damit ss?


Hier sind einige Ideen, um die Dinge zu beschleunigen:

  • Sie werden testen, ob eine Menge eine Teilmenge einer anderen ist, also sollten Sie wahrscheinlich die Größe beibehalten |s| von jedem Satz s verfügbar in O(1) so dass, wenn Sie testen müssen, ob ssSie überprüfen zunächst, ob |s||s|und wenn nicht, können Sie sofort false zurückgeben. Und das hast du tatsächlich|s||s|Dann führen Sie einfach den normalen langsamen Test aus.

  • Beachten Sie, dass, wenn Sie haben s1S und s2S, damit s1s2, dann wenn s2s, Sie haben auch s1s. Sie müssen also nicht behaltens2 im S zum O2. So können Sie darstellenS durch eine Reihe von Mengen, so dass sS und ssbedeutet . Mit anderen Worten, Sie müssen nur die Mengen in verfolgen , die für die Aufnahme minimal sind. Dies kann ziemlich effizient implementiert werden: Beim Hinzufügen einer Menge für alle Mengen so dass(geordnet nach zunehmendem Kardinal), wenn , dann füge nicht hinzu da es nicht minimal ist (oder bereits in ). Andernfalls addiere und dann zwischen den Mengen so dassEntfernen Sie diese so, dass (weil sie nicht mehr minimal sind).sSSssS|s||s|sssSssS|s|<|s|ss

  • Behalten Sie eine Menge , die der Vereinigung aller Mengen in . Dann wird anstelle der laufenden , können Sie laufen statt (weil , wenn für einige , , dann da , und, wenn , dann ).tSO2(S,s)O2(S,st)sSssstsstsstssts

Unter Berücksichtigung dieser Ideen würde ich durch ein Wörterbuch darstellen (implementiert als doppelt verknüpfte Liste von Paaren mit den Schlüsseln in aufsteigender Reihenfolge) so dass eine doppelt verknüpfte Liste ist, die genau das enthält minimale (zur Aufnahme) Mengen in von Kardinal .S(key,value)dd(k)Sk

O1(S,s')
  if O2(S,s')
    return
  if d(k) doesn't exist
    d(k) := new_doubly_linked_list()
  add(d(k),s')
  S.t := union(S.t, s')
  for each key k of d so that |s'|+1 <= k
    for s in d(k)
      if subset(s', s)
        remove s

_O2(S,s')
  for each key k of d so that k <= |s'|
    for s in d(k)
      if subset(s,s')
        return true
  return false

O2(S,s')
  return _O2(S,inter(S.t,s'))

(Beachten Sie, dass Sie, obwohl ich es im Code von nicht explizit O1getan habe, eine einzelne Durchquerung der doppelt verknüpften Liste durchführen können, die darstellt d)

Ich denke nicht, dass sich dies im schlimmsten Fall zu sehr verbessert, aber im Durchschnitt sollte es so sein.

xavierm02
quelle
Diese sehen nach nützlichen praktischen Verbesserungen aus. Aber ich denke, Sie meinen, dass eine verknüpfte Liste von Kartendatenstrukturen sein sollte (die selbst verknüpfte Listen sein könnten, die nach Schlüsseln geordnet sind - obwohl Hashtabellen oder ausgeglichene Bäume viel schneller wären). d
j_random_hacker
3
Auch in Bezug auf Ihren zweiten Vorschlag kann es im schlimmsten Fall immer noch Mengen geben, von denen laut Sperners Theorem keine die andere enthält . Dies tritt auf, wenn das Universum Elemente enthält und Sie alle Mengen von -Größen hinzufügen. (nn2)nn2
j_random_hacker
Schließlich denke ich, dass Sie die "Richtung" der Abfrage falsch herum haben - ich nehme die Frage des OP, um zu fragen, ob noch eine Teilmenge hinzugefügt wurde, die den Abfragesatz enthält. Dies kann natürlich leicht behoben werden (nach dem DeMorgan-Gesetz können Sie Ihre Implementierung sogar einfach mit Funktionen "umschließen", die alle Eingabesätze "invertieren" (dh den symmetrischen Unterschied zum Universum nehmen) und auch den Rückgabewert der Abfrage invertieren ).
j_random_hacker
In Ihrem zweiten Aufzählungszeichen sollte s eine strikte Teilmenge sein, um eine Nichtmitgliedschaft zu implizieren. Wie auch immer, ich denke, diese Antwort ist wahrscheinlich die bestmögliche, also werde ich sie akzeptieren.
Elliot Gorokhovsky
@j_random_hacker Richtig, aber Sie benötigen nur einen Satz (dh eine Karte zur Einheit). Wenn ich mit die lexikografische Reihenfolge für Mengen bezeichne, die gegeben sind, indem ich sie als Funktionen vom Universum bis , könnte die Karte unter Verwendung dieser Reihenfolge und ausgeglichener Bäume implementiert werden. Oder stellen Sie es alternativ als binäres Entscheidungsdiagramm dar und fügen Sie den einem Schlüssel zugeordneten Wert in das entsprechende Blatt ein. lex{0,1}
Xavierm02