Arquivo da tag: vetores

Ordenação por Seleção

ATENÇÃO: Este conteúdo foi publicado há 12 anos. Eu talvez nem concorde mais com ele. Se é um post sobre tecnologia, talvez não faça mais sentido. Mantenho neste blog o que escrevo desde os 14 anos por motivos históricos. Leia levando isso em conta.

Hoje vou apresentar mais um algoritmo de ordenação de vetores. É a Ordenação por Seleção (ou Selection Sort). Sem mais papo e antes mesmo da explicação, vamos ao seu pseudocódigo:

1. para i \leftarrow{} 1 até tamanho-1, faça
2.  minimo \leftarrow{} i
3.  para j \leftarrow{} i+1 até tamanho, faça
4.      se vetor[j] < vetor[minimo], então
5.          minimo \leftarrow{} j
6.      fim-se
7.  fim-para
8.  temp \leftarrow{} vetor[i]
9.  vetor[i] \leftarrow{} vetor[minimo]
10. vetor[minimo] \leftarrow{} temp
11. fim-para

tamanho = comprimento do vetor

Funcionamento

A idéia é sempre procurar o menor elemento do vetor e inseri-lo no início do vetor. Procuramos o menor valor do vetor e colocamos ele em vetor[1]. Procuramos o menor valor do vetor excluindo o já colocado e colocamos ele em vetor[2]. E assim vamos indo até termos todo o vetor ordenado.

Partindo sempre a partir do último elemento reordenado (a partir do i), o programa procura o menor elemento no vetor e o substitue pelo elemento i atual.

Exemplo de Funcionamento

O programa recebe o seguinte vetor.

v[1] v[2] v[3] v[4] v[5] v[6]
5 3 7 8 2 5

Aí ele começa com i=1. Vou sempre marcar i com a cor preta e min com a cor cinza.

v[1] v[2] v[3] v[4] v[5] v[6]
5 3 7 8 2 5

Ele marca o próprio índice i como a variável minimo, que é sempre o menor elemento do vetor. Então, ele faz um para de j=2 até o comprimento do vetor, com o objetivo de descobrir qual o menor elemento.

j=2v[j] = 3 < v[minimo] = v[1] = 5[/latex], portanto [latex]minimo = j = 2[/latex].  <table> <thead> <tr> <td>v[1]</td> <td>v[2]</td> <td>v[3]</td> <td>v[4]</td> <td>v[5]</td> <td>v[6]</td> </tr> </thead> <tr> <td class="preto">5</td> <td class="cinza">3</td> <td>7</td> <td>8</td> <td>2</td> <td>5</td> </tr> </table>  [latex]j=3 ... v[j] = 7 > v[minimo] = v[2] = 3, portanto não mexemos em nada.

j=4 ... v[j] = 8 > v[minimo] = v[2] = 3, portanto não mexemos em nada.

j=5 ... v[j] = 2 < v[minimo] = v[2] = 3[/latex], portanto [latex]minimo = j = 5[/latex].  <table> <thead> <tr> <td>v[1]</td> <td>v[2]</td> <td>v[3]</td> <td>v[4]</td> <td>v[5]</td> <td>v[6]</td> </tr> </thead> <tr> <td class="preto">5</td> <td>3</td> <td>7</td> <td>8</td> <td class="cinza">2</td> <td>5</td> </tr> </table>  [latex]j=6 ... v[j] = 5 > v[minimo] = v[5] = 2, portanto não mexemos em nada.

Agora substituímos o v[minimo] pelo v[i], formando com isto o novo vetor:

v[1] v[2] v[3] v[4] v[5] v[6]
2 3 7 8 5 5

E assim vamos fazendo com os outros elementos até que todo o vetor esteja ordenado.

Custo

Este algoritmo não tem um melhor/pior caso, porque todos os elementos são varridos, sempre. Medir seu custo é simples. Custo de linha por linha...

n = tamanho do vetor

  1. n
  2. n-1
  3. \sum_{j=1}^{n} + n
  4. \sum_{j=1}^{n}
  5. \sum_{j=1}^{n} ???
  6. 0
  7. 0
  8. n-1
  9. n-1
  10. n-1
  11. 0

Você pode estar se perguntando porque eu coloquei este custo para a linha 5. Afinal, a linha 5 diria que este programa tem um melhor/pior caso, porque ela não seria executada se o se retornar falso. Mas o caso é que ela é desprezível. Uma soma como estas para o custo geral do nosso algoritmo não vai influenciar em nada. Quer ver? Vamos somar os custos com esta linha valendo 0 (como se nenhum se entrasse) e depois com ela valendo \sum_{j=1}^{n}.

