Estrutura de Dados II - 2021-1
UnB-\(\gamma\)

Table of Contents

Table of Contents

1. Aulas

1.1. Aula 1   19_jul

1.1.1. Tópicos

  • Apresentação da disciplina em live no YouTube

1.1.2. Material de apoio

Para a aula de hoje é recomendado que o aluno veja os vídeos disponibilizados na seção Antes de Começar

1.1.3. Exercícios básicos para relembrar

É possível que vários alunos tenham perdido a prática durante o período de férias, e isso faz com que a ferrugem dificulte o início da retomada de implementação de problemas. Para isso estou liberando uma lista pública com alguns problemas selecionados.

  1. Lista pública no CD-MOJ
    • Resolva os exercícios propostos na PRIMEIRA lista pública do CD-MOJ.
    • Para ganhar credenciais de acesso à lista, envie uma mensagem para @mojinho_bot, no telegram AQUI, com o conteúdo:

      participar bcr-EDA2-2021_1-lista1-relembrando
      

1.2. Aula 2   21_jul ordenacao_elementar

Nesta aula vamos começar a trabalhar com algoritmos elementares de ordenação, em especial: BubbleSort; Selection Sort; Insertion Sort.

Antes de começar a trabalhar com os algoritmos de ordenação vamos definir as “regras do jogo”, o contexto, a terminologia e o arcabouço mínimo que se espera para começar a implementar os algoritmos de ordenação.

Nas seções abaixo você encontra todo o conjunto de vídeos explicando cada um dos algoritmos. Além disso temos na seção 1.2.2 um compilado dos tempos de execução dos algoritmos tratados. Por fim na seção 1.2.3 expõe um resumo sobre os algoritmos tratados na seção abaixo.

Não esqueça:

1.2.1. Entenda os Algoritmos passo a passo


1.2.2. Tempo de execução dos Algoritmos Elementares de Ordenação

1.2.3. Sumarização dos algoritmos

