Essa pergunta e essa pergunta me fizeram pensar um pouco. Para classificar uma matriz de comprimento com elementos únicos em , precisamos ser capazes de armazenar contagens de valores na matriz. Existem algumas sugestões, mas estou procurando uma maneira de fazer isso no pior dos casos, no tempo linear. Mais especificamente:
Dada uma lista dos elementos com elementos distintos, determinar uma lista de tuplos de todos os elementos exclusivos, tal que é a contagem de elemento em .
Aqui estão algumas idéias (com falha) que tive e foram sugeridas:
- Árvore de Pesquisa Binária Balanceada - Com isso, será necessário para inserir na árvore e aumentar os valores. Após as inserções, poderíamos fazer uma travessia de árvore em . Assim, o tempo total sai para que é muito lento.
- Hash Map - Com isso, podemos obter inserções esperadas e, portanto, tempo esperado . No entanto, este ainda não é pior caso.
- Espaço vazio Mapeamento - Encontrar o elemento mínimo e máximo em . Aloque (mas não inicialize) memória suficiente para cobrir esse intervalo. Use essa memória basicamente como um mapa de hash e inclua um hash aleatório para que não tentemos acessar a memória corrompida. Essa estratégia apresenta problemas. (1) É probabilístico com muito, muito, muito baixa probabilidade de falhar, mas ainda não é garantido. Usar memória como essa nos limita a restrições de ponto flutuante ou inteiro.
- Matrizes associativas - Existem muitas outras matrizes associativas que podem ser usadas, semelhantes aos mapas de hash e BSTs, mas não estou encontrando nenhuma que corresponda a essas restrições.
Talvez esteja faltando algum método óbvio, mas também acho que poderia não ser possível. Quais são seus pensamentos?
Respostas:
Esta é uma boa pergunta.
No modelo de comparação ou, o que é mais geral, no modelo algébrico de árvore de decisão, o problema da distinção de elementos tem um limite inferior deΘ ( n logn ) complexidade do tempo, na pior das hipóteses, como dito neste artigo da Wikipedia . Portanto, não há algoritmo para contar elementos distintos em tempo linear no pior dos casos, mesmo sem contar as duplicidades.
No entanto, não está claro se isso pode ser feito em outro modelo computacional. Parece improvável em qualquer modelo computacional determinístico razoável.
fonte
Existem algoritmos aleatórios cujo tempo de execução esperado éO ( n ) ; ou onde a probabilidade de o tempo de execução demorar mais do quec n é exponencialmente pequeno em c .
Em particular, escolha aleatoriamente uma função de hash 2-universal e use-a para misturar todos os elementos da matriz. Isso atinge os tempos de execução indicados, se você escolher o comprimento da saída do hash 2-universal adequadamente.
Como outro exemplo, você pode criar um algoritmo aleatório cujo pior tempo de execução éO ( n ) (sempre é executado em tempo linear, não importa o quê) e tem uma probabilidade de erro de no máximo 1 /2100 . (Como? Execute o algoritmo acima e encerre-o se executar mais do quec n passos para alguns escolhidos adequadamente c .) Na prática, isso é bom o suficiente, pois a probabilidade de o seu computador dar a resposta errada devido a um raio cósmico já é muito maior do que 1 /2100 .
fonte
Sua abordagem 3 pode ser protegida usando uma solução para o exercício 2.12 de Aho, Hopcroft e Ullman (1974) The Design and Analysis of Computer Algorithms, como descrito, por exemplo, em Usando memória não inicializada para diversão e lucro .
Basicamente, além da sua matriz de N elementos com as contagens, você tem duas matrizes de N elementos e uma contagem auxiliar para criar um conjunto esparso indicando quais das contagens são válidas.
No pseudocódigo do tipo C:
A implementação prática do conjunto esparso é discutida nesta resposta do StackOverflow .
fonte
c
pode ser indexado emx
ouidx
, mas eu useiidx
para uma melhor localidade do cache.{a,b,c,len}
estruturas para, emc
vez de uma matriz de contagens. Por exemplo, se você usar o radix 512 para que cada uma das matrizes caiba em uma página (com ponteiros de 8 bytes), poderá ir até