Algoritmos e Estruturas de Dados I Prof. Daniel M. Martin ([email protected]) Aula 3 Observações dobre o EL1 ● Sempre que usar malloc(), verificar se o espaço foi alocado com sucesso: int *v, n = 1000; v = (int *) malloc(n * sizeof(int)); if (v == NULL) { fprintf(stderr, "Memória insuficiente"); return 1; } ● ● Não se esquecer de liberar a memória com a função free() Indentação de código! Observações sobre o EL1 ● ● Faça seus programas em C, não em C ++ (extensão do arquivo deve ser .c e não .cpp) Uso da função scanf(): scanf("%d", &n); ● – Não serve para imprimir uma string – Precisa do endereço da variável e não do valor Uso da função printf(): printf("O valor é: %d\n", n); – Não precisa de um endereço e sim de um valor Recordação: alocação de vetores ● Estatica: int v[1000]; – ● Espaço reservado na pilha (Stack) Dinâmica: int *v, n = 1000; v = (int *) malloc(n * sizeof(int)); – Espaço reservado na memória principal (Heap) – Liberar memória após o uso: free(v); Observações dobre o EL1 ● Não usem a função system("..."); – ● ● Usem getc(stdin); se precisarem manter o terminal de execução visível IDEs para desenvolvilemto no Windows: – Code::Blocks (Também disponível p/ Linux) – Dev C++ Code::Blocks faz um "system("pause");" no final (i.e. pede ENTER para fechar o terminal quando o programa termina de executar) Code::Blocks ● File – New ● Project Dev C++ ● File – New ● Project Compile & Run: F9 Estruturas de Dados ● ● ● ● Disciplina que estuda modos de se organizar coleções de dados na memória e sua relação com algoritmos para processar esses dados. Para a maior parte das applicações, a escolha das estruturas de dados é uma decisão crucial Para um mesmo conjunto de dados, algumas estruturas ocupam mais espaço de memória, e outras menos Algumas estruturas permitem algoritmos mais eficientes que outras Estruturas de Dados (Hipóteses Gerais) ● ● ● Dados não devem ser duplicados na memória Estrutura deve ocupar tamanho proporcional ao volume de dados (deve expandir/encolher conforme o necessário) Processamento de interesse nos dados: – Buscar por um dado na estrutura – Inserir dados na estrutura – Remover dados da estrutura Estruturas de Dados Vetores Vetores ● Estrutura de dados fundamental – Diversas outras estruturas dependem de vetor – Organiza dados de mesma natureza em posições sucessivas de memória – A própria memória pode ser vista como um grande vetor (de bytes) – Cada dado é identificado por um índice – Queremos ser capazes de fazer as operações de busca, inserção e remoção de elementos em um vetor. Vetores não-ordenados ● Suponha que temos um vetor v: – N – número de posições alocadas; – n – número de elementos guardados em v. Valores de interesse: A 0 ● ● F 1 J 2 B 3 Valores lixo: K 4 F 5 Z 6 T 7 Z 8 G 9 No exemplo: N = 10, e n = 5. Normalmente supõe-se que os valores de interesse são distintos. Busca – vetores não-ordenados ● ● ● Dado um valor x, como descobrir se x pertence ao vetor? Objetivo: determinar a posição (o índice) do vetor que contém o valor x ou determinar se x não está no vetor Solução: percorrer vetor do começo (esse algoritmo chama-se busca seqüencial) Busca – vetores não-ordenados ● Pseudo-código do algortimo de busca: (devolve o indice de x ou -1 se não houver) BUSCA-SEQUENCIAL(v[0 … (N-1)], n, x) i←0 enquanto i < n faça se v[ i ] = x então devolve i senão i ← i + 1 devolve -1 Busca – vetores não-ordenados ● Código em C supondo um vetor de inteiros: int busca_sequencial(int *v, int N, int n, int x) { int i; for (i = 0; i < n; i ++) if (v[i] == x) return i; return -1; } Busca – vetores não-ordenados ● Pode-se generalizar para um vetor de itens: int busca_sequencial(item *v, int N, int n, item x) { int i; for (i = 0; i < n; i ++) if (v[i] == x) return i; return -1; } Busca – vetores não-ordenados Análise do algoritmo de busca seqüencial (Na lousa) Inserção – vetores não-ordenados ● Dado um valor x, como inserir x no vetor v? ● O algoritmo de inserção é fácil ● ● ● Valores duplicados não são permitidos, então devemos buscar por x antes de inserir x em v Queremos saber a posição (o índice) do vetor em que x foi inserido. Se x já estiver no vetor, queremos saber a posição (o índice em que se encontra) Inserção – vetores não-ordenados ● Pseudo-código do algoritmo de inserção: (devolve o indice de x ou -1 se não couber) INSERE(v[0...(N-1)], n, x) se n = N então devolve -1 i ← BUSCA-SEQUENCIAL(v[0...(N-1)], n, x) se i = -1 então v[n] ← x n←n+1 devolve n – 1 devolve i Inserção – vetores não-ordenados ● Código errado em C do algoritmo de inserção: int insere(int *v, int N, int n, int x) { int i = busca_sequencial(v, N, n, x); if (i != -1) return i; if (n == N) return -1; v[n] = x; return n ++; /* Perderá o efeito */ } Inserção – vetores não-ordenados ● Código certo em C do algoritmo de inserção: int insere(int *v, int N, int *n, int x) { int i = busca_sequencial(v, N, *n, x); if (i != -1) return i; if (*n == N) return -1; v[*n] = x; return *n ++; } Inserção – vetores não-ordenados ● Código em C para inserção de um item geral: int insere(item *v, int N, int *n, item x) { int i = busca_sequencial(v, N, *n, x); if (i != -1) return i; if (*n == N) return -1; v[*n] = x; return *n ++; } Remoção – vetores não-ordenados ● Dado um valor x, como removê-lo do vetor v? REMOVE(v[0...(N-1)], n, x) i ← BUSCA-SEQUENCIAL(v[0...(N-1)], n, x) se i ≠ -1 então v[ i ] ← v[n – 1] n←n–1 Remoção – vetores não-ordenados ● Código em C do algoritmo de remoção: void remove(int *v, int N, int *n, int x) { int i = busca_sequencial(v, N, *n, x); if (i != -1) v[i] = v[-- *n]; } Remoção – vetores não-ordenados ● Codigo em C para remoção do valor x: void remove(item *v, int N, int *n, item x) { int i = busca_sequencial(v, N, *n, x); if (i != -1) v[i] = v[-- *n]; } Remoção – vetores não-ordenados ● Dado um índice i, como remover v[i]? Remoção – vetores não-ordenados ● Dado um índice i, como remover v[i]? REMOVE(v[0...(N-1)], n, x) se 0 <= i < n então v[ i ] ← v[n – 1] n←n–1 Remoção – vetores não-ordenados ● Código em C de remoção por índice: void remove(int *v, int N, int *n, int i) { if (0 <= i && i < n) v[i] = v[-- *n]; } Vetores não-ordenados ● ● Vetores sem elementos repetidos: – Busca: tempo O(n) – Inserção: tempo O(n) – Remoção por valor: tempo O(n) – Remoção por índice: tempo O(1) (constante) Permitindo elementos repetidos: – Inserção: tempo O(1) Simulação Na lousa Vetores ordenados ● Suponha que temos um vetor v: – N – número de posições alocadas; – n – número de elementos guardados em v. Valores de interesse: A 0 ● ● F 1 J 2 L 3 Valores lixo: P 4 F 5 Z 6 T 7 Z 8 G 9 No exemplo: N = 10, e n = 5. Também é costume supor que os valores de interesse são distintos. Busca – vetores ordenados ● ● ● Dado um valor x, como buscar x no vetor? É possível fazer melhor do que a busca seqüencial? Como você busca uma palávra no dicionário? Busca binária Na lousa