Vai uma busca binária aí?

Esses dias eu estava pensando comigo mesmo: "a gente vê várias idéias boas e, por não usar na hora em que vimos, acabamos esquecendo...". Alguém aí lembrou de algoritmos? É, caso típico. =)

Semana passada eu estava vendo um algoritmo em C++ de busca binária. Deixando o C++ um pouco de lado parei para pensar onde eu já havia aplicado esse algoritmo. Qual não foi a minha surpresa em lembrar de um lugar onde faria sentido e eu deixei de usar o algoritmo. A situação? Marcar uma cidade qualquer numa listagem (combo) HTML.

Permita-me ilustrar melhor o cenário. Imagine uma listagem beeeem grande de cidades (nota: arquivo pesado). Como toda boa lista de cidades, ela está ordenada alfabeticamente. Agora, por algum dado motivo, você gostaria de selecionar uma cidade qualquer X dessa listagem. Nota: a lista tem algumas cidades falsas apenas para aumentar o volume de dados.

Intuitivamente você faria um for percorrendo as opções da listagem e marcando a cidade desejada. Em termos de código isso seria:

var maximo = combo.options.length - 1;
for( var i = 0; i < maximo; i++ )
{
  if( combo.options[i].text == cidade )
  {
    combo.selectedIndex = i;
    return;
  }
}

O código acima funciona, só não funciona bem para a nossa listagem tamanho família. Se eu pedir para marcar uma cidade próxima do final da lista, por exemplo Salto, a busca vai demorar pois o for vai percorrer a lista desde a letra A até chegar no S, aí marcando a cidade desejada.

Se explorarmos um pouco mais nossa intuição veremos que podemos usar algo semelhante ao que fazemos pra pesquisar numa lista telefônica. Abro a lista num ponto e verifico se o nome que eu quero está antes ou depois da página que estou vendo. Por exemplo, estou procurando Vitória. Se eu abri na página com nomes próximos de Teobaldo, vou procurar mais pra frente da lista, não adianta eu olhar pra trás. Essa é a vantagem da ordem alfabética, afinal. =)

Em termos de algoritmos podemos usar uma busca binária para expressar esse comportamento. Ou ainda, falando em código:

var esquerda = 0;
var direita = combo.options.length - 1;
var meio;
while( esquerda <= direita )
{
  meio = esquerda + Math.floor( ( direita - esquerda ) / 2 );
  // Javascript consegue comparar strings usando < e >. Ahá! :D 
  if( combo.options[meio].text < cidade )
  {
    esquerda = meio + 1;
  }
  else if( combo.options[meio].text > cidade )
  {
    direita = meio - 1;
  }
  else
  {
    // é o cara, pode marcar e encerrar a função
    combo.selectedIndex = meio;
    return;
  }
}

Caso ainda não tenha ficado claro pra você, a busca binária funciona bem melhor para este cenário. Ao invés de percorrer a listagem item a item (linearmente), vamos tomar vantagem da organização alfabética e fazer uma pesquisa mais inteligente. =)

Fiz um arquivo de testes que permite, obviamente, testar as duas implementações (nota: arquivo pesado - cuidado com o pé =). Usei a jQuery somente fora dos algoritmos em questão, pra facilitar a manipulação dos eventos.

Como dá pra notar pelo arquivo de testes, a busca binária funciona melhor para a esmagadora maioria dos casos. O que é de se esperar dada a complexidade O(log n) da busca binária ante a complexidade O(n) da busca linear.

E fica o lembrete, até pra mim mesmo, que tal pesquisar um algoritmo mais eficiente da próxima antes de sair implementando qualquer coisa? :D

comentários (2)

Qual o botão do mouse gerou esse clique?

São vários os motivos em que pode ser interessante descobrir qual o botão do mouse seu visitante usou para clicar em um elemento. E como muitos já sabem, eventos sofrem bastante com a falta de padronização entre os navegadores. Mas com as popularização das bibliotecas de Javascript, por exemplo jQuery, essa é uma tarefa relativamente fácil.

Seguindo as dicas encontradas no site do PPK, QuirksMode, podemos ver como identificar qual o botão usado pelo visitante. Traduzindo isso em código teríamos algo assim: (com jQuery disponível na página):

var left_button = 0;
var middle_button = 1;
var right_button = 2;
if( $.browser.msie )
{
  left_button = 1;
  middle_button = 4;
  right_button = 2;
}
$( "#container" ).mouseup(
  function( e )
  {
    var botao = "";
    if( e.button == middle_button )
    {
      botao = "meio (rodinha)";
    }
    else if( e.button == right_button )
    {
      botao = "direito (contexto)";
    }
    else
    {
      botao = "esquerdo (principal)";
    }
    alert ( "botão: " + botao );
  }
);

Um fator importante é que se você usar o evento click, a informação sobre o botão usado poderá não estar disponível e o código provavelmente não irá funcionar. Por isso é importante usar eventos como mousedown, mouseup. Aproveitei e fiz uma contribuição com a documentação da jQuery sobre eventos adicionando uma nota sobre o fato acima. =)

