EEL170 COMPUTAÇÃO I
4a Série de slides
Versão 09/10/2015
PASCAL
Alocação dinâmica de memória
A Alocação Estática de Memória:
Definimos exatamente as variáveis necessárias
para resolver um problema
Usada quando conhecemos a quantidade e a
dimensão das variáveis necessárias
Ex.:





Var
Nr1, nr2, nr3: integer;


// variáveis tipo inteiro
Temperaturas: array[1..24] of integer;

// variável estruturada homogênea do tipo inteiro com uma
dimensão e 24 elementos
A Alocação Dinâmica de Memória



Permite criar variáveis dinamicamente, em tempo
de execução, a medida em que forem necessárias
Usada quando não sabemos a quantidade ou a
dimensão das variáveis que necessitamos para
resolver um problema
Em Pascal, C e C++ a alocação dinâmica de
memória é implementada via pointer
Pointer




Um pointer é uma variável que aponta para uma
outra variável, esta última criada em tempo de
execução
Isto permite definir, durante a execução de um
programa, quantas variáveis de um tipo de
pointer serão criadas, e a dimensão dessas
variáveis
O pointer tem um tipo: ele só pode apontar para
variáveis de seu tipo
Pode-se imaginar o pointer como contendo uma
referência de uma variável
Exemplo de alocação estática


Var
Nr1, nr2, nr3: integer;
nr1
Todas do
tipo inteiro
nr2
nr3
Exemplo de alocação dinâmica


