Escolar Documentos
Profissional Documentos
Cultura Documentos
12º Ano
Apontamentos
Prof. José Alberto Pereira
1ª Versão
1999/2000
NOTA INTRODUTÓRIA
I ALGORITMOS 1
1. PSEUDOCÓDIGO 1
2. VARIÁVEIS 2
3. OPERADORES 3
4. INSTRUÇÕES 4
4.1. INSTRUÇÕES SIMPLES 4
Instruções de escrita 4
Instruções de leitura 4
Instruções de atribuição 5
4.2. INSTRUÇÕES ESTRUTURADAS OU ESTRUTURAS DE CONTROLO 6
Instruções compostas 6
Estrutura de decisão condicional - "Se" 7
Estrutura de escolha múltipla - "Caso" 8
Estrutura de repetição ou ciclos 9
Estrutura de repetição ou ciclos - "Repita para" 9
Estrutura de repetição ou ciclos - "Repita enquanto" 11
Estrutura de repetição ou ciclos - "Repetir ... até" 11
5. SUBALGORITMOS 12
5.1. EXEMPLOS 14
Função MÉDIA 14
Exemplo de utilização da função MÉDIA 14
Procedimento DIVIDE 15
Exemplo de utilização do procedimento DIVIDE 15
II ESTRUTURAS DE DADOS 16
1. ESTRUTURA DE DADOS 16
2. ESTRUTURA DE DADOS SIMPLES 16
2.1. VALORES LÓGICOS 17
2.2. INTEIROS 17
2.3. REAIS 18
2.4. ALFANUMÉRICOS 20
2.5. PONTEIROS 21
3. ESTRUTURA DE DADOS COMPLEXAS 21
3.1. VECTORES 21
3.2. MATRIZES 23
3.3. REGISTOS 24
3.4. LISTAS 25
3.5. PILHAS 25
Representação de pilhas em pascal 26
3.6. FILAS 28
Representação de filas em pascal 29
3.7. LISTAS LIGADAS 38
Inserção de nós numa lista ligada 40
Remoção de nós numa lista ligada 41
Inserção de um elemento depois de um determinado nó 43
Implementação de uma pilha por meio de uma lista 44
Implementação de uma fila por meio de uma lista 45
3.8. FICHEIROS 46
Ficheiros do tipo texto 47
Ficheiros do tipo binário ou definidos pelo programador 47
Operações com ficheiros 48
Instruções em pseudocódigo para manipulação de ficheiros 49
Suportes físicos de ficheiros 50
3.9. ÁRVORES BINÁRIAS 51
Conceitos Básicos 51
Estrutura de uma árvore binária 52
Operações sobre uma árvore binária 52
Aplicações de árvores binárias 53
Travessias de uma árvores binárias 55
Algumas funções recursivas 57
4. MÉTODOS DE ORDENAÇÃO E PESQUISA 58
4.1. PESQUISA LINEAR NUM VECTOR NÃO ORDENADO 58
1ª Versão 58
2º Versão 59
4.2. PESQUISA LINEAR NUM VECTOR ORDENADA 59
4.3. PESQUISA BINÁRIA 60
4.4. FUSÃO SIMPLES 61
1. PSEUDOCÓDIGO
<Descrição>
<Passo>. [<Comentário>]
<Instruções>
(...)
1. [Inicializar variáveis]
SOMA ! 0
CONT ! 0
2. [Ler as 15 notas e calcular a sua soma]
Repita para K=1,2,...,15
Leia(NOTA[K])
SOMA ! SOMA + NOTA[K]
3. [Calcular a média]
MÉDIA ! SOMA / 15
4. [Calcular o número de alunos com nota superior à média]
Repita para K=1,2,...,15
Se NOTA[K] > MÉDIA
Então CONT ! CONT + 1
5. [Calcular e imprimir a percentagem]
PERC ! (100 * CONT) / 15
Escreva('A percentagem de alunos com nota superior à média é ',PERC,'%')
6. [Terminar]
Saída
2. VARIÁVEIS
3. OPERADORES
Operadores em pseudocódigo:
OPERADORES ARITMÉTICOS
Designação Operador
Adição +
Subtracção -
Multiplicação *
Divisão /
OPERADORES DE COMPARAÇÃO
Designação Operador
igual a =
diferente de ≠
Maior que >
menor que <
Maior ou igual a ≥
menor ou igual a ≤
4. INSTRUÇÕES
Instruções de escrita
As instruções de escrita são aquelas que servem para enviar dados (mensagens,
valores de variáveis, etc.) para um dispositivo de saída ou periférico de "output".
Como se sabe, o dispositivo de saída mais comum no trabalho com um
computador é o monitor de vídeo ou ecrã; no entanto, o envio de dados para a
impressora ou para um ficheiro em disco ou disquete também são tarefas normais e,
por vezes, mesmo imprescindíveis.
Exemplos das instruções de escrita, mais usuais, em pseudocódigo:
[Imprimir a mensagem]
Escreva('Não existe quarto vago do tipo escolhido.')
[Imprimir a percentagem]
Escreva('A percentagem de alunos com nota superior à media é ', PERC, '%')
Instruções de leitura
[Ler as variáveis X e Y ]
Leia(X, Y)
Instruções de atribuição
Muitos dos dados com que se opera num algoritmo são variáveis. As variáveis e
constantes num algoritmo são designadas por meio de identificadores. Um
identificador é um nome normalmente atribuído pelo algoritmo ou utilizador a um
elemento com que se pretende trabalhar dentro de um algoritmo.
Exemplos, apresentados numa tabela com possíveis entidades e os
correspondentes identificadores das variáveis:
Instruções compostas
[Exemplo 2a]
Se ANDAR = 0
Então QUARTO_VAGO ! 0
K!0
[Exemplo 2b]
Se ANDAR = 0
Então Início
QUARTO_VAGO ! 0
K!0
Fim
Numa estrutura "Caso" há uma variável, cujos valores que possa assumir vão
ser utilizados no controlo das alternativas ou acções a escolher - a esta variável é
costume chamar-se selector.
A Sintaxe desta estrutura, em pseudocódigo, é a seguinte:
Caso <Variável/Selector>
<Valor 1> : <Instrução 1>
<Valor 2> : <Instrução 2>
(...)
<Valor n> : <Instrução n>
[Senão : <Instrução>]
Fim (Caso).
Quando se indica <Valor 1>, <Valor 2>, etc., estamos a referir aos valores
possíveis que a variável de controlo poderá assumir. Pode ser apenas um valor ou
um conjunto de valores.
Quando de indica <Instrução 1>, < Instrução 2>, etc., pode tratar-se de uma só
instrução ou de uma instrução composta, portanto um conjunto de acção a realizar.
Em algumas implementações existe também uma cláusula "Senão" que se
destina a complementar o leque de alternativas, no caso de haver ainda mais
hipóteses não explicitadas, e em que pode haver ainda uma outra acção ou conjunto
de acções a indicar.
Enquanto numa estrutura do tipo "Repita para..." o número de vezes que vai
ocorrer a repetição do ciclo é determinada à partida por uma variável de controlo que
é incrementada ou decrementada à medida que o ciclo decorre. Na estrutura "Repita
Enquanto..." e "Repetir...até" o ciclo decorrerá um número indeterminado de vezes,
dependendo da verificação ou não da condição de controlo - o que depende dos
acontecimentos no decurso do próprio ciclo.
Ou ainda:
Repita até ao passo <Passo> para <Variável>=<Valores>
<Instrução>
...
Exemplos, em pseudocódigo:
[Ler 10 elementos de um vector]
Repita para K=1,2,...,15
Leia (VEC[K])
Outro exemplo:
1. [Percorre todos os dias da semana e inicializar a quantidade mínima]
Repita até ao passo 4 para J=1,2,...,7
QUANT_MIN ! SEMANAS[J]
2. [Procura o dia da semana mais eficiente]
(...)
Exemplo, em pseudocódigo:
[Pesquisa um quarto vago]
J!1
QUARTO_VAGO ! 0
Repita enquanto J ≤ 10 e QUARTO_VAGO=0
Se QUARTOS[J] = 0
Então QUARTO_VAGO ! J
J!J+1
Sintaxe em pseudocódigo:
Repetir
<Instrução 1>
<Instrução 2>
...
<Instrução n>
até <Condição>
5. SUBALGORITMOS
5.1. Exemplos
Função MÉDIA
1. [Calcula a média]
MED ! (VALOR1 + VALOR2 + VALOR3) / 3.0
2. [Devolve resultado e regressa ao ponto de chamada - Saída da função]
Regresso(MED)
Algoritmo TESTA_MÉDIA
Este algoritmo ilustra o uso da função MÉDIA com vários argumentos. Todas as
variáveis são reais.
Procedimento DIVIDE
1. [Testa divisão]
SE DIVISOR = 0
Então Escreva('Divisão por zero. Impossível!')
Regresso
2. [Executar divisão de inteiros]
QUOC ! DIVIDENDO / DIVISOR
3. [Determina Resto]
RESTO ! DIVIDENDO - (QUOC * DIVISOR)
4. [Regressa ao ponto de chamada - Saída do procedimento]
Regresso
Algoritmo TESTA_DIVIDE
Este algoritmo ilustra o uso do procedimento DIVIDE. Todas as variáveis são inteiros.
1. ESTRUTURA DE DADOS
Simples
Estrutura de Dados
Complexas ou Estruturadas
Valores Lógicos
Numéricas Inteiros
Estrutura de Dado Simples Reais
Alfanuméricos : Caracteres e Cadeias de Caracteres
Dinâmicas : Ponteiros
Os dados deste tipo, são dados que podem assumir apenas dois valores
possíveis: verdadeiro e falso. A sua utilidade reside, fundamentalmente, ao nível do
seu emprego em estruturas de controlo.
2.2. Inteiros
2.3. Reais
1 8 23
1 11 52
Precisão
Sinal Expoente Mantissa 64 bits = 8 bytes
dupla
1 15 64
2.4. Alfanuméricos
2.5. Ponteiros
Vectores
Comprimento fixo
Matrizes
Registos
Estruturas de Dados Complexas
Pilhas
Lineares Filas
Comprimento variável : Listas Ficheiros
Não Lineares : Árvores
3.1. Vectores
Em que:
• GASTOS_MES - é o identificador ou nome atribuído à variável;
• Vector - indica que a variável é do tipo Vector;
• [1,...,12] - define o número de elementos da variável e ao mesmo tempo o
intervalo dos seus índices, neste caso entre 1 e 12;
• de Real - indica qual o tipo de dados dos elementos do vector.
ou ainda
GASTOS_MES[12]
De um modo geral, cada elemento desta variável de tipo Vector designa-se por:
GASTOS_MES[K]
3.2. Matrizes
[Instrução de atribuição]
M[4, 3] ! 20
3.3. Registos
3.4. Listas
lineares
Listas
não lineares
Uma lista linear é uma Lista que apresenta a propriedade de adjacência entre os
seus elementos.
Algumas operações a realizar com Listas:
• Inserir um elemento na lista
• Eliminar um elemento na lista
• Remover um elemento na lista
• Fundir duas ou mais listas numa só
• Formar várias listas a partir de uma só
• Copiar uma lista
• Determinar o comprimento de uma lista, ou seja, o número de elementos de
uma lista
• Ordenar os elementos de uma lista
• Pesquisar um elemento na lista, que contenha um campo com um certo valor
• etc.
3.5. Pilhas
C Topo da pilha
A 1º elemento da pilha
Quando se retira o último elemento de uma pilha, a pilha diz-se vazia. Não se
pode, portanto, aplicar-se sempre a operação POP a uma pilha, ao contrário do que
acontece com a operação PUSH. É necessário saber se uma pilha ainda tem
elementos para retirar ou não. É necessário definir uma função EMPTY.
• Function EMPTY(S) - Determina se uma pilha está ou não vazia. Se vazia
EMPTY devolve o valor verdadeiro.
É ainda útil definir uma outra função STACK_TOP(S) que permite determinar
qual é o elemento que está no topo da pilha sem contudo o remover da pilha.
• Function STACK_TOP(S)
Esta função é equivalente a: X ! POP (S, TOP)
PUSH (S, TOP, X)
Tal como POP, STACK_TOP não é definida para uma pilha vazia.
TOP representa o elemento localizado no topo da pilha. Inicialmente quando a
pilha está vazia o valor de TOP é zero. De cada vez que se insere um elemento na
pilha, POP é incrementado de uma unidade, antes do elemento ser colocado na
pilha. POP é decrementado de uma unidade sempre que se elimina um elemento da
pilha.
Pseudocódigo de algumas operações sobre Pilhas:
Function STACK_TOP(S)
Dados um vector S, com N elementos e cujo elemento do topo é indicado por TOP, essa
função devolve o elemento do topo da pilha.
3.6. Filas
Uma fila (queue) é uma lista linear na qual todas as inserções são feitas num
extremo da lista (a parte de trás) e todas as eliminações, e normalmente todos os
acessos, são feitos no outro extremo da lista (parte da frente).
1 2 3 4 5 6
A B C D E F
Frente Retaguarda
Eliminar Inserir
Apesar de uma fila ser uma entidade dinâmica, as suas operações podem ser
simuladas utilizando um vector com um número suficientemente grande de
elementos que nos permita manter a propriedade de comprimento variável. A
representação vectorial Q[1, ..., N] (vector de N elementos) de uma fila requer o uso
de dois ponteiros F e R, que representam a posição do elemento da Frente (primeiro
elemento da fila) e da Retaguarda (último elemento da fila), respectivamente.
Pode-se então declarar-se uma fila usando um registo (record) contendo três
campos: um vector contendo os elementos da lista; um inteiro para indicar a posição
do elemento da frente e outro para indicar o elemento da retaguarda.
Ignorando, para já, a possibilidade de ocorrência de overflow e underflow, as
operações de inserção e remoção poderiam ser implementadas do seguinte modo:
[Inserção de um elemento Y: Incrementa primeiro R e depois insere o elemento]
R!R+1
Q[R] ! Y
[Remoção de um elemento Y: Primeiro remove o elemento e depois incrementa F]
Y ! Q[F]
F!F+1
Quando se retira o último elemento de uma fila, a fila diz-se vazia. Não se pode,
portanto, aplicar-se sempre a operação QDELETE a uma fila, ao contrário do que
acontece com a operação QINSERT.
A B C
1 2 3 4 5 1 2 3 4 5
1ª Situação 2ª Situação
F=1 e R=0 F=1 e R=3
Fila Vazia: R<F Inserir 3 elementos
C C D E
1 2 3 4 5 1 2 3 4 5
3ª Situação 4ª Situação
F=R=3 F=3 e R=5
Remover 2 elementos Inserir 2 elementos
Procedure QINSERT(Q, F, R, N, Y)
Dados F e R, ponteiros para os elementos da frente e retaguarda da fila, uma fila
vectorial Q com N elementos e um elemento Y, este procedimento insere Y na parte de trás da
fila. Antes do 1º uso do procedimento, F e R são inicializados a 0 e 1 respectivamente (F ! 1,
R ! 0).
Function QDELETE(Q, F, R, N)
Dados F e R, ponteiros para os elementos da frente e retaguarda da fila, uma fila
vectorial Q com N elementos, esta função elimina e devolve o último elemento da fila (na
parte da frente da fila). Y é uma variável temporária.
Procedure QINSERT(Q, F, R, N, Y)
Dados os ponteiros F e R para a frente e retaguarda duma fila Q com N elementos e um
elemento Y, este procedimento insere Y na retaguarda da fila. Antes do 1º uso do
procedimento, F e R são limpos (F ! 0, R ! 0).
Function QDELETE(Q, F, R, N)
Dados os ponteiros F e R para a frente e retaguarda duma fila Q com N elementos, esta
função elimina e devolve o último elemento da fila (na parte da frente da fila). Y é uma
variável temporária.
O problema com estas duas possíveis implementações é que o vector pode ter
até 5 elementos e no entanto a fila não pode crescer mais, pois R teria que assumir
o valor 6, que corresponde ao índice do vector. Ou seja, a fila pode não crescer mais
(overflow) ao tentarmos inserir um elemento apesar de algumas das primeiras
localizações não estarem a ser usadas.
Uma solução possível, seria alterar a operação de remoção de um elemento, de
modo a que sempre que um elemento seja apagado, toda a fila seja deslocada para
o início do vector. Deixaria de ser necessário especificar o campo F, pois, a frente da
fila passaria a ser sempre o primeiro elemento do vector. Mas este método é
ineficiente, pois , cada vez que um elemento é removido, todos os outros têm que
ser deslocados.
A solução mais eficiente de todos estes problemas é tratar o vector que contem
os elementos da fila como sendo circular e não um segmento de recta, ou seja, o
primeiro elemento do vector segue-se ao seu ultimo elemento.
Com este tipo de implementação a condição R < F não serve para determinar se
a fila está vazia. Uma possível solução é convencionar que F é o índice do elemento
do vector que precede o 1º elemento da fila e R é o índice do elemento da
retaguarda do vector. Assim o teste de fila vazia seria: F=R. Os ponteiros F e R são
inicializados no último índice do vector, pois F precede o primeiro nesta
representação.
Antes da inserção de um elemento na fila, quando o vector está totalmente
preenchido, verifica-se a condição F = R que é utilizada para verificar a ocorrência
de underflow (fila vazia). O problema é que deste modo não há possibilidade de
distinguir a situação de underflow da situação de overflow. A solução deste
problema, é permitir que a fila cresça apenas até um número de elementos igual ao
total do vector menos um. Para isso na implementação da inserção implementa-se o
ponteiro R antes de efectuar o teste F=R.
Ignorando, para já, a possibilidade de ocorrência de overflow e underflow, as
operações de inserção e remoção para uma fila circular poderiam ser
implementadas do seguinte modo:
[Inserção de um elemento Y]
R!R+1
Q[R] ! Y
[Remoção de um elemento Y]
F!F+1
Y ! Q[F]
1 1
A
5 5
2 2
4 4
3 3
1ª Situação 2ª Situação
F=R=5 F=5 e R=1
Fila Vazia - Underflow Inserir 1 elemento
F precede o 1º elemento
1 1
F F
5 5
E E
2 2
C D
4 4
3 3
5ª Situação 6ª Situação
F=2 e R=1 F=4 e R=1
Inserir 2 elementos Remover 2 elementos
Fila cheia - Overflow
1 1
A
5 5
1
2 B 2
C D C D
4 4
3 3
3ª Situação 4ª Situação
F=5 e R=4 F=2 e R=4
Inserir 3 elementos Remover 2 elementos
Procedure QINSERT(Q, N, F, R, Y)
Dado o ponteiro F que precede o 1º elemento da fila (da frente) e o ponteiro R da
retaguarda duma fila circular Q de N elementos, e um elemento Y, este procedimento insere Y
na retaguarda da fila. Os ponteiros F e R são inicializados no último índice do vector:
(F ! N, R ! N).
Function QDELETE(Q,, F, R, N)
Dado o ponteiro F que precede o 1º elemento da fila (da frente) e o ponteiro R da
retaguarda duma fila circular Q de N elementos, esta função elimina e devolve o último
elemento da fila (na parte da frente da fila). Y é uma variável temporária.
Procedure QINSERT(Q, N, F, R, Y)
Dado os ponteiros F e R da frente e da retaguarda duma fila circular Q de N elementos, e
um elemento Y, este procedimento insere Y na retaguarda da fila. Inicialmente F e R são
limpos: (F ! 0, R ! 0).
Function QDELETE(Q, F, R, N)
Dado os ponteiros F e R da frente e da retaguarda duma fila circular Q de N elementos,
esta função elimina e devolve o último elemento da fila (na parte da frente da fila). Y é uma
variável temporária.
Atendendo à definição de lista ligada (linked list), muitos autores chamam à lista
ligada, lista simplesmente ligada, ou ainda, lista ligada encadeada.
Primeiro Último
elemento elemento
A B C D NIL
Ponteiro do
Ponteiro de Informação endereço seguinte
Início
Tem-se assim a estrutura de uma lista ligada, em que cada "caixa" representada
na figura dá-se o nome de nodo ou nó (node).
Cada elemento de uma lista ligada é um nó com dois campos: o da informação e
o campo do endereço do elemento seguinte. Este endereço é designado por
ponteiro. O último nodo da lista não tem sucessor, e consequentemente, não tem
nenhum endereço no campo do ponteiro. O ponteiro nil é utilizado para indicar o fim
da lista. Uma lista sem elementos é uma lista vazia. A lista é acedida por meio de
um ponteiro externo, que aponta para o primeiro nó.
Desde que não seja dito nada ao contrário, o nó é composto por dois campos: o
campo da informação e o campo do ponteiro para o próximo nó.
A lista é uma estrutura dinâmica que pode crescer ou diminuir, não tendo um
número predeterminado de elementos.
Suponhamos que se tem uma lista com 3 elementos com informação do tipo
inteiro:
List
5 3 8 NIL
List
5 3 8 NIL
Resultando:
List
5 3 8 NIL
É necessário mudar o valor de List para que este ponteiro passe o apontador
para o novo primeiro elemento da lista.
List ! p
List
6 5 3 8 NIL
Para remover o primeiro nó de uma lista não vazia é armazenado o valor do seu
campo Info numa variável temporária x.
List
5 3 8 NIL
P ! List
List
5 3 8 NIL
List ! Próximo(p)
x ! Info(p)
p
5 3 8 NIL
List
List
3 8 NIL
List
5 3 8 NIL
List
5 3 8 NIL
Uma pilha só pode ser acedida pelo seu elemento de topo, assim como, a lista.
Seja uma pilha S, implementada por meio de uma lista:
3 2 1 NIL
F R
1 2 3 NIL
Seja Q o ponteiro de início da fila e Frente(Q) uma função que acede à frente da
fila Q, e a função Retaguarda(Q) que acede à sua retaguarda. Uma implementação
da operação X ! QDelete(Q) de uma fila Q, que remove e devolve um elemento X da
fila Q (tira um nodo na frente da fila), poderia ser:
Se FilaVazia(Q)
Então Escreva(‘Fila Vazia’)
Senão P ! Frente(Q)
X ! Info(P)
Frente(Q) ! Próximo(P)
Se Frente(Q) = Nil
Então Retaguarda(Q) ! Nil
LibertaNodo(P)
P ! CriarNodo
Info(P) ! X
Próximo(P) ! Nil
Se Retaguarda(Q) = Nil
Então Frente(Q) ! P
Senão Próximo(Retaguarda(Q)) ! P
Retaguarda(Q) ! P
3.8. Ficheiros
3. Escrita de um registo
Escrever NOMES.DAT, ALUNO
6. Leitura de um registo
Ler ALUNO, NOMES.DAT
7. Fechar ficheiro
Fechar NOMES.DAT
Conceitos Básicos
B C
D
E F
G H I
Se n1 for a raiz de uma árvore binária e n2 for a raiz da sua sub-árvore direita ou
esquerda, então diz-se que n1 é o pai de n2, e que n2 é o filho direito ou esquerdo
de n1. O nó n2 é um descendente de n1 e n1 é o seu ascendente.
Um nó que não tenha filhos é uma folha. Dois nós são irmãos se são os filhos
direito e esquerdo do mesmo pai.
Nível de um nó numa árvore binária: a raiz da árvore tem nível 0. O nível de
outro nó qualquer é uma unidade mais que o nível do pai. Uma árvore binária
completa de nível n é uma árvore em que cada nó de nível “n” é uma folha e em que
todos os nós de nível menor que “n” têm sub-árvores direita e esquerda não vazias.
Uma árvore binária completa de nível 3 seria:
Pode considerar-se que cada nó de uma árvore binária tem três campos. O
campo de informação, que armazena informação Info(nodo), e dois campos de
ponteiros Esq(nodo) e Dir(nodo) que referenciam as raízes das sub-árvores esquerda
e direita da árvore binária cuja raiz é nodo. Se uma sub-árvore está vazia o seu
ponteiro é nil.
A estrutura de dados em pascal, de uma árvore binária, poderia ser a seguinte:
Type NodoPtr = ^Nodo;
Nodo = Record
Info: TipoDados;
Esq: NodoPtr;
Dir: NodoPtr;
End;
Var Tree: NodoPtr;
Uma árvore binária é uma estrutura de dados útil quando decisões com duas
alternativas são tomadas em cada ponto de um processo.
1. [Lê-se o primeiro número e insere-se numa árvore binária com um único nó.]
Ler(NUM)
TREE ! MakeTree(NUM)
P ! TREE
Enquanto NUM ≠ Info(P) e Q ≠ NIL {Continua até que um duplicado seja encontrado
ou até se chegar a uma sub-árvore vazia}
P!Q
Se NUM < Info(P)
Então Q ! Esq(P)
Senão Q ! Dir(P)
Fim Enquanto {Fim da pesquisa}
Senão Se NUM < Info(P) {Colocar num novo nodo com o número da entrada}
Exemplo do algoritmo:
Sequência de números da lista: 14, 15, 4, 9, 7, 18, 3, 5, 16, 4, 20, 17, 9, 14, 5
14
4 15
3
9 18
7 16 20
17
5
Nem sempre os nós de uma árvore binária contêm todos o mesmo tipo de
informação. Por exemplo para representar uma expressão binária com operadores
numéricos constantes, podemos usar uma árvore binária cujas folhas contêm
números, contendo os outros nós caracteres representando operadores. Para
representar este tipo de árvores em pascal podemos usar registos variáveis.
Outra aplicação seria percorrer uma árvore binária, atravessando todos os seus
nós, e enumerando-os.
No caso de uma árvore não há uma ordem “natural” de percurso. Vamos definir
três métodos para percorrer a árvore. Os métodos são definidos recursivamente de
modo que percorrer uma árvore binária implicará percorrer a raiz e as suas
sub-árvores esquerda e direita.
Métodos:
• Pré-ordem (ou em profundidade)
• Em-ordem (ou da ordem simétrica)
• Post-ordem
Método da pré-ordem
1. Visitar a raiz
2. Percorrer a sub-árvore esquerda em pré-ordem
3. Percorrer a sub-árvore direita em pré-ordem
Se p ≠ NIL
Então Escrever(Info(p))
PréOrdem(Esq(p))
PréOrdem(Dir(p))
Método da em-ordem
1. Percorrer a sub-árvore esquerda em em-ordem
2. Visitar a raiz
3. Percorrer a sub-árvore direita em em-ordem
Se p ≠ NIL
Então EmOrdem(Esq(p))
Escrever(Info(p))
EmOrdem(Dir(p))
Método da post-ordem
1. Percorrer a sub-árvore esquerda em post-ordem
2. Percorrer a sub-árvore direita em post-ordem
3. Visitar a raiz
Se p ≠ NIL
Então PostOrdem(Esq(p))
PostOrdem(Dir(p))
Escrever(Info(p))
Exemplos:
Pré-ordem: A B D G C E H I F
A Em-ordem: D G B A H E I C F
Post-ordem: G D B H I E F C A
B C
D
E
F
G H
I
1ª Versão
1. [Inicializações]
L!1
2. [Pesquisar o vector enquanto não achar]
Repita enquanto L ≤ N e K[L] ≠ X
L!L+1
3. [Verificar se a pesquisa foi com ou sem sucesso]
Se L = N+1
Então Escrever(‘Insucesso’)
Senão Escrever(‘Sucesso em ‘, L)
4. [Termina]
Saída
2º Versão
1. [Inicializações]
L!1
K[N+1] ! X
2. [Pesquisar no vector]
Repita enquanto K[L] ≠ X
L!L+1
3. [Verificar se a pesquisa foi com ou sem sucesso]
Se L = N+1
Então Escrever(‘Insucesso’)
Senão Escrever(‘Sucesso em ‘, L)
4. [Termina]
Saída
Dado um vector K ordenado, com N elementos, K[1] < K[2] < ... < K[N], este algoritmo
pesquisa no vector um dado elemento X. Por conveniência e rapidez supõe-se existir um
elemento K[N+1] que actua como sentinela: K[N+1] = ∞ > X.
1. [Inicializações]
L!1
K[N+1] ! 9999999
2. [Pesquisar no vector]
Repita enquanto X > K[L]
L!L+1
3. [Verificar se a pesquisa foi com ou sem sucesso]
Se X = K[L]
Então Escrever(‘Sucesso em ‘, L)
Senão Escrever(‘Insucesso’)
4. [Termina]
Saída
4. [Termina]
Saída
1. [Inicialização]
I!J!K!1
2. [Comparar elementos e escolher o menor]
Repita enquanto I ≤ N e J ≤ M
Se A[I] ≤ B[J]
Então C[K] ! A[I]
I!I+1
K!K+1
Senão C[K] ! B[J]
J!J+1
K!K+1
3. [Copiar os elementos não processados para o vector de saída]
Se I = N
Então Repita para L = J, J+1, ..., M
C[K] ! B[L]
K ! K +1
Senão Repita para L = I, I+1, ..., N
C[K] ! A[L]
K ! K +1
4. [Termina]
Saída
J!J–1
K[J+1] ! X
4. [Terminar]
Saída
Exemplo:
K[1] K[2] K[3] K[4] K[5] K[6]
44 55 11 22 66 33
5. [Terminar]
Saída
Exemplo:
K[1] K[2] K[3] K[4] K[5] K[6]
44 55 11 22 66 33
1. [Inicialização]
LIMITE ! N
TROCA ! 1 { Número qualquer maior que zero, isto é, que torna a condição de
controlo do ciclo ‘Repita Enquanto’ verdadeira. }
K[J] ! K[J+1]
K[J+1] ! X
TROCA ! J { Armazena a posição da troca }
Fim Repita
LIMITE ! TROCA { Os elementos acima de ‘Limite’ já estão ordenados.
Elementos de maior valor }
3. [Termina]
Saída
Quando uma passagem do ciclo ‘Repita para’ não tem trocas (TROCA = 0) o
algoritmo pode terminar, já que o vector K já está ordenado.
No fim de cada ciclo ‘Repita para’, deve-se memorizar a posição (valor do índice
do vector K) da última troca na variável Limite. Todos os pares de itens adjacentes
acima deste limite já estão ordenados, e por isso, nas passagens seguintes deve-se
terminar em limite.
Exemplo:
K[1] K[2] K[3] K[4] K[5] K[6]
44 55 11 22 66 33
EXERCÍCIOS