Se quiser ver o exemplo acima em uma página funcional, acesse este exemplo.

Nota: Ainda não tive tempo de testar o código em diversos navegadores, farei isso assim que possível. Testei no Firefox 3, no Firefox 2, IEs 7 e 6, e Safari 3, todos funcionam. Só no Opera 9.5 que o único botão "capturável" parece ser o botão esquerdo.

comentários (1)

Último dia da oficina de Javascript e Ajax

A oficina de Ajax que começou no dia 1 deste mês acabou hoje, dia 17. Nestes vários dias de curso/oficina deu pra abordar vários temas, desde os fundamentais para o bom entendimento da linguagem até o uso prático e produtivo do Javascript.

Durante esse período mostrei desde a sintaxe base da linguagem, passando por manipulação de CSS e DOM, eventos e listeners, até chegar no tão falado Ajax. E no último dia ainda deu tempo de apresentar a ótima biblioteca jQuery sob o tópico produtividade.

Ah, tirei uma foto com o pessoal que participou da oficina:

Na foto estão os alunos da oficina e eu, quase no centro, de camisa azul.

Espero que todos possam ter aprendido pelo menos algo de novo e interessante. Aproveito para agradecer a presença de todos, que se esforçaram pra acordar cedo mesmo durante as férias letivas. Bom, agora deixa eu mostrar a foto para minha mãe... =)

Gostei de ministrar essas oficinas, e já estou até pensando qual pode ser o tema da oficina de verão, no final do ano? LAMP? Ruby on Rails? Só o tempo dirá... :D

comentários (4)

Javascript é com jQuery

Se você programa ou já programou em Javascript sabe que, entre as maiores dores de cabeça na hora de codificar temos: a incompatibilidade entre navegadores distintos ou mesmo um comportamento inesperado naquele navegador de ícone azul. =)

Já há algum tempo que eu tenho feito vários códigos usando uma biblioteca leve e poderosa chamada jQuery. Ela é uma ferramenta muito versátil, que vai te ajudar a se concentrar mais no que realmente importa: a lógica para implementar a solução.

E como essa jQuery, basicamente, funciona?

Um dos grandes trunfos, e talvez o principal, é o modo com que você consegue acessar os elementos da sua página. Usando seletores CSS e/ou seleção por XPath você consegue alcançar quaisquer combinações de elementos, ou elementos isolados, em sua página.

Feita a seleção dos elementos, a jQuery vai, digamos, encapsular cada um dos elementos e te dar um leque grande, realmente grande, de métodos diversos extremamente úteis.

Como os métodos estão todos concentrados na jQuery e já possuem os devidos tratamentos para um suporte amplo cross-browser, sua única preocupação será implementar a lógica do código. Muito bom!

Selecionando

OK, até agora muita teoria e entusiasmo mas nenhum código. Que tal uns exemplos? :D

Primeiramente, vamos selecionar todos os elementos "p" de nossa página. Não vamos fazer nada com eles, ainda:

$( "p" );

Só isso! Agora imagine que você gostaria de esconder todos esses elementos "p" que selecionamos. Nosso código ficaria:

$( "p" ).hide();

Fácil, não? Porém, suponha que esconder todos os "p"'s não é o que queremos realmente, seria bom esconder apenas os "p"'s de uma "div#menu". Veja:

$( "p", "div#menu" ).hide();

Adicionando e modificando conteúdo na página

Modificar o conteúdo de um elemento já é, de certa forma, fácil se você usar o innerHTML comum. Mas, como você já deve imaginar, com jQuery é muito mais:

$( "p#exemplo" ).html( "<strong>Novo</strong> conteúdo!" );

O pequeno código acima vai acessar um "p#exemplo" e alterar seu markup interno por aquele outro, passado como parâmetro à função. Se você quiser apenas saber qual o markup atual do elemento:

$( "p#exemplo" ).html();

E que tal adicionar um novo elemento após nosso "p" de exemplo? Veja:

$( "p#exemplo" ).after( "<p>Um elemento depois!</p>" );

Ou seja, usando o método intuitivo after conseguimos adicionar elementos após o nosso elemento original. Se você está pensando que podemos inserir elementos antes usando o método análogo before:

$( "p#exemplo" ).before( "<p>Um elemento antes!</p>" );

Acertou! Simples e intuitivo, não? =)

E o que mais?

Acesse a página com uma visão geral dos métodos e veja quantas outras coisas o jQuery ainda pode fazer por você. AJAX, animações, tratamento de eventos, só pra citar algumas delas.

Além disso, a jQuery possui uma boa documentação e uma comunidade ativa, que pode interagir diretamente com a biblioteca através de plugins. Ah sim, você pode adicionar novos comportamentos com plugins. =)

Referências
jQuery
15 dias de jQuery - Uma visão geral sobre o poder da jQuery
Seletores CSS
Seleção por XPath
Métodos diversos da jQuery
Documentação da jQuery

comentários

« Textos anteriores Textos mais recentes »