Var
Var1, var2: ^integer
var1
var2
Podem apontar
para variáveis
do tipo inteiro
Var
nr1, nr2: inteiro
// variável estática
Var1, var2: ^inteiro // pointer
Begin
...
nr1 nr2 var1 var2
nr1  15
15
nr2  nr1
15
new (var1)
var1^  25
nr2  var1^
25
25
Lista encadeada por pointer
início
nó
Encadeamento
Exemplo: agenda por pointer
Algoritmo agendaPointer
(* agenda em pointer com inclusão no início *)
Tipo
tcontato = ^rcontato (* pointer *)
Rcontato = registro nome
fone
proximo: tcontato (* recursão *)
fim
Var
Inicio
Primeiro  nil // para inicializar com nulo
(* aqui devem seguir os comandos para o programa na estrutura de menu, vai
ser apresentado apenas o procedimento para incluir contato *)
//
Procedimento incluirContatoInicio
(* procedimento para incluir contato no inicio *)
inicio
New (novo)
// alocação dinâmica de memória
Leia (novo^.nome, novo^.fone) (* orientar e testar *)
Novo^.proximo  nil
Se primeiro = nil então
primeiro  novo
// primeira inclusão
Exemplo de agenda
Primeiro contato: zé fone 45
primeiro
Ze 45
Segundo contato: rui fone 80
primeiro
Rui 80
Ze 45
Terceiro contato: lui fone 10
primeiro
Lui 10
Rui 80
Ze 45
Procedimento listarContatos
(* procedimento para listar os contatos *)
Inicio
Atual  primeiro
Enquanto atual <> nil faça
Escreva(atual^.nome, atual^.fone)
Atual  atual^.proximo
fim
procedimento incluirContatoFim
(* procedimento para incluir contato no fim – inclusão
mantendo a ordem cronológica *)
new (novo)
// alocação dinâmica de memória
leia (novo^.nome, novo^.fone) // orientar e testar
novo^.proximo  nil
se primeiro = nil então
primeiro  novo
Ultimo  novo
senão
// demais inclusões
ultimo^.proximo  novo
ultimo  novo
fim
// primeira inclusão
Exemplo de agenda
Primeiro contato: zé fone 45
ultimo
Ze 45
primeiro
Segundo contato: rui fone 80
primeiro
Ze 45
ultimo
Rui 80
Terceiro contato: lui fone 10
ultimo
primeiro
Ze 45
Rui 80
Lui 10
Novo exemplo linear
Agenda que permita manter os nomes e telefones
de contatos em ordem alfabética em lista circular
O contato atual deve ser apresentado na tela
Opções:
Incluir novo contato – este passa a ser o atual
Excluir o contato atual – atual será o próximo
Alterar o telefone do contato atual
Apresentar o próximo – será o atual
Apresentar o anterior – será o atual
Consultar um contato pelo nome - será o atual
Listar todos os contatos – mantido o atual
Estruturas não lineares
Nas estruturas lineares pode-se definir, dado um elemento,
quais são seus sucessor e antecessor
Nas estruturas não lineares pode haver mais de um sucessor
ou antecessor
As árvores são estruturas não lineares que iniciam num “nó”
chamado raiz, e deste pode-se passar a seus “filhos”, em
uma estrutura pai-filho, até chegar aos nós que não em filhos,
chamados “folhas” da árvore.
Pode-se imaginar estas estruturas como árvores invertidas
A quantidade de filhos de cada nó dá a ordem da árvore
Nas árvores binárias cada nó pode ter até dois filhos
Exemplo de árvore binária
raiz
d
b
folhas
a
f
c
e
g
Exemplo não linear
Agenda que permita manter os nomes e telefones de
contatos em ordem alfabética em uma árvore
binária
Opções:
Incluir novo contato
Alterar o telefone de um contato
Consultar um contato pelo nome
Listar todos os contatos em ordem alfabética
algoritmo agendaArvore
(* agenda em árvore binária; responsável:...; data:...*)
tipo
noAgenda= ^regAgenda
regAgenda= estrutura nome: string(30)
Telefone: string(16)
esq, dir: noAgenda
fim
var
raiz, atual, novo, aux: noAgenda
inicio
raiz ← nil
repita
opção ← funMenu // função para apresentar as opções
caso opção seja:
1: procIncluir
2: procAlterar
3: procConsultar
4: procListar(raiz)
fim
ate que opção = 5
fim
procedimento procIncluir // para incluir novo contato
inicio
new(novo) // criação dinâmica de variável
leia(novo^.nome, novo^.telefone) // Orientar e validar
novo^.esq, novo^.dir ← nil
se raiz = nil então // agenda vazia
raiz ← novo
senão buscarLugar(raiz, novo) // demais casos
atual ← novo
fim
procedimento buscarLugar(var atual: noAgenda; novo:
noagenda)
(* buscar o lugar na árvores descendo até um nó livre;
ATENÇÃO: o primeiro parâmetro é por referência, o que
é necessário para o novo nó ser ligado à árvore *)
inicio
se atual = nil então
atual ← novo
senão se novo^.nome > atual^.nome então
buscarLugar(atual^.dir,novo)
senão buscarLugar(atual^.esq,novo)
fim
Para listar em ordem alfabética:
Vamos nos basear na topologia da árvore binária:
a
b
c
O nó “a” tem os filhos “b” e “c”; para se listar estes nós
em ordem alfabética crescente será necessário listálos na ordem “b a c”; esta será a base para o algoritmo
de listar em ordem alfabética crescente
procedimento procListar(atual: noAgenda)
// para listar os contatos em ordem alfabética
inicio
se atual <> nil então
inicio
procListar(atual^.esq)
escrever(atual^.nome, atual^.telefone)
procListar(atual^.dir)
fim
fim
Para listar em outras ordens
Para listar em ordem alfabética decrescente basta
chamar primeiro pela direita no algoritmo anterior,
escrever e depois chamar pela esquerda
Para outras ordens basta alterar a ordem dos três
comandos que navegam e escrevem os dados
Isto é possível porque nos baseamos na topologia da
árvore, e porque tanto a definição da árvore como o
algoritmo são recursivos
Demais procedimentos do problema
Baseados no que foi exposto pode-se construir os
demais procedimentos.
Fica como exercício.
Download

Apresentação parte 4