1.2.4. Exercícios

  1. Lista pública no CD-MOJ
    • Resolva os exercícios propostos na lista pública do CD-MOJ.
    • As credenciais de acesso à lista são as mesmas da primeira. Caso não tenha criado uma conta, envie uma mensagem para @mojinhobot, no telegram AQUI, com o conteúdo:

      participar bcr-EDA2-2021_1-ordena-elementar
      
  2. Implemente
    • cada um dos algoritmos discutidos em aula (evite consultar o material e deduza os passos);
  3. Compare o tempo de execução dos algoritmos
    • Gere entradas aleatórias com 100000 elementos (experimente outras variações de tamanho também)
    • Para gerar uma entrada aleatória em bash
           for((i=0;i<100000;i++)); do echo $RANDOM; done > aleatorio.in
    
    • Caso prefira implementar em C
          srand(time(NULL));
          for(int i=0;i<100000;i++) printf("%d\n",rand());
    
    • compile o código e execute da seguinte forma:

             ./meuprograma > aleatorio.in
      
      • O seu programa deve ler o conjunto de números da entrada padrão, e você poderá verificar o tempo executado através dos comandos:
             time ./bubblesort < aleatorio.in > bubblesort.out
      
      • assim o seu programa irá ler o conteúdo do arquivo aleatorio.in como se fosse digitado pelo teclado e toda a saída será gravada no arquivo bubblesort.out (você pode trocar o nome do arquivo se assim desejar [recomendo um arquivo diferente para cada algoritmo implementado].
      • Crie variações dos arquivos, gere arquivos maiores, menores, ordenados, ordenados reversamente… E compare o tempo entre esses arquivos, há diferença?
  4. Verifique a quantidade de operações executadas
    • Modifique a sua implementação de forma a mostrar a quantidade de operações de troca e quantas comparações foram feitas.
    • Compare o resultado com todos os algoritmos implementados para diversas entradas
  5. Escreva uma função que coloque em ordem lexicográfica um vetor de strings
  6. Resolva a Terceira questão desta prova
  7. Resolva a Segunda questão desta prova
  8. Defina o conceito de estabilidade de um algoritmo de ordenação.
    • Liste quais algoritmos trabalhados nesta aula são estáveis e quais não são
  9. Ordenando um registro

    Suponha que cada elemento de um vetor é um registro com dois campos: um inteiro e outro uma string:

      struct registro { int aa; char *bb;};
    

    Escreva uma função que rearranje o vetor de modo que os campos aa fiquem em ordem crescente. Escreva outra função que rearranje o vetor de modo que os campos bb fiquem em ordem lexicográfica.

  10. Execute o benchmark disponibilizado no Github

    Faça o git clone do repositório https://github.com/bcribas/benchmark-ordenacao e siga as instruções do README para executar o experimento com algumas implementações.

  11. Você pode me ajudar com alguma das issues abaixo?

1.3. Aula 3   26_jul merge_sort

A aula de hoje é dedicada à resolução dos exercícios referentes aos Algoritmos Elementares de Ordenação divulgados na Aula 2.

Havendo dúvidas, os alunos podem enviar um e-mail ao professor, caso não haja dúvidas até às 8h50 a live de hoje não ocorrerá. No entanto, os alunos podem enviar as dúvidas ao professor durante todo o período da aula.

  • Atualizações
    • (Mon, 26 Jul 2021 08:51:06 -0300) Turma, por falta de dúvidas graves, não teremos a live hoje. Estarei respondendo e-mails de todos até o horário da aula.

1.4. Aula 4   28_jul exercicios


1.4.1. MergeSort explicado de outra maneira


1.4.2. Tópicos e materiais

Discussão e implementação do Algoritmo linearítmico de Ordenação MergeSort.

Nesta aula foi discutido o algoritmo MergeSort, mas antes, iniciamos a discussão sobre o funcionamento da função intercala (merge) que é a base para o funcionamento do algoritmo de ordenação.

Na live foi implementada a intercalação que recebe dois ponteiros de vetores e seus respectivos intervalos fechados [l,r] (l para left [ou elemento mais a esquerda] e r para right [ou elemento mais a direita]) devolvendo um vetor alocado com os elementos dos dois vetores, a e b, intercalados. A função implementada em aula segue o conceito implementado abaixo:

 1:   Item *intercala(Item *a, int la, int ra, Item *b, int lb, int rb)
 2:   {
 3:       //Tamanhos dos vetores a e b
 4:       int ta=(ra-la+1);
 5:       int tb=(rb-lb+1);
 6: 
 7:       Item *c=malloc(sizeof(Item)*(ta+tb));
 8: 
 9:       //intervalos do vetor c
10:       int lc=0;
11:       int rc=(ta+tb-1);
12: 
13:       int ia=la, ib=lb,ic=lc;
14: 
15:       while(ia<=ra && ib<=rb)
16:       {
17:           if(lesseq(a[ia],b[ib]))
18:               c[ic++]=a[ia++];
19:           else
20:               c[ic++]=b[ib++];
21:       }
22:       while(ia<=ra)
23:           c[ic++]=a[ia++];
24:       while(ib<=rb)
25:           c[ic++]=b[ib++];
26:       return c;
27:   }

Esta implementação difere, ligeiramente, da versão feita no vídeo indicado como MergeSort (no início da aula), que faz com que a função de intercalação receba um único vetor com os índices l,m,r (left,middle,right).

O efeito da intercalação é o mesmo, porém, a implementação feita em aula exige que o vetor c seja manipulado dentro do procedimento mergesort, diferentemente do outro vídeo.

A complexidade assintótica não é modificada e tão pouco agrega overhead adicional entre as versões. Fica interessante ter a manipulação diferente dos elementos para ter uma visão ampla da implementação.

Dessa forma o mergesort, em aula, foi implementado da seguinte forma:

28:   void mergesort(Item *v,int l,int r)
29:   {
30:       if(l>=r) return;
31:       int meio=(l+r)/2;
32:       mergesort(v,l,meio);
33:       mergesort(v,meio+1,r);
34:       //principal diferença do intercala não ser in-place
35:       Item *c=intercala(v,l,meio,v,meio+1,r);
36:       for(int i=0;i<r-l+1;i++)
37:           v[l++]=c[i];
38:       free(c);
39:   }

A principal diferença na mergesort acontece a partir da linha 35, onde o nosso procedimento manipula o vetor resultante da intercalação para dentro do vetor que está sendo ordenado.

Outra maneira de passar os parâmetros do vetor v como se fossem dois vetores realmente disjuntos, seria passando o ponteiro da posição inicial de cada left do vetor, substituindo a Linha 35 pela linha indicada abaixo:

1:   Item *c=intercala(&v[l],0,meio-l,&v[meio+1],0,r-(meio+1));

O que acontece neste ponto é que passamos os ponteiros dos left de cada um dos vetores que devem ser intercalados, um deles começa em l e o outro em meio+1, o que precisamos calcular agora é qual seria o novo right de cada vetor, pois como cada vetor não começa no l do vetor original temos que recalcular o deslocamente de cada parte, ficando meio-l para a primeira metade e r-(meio+1) para a segunda metade.

  1. Material de apoio

1.4.3. Exercícios

  1. Lista pública no CD-MOJ
    • Resolva os exercícios propostos na lista Mergesort pública do CD-MOJ.
    • Para ganhar credenciais de acesso à lista, envie uma mensagem para @mojinhobot, no telegram AQUI, com o conteúdo:

      participar bcr-EDA2-2021_1-mergesort
      
      • Se você já conta para a outra lista (disponibilizada na Aula 1), pode utilizar as mesmas credenciais.
  2. Implemente o algoritmo da Intercalação (merge)
  3. Implemente o algoritmo de ordenaçao por intercalação (mergesort)
  4. Escreva uma função que
    • receba vetores disjuntos x[0..m-1] e y[0..n-1], ambos em ordem crescente, e produza um vetor z[0..m+n-1] que contenha o resultado da intercalação dos dois vetores dados.
      • É claro que z estará em ordem crescente.
    • Escreva duas versões da função: uma iterativa e uma recursiva.
  5. Exercícios baseados do Professor Paulo Feofiloff
  6. A respeito do problema da Intercalação (merge)

    O problema da intercalação (merge) é clássico na computação e consiste em resolver o seguinte problema: dados vetores crescentes v[p .. q-1] e v[q .. r-1], rearranjar v[p .. r-1] em ordem crescente.

    Uma leO é uma lista encadeada que contém uma sequência crescente de números inteiros. Escreva uma função que intercale duas leO dadas, produzindo assim uma terceira leO. Sua função não deve alocar novas células na memória, mas reaproveitar as células das duas listas dadas.

  7. Execute o benchmark disponibilizado no Github

    Faça o git clone do repositório https://github.com/bcribas/benchmark-ordenacao e siga as instruções do README para executar o experimento com algumas implementações.

    Recomendo que neste momento você execute da seguinte maneira

    TIMEOUT=3 BINARY="dummy bubblesort selectionsort insertionsortslow insertionsort mergesort" make time.reverso time.ordenado
    
    • Após a execução compare a diferença de execução entre os algoritmos e pondere suas implicações
  8. Modifique a sua implementação do MergeSort para que ela mostre a quantidade de comparações feitas e compare com execuções feitas com os algoritmos elementares
  9. O algoritmo MergeSort é estável?
  10. Um algoritmo de intercalação é estável se não altera a posição relativa de elementos iguais. A função intercala é estável? E se a comparação lesseq(a[ia],b[ib]), for trocada por less(a[ia],b[ib])?
  11. Implemente uma versão modificada do MergeSort com que ele considere os números ímpares sempre maiores que os números pares   HOT
    • Dessa maneira o vetor, sem ordenação, abaixo:

      30 44 1 93 44 77
      
    • Ficaria ordenado da seguinte maneira:

      30 44 44 1 77 93
      

1.5. Aula 5   02_ago recap

Nesta aula o professor irá conversar e discutir com os alunos alguns dos problemas disponibilizados nas listas de exercícios de fixação, liberadas em aulas anteriores.

Os alunos devem ler a maior parte dos problemas para que entendam a motivação de cada um deles.

Preste atenção. A aula de hoje é dividida em 2 partes: A primeira é assíncrona, e o aluno deverá ler e assistir as seções abaixo; Em seguida, às 8h45 inicia-se a parte síncrona com o professor.

1.5.1. Corte

1.5.2. Vídeo com TIMESTAMPS

Vídeo com TIMESTAMPS sobre vários problemas sendo resolvidos. Veja se a sua dúvida já não foi resolvida neste vídeo:

1.5.3. Explicação Número Proibido

A descrição do problema é bastante clara e não esconde o que precisa ser feito, no entanto é necessário que o aluno tenha alguma “malícia” algorítmica para entender como atacar o problema, mas vamos discutir isso com calma.

Primeiramente o enunciado explica que existe uma lista de números proibidos e eles possuem um tamanho bem específico, até \(140000\) números, e cada um deles é um número positivo entre \([0,2^{31}]\) (note que o intervalo é fechado), o que significa que esses números cabem em um número inteiro.

A entrada dos números inteiros é dada por um \(N\), indicando a quantidade de números proibidos, e depois os \(N\) numerais. O código para entrada é bastante direto e possui complexidade em \(\mathcal{O}(N)\), parecido com o código abaixo:

1:   int proibidos[140000];
2:   int proibidos_ct;
3:   scanf("%d",&proibidos_ct);
4:   for(int i=0;i<proibidos_ct;i++)
5:     scanf("%d",&proibidos[i]);

O código acima não tem nenhum segredo, mas o problema começa a apareser nas próximas linhas do enunciado.

O enunciado nos conta que o depois da lista de números proibidos acontecerá um número indeterminado de perguntas, e cada pergunta consiste em saber se um número dado pertence ao conjunto de números proibidos.

A informação da quantidade indeterminada de perguntas nos sugere que elas devem acontecer diversas vezes, muitas vezes mais que a quantidade de números proibidos. E é nesse ponto que você deve ficar encafifado.

Caso você já tenha levado um Time Limit Exceeded, você percebeu que o tempo limite de execução é de meros \(0,2495\) segundos, você identifica isso dentro do log enviado pelo mojinho ao invocar o comando getlog.

Mas vou um pouco mais além e vou mostrar a informação presente nas máquinas. Hoje temos duas máquinas operando como juízes, a jaguapitanga e a ovomaltine (principal), veja a spec delas:

  • jaguapitanga
    • arch: x8664
    • cpu: Intel(R) Celeron(R) CPU 3867U @ 1.80GHz
    • memory: 8077352
  • ovomaltine
    • arch: x8664
    • cpu: Intel(R) Core(TM) i5-4200U CPU @ 1.60GHz
    • memory: 16315452

As máquina são pouco diferentes e o tempo de execução são:

  • jaguapitanga
    • c: .3980
  • ovomaltine
    • c: .2495

Mesmo a ovomaltine sendo mais rápida os tempos não são tão diferentes. Note que a jaguapitanga só é utilizada quando a ovomaltine fica fora do ar, opera como um backup.

Agora vou executar alguns experimentos na jaguapitanga para que consigamos ter uma noção dos tempos que as coisas levam.

Considerando uma ideia bobinha, por exemplo, um código com um vetor de \(140000\) elementos procurando um elemento que não existe, ou seja, efetuando uma busca sequencial. Como o problema nos fala que a quantidade de perguntas é indeterminada, vamos monstar um exemplo que procure \(140000\) vezes um número que não existe.

Como vamos utilizar uma busca sequencial, significa que vamos ter que percorrer o vetor de números proibidos inteiro para descobrir que o número não está lá, então podemos dizer que a busca sequencial é proporcional a \(\mathcal{O}(N)\) operações, como \(N\) é \(140000\) e vamos realizar \(140000\) buscas falhas temos operações propocionais a \(N^2\).

Vamos ver como se comporta um código bobinho desses:

 1:   #include <stdio.h>
 2:   #include <stdlib.h>
 3:   int achou(int num,int *v,int l,int r)
 4:   {
 5:     for(int i=l;i<=r;i++)
 6:       if(v[i]==num)
 7:         return 1;
 8:     return 0;
 9:   }
10:   int main(void)
11:   {
12:     int vetor[140000];
13:     //preparando para gerar números aleatórios
14:     srand(140000);
15:     //preenchendo o vetor com números aleatórios inferiores a 1milhão
16:     for(int i=0;i<140000;i++)
17:       vetor[i]=rand()%1000000;
18: 
19:     //fazendo 140000 buscas pelo número 1milhão
20:     for(int i=0;i<140000;i++)
21:       if(!achou(1000000,vetor,0,140000-1))
22:         printf("nao\n");
23:       else
24:         printf("sim\n");
25:   }
26: 

Executando este código na jaguapitanga, e compilando com os mesmos parâmetros que usamos no MOJ o tempo de execução fica em enormes \(15,61\) segundos. Muito acima do tempo limite estipulado pelo MOJ.

Veja abaixo como foi executado:

  ribas@jaguapitanga:/tmp$ make busca_bobinha CFLAGS='-O2 -static'
  cc -O2 -static    busca_bobinha.c   -o busca_bobinha
  ribas@jaguapitanga:/tmp$ time ./busca_bobinha > /dev/null

  real  0m15.616s
  user  0m15.607s
  sys   0m0.008s

O resultado é muito aquém ao que esperamos, pois o TL é de \(0,2495\) segundos. Como poderíamos reduzir este tempo?

Lá em EDA-1 você deve ter aprendido que existe um algoritmo que sabe fazer uma busca mais rapidamente que a busca sequencial. Esta é a busca binária. O problema é que a busca binária precisa de um vetor ordenado para poder realizar a busca rapidamente.

Então PARA TUDO! Precisamos ordenar esse vetor antes de fazer a busca!

Aprendemos diversos algoritmos de ordenação neste semestre e temos uma noção de como cada um se comporta.

Peguei rapidamente o Benchmark de Ordenação e resolvi experimentar na jaguapitanga primeiramente testando os clássicos:

  • bubblesort

    • seletionsort
    • insertionsort
    • mergesort

    Sabemos que somente o mergesort, dentre os listados acima, possui complexidade em \(\mathcal{O}(N \log{}(N))\), enquanto que os outros estão em \(\mathcal{O}(N^2)\).

    Table 1: Tabela de tempos de execução para os algoritmos de ordenação para entradas de tamanhos entre \(2^8\) e \(2^{20}\), com tempo limite de execução em 20 segundos
    Alg/#Elementos 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576
    bubblesort 0.00 0.00 0.00 0.01 0.04 0.20 0.91 3.89 16.01 TLE TLE TLE TLE
    selectionsort 0.00 0.00 0.00 0.00 0.01 0.05 0.23 0.91 3.61 14.42 TLE TLE TLE
    insertionsort 0.00 0.00 0.00 0.00 0.00 0.01 0.04 0.16 0.67 2.79 11.69 TLE TLE
    mergesort 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.01 0.03 0.06 0.12 0.25 0.53

Para gerar a tabela acima o benchmark de ordenação foi executado da seguinte maneira na jaguapitanga:

      TIMEOUT=20 BINARY="bubblesort selectionsort insertionsort mergesort" make time.aleatorio

Veja que os algoritmos quadráticos (os três primeiros) crescem na proporção esperada, ou seja, ~4x mais tempo é necessário para ordenar um vetor com o dobro do tamanho.

Logo, é perceptível que somente o mergesort consegue ordenar o vetor dentro do limite de tempo tão justo, ou seja, sabemos que ele ordena \(262144\) elementos em \(0,12\) segundos.

Nesse ponto sabemos o que fazer! Para poder utilizar a busca binária devemos ordenar o vetor com o mergesort, para que seja possível sobrar mais tempo para realizar as consultas.

Modificando o Código da Busca Bobinha para ordenar com MergeSort e realizar a busca binária, ficaria da seguinte forma:

 1:       #include <stdio.h>
 2:       #include <stdlib.h>
 3:       //Mergesort e Intercala OMITIDOS! Use a versão disponibilizada na Aula 3, seção 3.1
 4: 
 5:       int buscabinaria(int num,int *v,int l,int r)
 6:       {
 7:         if(l>r) return -1;
 8:         int meio=(l+r)/2;
 9:         if(less(v[meio],num))
10:           return achou(num,v,meio+1,r);
11:         else if(lesseq(v[meio],num))
12:           return meio;
13:         else
14:           return achou(num,v,l,meio-1);
15:       }
16:       int main(void)
17:       {
18:         int vetor[140000];
19:         //preparando para gerar números aleatórios
20:         srand(140000);
21:         //preenchendo o vetor com números aleatórios inferiores a 1milhão
22:         for(int i=0;i<140000;i++)
23:           vetor[i]=rand()%1000000;
24: 
25:         //Tenha cuidado com a chamada do MergeSort, o intervalo é FECHADO [l,r]
26:         //por isso é subtraído 1 do tamanho do vetor, para ficar [0,139999]
27:         //que representa os 140000 elementos.
28:         mergesort(vetor,0,140000-1);
29: 
30:         //fazendo 140000 buscas pelo número 1milhão
31:         for(int i=0;i<140000;i++)
32:           if(!buscabinaria(1000000,vetor,0,140000-1))
33:             printf("nao\n");
34:           else
35:             printf("sim\n");
36:       }
37: 

O código acima possui a implementação da BuscaBinária e utiliza o MergeSort implementado na Aula 3.

Seguimos a execução conforme abaixo:

ribas@jaguapitanga:/tmp$ make busca2 CFLAGS='-O2 -static'
cc -O2 -static    busca2.c   -o busca2
ribas@jaguapitanga:/tmp$ time ./busca2 >/dev/null

  real  0m0.032s
  user  0m0.028s
  sys   0m0.005s


O que antes demorava mais de \(15\) segundos, passou a executar em apenas \(0,032\) segundos, bem abaixo do tempo limite estipulado no sistema MOJ.

Implementado um código que utiliza esta estratégia sai do custo de \(\mathcal{O}(N^2)\) operações para \(\mathcal{O}(N log{}(N) + N log{}(N))\), pois a ordenação fica em \(\mathcal{O}(N log{}(N)\), e a busca binária fica em \(\mathcal{O}(log{}(N))\), sendo executada \(N\) vezes, pois são feitas \(140000\) perguntas.

A busca que implementamos neste exercício mental trata de uma entrada próxima do pior caso, e que força uma implementação simples a ficar com custo proporcional a \(\mathcal{O}(N^2)\), enquanto que podemos implementar de uma maneira mais eficiente apenas pensando nos custos envolvidos.

1.5.4. LIVE síncrona

LIVE começando às 8h45

1.6. Aula 6   04_ago sanidade

Sem perder a SANIDADE, resolva os exercícios REMOÇÃO e SANIDADE que, dentre todas as listas, está disponível na lista abaixo.

1.6.1. Lista pública no CD-MOJ

  • Resolva os exercícios propostos na lista Sanidade e Remoção
  • Para ganhar credenciais de acesso à lista, envie uma mensagem para @mojinhobot, no telegram AQUI, com o conteúdo:

    participar bcr-EDA2-2021_1-sanidade-e-remocao
    
    • Se você já conta para a outra lista (disponibilizada na Aula 1), pode utilizar as mesmas credenciais.

1.7. Aula 7   09_ago quicksort

Segue nesta seção um conjunto de vídeos a respeito do QuickSort, e que serão tema das próximas aulas, assista para que possamos elevar a discussão a respeito deste algoritmo.

1.7.1. Exercícios

  1. Lista pública no CD-MOJ
    • Resolva os exercícios propostos na lista QuickSort
    • Para ganhar credenciais de acesso à lista, envie uma mensagem para @mojinhobot, no telegram AQUI, com o conteúdo:

      participar bcr-EDA2-2021_1-quicksort
      
      • Se você já conta para a outra lista (disponibilizada na Aula 1), pode utilizar as mesmas credenciais.
  2. Escreva o algoritmo da separação
  3. Escreva uma função que rearranje um vetor v[p..r] de inteiros de modo que tenhamos v[p..j-1] <=0 e v[j..r] > 0 para algum j em p..r+1.
    • Faz sentido exigir que j esteja em p..r?
    • Procure fazer uma função rápida que não use vetor auxiliar.
    • Repita o exercício depois de trocar v[j..r] > 0 por v[j..r] >=0.
    • Faz sentido exigir que v[j] seja 0?
  4. Um vetor v[p..r] está arrumado se existe j em p..r tal que v[p..j-1] <=v[j] < v[j+1..r] . Escreva um algoritmo que decida se v[p..r] está arrumado. Em caso afirmativo, o seu algoritmo deve devolver o valor de j.
  5. Um programador inexperiente afirma que a seguinte implementação da função de separação rearranja o vetor v[p..r], com p < r, e devolve um índice j em p..r-1 tal que v[p..j] <= v[j+1..r].
    int sep( int v[], int p, int r) {
       int q, i, j, t;
       i = p; q = (p + r) / 2; j = r;
       do {
          while (v[i] < v[q]) ++i;
          while (v[j] > v[q]) --j;
          if (i <= j) {
             t = v[i], v[i] = v[j], v[j] = t;
             ++i, --j;
          }
       } while (i <= j);
       return i;
    }
    

    Mostre um exemplo onde essa função não dá o resultado esperado. E se trocarmos return i por return i-1? É possível fazer algumas poucas correções de modo que a função dê o resultado esperado?

  6. Qual o resultado da função separa quando os elementos de v[p..r] são todos iguais? E quando v[p..r] é crescente? E quando v[p..r] é decrescente? E quando cada elemento de v[p..r] tem um de dois valores possíveis?
  7. A função separa produz um rearranjo estável do vetor, ou seja, preserva a ordem relativa de elementos de mesmo valor?   HOT
  8. Escreva uma versão recursiva da função separa.
  9. Implemente o QuickSort
  10. Submeta o vetor 77 55 33 99 indexado por 1..4 à função quicksort. Teremos a seguinte sequência de invocações da função (observe a indentação):
       quicksort( v,1,4)
           quicksort( v,1,2)
               quicksort( v,1,0)
               quicksort( v,2,2)
           quicksort( v,4,4)
    

    Repita o exercício com o vetor 55 44 22 11 66 33 indexado por 1..6.

  11. A função quicksort produz uma ordenação estável do vetor?
  12. Escreva uma versão não recursiva do algoritmo Quicksort. sol
  13. Execute todas as variações do QuickSort distribuídas no Benchmark de Ordenação e reflita sobre os resultados

1.8. Aula 8   11_ago quickselect

1.8.1. Material Adicional

  1. Conversa sobre o exercício NMUR
  2. Visão geral do algoritmo QuickSort e QuickSelect

1.9. Aula 9   16_ago quicksort_final

Implementação e resolução dos exercícios de Ordenação.

1.9.1. Cortes com problemas resolvidos

1.10. Aula 10   18_ago hash

1.10.1. Exercícios

  1. Veja o material sobre hash do Prof. Paulo Feofiloff
  2. Você consegue aplicar as ideias de HASH nos exercícios Remoção e Sanidade?
  3. Você consegue aplicar as ideias de HASH no exercício Eleição U.R.S.A.L?
  4. Considere as técnicas de busca sequencial, busca binária e busca baseada em hashing:
    • Descreva as vantagens e desvantagens de cada uma dessas técnicas, indicando em que situações você usaria cada uma delas.
    • Qual é a eficiência de utilização da memória (relação entre o espaço necessário para dados e o espeço total necessário) para cada método?
  5. Sobre Tabelas HASH:
    • É possível criar uma função HASH em que é garantido que nunca haverá colisão? Porquê?
    • Quando existe colisão, quais estratégias podem ser utilizadas para contornad esse problema? Quando cada estratégia é melhor utilizada?
  6. Resolva os exerícios DESTA PROVA   hot

1.11. Aula 11   23_ago hash

1.11.1. Vídeos adicionais sobre HASH

Os alunos devem finalizar os vídeos sobre HASH disponibilizados na Aula 10.


1.11.2. Exercícios

  1. Você consegue aplicar os conhecimentos, adquiridos pelos vídeos acima, no problema Desfile dos Patos (em nossa segunda lista de presença).
  2. Lista pública no CD-MOJ
    • Para ganhar credenciais de acesso à lista, envie uma mensagem para @mojinhobot, no telegram AQUI, com o conteúdo:

      participar bcr-EDA2-2021_1-hash
      
      • Se você já conta para a outra lista (disponibilizada na Aula 1), pode utilizar as mesmas credenciais.
  3. Imagine que você tenha um bug em sua implementação de tabela hash utilizando hash-dupla (double-hashing) de tal forma que a primeira ou a segunda função de hash retornam sempre o mesmo valor (porém diferente de \(0\)). Descreva o que ocorre (exemplo: os custos de inserção e busca permanecem o esperado?) quando:
    1. a primeira hash está errada;
    2. a segunda hash está errada;
    3. ambas funções hash estão erradas.
  4. Resolva o exerício HASHIT da lista de HASH no CD-MOJ

    Veja a discussão deste exercício com o Monitor Felipe Borges

  5. Resolva o exercício Desfile dos Patos com o seguinte algoritmo

1.12. Aula 12   25_ago

Aula dedicada à resolução dos exercícios de HASH disponibilizados no MOJ.

1.13. Aula 13   30_ago

1.14. Aula 14   01_set árvore

A aula de hoje terá caráter assíncrono. Os alunos devem relembrar os conceitos de árvores binárias.

Já deixo separado e recomendado que vocês iniciem a leitura de:

1.14.1. Vídeos de apoio


1.14.2. Exercícios

  1. Lista pública no CD-MOJ
    • Para ganhar credenciais de acesso à lista, envie uma mensagem para @mojinhobot, no telegram AQUI, com o conteúdo:

      participar bcr-EDA2-2021_1-arvorebinaria
      
      • Se você já conta para a outra lista (disponibilizada na Aula 2), pode utilizar as mesmas credenciais.
  2. Tente resolver o exercício https://br.spoj.com/problems/PREEMPOS/
  3. Suponha que as chaves 50 30 70 20 40 60 80 15 25 35 45 36 são inseridas, nesta ordem, numa árvore de busca inicialmente vazia. Desenhe a árvore que resulta.   prof_Feofiloff
  4. Considere árvores binárias de busca cujos nós têm a estrutura indicada abaixo.   prof_Feofiloff
    • Escreva uma função que receba a raiz de uma tal árvore e o endereço de um nó x e devolva o endereço do pai de x.

           typedef struct reg {
          int         chave;
          int         conteudo;
          struct reg *esq, *dir;
           } noh;
      
  5. [NÚMERO DE NÓS.] Escreva uma função que calcule o número de nós de uma árvore binária.   prof_Feofiloff
  6. [FOLHAS.] Escreva uma função que imprima, em ordem in-order, os conteúdos das folhas de uma árvore binária.   prof_Feofiloff
  7. Dada uma árvore binária, encontrar um nó da árvore cujo conteúdo tenha um dado valor val.   prof_Feofiloff
  8. [VARREDURA r-e-d.] Escreva uma função que faça a varredura r-e-d (varredura prefixa) de uma árvore binária.   prof_Feofiloff
  9. [VARREDURA e-d-r.] Escreva uma função que faça varredura e-d-r (varredura posfixa) de uma árvore binária.   prof_Feofiloff
  10. Escreva uma função para calcular a altura de uma árvore binária
  11. Escreva uma função que determine a profundidade de um nó dado.   prof_Feofiloff
  12. Escreva uma função que decida se uma dada árvore binária é quase completa.   prof_Feofiloff

1.15. Aula 15   06_set exercício

1.16. Aula 16   08_set exercícios

A aula de hoje é dedicada à resolução de exercícios relativos a árvores binárias e HASH.

1.17. Aula 17   13_set


1.17.2. Exercícios

  1. Resolva os exercícios de PQ   prof_Feofiloff
  2. (SW 9.1) Suponha que a sequência P R I O * R * * I * T * Y * * * Q U E * * * U * E é aplicada a uma PQ de máximo inicialmente vazia. Uma letra significa inserção e um asterisco significa remoção do máximo. Dê a sequência de letras produzida pelas remoções.   Sedgewick
  3. (SW 9.17) Um vetor em ordem decrescente é um heap decrescente? Um vetor em ordem crescente é um heap crescente?   Sedgewick
  4. Insira os itens E A S Y Q U E S T I O N, nessa ordem, em um heap decrescente inicialmente vazio. Mostre o heap que resulta.   Sedgewick
  5. Escreva um método isMaxHeap() para verificar se o vetor pq[] é um heap decrescente. O seu algoritmo deve consumir tempo linear. Repita para heap crescente.   Sedgewick
  6. Fila priorizada min/max. Projete um tipo-de-dados que dê suporte às seguinte operações: inserção, remoção do mínimo, remoção do máximo, encontrar o mínimo (sem remover), e encontrar o máximo (sem remover). As três primeiras operações devem consumir tempo logarítmico e as duas últimas devem consumir tempo constante. Dica: Use dois heaps.   Sedgewick
  7. Escreva a API completa de Filas de Prioridade de maneira que ela suporte mais de um Fila de prioridades no seu programa
  8. Como você pode implementar um algoritmo de Ordenação utilizando o conceito de filas de prioridade?
    • Analise e entenda a implementação simples usando fila de prioridades AQUI
    • Pense em como modificar o algoritmo acima para não utilizar memória auxiliar, uma solução está AQUI
  9. Rode o conjunto de benchmark de ordenação e idenfique o comportamento dos algoritmos HeapSort e PQsortsimple quando se comparado com o melhor quicksort e o mergesort
  10. O HeapSort é estável?
  11. Você é capaz de ressolver esta ISSUE?
  12. Qual implementação (em vetor ordenado ou não ordenado, com lista encadeada ordenada ou não ordenada, árvore binária em vetor) para encontrar os \(100\) menores elementos de um conjundo de \(10^6\) números aleatórios?   Sedgewick
    • Implemente e faça testes de desempenho
  13. Resolva o problema Classificados de Sementes utilizando os conceitos de fila de prioridades
  14. É possível resolver o problema kk-página utilizando os conceitos de fila de prioridades?
  15. Resolva o problema Eu posso advinhar a estrutura de dados!   urionlinejudge
  16. Implemente a ADT de fila de prioridades para fazer a troca baseada em índice (como vimos no fim da última aula)

  17. Suponha que um vetor está preenchido com as seguintes chaves E A S Y Q U E S T I O N. Imprima o conteúdo do vetor pq e qp após a inserção dos elementos da fila de prioridades implementada no exercício 1.17.2.16
  18. Adicione a operação remover na sua implementação do problema 1.17.2.16
    • esta função serve para quando se remover um elemento qualquer do vetor original
  19. Resolva o exercício Churrascarias da Avenida utilizando a implementação feita no exercício 1.17.2.16   spoj br

1.18. Aula 18   15_set

  • Aula assíncona para assistir aos vídeos disponibilizados na aula 17 e resolução de exercícios

1.19. Aula 19   20_set

1.20. Aula 20   22_set

Veja no primeiro vídeo a explicação sobre a “fila de prioridades baseada em índice”, o vídeo possui os timestamps.

No segundo vídeo veja a explicação de alguns exercícios, mas veja depois de tentar resolver os problemas disponibilizados na Aula 17.

1.20.1. Exercícios

  1. Lista pública no CD-MOJ
    • Para ganhar credenciais de acesso à lista, envie uma mensagem para @mojinhobot, no telegram AQUI, com o conteúdo:

      participar bcr-EDA2-2021_1-pq
      
      • Se você já conta para a outra lista (disponibilizada na Aula 2), pode utilizar as mesmas credenciais.

1.21. Aula 21   27_set semana_academica

  • Semana acadêmica, não haverá encontro.

1.22. Aula 22   29_set semana_academica

  • Semana acadêmica, não haverá encontro.

1.23. Aula 23   06_out


1.23.2. TRABALHO 2 - EDAzinho da Dominação

1.24. Aula 24   04_out


1.25. Aula 25   11_out feriado

1.26. Aula 26   13_out


1.26.1. Material de Apoio

1.27. Aula 27   18_out


1.28. Aula 28   20_out

  • aula assíncrona para os alunos desenvolverem o trabalho

1.28.1. Lista pública no CD-MOJ

  • Para ganhar credenciais de acesso à lista, envie uma mensagem para @mojinhobot, no telegram AQUI, com o conteúdo:

    participar bcr-EDA2-2021_1-grafos
    
    • Se você já conta para a outra lista (disponibilizada na Aula 2), pode utilizar as mesmas credenciais.

1.29. Aula 29   25_out

1.30. Aula 30   27_out

Exercícios de grafos. Dúvidas por e-mail.

1.31. Aula 31   01_nov feriado

1.32. Aula 32   03_nov

  • Avaliação da disciplina com exercícios que podem abranger toda a disciplina, no entanto será focado em grafos.
    • Será no MOJ, com as duplas do T2 e acontecerá das 6:00 às 10:00.

2. Antes de Começar

Nesta disciplina é esperado que o aluno tenha conhecimento básico da linguagem C tais como:

  • Ponteiros
  • Strings
  • Leitura da Entrada padrão

As subseções abaixo elencam alguns vídeos que recaptulam o conhecimento necessário.

2.1. Material no Youtube

Vídeos com material relacionado ao conteúdo esperado para uso na disciplina.

Tenho disponibilizado vários materiais em meu canal no YouTube, por favor, considere assinar o canal e deixar o joinha :)

2.1.1. Revisão de Ponteiros

Segue abaixo a playlist da revisão de ponteiros no Youtube. Por ora são 5 vídeos que exploram o que é necessário saber para a disciplina de EDA-2.

2.1.2. Strings em C

Aqui um apanhando geral em como se manipula strings na linguagem C. Em uma série que chamei de “Umas Palavras sobre String”

2.1.3. SCANF

O SCANF é uma poderosa função capaz de ler dados da entrada padrão (e de outros arquivos com suas aliases como fscanf(3).

Na série Detonando o SCANF temos, além do uso básico da função abordo algumas curiosidades sobre as funções.

3. Plano de Aulas

O plano de ensino e plano de aulas é um PLANO e pode sofrer modificações ao longo do semestre de acordo com o rendimento da turma.

Curso: Engenharia de Software Período Letivo 2021/1
Disciplina: Estrutura de Dados 2 Código  
Carga Horária: 60 horas Créditos 04

3.1. Ementa

  • Estruturas não-lineares. Árvores. Tabelas hash. Grafos
  • Filas de prioridade. Heap
  • Algoritmos de ordenação avançados \(\mathcal{O}(n\log{}n)\)
  • Algoritmos de manupalição e análise de grafos
  • Aplicações

3.2. Horários das aulas e atendimento

  • Aulas:
    • {segunda,quarta}-feira, das 8:00 às 9:50
  • Atendimento:
    • por e-mail nos dias e horário das aulas
      • caso necessário será aberto uma CALL para sanar as dúvidas
  • E-mail:
    • bruno.ribas EM unb.br
  • Página:

3.3. Método

Aula expositiva por meio de vídeos no Youtube (gravados ou em live stream), conversas periódicas em vídeo conferências com os alunos nos horários das aulas, quadro branco (representado pelo tablet), listas de exercícios.

3.4. Critérios de Avaliação

  • A avaliação será feita por um conjunto de trabalhos com peso variável, ou seja, o primeiro trabalho tem peso 1, o segundo peso 2, e assim por diante.
  • As notas serão compostas por um número inteiro no intervalo \([0,100]\);
  • As avaliações serão compostas por questões, podendo ser, a critério do professor, teóricas e/ou práticas
    • O método de entrega será combina previamente com os alunos, podendo ser realizada por meio: do corretor automático MOJ; questionários no sistema SIGAA e/ou; submissão por e-mail para o professor;
  • Qualquer tentativa de fraude nas provas implicará em média ZERO no semestre para todos os envolvidos.

3.4.1. Presença

A presença na disciplina se dará pela entrega das avaliações, listadas acima.

A entrega DENTRO do prazo é obrigatória para todos os alunos.

3.4.2. Menção Final

As notas serão calculadas conforme a equação abaixo:

\begin{align} M_F = \frac{ \sum_{i=1}^{N}{i \cdot A_i}}{\sum_{i=1}^{N}{i}} \end{align}

3.4.3. Critérios de aprovação

Obterá aprovação no curso o aluno que cumprir todas as exigências listadas abaixo:

  1. \(M_F >= 50\); e
  2. Presença em \(75\%\) ou mais das aulas.

Por fim, a menção final do curso é dada de acordo com a tabela abaixo:

\(M_F\) Menção Descrição
\(0\) SR Sem rendimento
\([1,29]\) II Inferior
\([30,49]\) MI Médio Inferior
\([50,69]\) MM Médio
\([70,89]\) MS Médio Superior
\([90,100]\) SS Superior

3.5. Cronograma

Data Atividade
Semanas {1,2,3} Ordenação Elementar, QuickSort, MergeSort
Semanas {4,5,6} Hashing, Filas de Prioridades
Semanas {7,8,9,10} Heap, Árvores Balanceadas
Semanas {11,12,13,14,15,16} Grafos

3.6. Bibliografia

  • CORMEN, Thomas H.; LEISERSON, Charles E.; RIVEST, Ronald L.; STEIN, Cli or. Algoritmos: Teoria e Prática. 2a.edição, Campus.
  • (eBrary) CORMEN, Thomas H.; LEISERSON, Charles E.; RIVEST, Ronald
    1. Introduction to Algorithms. MIT Press, 2014.
  • (eBrary) MEHLHORN, K; SANDERS, P. Algorithms and Data Structures: The Basic ToolBox, 1st. ed. Springer, 2008.
  • (open access) HALIM, Steve S; HALIM, Felix. Competitive Programming, 1st ed, Lulu, 2010.
  • (eBrary) STEPHENS, Rod. Essential Algorithms: A Pratical Approach to Computer Algorithms. John Wiley Sons, 2013.
  • (open access) AHO, A. V.; ULLMAN, J. D. Foundations of Computer Science: C Edition (Principles of Computer Science Series), 1st ed.,
    1. H. Freeman, 1994.

4. Monitor

Em busca de um MONITOR.

5. Presença

  • VAZIO

6. Notas

  • AVx são as avaliações
  • PP é a porcentagem de presença (consolidada nesta tabela no fim do semestre)
    • Na seção anterior você pode ver o acompanhamento das presenças
  • situação é a situação final na disciplina, gerada após todas avaliações
  • As penalidades nas avaliações são relativas às chamadas ao getlog do MojinhoBot
matricula PP AV1 AV2 AV3 MM situacao nome
160000572   099= 099 100= 100 100= 100 99 SS **
180011961   090= 090 100= 100 012= 012 54 MM **
180030264   100= 100 100= 100 040= 040 70 MS **
180098021   100= 100 000= 000 073= 073 53 MM **
190024950   098= 098 000= 000 010= 010 21 MI **
190025379   100= 100 100= 100 060= 060 80 MS **
180074741   100= 100 100= 100 030= 030 65 MM **
190056843   100= 100 100= 100 100= 100 100 SS **
180118005   100= 100 100= 100 060= 060 80 MS **
190011602   100= 100 100= 100 008= 008 54 MM **
170139981   096= 096 ** 070= 070 51 MM **
180015311   100= 100 100= 100 100= 100 100 SS **
190042419   100= 100 000= 000 100= 100 66 MM **
170161871   093= 093 100= 100 040= 040 68 MM **
190012200   100= 100 ** 060= 060 46 MI **
190012307   100= 100 100= 100 080= 080 90 SS **
190027088   098= 098 000= 000 010= 010 21 MI **
180119508   006= 006 ** ** 1 SR **
180016067   100= 100 ** 060= 060 46 MI **
190027355   100= 100 100= 100 060= 060 80 MS **
180113259   095= 095 100= 100 080= 080 89 SS **
180063723   100= 100 000= 000 100= 100 66 MM **
190106565   100= 100 100= 100 007= 007 53 MM **
150125682   ** 100= 100 ** 33 SR **
170103200   096= 096 ** 070= 070 51 MM **
180100831   098= 098 100= 100 024= 024 61 MM **
170011020   100= 100 ** ** 16 SR **
180017870   100= 100 100= 100 000= 000 50 MM **
180101617   100= 100 000= 000 073= 073 53 MM **
170034941   099= 099 100= 100 010= 010 54 MM **
190014032   100= 100 100= 100 080= 080 90 SS **
190046091   100= 100 100= 100 060= 060 80 MS **
170034992   100= 100 ** ** 16 SR **
180018728   100= 100 100= 100 040= 040 70 MS **
180102613   100= 100 100= 100 040= 040 70 MS **
170069800   100= 100 000= 000 100= 100 66 MM **
190030291   100= 100 070= 070 040= 040 60 MM **
180102711   100= 100 ** 100= 100 66 MM **
180123203   090= 090 100= 100 012= 012 54 MM **
180103431   098= 098 100= 100 024= 024 61 MM **
180103580   100= 100 ** 000= 000 16 MI **
190046945   ** ** ** 0 SR **
180022237   100= 100 100= 100 100= 100 100 SS **
190032863   100= 100 ** 060= 060 46 MI **
190033088   100= 100 100= 100 080= 080 90 SS **
170016838   100= 100 ** 060= 060 46 MI **
180105604   100= 100 100= 100 040= 040 70 MS **
190113031   000= 000 ** ** 0 SR **
190134623   ** ** ** 0 SR **
180145231   000= 000 ** ** 0 SR **
180127535   100= 100 100= 100 100= 100 100 SS **
180024868   100= 100 100= 100 010= 010 55 MM **
190055201   100= 100 100= 100 060= 060 80 MS **
150141629   100= 100 100= 100 000= 000 50 MM **
170111288   100= 100 100= 100 060= 060 80 MS **
190129221   098= 098 100= 100 010= 010 54 MM **
190058650   100= 100 000= 000 100= 100 66 MM **
140156909   060= 060 ** ** 10 SR **
190047968   100= 100 100= 100 100= 100 100 SS **
190036435   100= 100 070= 070 040= 040 60 MM **
170153975   100= 100 ** 040= 040 36 MI **
190098287   090= 090 100= 100 010= 010 53 MM **
180011308   100= 100 100= 100 060= 060 80 MS **
180108344   095= 095 100= 100 080= 080 89 SS **
190019085   100= 100 100= 100 080= 080 90 SS **
170021581   093= 093 100= 100 040= 040 68 MM **
190048221   100= 100 000= 000 040= 040 36 MI **
180037242   100= 100 100= 100 060= 060 80 MS **
180130889   100= 100 100= 100 100= 100 100 SS **
170045943   ** ** ** 0 SR **
180028260   100= 100 100= 100 040= 040 70 MS **
170114929   090= 090 070= 070 060= 060 68 MM **
190020377   100= 100 100= 100 100= 100 100 SS **
190055294   100= 100 100= 100 008= 008 54 MM **
190038969   100= 100 000= 000 040= 040 36 MI **
180149598   000= 000 ** ** 0 SR **
190044390   100= 100 100= 100 010= 010 55 MM **
190044403   100= 100 100= 100 080= 080 90 SS **
190020903   100= 100 100= 100 080= 080 90 SS **
180029223   100= 100 100= 100 080= 080 90 SS **
180029240   000= 000 ** ** 0 SR **
180145363   090= 090 100= 100 010= 010 53 MM **
160149410   100= 100 100= 100 100= 100 100 SS **
180078640   100= 100 100= 100 030= 030 65 MM **
média ** 92 82 54 ** ** Média da turma

Author: Bruno Ribas

Created: 2021-11-05 sex 23:50