aulas.txt Seg Nov 28 17:00:12 2005 1 MAC0122 - Princípios de Desenvolvimento de Algoritmos Zé Augusto Sala 102 Bloco C IME - [email protected]Página da disciplina: http://latin.ime.usp.br/moodle/ Fazer inscrição: 1. leia instruções "NOVOS USUÁRIOS" 2. como nome e sobrenome use o seu nome e sobrenome, dividido arbitrariamente. Não use apelidos nem abreviaturas. Depois da inscrição, fazer a matrícula na disciplina. Avaliação: provas e exercícios-programa. ********************************************************************** Geral: - Técnicas de Programação - Análise de Algoritmos - Estrutura de Dados Tópicos: - recursão - listas ligadas - backtracking - algoritmos de ordenação e busca - busca de padrão ********************************************************************** Linguagem C. Linux: compilar com gcc gcc -Wall -ansi -pedantic -O2 programa.c -o programa Windows: - Dev-C++ - Ver páginas http://www.ime.usp.br/˜mac2166/devcpp/ http://www.ime.usp.br/˜mac2166/devcpp/devcppintro/ ********************************************************************** EP0: teste de entregas de EPs ********************************************************************** http://www.ime.usp.br/˜pf/mac122/aulas/temperatura.html // Programa conversor de temperaturas // ---------------------------------- // Este programa converte graus Fahrenheit // em graus Celsius e vice-versa. ////////////////////////////////////////// public class Conversor { static double celsiusParaFahrenheit (double c) { return 9.0 * c / 5.0 + 32.0; } static double fahrenheitParaCelsius (double f) { return 5.0 * (f - 32.0) / 9.0; } public static void main (String[] args)
63
Embed
aulas.txt Seg Nov 28 17:00:12 2005 1 - ime.usp.brhitoshi/mac0122-2012/aulas/aulasJose.pdf · 1. leia instruções "NOVOS USUÁRIOS" 2. como nome e sobrenome use o seu nome e sobrenome,
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
aulas.txt Seg Nov 28 17:00:12 2005 1
MAC0122 - Princípios de Desenvolvimento de Algoritmos
Página da disciplina: http://latin.ime.usp.br/moodle/Fazer inscrição:1. leia instruções "NOVOS USUÁRIOS"2. como nome e sobrenome use o seu nome e sobrenome, dividido arbitrariamente. Não use apelidos nem abreviaturas.
Depois da inscrição, fazer a matrícula na disciplina.
Avaliação: provas e exercícios-programa.
**********************************************************************Geral: - Técnicas de Programação - Análise de Algoritmos - Estrutura de Dados
Tópicos: - recursão - listas ligadas - backtracking - algoritmos de ordenação e busca - busca de padrão
**********************************************************************Linguagem C.
Linux: compilar com gccgcc -Wall -ansi -pedantic -O2 programa.c -o programa
Windows: - Dev-C++ - Ver páginas http://www.ime.usp.br/˜mac2166/devcpp/ http://www.ime.usp.br/˜mac2166/devcpp/devcppintro/
**********************************************************************EP0: teste de entregas de EPs**********************************************************************http://www.ime.usp.br/˜pf/mac122/aulas/temperatura.html
// Programa conversor de temperaturas// ----------------------------------// Este programa converte graus Fahrenheit// em graus Celsius e vice-versa.//////////////////////////////////////////
public class Conversor{ static double celsiusParaFahrenheit (double c) { return 9.0 * c / 5.0 + 32.0; }
System.out.print ("Temperatura em graus Fahrenheit: "); far = sc.nextDouble (); cel = fahrenheitParaCelsius (far); System.out.println ("igual a " + cel + " graus Celsius");
System.out.print ("Temperatura em graus Celsius: "); cel = sc.nextDouble (); far = celsiusParaFahrenheit (cel); System.out.println ("igual a " + far + " graus Fahrenheit"); }}
Eis o mesmo programa escrito em linguagem C:
/* Programa conversor de temperaturas// ----------------------------------// Este programa converte graus Fahrenheit// em graus Celsius e vice-versa./////////////////////////////////////// */
Comando composto: 0 ou mais comandos agrupado por chaves
é um comando!{ comando1 comando2 ... comandok}
Significado: agrupa 0 ou mais comandos em um único comando.
aulas.txt Seg Nov 28 17:00:12 2005 4
Ex.: { soma = soma + num; num = 10*53; }---------------------------------------------------------------------Comando whilewhile (condição) comandoSignificado: enquanto a condição for verdadeira, executecomando. comando é executado 0 ou mais vezes.Ex. while (num != 0){ soma = soma + num; scanf("%d",&num); }---------------------------------------------------------------------Condição: usa os operadores >, >=. <, <=, ==, !=, &&, ||, !---------------------------------------------------------------------Expressão: usa os operadores +, -, *, /, %---------------------------------------------------------------------Comando if:
if (condição) comando
Significado: executa <comando> se e somente se <condição> é verdadeira.---------------------------------------------------------------------Comando if-else:
if (condição) comando1else comando2
Significado: executa comando1 se e somente se condição é verdadeira;executa comando2 se e somente se condição é falsa.---------------------------------------------------------------------Operadores / e %/ divisão % resto da divisão5/2 é 2 5%2 é 11/2 é 0 1%2 é 110/6 é 1 10%6 é 4
Cuidado com números negativos:-5/2 = -2 ou -3, dependendo do compilador-5%2 = -1 ou +1, dependendo do compilador
Sempre é verdade que a == (a/b)*b+a%b---------------------------------------------------------------------Comando for
for (atrib1; condição; atrib2) comandoatrib1 e atrib2: atribuições sem o ;(O comando de atribuição é id=expressão;)
for (i=0; i < 5; i++) printf("%d ",i); for (i=0; i < 5; i++); printf("%d ",i);---------------------------------------------------------------------Prioridades de operadores:
Operador Associatividade() [] -> . esquerda para a direita! ˜ ++ -- - (tipo) * & sizeof direita para a esquerda* / % esquerda para a direita+ - esquerda para a direita<< >> esquerda para a direita< <= > >= esquerda para a direita== != esquerda para a direita& esquerda para a direita^ esquerda para a direita| esquerda para a direita&& esquerda para a direita|| esquerda para a direita?: direita para a esquerda= += -= *= /= %= &= ^= |= <<= >>= direita para a esquerda, esquerda para a direita
Operadore unários & +, -, and * têm maior prioridade do que na formabinária.---------------------------------------------------------------------abreviaturas:++ e --i++; equivale a i = i + 1;
+= *= /= -= %=a+=b; equivale a a=a+b;a+=(b+c)*d equivale a a = a + (b + c)*d;a*=b+c equivale a a = a*(b + c);x op=expressão; equivale a x = x op (expressão);
atribuição múltiplaa=b=c=0; equivale a a=0; b=0; c=0;a=b=c=x; equivale a a=x; b=x; c=x;
int a=0, b=0, c=0, d=1, e=2;---------------------------------------------------------------------
Constantes simbólicas: define
aulas.txt Seg Nov 28 17:00:12 2005 6
#include <stdio.h>#define TRUE 1#define FALSE 0#define CHAPEU 3.14protótipo de funçõesmainfunções
Usando o "#define nome valor" todas [quase] as ocorrências de "nome"no programa são substituídas por "valor".---------------------------------------------------------------------Comando de leitura: scanf("%d %d",&a,&b); [espaço não é necessário] leitura de dados via teclado. O programa pára e espera pela digitação de dois inteiros, separados por espaço em branco e seguidos de <enter> Cada %d corresponde a uma variável na ordem em que aparece.Comando printf("A soma e’ %d\n",soma); Imprime mensagem na tela do computador. Imprime ao invés do %d o valor da variável "soma" e ao invés de "\n" muda o cursor de linha.Ex.: printf("%d %d\n",a,b); printf("Valor de a = %d Valor de b = %d\n",a,b);Cada %d corresponde a uma variável na ordem em que aparece.
%d - inteiro base dez%f - float e impressão de double%lf - leitura de double%c - char---------------------------------------------------------------------Tipo real: float e double
definição: float x,y;No Dev-C++:Tamanhos de inteiros: entre -2^{31} e 2^{31}-1 (usa 4 bytes) entre -2.147.483.647-1 e 2.147.483.647
Tamanhos de double: (8 bytes)menor valor positivo: 2.2250738585072014e-308maior valor: 1.7976931348623157e+30815 dígitos de precisão
Tamanhos de float: (4 bytes)menor valor positivo: 1.175494351E-38maior valor: 3.402823466E+386 dígitos de precisão
Leitura: int n; float x; scanf("%f",&x); scanf("%f %d",&x,&n);
Impressão printf("%f",x); printf("x = %f e n = %d\n",x,n);
float x,y;
x = 1.23456789; y = 9.87654321; printf("%f %f\n",x,y);Imprime: 1.234568 9.876543 (6 casas depois da vírgula)
Operadores: +, -, *, /, >, ...
aulas.txt Seg Nov 28 17:00:12 2005 7
Operações envolvendo dois operandos float: resultado é um float, comoesperado.Operações envolvendo um operando int e um operando float: antes daoperação o operando int é convertido em float e o resultado daoperação é um float.
Atribuições:
int n;float x;
n=x; o valor de n será o valor de x truncado[n=-1.9; resulta em n == -1]x=n; produz o resultado esperado
Como fazer em C a atribuição x=1/4?Operador cast: (tipo) expressãoEfeito: o resultado de expressão é convertido ao tipo floatExemplo: x = (float) 1/4;Efeito: 1. o 1 é transformado em float 2. como 1 é float agora, o 4 é transformado em float antes da divisão 3. a divisão é executada com floats.Precedências: () (tipo) * / % + - < > <= >= != == && ||
Tipo char: elementos de um conjunto de "caracteres". São símbolos, letras, dígitos. Esse conjunto é codificado por uma tabela. Uma codificação bastante usada é o código ASCII (American Standard Code for Information Interchange). Tem 128 símbolos. Outras codificações: ISO-8859-1 (extensão do ASCII), Iso-latin-1, EBCDIC (Extended Binary Coded Decimal Interchange Code)
Comparação: produz resultados de acordo com a codificação usada. NoASCII’A’ < ’B’ < ... < ’Z’ ’a’ < ’b’ < ... < ’z’ ’0’ < ’1’ < ... < ’9’
caractere posição na tabela’\n’ 10’ ’ 32’0’ 48’A’ 65’a’ 97
aulas.txt Seg Nov 28 17:00:12 2005 8
Imprimindo um caractere como inteiro, a ordem do caractere no conjunto(ASCII) é impresso:Ex.: s=’a’; printf("%d\n",s);Imprime 97E vice-versa: printf("%c\n",97);Imprime a
Aritmética com char: s=’a’+1; resulta em s com valor ’b’
’0’+3 é igual ao caractere ’3’
Somando um char x com um inteiro n resulta no char correspondente a n posições a frente do char x
Tabela ASCII: Decimal/Character 0 NUL 1 SOH 2 STX 3 ETX 4 EOT 5 ENQ 6 ACK 7 BEL 8 BS 9 HT 10 NL 11 VT 12 NP 13 CR 14 SO 15 SI 16 DLE 17 DC1 18 DC2 19 DC3 20 DC4 21 NAK 22 SYN 23 ETB 24 CAN 25 EM 26 SUB 27 ESC 28 FS 29 GS 30 RS 31 US 32 SP 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ’ 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G 72 H 73 I 74 J 75 K 76 L 77 M 78 N 70 O 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ 96 ‘ 97 a 98 b 99 c 100 d 101 e 102 f 103 g 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w 120 x 121 y 122 z 123 { 124 125 } 126 ˜ 127 DEL**********************************************************************
comando switchExemplo: int mes; scanf("%d",&mes); switch (mes) { case 1: printf("janeiro\n"); break; case 2: printf("fevereiro\n"); break; ... case 12: printf("dezembro\n"); break; default: printf("nao sei\n"); break; }
Formato: switch(expressão){ case cte1: comandos1 case cte2: comandos2 ...
aulas.txt Seg Nov 28 17:00:12 2005 9
default: comandosk }
expressão: valor inteiro ou char
ctes: constantes distintas. Não podem ser expressões com variáveis.
Significado: o valor da expressão é calculado e uma constante com esse valor é procurada. Os comandos que seguem o case dessa constante são executado até o final do switch ou até um break ser encontrado. Caso nenhuma constante corresponda à expressão, os comandos do default são executados. O default é opcional e pode aparecer em qualquer posição. Caso não exista default e nenhuma constante corresponda a expressão, o comando switch não faz nada. Quando um break é encontrado é encerrada a execução do switch.
/* Calcula n! para n >= 0 */int fat(int n){ if (n <= 1) return 1; else return n*fat(n-1);}______________________________________________________________________
1. Um ou mais casos simples são resolvidos diretamente
2. Outros caso podem ser redefinidos em termos de problemas "maispróximos" aos casos simples.
3. Pela aplicação sucessiva do processo de redefinição mais cedo oumais tarde o problema é reduzido inteiramente aos casos simples.
Se é um caso simples resolva o problema diretamentesenão redefina o problema usando recursão______________________________________________________________________
Simulação
fat(4) /24| -------------------- | n = 4 | | n <= 1 é falso | / | devolva 4*fat(3) | 6 ------------------ | ------------------ -- | n = 3 | | n <= 1 é falso | / | devolva 3*fat(2) | 2 ------------------ | ------------------ -- | n = 2 | | n <= 1 é falso | / | devolva 2*fat(1) | 1 ------------------ | --------------------- -- | n = 1 | | n <= 1 é verdadeiro | | devolva 1 | ---------------------______________________________________________________________________
/* Calcula o maior elemento dentre inteiros V[0], V[1], ..., V[n-1], para n >= 1*/int maxr(int v[], int n){ int max;
if (n == 1) max = v[0]; else { max = maxr(v,n-1); if (max < v[n-1])
aulas.txt Seg Nov 28 17:00:12 2005 11
max = v[n-1]; } return max;}______________________________________________________________________
/* Calcula valor da soma V[0] + V[1] + ...+ V[n-1], para n >= 1 */
| 2 | 3 | 1 | 2 <---- parte inteira da divisão275 | 121 | 33 | 22 | 11 33 | 22 | 11 | 0 | <---- resto da divisão
/* Calcula máximo divisor comum entre m e n com m e n inteiros não-negativos sendo um deles positivo*/int mdc(int m, int n){ if (n == 0) return m; else return mdc(n, m%n);}
A B C ---|--- | | ----|---- | | -----|----- | | ------|------ | | -------|------- | | --------|-------- | |____________________________________________________________________
Mover n discos de diâmetros diferentes do pino A para o pino C usandopino B quando necessário. Os movimentos seguem as regras:1. Somente um disco pode ser movido por vez e esse disco precisar ser o disco no topo do pino.2. Um disco maior nunca pode ser colocado sobre um disco menor.
Idéia: para mover n discos do pino *origem* para o pino destino:se n é 0, não faz nadasenão 1. mova n-1 discos de *origem* para *auxiliar* usando *destino* como auxiliar 2. mova disco n de *origem* para *destino* 3. mova n-1 discos de *auxiliar* para *destino* usando *origem* como auxiliar
-------- ------------------------ | n = 0 | | n = 1 | | | | origem = ’A’ | | | | aux = ’B’ | -------- | destino = ’C’ | -------- ------------------------- | Hanoi(0, ’A’, ’C’, ’B’) | | n = 0 | | n = 2 | | mova 1 de ’A’ para ’C’ | | | | origem = ’A’ | | Hanoi(0, ’B’, ’A’, ’C’) | | | | aux = ’C’ | ---------------------- -------- | destino = ’B’ | -------- | Hanoi(1, ’A’, ’B’, ’C’) | ------------------------- | n = 0 | | mova 2 de ’A’ para ’B’ | | n = 1 | | | | Hanoi(1, ’C’, ’A’, ’B’) | | origem = ’C’ | | | ------------------------- | aux = ’A’ | -------- | destino = ’B’ | -------- | Hanoi(0, ’C’, ’B’, ’A’) | | n = 0 | ------------------------- | mova 1 de ’C’ para ’B’ | | || n = 3 | | Hanoi(0, ’A’, ’C’, ’B’) | | || origem = ’A’ | ------------------------ --------| aux = ’B’ || destino = ’C’ | --------| Hanoi(2, ’A’, ’C’, ’B’) | ------------------------- | n = 0 || mova 3 de ’A’ para ’C’ | | n = 1 | | || Hanoi(2, ’B’, ’A’, ’C’) | | origem = ’B’ | | | ------------------------- | aux = ’C’ | -------- | destino = ’A’ | -------- ------------------------- | Hanoi(0, ’B’, ’A’, ’C’) | | n = 0 | | n = 2 | | mova 1 de ’B’ para ’A’ | | | | origem = ’B’ | | Hanoi(0, ’C’, ’B’, ’A’) | | | | aux = ’A’ | ------------------------- --------
aulas.txt Seg Nov 28 17:00:12 2005 13
| destino = ’C’ | | Hanoi(1, ’B’, ’C’, ’A’) | ------------------------- -------- | mova 2 de ’B’ para ’C’ | | n = 1 | | n = 0 | | Hanoi(1, ’A’, ’B’, ’C’) | | origem = ’A’ | | | ------------------------- | aux = ’B’ | | | | destino = ’C’ | -------- | Hanoi(0, ’A’, ’C’, ’B’) | -------- | mova 1 de ’A’ para ’C’ | | n = 0 | | Hanoi(0, ’B’, ’A’, ’C’) | | | ------------------------- | | --------
Seguindo as flechas:
mova 1 de ’A’ para ’C’mova 2 de ’A’ para ’B’mova 1 de ’C’ para ’B’mova 3 de ’A’ para ’C’mova 1 de ’B’ para ’A’mova 2 de ’B’ para ’C’mova 1 de ’A’ para ’C’----------------------Total de movimentos: 7Total de chamadas: 15
Em geral: para n discos: 2^{n} - 1 movimentos 2^{n+1} - 1 chamadas da função
/* Imprime movimento de torres de Hanoi para n discos para n >= 0*/
void Hanoi(int n, char origem, char auxiliar, char destino){ if (n > 0) { Hanoi(n-1, origem, destino, auxiliar); printf("Mova disco %d do pino %c para o pino %c\n", n, origem, destino); Hanoi(n-1, auxiliar, origem, auxiliar); }}______________________________________________________________________
Tempo para computar Fib(n+1)--------------------------- aprox 1.6Tempo para computar Fib(n)______________________________________________________________________
Versão iterativa: muito mais eficiente
int Fib(int n){ int ant, atual, i;
if (n <= 1) return n;
ant = 0; atual = 1; for (i = 1; i < n; i++) { /* atual é Fib(i) */ atual = atual + ant; ant = atual - ant; } return atual;}
A: D <- A | A -> BB: C ^ B -> B | AC: B -> C ^ C <- DD: A | D <- D ^ C
| flecha para baixo
#define BRANCO 255#define PRETO 0
int main(){ /* leitura de dados */ /* criação da imagem */ /* determinação do tamanho da aresta */ /* determinação da posição inicial do desenho */ a(imagem, ordem, &x, &y, tamanho_aresta); /* Gravação do arquivo */
return 0;}
/* A */void a (Imagem imagem, int k, int *x, int *y, int comprimento) { if (k > 0) { d(imagem, k - 1, x, y, comprimento); DesenhaeMove(imagem, x, y, -comprimento, 0, PRETO); a(imagem, k-1, x, y, comprimento); DesenhaeMove(imagem, x, y, 0, -comprimento, PRETO); a(imagem, k-1, x, y, comprimento); DesenhaeMove(imagem, x, y, comprimento, 0, PRETO); b(imagem, k-1, x, y, comprimento); }}
/* B */void b (Imagem imagem, int k, int *x, int *y, int comprimento) { if (k > 0) { c(imagem, k-1, x, y, comprimento); DesenhaeMove(imagem, x, y, 0, comprimento, PRETO); b(imagem, k-1, x, y, comprimento); DesenhaeMove(imagem, x, y, comprimento, 0, PRETO); b(imagem, k-1, x, y, comprimento); DesenhaeMove(imagem, x, y, 0, -comprimento, PRETO); a(imagem, k-1, x, y, comprimento); }}
/* C */void c (Imagem imagem, int k, int *x, int *y, int comprimento) { if (k > 0) { b(imagem, k-1, x, y, comprimento); DesenhaeMove(imagem, x, y, comprimento, 0, PRETO); c(imagem, k-1, x, y, comprimento); DesenhaeMove(imagem, x, y, 0, comprimento, PRETO); c(imagem, k-1, x, y, comprimento); DesenhaeMove(imagem, x, y, -comprimento, 0, PRETO); d(imagem, k-1, x, y, comprimento); }}
aulas.txt Seg Nov 28 17:00:12 2005 16
/* D */void d (Imagem imagem, int k, int *x, int *y, int comprimento) { if (k > 0) { a(imagem, k-1, x, y, comprimento); DesenhaeMove(imagem, x, y, 0, -comprimento, PRETO); d(imagem, k-1, x, y, comprimento); DesenhaeMove(imagem, x, y, -comprimento, 0, PRETO); d(imagem, k-1, x, y, comprimento); DesenhaeMove(imagem, x, y, 0, comprimento, PRETO); c(imagem, k-1, x, y, comprimento); }}
/* Desenha o segmento de (*x0, *y0) até (*x0+deltax, *y0+deltay), alterando o valor de *x0 e *y0 para *x0+deltax e *y0+deltay */void DesenhaeMove(Imagem imagem, int *x0, int *y0, int deltax, int deltay, int cor){ DesenhaSegmento(imagem, *x0, *y0, *x0 + deltax, *y0 + deltay, cor); *x0 = *x0 + deltax; *y0 = *y0 + deltay;}**********************************************************************
Variáveis tipo endereço:
Como fazer uma função que troca os valores de duas variáveis?
Obs.: Vamos sempre pensar endereços como inteiros, embora o C nãoespecifique isso: não podemos manipular endereços como manipulamosinteiros.
Ocorrências de a,b,c,... no programam se referem ao conteúdo dasvariáveis. Como acessar os endereços?
Variáveis tipo endereço:int a, b, c, *end1, *end2, *end3;float x, y, z, *w;char s, t, u, *es, *et, *eu;
Atribuições:end1=&a; a=10;b=78; end2=&b;end3=&c;A seguinte atribuição, depois das atribuições acima, equivale a c=a+b;*end3 = *end1 + *end2;
Operadores * e &:&a - endereço da variável a*p - conteúdo do endereço armazenado em p. p também é conhecido como apontador ou ponteiro.
*end1, *end2 e *end3 devem ser pensadas como variáveis inteiras se end1, end2 e end3 são endereços de inteiros.
NãO VáLIDO:
w = &a; pois chapeu1 armazena endereço de float e a é inteiroend1 = chapeu; endereços de tipos distintos não se confundem&a = eb; NUNCA podemos mudar o endereço de uma variável
malloc(expressão inteira) - devolve um apontador (endereço) para umbloco de memória com _expressão_ bytes, ou devolve NULL se não foipossível alocar a memória
z = &p; | endereço (inventado) | conteúdoprintf("%d\n", **z); a | 5224 | 5**z = 12; p | 5232 | 5224printf("%d\n", a); z | 5236 | 5232 ^ __| estes endereços não podem ser mudados----------------------------------------------------------------------
for (i = 0; i < 8; i++) a[i] = malloc(30*sizeof(int));
cada a[i] é um vetor de inteiros
/* Aloca memória para uma matriz mXn de inteiros *//* Devolve NULL se não foi possível alocar a memória */int **AlocaMatriz(int m, int n){ int **a; int i, j;
a = malloc(m*sizeof(int *)); if (a == NULL) return NULL;
for (i = 0; i < m; i++){ a[i] = malloc(n*sizeof(int)); if (a[i] == NULL){ for (j = 0; j < i; j++) free(a[j]);
aulas.txt Seg Nov 28 17:00:12 2005 20
free(a); return NULL; } }
return a;}
/* Libera (free) a memória alocada para uma matriz de inteiros com m linhas */void LiberaMatriz(int **A, int m){ int i;
typedef struct cel { int valor; struct cel *prox;} celula;
celula *insere(celula *inicio, int n);void LiberaLista(celula *inicio);void LiberaListaR(celula *inicio);void imprime(celula *inicio);celula *busca(celula *inicio, int n);celula *buscaR(celula *inicio, int n);celula *Remove(celula *inicio, int n); /* remove e’ funcao do stdio.h */
int main(){ celula *inicio, *p; int n;
inicio = NULL; /* lista vazia */
/* Le inteiros ate um 0 ser digitado */ printf("Digite um inteiro (0 para terminar): "); scanf("%d", &n); while (n != 0) { inicio = insere(inicio, n); if (inicio == NULL) { printf("Sem memória\n"); return 1; } printf("Digite um inteiro (0 para terminar): "); scanf("%d", &n); }
imprime(inicio);
printf("Digite numero a ser procurado: "); scanf("%d", &n);
printf("Digite numero a ser removido: "); scanf("%d", &n);
inicio = Remove(inicio, n); imprime(inicio);
LiberaLista(inicio);
return 0;}
/* Insere celula com valor n no inicio da lista devolve endereco do início da nova lista ou NULL se nao foi possivel fazer a insercao*/
aulas.txt Seg Nov 28 17:00:12 2005 25
celula *insere(celula *inicio, int n){ celula *nova;
nova = malloc(sizeof(celula)); /* |nova| -> |_?_|_?_| */
if (nova == NULL) return NULL;
nova->valor = n; nova->prox = inicio;
return nova;}
/* Libera memoria alocada para lista */void LiberaLista(celula *inicio){ celula *ant;
while (inicio != NULL) { ant = inicio; inicio = inicio->prox; free(ant); }}
/* Libera memoria alocada para lista */void LiberaListaR(celula *inicio){ celula *ant;
if (inicio != NULL) { ant = inicio; inicio = inicio->prox; free(ant); LiberaListaR(inicio); }}
/* Imprime valores armazenados na lista */void imprime(celula *inicio){ while (inicio != NULL) { printf("%d ", inicio->valor); inicio = inicio->prox; } printf("\n");}
/* Devolve endereco de celula com valor n ou NULL caso esse valor nao apareca na lista*/celula *busca(celula *inicio, int n){ while (inicio != NULL) { if (inicio->valor == n) return inicio; inicio = inicio->prox; } return NULL;}
aulas.txt Seg Nov 28 17:00:12 2005 26
/* Devolve endereco de celula com valor n ou NULL caso esse valor nao apareca na lista*/celula *buscaR(celula *inicio, int n){ if (inicio == NULL || inicio->valor == n) return inicio; return busca(inicio->prox,n);}
/* Remove, se existir, celula com valor n Devolve lista sem a celula, com valor de inicio possivelmente alterado*/celula *Remove(celula *inicio, int n){ celula *corrente, *ant;
/* Remove primeiro da fila, devolvendo seu valor. Não pode ser usado com fila vazia*/int remove_fila(celula **ini, celula **fim){ int valor; celula *prim;
prim = *ini; valor = prim->valor;
*ini = (*ini)->prox; if (*ini == NULL) *fim = NULL;
/* Remove topo da pilha, alterando valor do topo Devolve valor armazandado no topo Não pode ser usado com pilha vazia*/int desempilha(celula **topo){ int valor; celula *aux;
aux = *topo; valor = aux->valor; *topo = (*topo)->prox; free(aux);
#define D 10 /* numero maximo de digitos de um numero */#define TAMANHO 80 /* numero maximo de caracteres na expressao infixa */
/* Pilha de caracteres para auxiliar montagem da expressao posfixa a partir da expressao infixa */typedef struct pilha_aux_ { char simbolo; struct pilha_aux_ *prox;} pilha_aux;
int calcula_posfixa(posfixa *ini){ valores *topo; int valor1, valor2, valor; char *s;
topo = NULL; while (ini != NULL){ s = remove_pos(&ini); switch (s[0]){ case ’+’: valor1 = des_val(&topo); valor2 = des_val(&topo); topo = emp_val(topo, valor1+valor2); break; case ’*’: valor1 = des_val(&topo); valor2 = des_val(&topo); topo = emp_val(topo, valor1*valor2); break; case ’-’: valor1 = des_val(&topo); valor2 = des_val(&topo); topo = emp_val(topo, valor2-valor1); break; case ’/’: valor1 = des_val(&topo); valor2 = des_val(&topo); topo = emp_val(topo, valor2/valor1); break; default: /*sscanf(ini->s,"%d",&valor);*/ valor = atoi(s); topo = emp_val(topo,valor); break; } free(s); } valor = des_val(&topo); if (topo != NULL){ printf("Erro em expressao posfixa\n"); exit(-1); } return valor;}
valores *emp_val(valores *topo, int n){ valores *nova; nova = malloc(sizeof(valores)); if (nova == NULL){ printf("Erro Memoria\n"); exit(-1); } nova->valor = n;
aulas.txt Seg Nov 28 17:00:12 2005 33
nova->prox = topo; return nova;}
int des_val(valores **topo){ valores *aux; int valor;
if (*topo == NULL){ printf("Erro na pilha de valores\n"); exit(-1); } aux = *topo; valor = aux->valor; *topo = (*topo)->prox; free(aux); return valor;}
O valor da primeira célula é irrelevante: ela serve apenas para marcaro início da lista. O endereço da primeira célula nunca muda. Issofacilita a implementação de algumas funções.
typedef struct _celula_ { int valor; struct cel *prox;} celula;
Lista com 3 células:
|_|
|___|___| -> |___|___| -> |___|___| -> |___|___| cabeçavalor faz parte da lista
/* Insere celula com valor n no inicio da lista devolve endereco do início da nova lista ou NULL se nao foi possivel fazer a insercao
aulas.txt Seg Nov 28 17:00:12 2005 35
*/celula *insere(celula *inicio, int n){ celula *nova;
nova = malloc(sizeof(celula)); /* |nova| -> |_?_|_?_| */
if (nova == NULL) return NULL;
nova->valor = n; nova->prox = inicio;
return nova;}
/* Lista sem cabeça Remove, se existir, celula com valor n Devolve lista sem a celula, com valor de inicio possivelmente alterado*/celula *Remove(celula *inicio, int n){ celula *corrente, *ant;
corrente = inicio; ant = NULL;
while (corrente != NULL && corrente->valor != n) { ant = corrente; corrente = corrente->prox; }
if (corrente == NULL) /* n nao foi encontrado */ return inicio;
if (ant == NULL) /* n esta no inicio */ inicio = inicio->prox; else ant->prox = corrente->prox;
free(corrente); return inicio;}
/* Lista com cabeça Remove, se existir, celula com valor n*/void Remove(celula *inicio, int n){ celula *corrente, *ant;
corrente = inicio->prox; ant = inicio;
while (corrente != NULL && corrente->valor != n) { ant = corrente; corrente = corrente->prox; }
if (corrente != NULL) {/* n foi encontrado */ ant->prox = corrente->prox; free(corrente);
Dados x e um vetor v[0], v[1], ..., v[n-1], determinar se x ocorre novetor e, em caso positivo, qual índice i para o qual v[i] = x
Busca sequencial
aulas.txt Seg Nov 28 17:00:12 2005 37
/* devolve i se existe i tal que v[i] = x devolve -1 caso contrário.*/int ocorre(int x, int n, int v[]){ int i; i = 0; while (i < n && v[i] != x) i++; if (i < n) return i; else return -1;}
Número de operações no pior caso --- x não ocorre no vetor: 1 (atribuição) i = 0 n+1 comparações i < n (while) n comparações v[i] != x n atribuições i++ 1 comparação i < n (if)
Total: n+1 atribuições 2n+1 comparações
Número de operações proporcional a n
Busca binária: vetor ordenado
/* devolve i se existe i tal que v[i] = x devolve -1 caso contrário.*/
int buscabinaria(int x, int n, int v[]){ int e, m, d;
e = 0; d = n-1; while (e <= d) { m = (e + d)/2; if (v[m] == x) return m; if (v[m] < x) e = m+1; else d = m-1; } return -1;}
Cada vez que o while é executado, o valor de "d-e" é no máximo ametade do valor anterior. O valor inicial de "d-e" é n-1. Onúmero de vezes que n pode ser dividido por 2 a ainda se manter maiorou igual a 1 é aproximadamente log n. Portanto, o número de operaçõesexecutadas pela função é proporcional a log n.Uma análise detalhada é mais confusa e, como veremos, desnecessária.
Eliminamos constantes multiplicativas: (a) padrão de crescimento é o mesmo (b) na análise de tempo as constantes podem ser alteradas pelo aumento de velocidades das CPU’s (c) velocidades são diferentes para operações diferentes
Eliminamos termos com contribuição assintótica desprezível: estamosenteressados em valores grandes de n.
IMPORTANTE: esse tipo de análise tem se mostrado útil
Definição formal:
Dizemos que g(n) é O(f(n)) se existem constantes positivas c e n_0tal que g(n) <= c.f(n) para todo n >= n_0
Ordenação por seleção: 1. seleciona o maior e coloca na última posição do vetor. 2. seleciona o segundo maior e coloca na penúltima posição do vetor. ..../* Rearranja o vetor v[0..n-1] em ordem crescente.*/
void selecao(int n, int v[])
aulas.txt Seg Nov 28 17:00:12 2005 39
{ int i, indice;
for (i = n; i > 1; i--) { indice = maior(i, v); troca(v, indice, i-1); }}
/* Devolve o indice do maior elemento de v */int maior(int n, int v[]){ int i, indice;
indice = 0;
for (i = 1; i < n; i++) if (v[i] > v[indice]) indice = i;
return indice;}
/* troca v[i] com v[j] */void troca(int v[], int i, int j){ int aux;
aux = v[i]; v[i] = v[j]; v[j] = aux;}
Número de operações:
-- O número de operações da função maior é proporcional a n -- O número de operações da função troca é constante -- Número de operações da função seleção: em cada execução do "for" o número de operações é proporcional a i (função maior) mais uma constante (função troca) O total de operações, considerando i = n, n-1, ..., 2, 1 é proporcional a n + n-1 + n-2 + n-3 + ... + 2 + 1 = (n+1)n/2 = O(n^2)
1. ordenamos uma segmento inicial do vetor 2. fazemos a inserção do próximo elemento em sua posição correta
void insercao(int n, int v[]){ int i, j, x;
for (i = 1; i < n; i++) { /* segmento v[0], v[1], ..., v[i-1] já ordenado */ x = v[i]; j = i - 1; while (j >= 0 && x < v[j]) { v[j+1] = v[j]; j--; } v[j+1] = x; }}
aulas.txt Seg Nov 28 17:00:12 2005 40
Número de operações: -- O número de operações do "for" mais externo é proporcional a i -- O número total de operação é proporcional a 1 + 2 + 3 + .. + n-2 + n-1 + n = (n+1)n/2 = O(n^2)
inicio = 0 fim = 3 inicio = 4 fim = 7 [25 37 56 58] [19 30 73 95]
inicio = 0 fim = 7 [19 25 30 37 56 58 73 95]
void mergesort(int *v, int inicio, int fim){ int meio;
if (inicio < fim){ meio = (inicio + fim)/2; mergesort(v, inicio, meio); mergesort(v, meio+1, fim); intercala(v, inicio, meio, fim); }}
/* Copia v[inicio], ...,v[meio] em w[0], ..., w[meio-inicio] e depois intercala w[0], ..., w[meio-inicio] com v[meio+1], ..., v[fim] colocando o resultado da intercalacao em v[inicio], ..., v[fim]*/void intercala(int *v, int inicio, int meio, int fim){ int *w; int i, j, k, n;
n = meio - inicio + 1; w = alocavetor(n);
for (i=0; i < n; i++) w[i] = v[i+inicio];
k = inicio; i = 0; j = meio+1;
while (i < n && j <= fim){ if (w[i] < v[j]) v[k++] = w[i++];
1. Escolha um pivô2. Rearranje ios elementos do vetor de forma a deixar os menores do que o pivô no início e os maiores no fim.3. Ordene o início e fim do vetor
/* Escolhe v[fim] como pivô, rearranja vetor e devolve limite tal que v[limite] = pivo e para k < limite vale que v[k] <= pivô e para k > limite vale que v[k] > pivo*/int particiona(int *v, int inicio, int fim){ int pivo, i, j, aux;
i = inicio - 1; pivo = v[fim]; for (j = inicio; j < fim; j++) { if (v[j] <= pivo) { i++; aux = v[i]; v[i] = v[j]; v[j] = aux; } }
/* Busca celula com valor n em uma arvore de busca binaria; * devolve NULL caso nao exista tal celula */arvore *busca(arvore *raiz, int n){ if (raiz == NULL || n == raiz->valor) return raiz; if (n < raiz->valor) return busca(raiz->esq,n); else return busca(raiz->dir,n);}
/* Acha a celula de valor minimo de uma arvore de busca binaria */arvore *minimo(arvore *x){ if (x == NULL) return NULL; while (x->esq != NULL) x = x->esq; return x;}
/* Acha a celula de valor maximo de uma arvore de busca binaria */arvore *maximo(arvore *x){ if (x == NULL) return NULL; while (x->dir != NULL) x = x->dir; return x;}
Sucessor de uma célula x: célula y com menor y->valor tal quey->valor > x->valor
15 / \ 6 18 / \ / \ 3 7 17 20 / \ \2 4 13 / 9
sucessor(x): mínimo de x->dir ou (caso x->dir == NULL) primeiroancestral y com y->valor > x->valor
/* Encontra a célula sucessora da celula x em uma arvore de busca binaria * devolve NULL se a x->valor é máximo */arvore *sucessor(arvore *x);
aulas.txt Seg Nov 28 17:00:12 2005 48
{ arvore *y;
if (x == NULL) return NULL; if (x->dir != NULL) return minimo(x->dir); y = x->pai;---------------------------------------- while (y != NULL && x == y->dir){ x = y; y = y->pai; }---------------------------------------- while (y != NULL && y->valor < x->valor){ (alternativa) y = y->pai;---------------------------------------- return y;}
/* Insere nova celula com valor n em uma arvore de busca binaria * devolve nova raiz da arvore */arvore *insercao(arvore *raiz, int n){ arvore *nova, *ant, *aux;
nova = malloc(sizeof(arvore)); if (nova == NULL){ printf("Erro memoria\n"); exit(-1); } nova->valor = n; nova->pai = nova->esq = nova->dir = NULL; if (raiz == NULL) return nova; /* arvore estava vazia; nova agora e’ a raiz */ aux = raiz; while (aux != NULL){ ant = aux; if (n < aux->valor) aux = aux->esq; else aux = aux->dir; } nova->pai = ant; if (n < ant->valor) ant->esq = nova; else ant->dir = nova; return raiz; /* raiz nao mudou */}
Caso 3: z tem dois filhos - y, sucessor de z, tem no máximo 1 filho (o direito) y é removido e seu valor copiado em z
y - célula a ser removidaCasos 1 e 2: y é o próprio zCaso 3: sucessor de zx - filho de y; pode ser NULL
/* Remove celula apontada por z de uma arvore de busca binaria * devolve nova raiz da arvore */arvore *remocao(arvore *raiz, arvore *z){ arvore *y, *x;
/* determinacao de y que sera’ removido */ if (z->esq == NULL || z->dir == NULL) /* z tem 0 ou 1 filho; y é o proprio z */ y = z; else{ y = sucessor(z); /* z tem 2 filhos; y é o sucessor de z */ z->valor = y->valor; } Situações possíveis /* determinacao do filho de y */ if (y->esq != NULL) y->pai O O y->pai x = y->esq; / \ else y O 0 y y 0 raiz x = y->dir; / / / /* acerta o apontador de x, o filho de y */ x x x if (x != NULL) tanto faz se x->pai = y->pai; x é filho esq ou dir /* acerta o apontador do pai de y */ if (y->pai == NULL) raiz = x; /* y é raiz e sera’ removido */ else /* y nao é raiz */ if (y == y->pai->esq) /* y é filho esquerdo? */ y->pai->esq = x; else y->pai->dir = x;
Para muitos problemas o processo de solução consiste em a cada passotomar uma decisão dentre um certo número de possibilidade. Se asdecisões são boas, uma solução é encontrada. Se ficar claro que algumadecisão errada foi tomada, essa decisão é alterada e se tentanovamente encontrar a solução.
Objetivo: sair do labirintoDecisões: andar Norte, Leste, Sul ou Oeste.
A posição marcada com ’0’ indica uma posição já visitada.
Casos simples: 1. A posição está fora do labirinto: a saída foi encontrada. 2. A posição é parede 3. A posição já está marcada com ’0’
Caso Geral: 1. Marque a posição com ’0’ 2. Tente cada um dos 4 possíveis movimentos 3. Se algum movimento der certo, pare com a solução e devolva 1 (recursão) 3. Caso nenhum movimento leva à solução, desmarque a posição e devolva 0
Função recursiva para Labirinto
1. Se a posição está fora do labirinto, deolva 1 (solução encontrada) 2. Se a posiçã0 está marcada ou é parede, devolva 0 (solução impossível) 3. Marque a posição com ’0’ 4. Chame a função recursivamente para movimento ao Norte (depois Leste, Sul e Oeste); se 1 é devolvido, então devolva 1 5. Desmarque a posição 6. Devolva 0
Colocar, se possível, n rainhas em um tabuleiro nXn sem que duas delasse ataquem
Idéia: uma rainha para cada linha. Na linha, todas as colunas são tentadas.
Exs para n=2, n=3, n=4
aulas.txt Seg Nov 28 17:00:12 2005 51
Representação do tabuleiro: matriz de char com ’ ’ ou ’R’ em cada entrada.
/* Programa para resolver o problema das n rainhas num tabuleiro nXn */#include <stdio.h>#include <stdlib.h>
char **alocamatriz(int m, int n);void libera(char **tab, int m);int colocarainhas(char **tab, int x, int y, int n);int atacada(char **tab, int x, int y, int n);void impressao(char **tab, int m, int n);
int main(){ int n, i, j; char **tab;
printf("Tamanho do tabuleiro: "); scanf("%d",&n); tab = alocamatriz(n, n); if (tab == NULL){ printf("Leitura nao pode ser feita\n"); return 1; }
for (i = 0; i < n; i++) for (j = 0; j < n; j++) tab[i][j] = ’ ’;
if (colocarainhas(tab, 0, 0, n)) impressao(tab,n,n); else printf("problema sem solucao\n");
libera(tab,n); return 0;}
void impressao(char **tab, int m, int n){ int i, j;
for (i = 0; i < m; i++){ for (j = 0; j < n; j++) printf("|%c", tab[i][j]); printf("|\n"); }}
/* Tenta colocar as rainhas x, x+1, ..., n-1 nas linhas x, x+1, ..., n-1 * a partir da posicao (x,y) * Devolve 1 se deu para colocar * Devolve 0 caso contrario */int colocarainhas(char **tab, int x, int y, int n){ /* coluna válida? */ if (y == n) return 0;
/* posição atacada? */ if (atacada(tab,x,y,n)) return colocarainhas(tab,x,y+1,n);
aulas.txt Seg Nov 28 17:00:12 2005 52
tab[x][y] = ’R’;
/* última rainha? */ if (x == n-1) return 1;
/* Faltam rainhas... */ if (colocarainhas(tab,x+1,0,n)) return 1;
char **alocamatriz(int m, int n){ char **tab; int i, j;
tab = malloc(m*sizeof(char *)); if (tab == NULL) return NULL;
for (i = 0; i < m; i++){ tab[i] = malloc(n*sizeof(char)); if (tab[i] == NULL){ for (j = 0; j < i; j++) free(tab[j]); free(tab); return NULL; } } return tab;}
void libera(char **tab, int m){ int i;
for (i=0; i < m; i++) free(tab[i]); free(tab);}
/* Verifica se a posicao (x,y) esta’ atacada por alguma das rainhas colocadas nas * linhas 0, 1, .., x-1 * Devolve 1 caso a posicao esteja atacada; devolve 0 caso contrario */int atacada(char **tab, int x, int y, int n){ int i;
/* Verifica coluna */ for (i = 0; i < x; i++) if (tab[i][y] == ’R’) return 1;
/* Verifica uma diagonal */ for (i = 0; x-i >= 0 && y-i >= 0; i++) if (tab[x-i][y-i] == ’R’) return 1;
aulas.txt Seg Nov 28 17:00:12 2005 53
/* Verifica outra diagonal */ for (i = 0; x - i >= 0 && y+i < n; i++) if (tab[x-i][y+i] == ’R’) return 1;
return 0;}
********************************************************************** Busca de palavras em texto
Determinar o número de ocorrências de uma palavra em um texto.
Dados: um vetor p com m caracteres um vetor t com n caracteres
Exemplo: p = ANA t = ANA E MARIANA GOSTAM DE BANANA
Número de ocorrências: 4
Idéia: 1. Compara p com cada posição de t, da esquerda para a direita.2. Para comparar p com uma posição k de t, compara da direita para aesquerda. Ou seja, compara p[m-1] com t[k-1], depois p[m-2] com t[k-2]etc.
/* Recebe vetores p com m >= 1 caracteres e vetor t com n >= 0 caracteres e devolve o número de ocorrências de p em t.*/
int trivial (unsigned char p[], int m, unsigned char t[], int n){ int i, k, ocorre = 0; for (k = m; k <= n; k++) { for (i = 1; i <=m && p[m-i] == t[k-i]; i++); if (i == m+1) ocorre++; } return ocorre;}
O uso do unsigned garante que código ASCII usará valore de 0..255[poderia ser de -128..127]
/* Recebe vetores p com m>= 1 caracteres e vetor t com n >= 0 caracteres e devolve o número de ocorrências de p em t.*/int boyermoore1 (unsigned char p[], int m, unsigned char t[], int n){ int ult[256]; int i, k, ocorre;
/* pré-processamento do padrão p */ for (i = 0; i < 256; ++i) ult[i] = -1; for (i = 0; i < m; ++i) ult[p[i]] = i;
/* busca do padrão p no texto t */
aulas.txt Seg Nov 28 17:00:12 2005 55
ocorre = 0; k = m; while (k <= n) { for (i = 1; i <=m && p[m-i] == t[k-i]; i++); if (i == m+1) ocorre++;
if (k < n) k += m - ult[t[k]]; else k++; /* sai do while */ } return ocorre;}
Geração dos subconjuntos de {1,2,3}{}, {1}, {2}, {3}, {1,2}, ...11 21 2 31 322 33
Estratégia: - subconjuntos representados em um vetor s - tamanho corrente do vetor: i+1 - soma 1 em s[i]. Se s[i] <= n, imprime o subconjunto e coloca mais um elemento no vetor com valor igual ao s[i]; senão, diminui valor de i
s = (0)i = 0, s = (1) imprime e altera s para (1 1)i = 1, s = (1 2) imprime e altera s para (1 2 2)i = 2, s = (1 2 3) imprime e não altera si = 2, s = (1 2 4) diminui valor de ii = 1, s = (1 3) imprime e não altera si = 1, s = (1 4) diminui valor de ii = 0, s = (2) imprime e altera s para (2 2)i = 1, s = (2 3) imprime e altera s para (2 3 3)i = 2, s = (2 3 4) diminui ii = 1, s = (2 4) diminui ii = 0, s = (3) imprime altera s para (3 3)i = 1, s = (3 4) diminui i1 = 0, s = (4) diminui ii = -1, pára
Aplicação: dados um inteiro k>0 e um conjunto de inteiros v = {v_{0},v_{1}, v_{n-1}} imprimir todos os subconjuntos de v cuja soma é k.
/* Imprime o subconjunto de v representado por s se a soma dos elementos do subconjunto é igual a k*/void verifica(int *v, int *s, int m, int k){ int soma, i;
soma = 0;
for(i=0; i < m; i++) soma += v[s[i]-1];
if (soma == k){ for(i=0; i < m; i++) printf("%d ", v[s[i]-1]); printf("\n"); }}
/* Gera os subconjuntos de v e testa para soma igual a k */void soma_sub(int k, int *v, int n){ int *s, i;
s = malloc(n*sizeof(int)); if (s == NULL) { printf("Sem memoria\n"); exit(1); } s[0] = 0; i = 0;
while (i >= 0){ s[i]++; if (s[i] <= n){ verifica(v, s, i+1, k); if (i+1 < n){ i++; s[i] = s[i-1]; } } else i--; }
Dados m e n, imprimir todos os subconjuntos de {1, 2, ..., m} com nelementos.m = 4, n = 2 m = 5 n = 31 2 1 2 31 3 1 2 41 4 1 2 52 3 1 3 42 4 1 3 53 4 1 4 5 2 3 4 2 3 5 2 4 5 3 4 5
Estratégia: gerar a próxima combinação a partir da anterior
/* Gera proxima combinacao de m n-a-n, representada no vetor v * Pos: devolve 1 se existe proxima combinacao; 0 caso contrario */int geraproxima(int *v, int m, int n){ int i;
i = n-1; /* encontra v[i] que pode ser aumentado */ while(i >= 0 && v[i] == m-n+i+1) i--;
/* nenhum v[i] pode ser aumentado */ if (i < 0) return 0;
/* aumenta v[i] */ v[i]++; /* preenche resto da combinação */ for (i++; i < n; i++) v[i] = v[i-1]+1;
return 1;}
void comb(int m, int n){ int *v, i,cont=0;
v = malloc(n*sizeof(int)); if (v == NULL) { printf("Sem memória\n"); exit(1); }
/* prepara primeira combinação */ for (i = 0; i < n; i++) v[i] = i+1; printf("%2d: ",++cont);
aulas.txt Seg Nov 28 17:00:12 2005 60
imprime(v,n);
while (geraproxima(v,m,n)){ printf("%2d: ",++cont); imprime(v,n); } free(v);}
void imprime(int *s, int n){ int i; for(i=0; i < n; i++) printf("%d ",s[i]); printf("\n");}
- ’A’ seguido de permutações de "BCDE"- ’B’ seguido de permutações de "ACDE"- ’C’ seguido de permutações de "ABDE"- ’D’ seguido de permutações de "ABCE"- ’E’ seguido de permutações de "ABCD"
Estratégia: (para "ABC")
Fixe ’A’ na primeira posição Fixe ’B’ na segunda posição Fixe ’C’ na terceira posição Imprime "ABC" Fixe ’C’ na segunda posição Fixe ’B’ na terceira posição Imprime "ACB"Fixe ’B’ na primeira posição ....Fixe ’C’ na primeira posição ....
Para gerar todas as permutações considerando k caracteres fixos: - para cada possível caractere fixo na posição k+1 gere todas as permutações considerando-se k+1 caracteres fixos
n - número total de caracteresk - número de caracteres fixo
void permutacao(char *v, int n, int k){ se (n == k) imprima v senão { para cada possível caractere fixo na posição k+1 permutação(v, n, k+1) }}
for (i = k; i < n; i++){
aulas.txt Seg Nov 28 17:00:12 2005 61
troca(v, i, k); /* v[k] é o caractere na posição k+1 */ perm(v, n, k+1); troca(v, k, i); }
Outubro Novembro DezembroDo Se Te Qu Qu Se Sá Do Se Te Qu Qu Se Sá Do Se Te Qu Qu Se Sá 1 X 2 X 4 5 P 2 3 2 3 4 5 6 7 8 6 7 X 9 X 11 12 4 5 6 7 P 9 10 9 10 11 12 13 14 15 13 14 15 16 X 18 19 11 12 13 14 15 16 1716 17 18 19 X 21 22 20 21 X 23 X 25 26 18 19 20 21 22 23 2423 24 X 26 X 28 29 27 28 X 30 25 26 27 28 29 30 3130 31
Dezembro 9 ENCERRAMENTO DAS AULAS. 15 Data máxima para cadastro e/ou entrega, pelos docentes, das Listas de Avaliação Final do 2º semestre, nas Unidades.
Minha sugestão:
EP4 - correção até 22/11EP5 - correção até 3/12EP6 - entrega 30/11 correção até 12/12
Dada uma lista ligada que armazena números inteiros, escreva umafunção que transforma a lista dada em duas listas ligadas: aprimeira contendo os elementos com valores pares e a segunda comvalores ímpares. A função não deve alocar mais células, mas usar asexistentes na lista dada.
typedef struct cel { int valor; struct cel *prox;} celula;
/* separa lista em duas lista: com ímpares e com pares */void separa(celula *inicio, celula **impar, celula **par){ celula *aux, *inicimpar, *inicpar;
**********************************************************************Escreva uma função que recebe um apontador para uma árvorebinária e troca os filhos direito e esquerdo de cada nó.
void troca(arvore *x){ arvore *aux;
if (x != NULL) { troca(x->esq); troca(x->dir); aux = x->esq; x->esq = x->dir; x->dir = aux; }}