A. O valor é um int menor do que o tamanho da tabela hash. Portanto, o valor é seu próprio hash, portanto, não há tabela de hash. Mas se houvesse, seria O (1) e ainda seria ineficiente.
Este é um caso em que você poderia mapear trivialmente as chaves para depósitos distintos, portanto, uma matriz parece uma escolha melhor de estrutura de dados do que uma tabela hash. Ainda assim, as ineficiências não aumentam com o tamanho da mesa.
(Você ainda pode usar uma tabela hash porque não confia que os ints permaneçam menores do que o tamanho da tabela à medida que o programa evolui, você deseja tornar o código potencialmente reutilizável quando essa relação não se mantém, ou simplesmente não quer que as pessoas que leiam / mantenham o código tenham que desperdiçar esforço mental para entender e manter o relacionamento).
B. Você deve calcular um hash do valor. Nessa situação, a ordem é O (n) para o tamanho dos dados que estão sendo pesquisados. A pesquisa pode ser O (1) depois que você faz o trabalho O (n), mas ainda assim resulta em O (n) aos meus olhos.
Precisamos distinguir entre o tamanho da chave (por exemplo, em bytes) e o tamanho do número de chaves armazenadas na tabela hash. Afirma que as tabelas de hash fornecem operações O (1) significam que as operações (inserir / apagar / localizar) não tendem a ficar mais lentas conforme o número de chaves aumenta de centenas para milhares para milhões e bilhões (pelo menos não se todos os dados é acessado / atualizado em armazenamento igualmente rápido, seja na RAM ou no disco - os efeitos do cache podem entrar em ação, mas mesmo o custo de uma falha de cache no pior caso tende a ser algum múltiplo constante do acerto no melhor caso).
Considere uma lista telefônica: você pode ter nomes bem longos, mas se o livro tiver 100 nomes, ou 10 milhões, o tamanho médio do nome será bastante consistente, e o pior caso da história ...
O recorde mundial do Guinness para o nome mais longo usado por alguém já foi estabelecido por Adolph Blaine Charles David Conde Frederick Gerald Hubert Irvin John Kenneth Lloyd Martin Nero Oliver Paul Quincy Randolph Sherman Thomas Uncas Victor William Xerxes Yancy Wolfeschlegelsteinhausenbergerdorff, Sênior
... wc
me diz que são 215 caracteres - não é um limite superior rígido para o comprimento da chave, mas não precisamos nos preocupar com a existência de muito mais.
Isso vale para a maioria das tabelas de hash do mundo real: o comprimento médio da chave não tende a aumentar com o número de chaves em uso. Existem exceções, por exemplo, uma rotina de criação de chave pode retornar strings incorporando inteiros incrementais, mas mesmo assim, toda vez que você aumenta o número de chaves em uma ordem de magnitude, você apenas aumenta o comprimento da chave em 1 caractere: não é significativo.
Também é possível criar um hash a partir de uma quantidade de dados-chave de tamanho fixo. Por exemplo, o Visual C ++ da Microsoft vem com uma implementação de biblioteca padrão std::hash<std::string>
que cria um hash incorporando apenas dez bytes uniformemente espaçados ao longo da string, portanto, se as strings variam apenas em outros índices, você obtém colisões (e, portanto, na prática, comportamentos não O (1) no lado da pesquisa pós-colisão), mas o tempo para criar o hash tem um limite superior rígido.
E, a menos que você tenha um hash perfeito ou uma grande tabela de hash, provavelmente há vários itens por balde. Então, ele se transforma em uma pequena busca linear em algum ponto.
Geralmente é verdade, mas a coisa mais incrível sobre as tabelas de hash é que o número de chaves visitadas durante essas "pequenas pesquisas lineares" é - para a abordagem de encadeamento separado para colisões - uma função do fator de carga da tabela de hash (proporção de chaves para baldes).
Por exemplo, com um fator de carga de 1,0, há uma média de ~ 1,58 para o comprimento dessas pesquisas lineares, independentemente do número de chaves (veja minha resposta aqui ). Para hashing fechado é um pouco mais complicado, mas não muito pior quando o fator de carga não é muito alto.
É tecnicamente verdade porque a função hash não é necessária para usar todas as informações na chave e, portanto, pode ser um tempo constante, e porque uma tabela grande o suficiente pode reduzir as colisões a um tempo quase constante.
Isso meio que perde o ponto. Em última análise, qualquer tipo de estrutura de dados associativa tem que fazer operações em todas as partes da chave às vezes (a desigualdade às vezes pode ser determinada a partir de apenas uma parte da chave, mas a igualdade geralmente requer que cada bit seja considerado). No mínimo, ele pode fazer o hash da chave uma vez e armazenar o valor do hash, e se usar uma função de hash forte o suficiente - por exemplo, MD5 de 64 bits - ele pode praticamente ignorar até mesmo a possibilidade de hash de duas chaves para o mesmo valor (uma empresa Trabalhei para fazer exatamente isso para o banco de dados distribuído: o tempo de geração de hash ainda era insignificante em comparação com as transmissões de rede em toda a WAN). Portanto, não há muito sentido ficar obcecado com o custo para processar a chave: isso é inerente ao armazenamento de chaves, independentemente da estrutura de dados e, como dito acima - não
Quanto às tabelas hash grandes o suficiente para reduzir as colisões, isso também está perdendo o ponto. Para encadeamento separado, você ainda tem um comprimento de cadeia de colisão médio constante em qualquer fator de carga - é apenas mais alto quando o fator de carga é mais alto e essa relação não é linear. O usuário do SO, Hans, comenta minha resposta também no link acima :
o comprimento médio do balde condicionado a baldes não vazios é uma medida melhor de eficiência. É a / (1-e ^ {- a}) [onde a é o fator de carga, e é 2,71828 ...]
Portanto, o fator de carga sozinho determina o número médio de chaves em colisão que você deve pesquisar durante as operações de inserir / apagar / localizar. Para encadeamento separado, não se trata apenas de ser constante quando o fator de carga é baixo - é sempre constante. Para endereçamento aberto, embora sua afirmação tenha alguma validade: alguns elementos em colisão são redirecionados para depósitos alternativos e podem, então, interferir nas operações em outras chaves, portanto, em fatores de carga mais altos (especialmente> 0,8 ou 0,9), o comprimento da cadeia de colisão fica mais dramaticamente pior.
É verdade na prática porque, com o tempo, funciona, desde que a função hash e o tamanho da tabela sejam escolhidos para minimizar as colisões, embora isso geralmente signifique não usar uma função hash de tempo constante.
Bem, o tamanho da tabela deve resultar em um fator de carga lógico, dada a escolha de hash próximo ou encadeamento separado, mas também se a função hash for um pouco fraca e as chaves não forem muito aleatórias, ter um número primo de baldes geralmente ajuda a reduzir colisões também ( hash-value % table-size
então envolve de forma que as alterações apenas para um ou dois bits de ordem superior no valor de hash ainda resolvem em intervalos espalhados pseudo-aleatoriamente por diferentes partes da tabela de hash).