Primeiro cálculo

T(n) = (n) + (n-1) + (\sum_{j=1}^{n} + n) + (\sum_{j=1}^{n}) + (0) + (0) + (0) + (n-1) + (n-1) + (n-1) + (0)

T(n) = n^{2} + 6n -3 \Theta{}(n^{2}) = f(n)

Segundo cálculo

T(n) = (n) + (n-1) + (\sum_{j=1}^{n} + n) + (\sum_{j=1}^{n}) + (\sum_{j=1}^{n}) + (0) + (0) + (n-1) + (n-1) + (n-1) + (0)

T(n) = 1,5 n^{2} + 6,5 n - 3 \Theta{}(n^{2}) = f(n)

Conclusão

Como vocês puderam ver, não faz diferença alguma o \frac{n^{2} + n}{2} que aquela somatória nos proporciona. Já que todo o cálculo de algoritmos é baseado apenas no maior expoente de n e desprezamos todas as constantes (inclusive as que multiplicam o n de maior expoente, muitos passos são desprezíveis.

Ordenação por Inserção

ATENÇÃO: Este conteúdo foi publicado há 12 anos. Eu talvez nem concorde mais com ele. Se é um post sobre tecnologia, talvez não faça mais sentido. Mantenho neste blog o que escrevo desde os 14 anos por motivos históricos. Leia levando isso em conta.

Também conhecida como Insertion Sort, a Ordenação por Inserção consiste em inserir um elemento n num vetor já ordenado de n-1 elementos. Neste artigo, apresento-lhes este simples algoritmo para ordenação de vetores.

O pseudocódigo da ordenação por inserção é o seguinte:

1. para j \leftarrow{} 2 até comprimento do vetor, faça
2.  elemento \leftarrow{} vetor[j]
3.  i \leftarrow{} j - 1
4.  enquanto i > 0 e vetor[i] > elemento, faça
5.      vetor[i + 1] \leftarrow{} vetor[i]
6.      i \leftarrow{} i - 1
7.  fim-enquanto
8.  vetor[i + 1] \leftarrow{} elemento
9. fim-para

Para explicar eu vou fazer uma coisa que sempre faço para corrigir meus algoritmos, fingir que sou o programa, executando cada passo manualmente (claro que geralmente faço mais rápido, porque não preciso escrever tudo que faço). Vamos iniciar com o seguinte vetor v.

v[1] v[2] v[3] v[4] v[5] v[6]
5 3 7 8 2 5

Aí o código me manda começar com j=2 e iterar até o comprimento do vetor (6). A primeira ordem que ele me dá é para armazenar o elemento a[j] (a[2]) na variável elemento. Para facilitar toda a explicação eu vou sempre pintar de cinza o v[j] onde eu estou (no caso, o segundo elemento do vetor, 3) e de preto o vetor ainda não ordenado (elementos \geq{}j).

v[1] v[2] v[3] v[4] v[5] v[6]
5 3 7 8 2 5

Então ele me diz que i \leftarrow{} j-1. Portanto, i=1. E agora ele me faz um enquanto (que poderia ser substituído por para) onde meu i deverá ir diminuindo. Vamos entrar no loop…

Bom, meu i =1 é maior que 0. v[1]=5 é maior que o elemento=3? Sim, então vamos entrar no corpo do enquanto… Aqui ele me manda fazer um vetor[i+1] = vetor[i], que nesse caso é fazer um v[2]=v[1]=5.

v[1] v[2] v[3] v[4] v[5] v[6]
5 5 7 8 2 5

E agora subtrae de i um valor. Portanto, i=0. Ele retorna ao enquanto, mas agora não satisfazemos a condição i>0, por isso saímos do enquanto. Então ele pede para vetor[i+1]=elemento (v[1]=elemento). Portanto, o vetor fica assim:

v[1] v[2] v[3] v[4] v[5] v[6]
3 5 7 8 2 5

E incrementamos o j, agora j=3.

v[1] v[2] v[3] v[4] v[5] v[6]
3 5 7 8 2 5
elemento = 7 i = 3-1 = 2

i > 0 … E 5 > 7? Não! Portanto, não entramos no enquanto.

v[3] = elemento (nenhuma mudança)

E lá vamos para j=4 e continuando até que vamos ter o vetor ordenado:

v[1] v[2] v[3] v[4] v[5] v[6]
2 3 5 5 7 8

Qual a lógica?

Como eu já disse na introdução, mas lá sem grandes explicações, a Ordenação por Inserção divide o vetor em dois. O primeiro (de elementos <j[/latex]) contém todos seus valores ordenados e o segundo (de elementos [latex]\geq{}j[/latex]) contém os valores que devem ser <strong>inseridos</strong> no <em>primeiro</em> vetor já ordenado (por isso ele se chama <strong>Algoritmo de Inserção</strong>).   A chave do algoritmo é o <strong>enquanto</strong> que acontece para ir deslocando todos os elementos para seu índice [latex]+1 enquanto o elemento for menor que eles (para depois o elemento ser colocado onde parou).

A variável elemento só serve para não perdermos o valor de v[j] (porque depois fazemos v[i+1]=v[i] quando i=j-1)

Acredito que não tenham restado dúvidas. Dê mais uma olhada no algoritmo e tente implementar. Se tiver dificulade, coloque mensagens de debug estratégicas para entender o algoritmo. (ex.: no início do para coloque para imprimir o valor de j e no início de cada enquanto coloque para imprimir os valores elemento, i e v[i])

Custo

Você deve ter percebido que este algoritmo não tem um custo fixo. Se todo o vetor estiver ordenado, ele nunca precisará iterar o i e portanto será executado bem mais rápido do que se o vetor estiver inteiro em ordem decrescente (quando ele sempre precisará iterar i até o fim - 0). Então, neste artigo, gostaria-lhes de apresentar a análise de algoritmos baseada em casos. Para este programa, dizemos que:

  • Melhor caso é quando todos os elementos já estão ordenados. Custo: \Theta{}(n)
  • Pior caso é quando os elementos estão em ordem decrescente. Custo: \Theta{}(n^{2})

Em alguns programas o caso médio é importante também, mas não é o caso da ordenação por inserção. Vemos que há uma diferença bem grande entre o custo dos dois casos. Por isso, precisamos conhecer onde que nosso algoritmo será implementado e quais as chances de ele ser o melhor ou pior caso. Em geral, o pior caso é o mais comum... Por isso, diremos que o custo deste algoritmo é \Theta{}(n^{2}).

Introdução à Ordenação de Vetores

ATENÇÃO: Este conteúdo foi publicado há 12 anos. Eu talvez nem concorde mais com ele. Se é um post sobre tecnologia, talvez não faça mais sentido. Mantenho neste blog o que escrevo desde os 14 anos por motivos históricos. Leia levando isso em conta.

O que é um vetor?

Vetor é uma estrutura de dados que serve para substituir várias variáveis. Para um problema pequeno onde desejo armazenar dois inteiros e tirar o MMC deles eu posso usar duas variáveis: n1 e n2. Mas existem casos em que seria um número muito grande de variáveis (e em alguns deles nem sabemos ao certo, porque faremos uma alocação a partir de um número que o usuário pedir), por isso vetores são extremamente úteis.

No que consiste a ordenação?

Os algoritmos de ordenação tem como objetivo permutar uma seqüência n_{1}, n_{2}, n_{3}, \ldots{} de forma que n_{1} \leq{} n_{2} \leq{} n_{3} \leq{} \ldots{}. A ordenação não precisa ser exatamente de um vetor, mas vetor é geralmente a estrutura que usamos para guardar uma lista de números para podermos ordená-los.

Por que ordenar?

Citando o Cormen:

  • Às vezes, a necessidade de ordenar informações é inerente a uma aplicação. Por exemplo, para preparar os extratos de clientes, os bancos precisam ordenar os cheques pelo número do cheque.
  • Os algoritmos freqüentemente usam a ordenação como uma sub-rotina chave. Por exemplo, um programa que apresenta objetos gráficos dispostos em camadas uns sobre os outros talvez tenha de ordenar os objetos de acordo com uma relação “acima”, de forma a poder desenhar esses objetos de baixo para cima.
  • Existe uma ampla variedade de algoritmos de ordenação, e eles empregam um rico conjunto de técnicas. De fato, muitas técnicas importantes usadas ao longo do projeto de algoritmos são representadas no corpo de algoritmos de ordenação que foram desenvolvidos ao longo dos anos. Desse modo, a ordenação também é um problema de interesse histórico.

Algoritmos de ordenação

Você encontra nos links a esquerda, logo abaixo do título deste post (Introdução à Ordenação de Vetores)