Estrutura de dados para testar todos os subconjuntos de uma consulta para associação

7

Existe uma estrutura de dados que ofereça suporte eficiente às seguintes operações?

  1. Adicionar conjunto
  2. Pergunte se algum subconjunto de um conjunto foi adicionado.

Isso pode ser implementado com sobrecarga linear, testando todos os conjuntos adicionados durante cada consulta. Pode ser implementado com mais eficiência? Pequenas probabilidades de falsos positivos / negativos são aceitáveis ​​(por exemplo, estilo de filtro Bloom).

Elliot Gorokhovsky
fonte
É possível verificar mais rapidamente que o (n) se algum conjunto foi adicionado, onde n é o número de conjuntos adicionados? Quão?
Albert Hendriks
@alberthendriks Se todos os conjuntos são singleton você pode fazê-lo em tempo de log, então eu estou querendo saber se isso pode ser feito de forma mais eficiente neste cenário mais geral
Elliot Gorokhovsky
Vamos continuar esta discussão no chat .
Albert Hendriks
11
Você pode dar mais detalhes sobre seus sets? Eles são conjuntos de números inteiros? Se não, eles têm pelo menos uma ordem fraca?
orlp
11
@ RenéG Estes números inteiros são limitados ou não? Se sim, qual é o limite? Independentemente disso, edite essas informações na pergunta.
orlp

Respostas:

2

Digamos que todos os seus conjuntos sejam subconjuntos finitos de N. DeixeiSP(N) denotar seu conjunto de conjuntos.

Você quer duas operações:

  • O1(S,s): Para qualquer sN, adicionar s para S

  • O2(S,s): Para qualquer sN, existe algum sS de modo a ss?


Aqui estão algumas idéias para acelerar as coisas:

  • Você vai testar se um conjunto se um subconjunto de outro muito, então você provavelmente deve manter o tamanho |s| de cada conjunto s disponível em O(1) para que quando você precisar testar se ss, você começa verificando se |s||s|e se não, você pode retornar falso imediatamente. E você realmente tem|s||s|, basta executar o teste lento normal.

  • Observe que se você tiver s1S e s2S, de modo a s1s2, então se s2s, você também tem s1s. Então você não precisa manters2 no S para O2. Então você pode representarS por um conjunto de conjuntos para que sS e ss implica sS. Em outras palavras, você só precisa acompanhar os conjuntos emSque são mínimos para inclusão. Isso pode ser implementado com bastante eficiência: Ao adicionar um conjuntos, para todos os conjuntos sS de modo a |s||s| (ordenado pelo aumento do cardeal), se ss, então não adicione s porque não será mínimo (ou já está em S) Caso contrário, adiciones e depois entre conjuntos sS de modo a |s|<|s|, remova-os para que ss (porque eles não são mais mínimos).

  • Mantenha um conjunto t isso é igual à união de todos os conjuntos S. Então, ao invés de correrO2(S,s), você pode correr O2(S,st) em vez disso (porque se por algum sS, ssentão desde st, sst e se sst, então ssts)

Com essas idéias em mente, eu representaria S por um dictionnary (implementado como uma lista duplamente ligada de pares (key,value) com as teclas em ordem crescente) d de modo a d(k) é uma lista duplamente vinculada que contém exatamente o mínimo (para inclusão) de conjuntos S do cardeal k.

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'))

(Observe que, embora eu não tenha feito isso explicitamente no código de O1, você pode fazer uma única travessia da lista duplamente vinculada que representa d)

Não acho que isso melhore muito no pior dos casos, mas, em média, deveria.

xavierm02
fonte
Parecem melhorias práticas úteis. Mas acho que você quer dizer issoddeve ser uma lista vinculada de estruturas de dados de mapas (que podem ser listas vinculadas ordenadas por chave - embora hashtables ou árvores balanceadas sejam muito mais rápidas).
Jrandom_hacker
3
Também em relação à sua segunda sugestão, no pior dos casos, ainda pode haver (nn2)conjuntos, nenhum dos quais inclui o outro, de acordo com o Teorema de Sperner . Isso ocorre quando o universo temn elementos e você adiciona tudo n2conjuntos -tamanho deles.
Jrandom_hacker 5/05
Finalmente, acho que você tem a "direção" da consulta da maneira errada - tomo a pergunta do OP para perguntar se ainda foi adicionado algum subconjunto que contenha o conjunto de consultas. Obviamente, isso pode ser remediado facilmente (pela lei de DeMorgan, você pode até "envolver" sua implementação com funções que "invertem" todos os conjuntos de entradas (por exemplo, levam a diferença simétrica com o universo) e também invertem o valor de retorno da consulta )
Jrandom_hacker 5/05
No seu segundo marcador, s deve ser um subconjunto estrito para implicar a não associação. Enfim, acho que essa resposta é provavelmente a melhor possível, então vou aceitá-la.
Elliot Gorokhovsky
@j_random_hacker Certo, mas você só precisa de um conjunto (por exemplo, um mapa para a unidade). Se eu denotar porlex a ordem lexicográfica nos conjuntos dados por vê-los como funções do universo para {0,1}, o mapa pode ser implementado usando essa ordem e árvores balanceadas. Ou, como alternativa, represente-o como um diagrama de decisão binário e coloque o valor associado a uma chave na folha correspondente.
Xavierm02 9/17