Upload
manoel-ribeiro
View
216
Download
0
Embed Size (px)
Citation preview
8/20/2019 Estrutura Dados Dovicchi UFSC
1/164
Estrutura de Dados
João Dovicchi
8/20/2019 Estrutura Dados Dovicchi UFSC
2/164
2
8/20/2019 Estrutura Dados Dovicchi UFSC
3/164
Conteúdo
1 Dados 91.1 Tipos de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . 91.2 Tipo de dado abstrato . . . . . . . . . . . . . . . . . . . . . . . 101.3 Tipos de dados em C . . . . . . . . . . . . . . . . . . . . . . . . 121.4 Operações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131.5 Referências . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141.6 Dados em C: Tipos e modificadores . . . . . . . . . . . . . . . . 15
1.6.1 O tipo int . . . . . . . . . . . . . . . . . . . . . . . . . . 161.6.2 O tipo float . . . . . . . . . . . . . . . . . . . . . . . . 161.6.3 O tipo double . . . . . . . . . . . . . . . . . . . . . . . . 161.6.4 O tipo char . . . . . . . . . . . . . . . . . . . . . . . . . 171.6.5 O tipo enum . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.7 Modificadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.8 Qualificadores de dados . . . . . . . . . . . . . . . . . . . . . . . 19
2 Representação de dados 212.1 Representação em array . . . . . . . . . . . . . . . . . . . . . . 222.2 Usando vetores como parâmetros de funções . . . . . . . . . . . 252.3 Operações com arrays . . . . . . . . . . . . . . . . . . . . . . . . 262.4 Linguagens funcionais e array . . . . . . . . . . . . . . . . . . . 302.5 Representação de dados e matrizes . . . . . . . . . . . . . . . . 31
2.5.1 Matrizes: conceitos gerais . . . . . . . . . . . . . . . . . 312.5.2 Operações com matrizes . . . . . . . . . . . . . . . . . . 33
2.5.3 Matrizes booleanas . . . . . . . . . . . . . . . . . . . . . 352.5.4 Matrizes esparsas . . . . . . . . . . . . . . . . . . . . . . 37
2.6 Tipos de dados definidos pelo usuário . . . . . . . . . . . . . . . 392.6.1 Estruturas . . . . . . . . . . . . . . . . . . . . . . . . . . 392.6.2 Unĩoes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442.6.3 Campos de bits . . . . . . . . . . . . . . . . . . . . . . . 45
3
8/20/2019 Estrutura Dados Dovicchi UFSC
4/164
4 CONTE ÚDO
2.7 Exerćıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3 Listas 49
3.1 Definições e declarações . . . . . . . . . . . . . . . . . . . . . . . 493.2 Operações com listas . . . . . . . . . . . . . . . . . . . . . . . . 513.3 Pilhas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.3.1 Operações e TDA . . . . . . . . . . . . . . . . . . . . . . 553.3.2 Implementação e Exemplos em C . . . . . . . . . . . . . 57
3.4 Filas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603.4.1 Filas: operações e TDA . . . . . . . . . . . . . . . . . . . 613.4.2 Implementação em C . . . . . . . . . . . . . . . . . . . . 613.4.3 Filas circulares . . . . . . . . . . . . . . . . . . . . . . . 633.4.4 Listas ligadas . . . . . . . . . . . . . . . . . . . . . . . . 64
3.4.5 Operações com listas ligadas . . . . . . . . . . . . . . . . 673.5 Pilhas e Funções . . . . . . . . . . . . . . . . . . . . . . . . . . 703.6 Exerćıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
4 Grafos e ́arvores 754.1 Grafos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
4.1.1 Definições . . . . . . . . . . . . . . . . . . . . . . . . . . 764.1.2 Terminologia . . . . . . . . . . . . . . . . . . . . . . . . 77
4.2 Grafos e Estrutura de dados . . . . . . . . . . . . . . . . . . . . 804.2.1 Grafos direcionados e matriz adjaĉencia . . . . . . . . . . 81
4.2.2 Acessibilidade dos nós de um grafo . . . . . . . . . . . . 824.3 Caminho mı́nimo . . . . . . . . . . . . . . . . . . . . . . . . . . 84
4.3.1 Um exemplo . . . . . . . . . . . . . . . . . . . . . . . . . 854.4 Algoritmos para grafos . . . . . . . . . . . . . . . . . . . . . . . 85
4.4.1 Algoritmo de Warshall . . . . . . . . . . . . . . . . . . . 854.4.2 Caminho de Euler . . . . . . . . . . . . . . . . . . . . . . 864.4.3 Algoritmo do Caminho Mı́nimo . . . . . . . . . . . . . . 884.4.4 Problema do Caixeiro Viajante . . . . . . . . . . . . . . 90
4.5 Listas adjacência . . . . . . . . . . . . . . . . . . . . . . . . . . 914.5.1 Matriz Adjacência . . . . . . . . . . . . . . . . . . . . . 91
4.5.2 Lista de Adjacências . . . . . . . . . . . . . . . . . . . . 914.6 Exerćıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 924.7 Árvores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
4.7.1 Percurso . . . . . . . . . . . . . . . . . . . . . . . . . . . 944.7.2 Um exemplo . . . . . . . . . . . . . . . . . . . . . . . . . 95
4.8 Árvore Geradora Mı́nima . . . . . . . . . . . . . . . . . . . . . . 96
8/20/2019 Estrutura Dados Dovicchi UFSC
5/164
CONTE ÚDO 5
4.8.1 Algoritmo de Kruskal . . . . . . . . . . . . . . . . . . . . 97
4.8.2 Algoritmo de Prim . . . . . . . . . . . . . . . . . . . . . 97
4.9 Exerćıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
5 Máquinas de Estado 99
5.1 Máquinas de estado finito . . . . . . . . . . . . . . . . . . . . . 100
5.1.1 Um exemplo . . . . . . . . . . . . . . . . . . . . . . . . . 100
5.2 Exerćıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
5.3 Máquinas de Turing . . . . . . . . . . . . . . . . . . . . . . . . . 105
5.4 Exerćıcios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
6 Algoritmos 109
6.1 Algoritmos determińısticos e não-determińısticos . . . . . . . . . 110
6.2 Otimização de algoritmos . . . . . . . . . . . . . . . . . . . . . . 112
6.3 Precisão de al gori tmo . . . . . . . . . . . . . . . . . . . . . . . . 112
6.4 Complexidade . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
6.5 Algoritmos de Ordenação e B usca . . . . . . . . . . . . . . . . . 116
6.5.1 Método “bolha” (bubble sort) . . . . . . . . . . . . . . . 116
6.5.2 Método Troca de partição (Quick Sort) . . . . . . . . . . 118
A Introdução à programação funcional 121
A.0.3 Linguagem Funcional - O que é e porque usar? . . . . . . 122
A.0.4 Funções hierárquicas . . . . . . . . . . . . . . . . . . . . 124A.0.5 Lazy Evaluation . . . . . . . . . . . . . . . . . . . . . . . 125
A.0.6 Um exemplo . . . . . . . . . . . . . . . . . . . . . . . . . 126
A.1 Programação Funcional e listas . . . . . . . . . . . . . . . . . . 131
A.1.1 Mais sobre listas . . . . . . . . . . . . . . . . . . . . . . 131
A.1.2 Programação Funcional e E/S (IO) . . . . . . . . . . . . 135
A.1.3 Módulos . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
B Cálculo λ: Uma introdução 143
B.1 O Cálculo-λ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
B.1.1 Computabilidade de funções . . . . . . . . . . . . . . . . 145B.1.2 Cópia e reescrita . . . . . . . . . . . . . . . . . . . . . . 147
B.1.3 Redução . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
B.1.4 Forma normal . . . . . . . . . . . . . . . . . . . . . . . . 150
B.2 Aplicações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
B.2.1 Exerćıcios . . . . . . . . . . . . . . . . . . . . . . . . . . 151
8/20/2019 Estrutura Dados Dovicchi UFSC
6/164
6 CONTE ÚDO
C Exerćıcios complementares 153C.1 Lista de Exerćıcios - ARRAY . . . . . . . . . . . . . . . . . . . 153C.2 Lista de Exerćıcios - Listas . . . . . . . . . . . . . . . . . . . . . 155C.3 Lista de Exerćıcios - Listas, Pilhas e Filas . . . . . . . . . . . . 156C.4 Lista de Exerćıcios - Grafos . . . . . . . . . . . . . . . . . . . . 158C.5 Lista de Exerćıcios - Á rv ores . . . . . . . . . . . . . . . . . . . . 159C.6 Lista de Exerćıcios - Máquinas de estado finito . . . . . . . . . . 160C.7 Lista de Exerćıcios - Máquinas de Turing . . . . . . . . . . . . . 162C.8 Lista de Exerćıcios - Ordenação e Busca . . . . . . . . . . . . . 162
8/20/2019 Estrutura Dados Dovicchi UFSC
7/164
Prefácio
Este livro aborda alguns dos principais conceitos da área de programação eestrutura de dados. Podemos considerar os dados como conjuntos de elemen-tos de determinados tipos que podem ser tratados como unidades informacio-nais. A informação, entretanto, depende da contextualização dos dados, isto é,como são selecionados, relacionados e organizados. Uma vez que a ciência dacomputação está fundamentada no processamento da informação, o estudo doconteúdo desta informação depende dos tipos de dados que são manipulados esua organização. Assim, a disciplina Estrutura de Dados trata da manipulação,organização e utilização destes dados.
Estrutura de Dados
Como manipularComo organizarComo utilizar
Com a finalidade de compreender os dados e a maneira como eles s ão tipa-dos, armazenados, ordenados etc., vamos utilizar, neste livro, alguns conceitosde programação procedural e funcional1. Para isso, escolhemos a linguagem CANSI para apresentar os algoritmos conceituais no modelo procedural e a lin-guagem Haskell no modelo funcional. A forma procedural (em C) apresentauma visão imperativa dos dados e algoritmos, enquanto a forma funcional apre-senta uma visão declarativa. As linguagens C e Haskell foram escolhidas pelasimplicidade, pela facilidade de compreensão e pelo poder de processamentode dados.
Como as linguagens de programação, em geral, são apenas formas semânticasde representação, elas facilitam a implementação dos algoritmos. Assim, quandonecessário faremos algumas incursões na sintaxe de C e Haskell , apenas osuficiente para compreender o processo de um algoritmo.
1Ver apêndice A
7
8/20/2019 Estrutura Dados Dovicchi UFSC
8/164
8
O conteúdo deste curso se encontra dividido em 4 partes. Na primeiraparte serão estudados os conceitos fundamentais e introdutórios das entidadese abstrações que compõem a representação dos dados, além das expressõesque formam os termos e sintaxe desta representação (capı́tulo 1). Na segundaparte, abordaremos as representações propriamente ditas, as operações com da-dos e a construção de funções que nos permitam fazer estas operações (capı́tulo2). Na terceira parte nos dedicaremos ao estudo da manipulação de dados emlistas, filas, pilhas e outras possibilidades de representação, tais como grafos eárvores (capı́tulos 3 e 4). Finalmente, na quarta parte vamos ver como as estru-turas de dados se relacionam com a atividade de programação e implementaçãode algoritmos, ressaltando os conceitos de máquinas abstratas, recursividade,classificação, busca, ordenação e hashing (caṕıtulos 5 e 6).
No apêndice A, encontra-se alguns conceitos básicos de programação fun-
cional, particularmente da linguagem Haskell . O apêndice B traz umaintrodução ao cálculo-λ que é a fundamentação teórica das estruturas em Lin-guagem Funcional . Finalmente, o apêndice C traz alguns exerćıcios relacio-nados aos conceitos dos caṕıtulos do livro.
Prof. Dr. João DovicchiFlorianópolis, agosto de 2007.
8/20/2019 Estrutura Dados Dovicchi UFSC
9/164
Caṕıtulo 1
Dados
Se partirmos do pressuposto de que a informação tem por objetivo a reduçãoda incerteza sobre determinado fato, podemos afirmar que informação é umamensagem resultante do processamento, manipulação e organização dos dados,com a finalidade de proporcionar o conhecimento de um fato a quem tiveracesso a ela. Assim, podemos definir dados como as unidades básicas de umconjunto de informações.
Em computação, dados são conjuntos de valores ou caracteres representa-dos por d́ıgitos binários (bits) e que se localizam em endereços de memória,arquivos ou qualquer outro meio digital. Eles podem ser representados porconjuntos de bits de tamanho variável, dependendo do seu tipo e tamanho, e
podem sofrer vários tipos de operações. Neste caṕıtulo, vamos entender comoos dados são definidos (tipados) e de que maneira podem ser manipulados.
1.1 Tipos de Dados
Os dados podem ser tipados dependendo de vários fatores que possibilitam asua caracterização. Eles devem ser definidos com relação a três propriedadesprincipais:
1. Conjunto de valores, ou seja, que conjunto de valores uma variável ou
campo de dados pode receber ou armazenar;2. Conjunto de operadores, ou seja, que conjunto de operadores podem
agir sobre os dados ou campo de dados; e
3. Referência, ou seja, de que maneira os dados podem ser localizados oureferenciados.
9
8/20/2019 Estrutura Dados Dovicchi UFSC
10/164
10 CAP ́ITULO 1. DADOS
Nos sistemas digitais de informação (informática), os dados podem ser de 3tipos: numéricos, literais e lógicos. Os dados numéricos representam entidadesaritméticas, podendo ser números inteiros, decimais ou racionais. Os dadosliterais representam caracteres, d́ıgitos e śımbolos de uma determinada tabelaou conjunto ou uma cadeia deles. Os dados lógicos representam os valoreslógicos de verdadeiro ou falso.
Algumas caracterı́sticas são implicitamente declaradas como, por exemplo,int, char, float etc.. Outras podem ser declaradas explicitamente, de formaabstrata. Este último tipo é denominado Tipo de Dado Abstrato (TDA).Um TDA consiste em duas partes: a definição de valores e a definição deoperadores.
Os valores dos dados podem ser armazenados em variáveis ou constantespara ser referenciados posteriormente. No caso das variáveis, seus conteúdos
podem ser alterados no decorrer do algoritmo, enquanto as constantes não.As variáveis, ao ser declaradas, fazem com que o compilador reserve o espaçoadequado de memória para o seu tipo.
1.2 Tipo de dado abstrato
A programação orientada a objetos — Object Oriented Programming (OOP) — pode ser descrita como a programação de tipos abstratos de dados e suasrelações. Independentemente da linguagem utilizada, um tipo abstrato de dadopode ser especificado por uma estrutura abstrata (abstract structure ), definiçãode valores e de operadores. A definição tem 2 propriedades:
1. Exporta um tipo, definindo suas condições e seu domı́nio; e
2. Exporta as operações, que define o acesso ao tipo de estrutura de dados.
Para compreender como se define um tipo de dado, vamos tomar comoexemplo a definição de um tipo de dado racional em C++ (RATIONAL). Umnúmero racional é aquele que pode ser expresso como um quociente de doisinteiros. Podemos, por exemplo, definir as operações adição, multiplicação eigualdade sobre os números racionais a partir de dois inteiros, como na espe-
cificação deste tipo de dado abstrato (TDA) na listagem 1.1.
Observe que a definição do tipo RATIONAL, em C, não deixa claro comoas operações funcionam, mas observe a mesma definição em uma linguagemfuncional (veja listagem 1.2)
8/20/2019 Estrutura Dados Dovicchi UFSC
11/164
1.2. TIPO DE DADO ABSTRATO 11
Listagem 1.1: Tipo Abstrato de Dado: Rational.
/* d ef in ic ao de v al or */
a bs tr ac t t y pe de f R AT IO NA L ;
c o nd i ti o n R AT IO NA L [ 1] < > 0 ;
/ * d e fi n ic o es d e o p er a do r es * / a b st r ac t R A TI O NA L m a k e r at i o n al ( a , b )
i nt a , b ;
p r e c on d i t io n b < > 0 ;
p o s t co n d i ti o n m a k e ra t i o n al [ 0] = = a ;
m a k e ra t i o n al [1] == b ;
a b st r ac t R A TI O NA L a dd ( a , b ) /* written a + b */
R A TI O NA L a , b ;
p o st c on d it i on a dd [ 1 ] = = a [ 1] * b [ 1 ];
add [ 0] == a [0] * b [1] + b [0] * a [1] ;
a b st r ac t R A TI O NA L m u lt ( a , b ) /* w ri tt en a * b */
R A TI O NA L a , b ;
p o st c on d it i on m ul t [0 ] = = a [ 0] * b [ 0 ];
mult [1] == a [1] * b [1];
a b st r ac t R A TI O NA L e q ua l ( a , b ) /* w rit te n a == b */
R A TI O NA L a , b ;
p os tc on di ti on e qu al == ( a [0 ] * b [ 1] == b [0 ] * a [ 1] );
8/20/2019 Estrutura Dados Dovicchi UFSC
12/164
12 CAP ́ITULO 1. DADOS
Listagem 1.2: Tipo Abstrato de Dado Rational em Haskell.
d at a ( I n te gr al a ) = > R at io a = ! a :% ! a d er iv in g ( Eq )t yp e R at io na l = R at io I nt eg er
(%) :: ( Integral a ) = > a -> a -> Ratio a
r ed uc e 0 = e rro r " Ra ti o .% : z er o d en om in at or "
reduce x y = ( x ‘ quot ‘ d ) :% ( y ‘ quot ‘ d )
where d = gcd x y
i ns ta nc e ( I n te gr al a ) = > Num ( Ra ti o a )
where
( x :% y ) + ( x ’: %y ’ ) = r ed uc e ( x* y’ + x ’* y ) ( y *y ’ )( x:% y) * ( x ’:% y ’) = r ed uce ( x * x ’) ( y * y ’)
/ + + ) ) ) + + /
Observe, na listagem 1.2, como é mais clara a definição de Rational. As-sim, pode-se perceber que, dado a + b, onde
a =
a0a1 e b =
b0b1
então
a + b = a0 × b1 + a0 × a1
a1 × b1
As linguagens orientadas ao objeto utilizam o TDA para disponibilizarnovos tipos de dados definidos pelo usuário (p. ex. C++, Java etc.), mas osTDAs podem ser definidos para outros tipos de estrutura.
1.3 Tipos de dados em CEm C, existem os tipos básicos int, float, double e char. Como já vimosuma variável declarada como int contém um inteiro; declarada como floatcontém um número real de ponto flutuante; e, se declarada como double con-terá um número real de ponto flutuante e de dupla precisão.
8/20/2019 Estrutura Dados Dovicchi UFSC
13/164
1.4. OPERAÇ ˜ OES 13
Ref.interpretar
Como
unsigned short int var
Mem.
Tam.da
Figura 1.1: Representação de dados em C
A variável do tipo int, por exemplo, pode ser declarada junto com trêstipos de qualificadores: short, long e unsigned. Os qualificadores short elong podem variar de uma máquina para outra mas, em geral têm as seguintesespecificações:
short int – normalmente valores entre -32768 e 32767
long int – normalmente valores entre -2147483648 e 2147483647
unsigned short int – valores entre 0 e 65535
unsigned long int – valores entre 0 e 4294967295
A declaração de variáveis em C especifica dois atributos: a quantidade dememória a ser reservada para o armazenamento do tipo de dado; e como osdados armazenados devem ser interpretados (veja figura 1.1).
1.4 Operações
As operações que podem ser efetuadas sobre dados são de três tipos: Aritméticas,Lógicas e Relacionais. É evidente que tais operações se referem aos dados
numéricos, enquanto que dados literais podem sofrer outros tipos de operações,tais como, concatenação, tamanho da cadeia, determinação de posição de umcaractere na cadeia, comparação etc.. As operações podem ser:
• Aritméticas, por exemplo: Adi̧cão, Subtração, Multiplicação, Divisãoetc.;
8/20/2019 Estrutura Dados Dovicchi UFSC
14/164
14 CAP ́ITULO 1. DADOS
• Lógicas, por exemplo: NOT, AND, OR, XOR;
• Relacionais. por exemplo: Maior que (>), menor que (
8/20/2019 Estrutura Dados Dovicchi UFSC
15/164
1.6. DADOS EM C: TIPOS E MODIFICADORES 15
Listagem 1.3: Programa exemplo de referência.
/* T ip os de v ar ia ve is e e nd er ec os */ # i n c lu d e < s t d io . h >
# i n c lu d e < s t d li b . h >
i nt m ai n ( i nt a rg v , c ha r * a rg c [ ]) {
i nt a ;
a = 5;
p ri nt f ( " Va lo r d e a : % d \ n" , a ) ;
p ri nt f ( " En de re co d e a : % x \n " , & a );
p ri nt f ( " Co nt eu do d e & a : % d \ n" , * (& a ) );
/ + + ) ) ) + + /
r e tu r n 0 ;}
1.6 Dados em C: Tipos e modificadores
A linguagem C trabalha com o conceito de tipo de dado com a finalidadede definir uma variável antes que ela seja usada. Em termos de estrutura,tal procedimento é utilizado para possibilitar a alocação de memória para avariável na área de dados do programa.
Quando se trata de definir variáveis, é importante ressaltar que tal definiçãopode se dar em dois escopos:
1. Definição da variável como declarativa com alocação de memória:
int a;
char c;
struct per_rec person;
2. Definição como construtor de nome, parâmetro e tipo de retorno de umafunção:
long sqr(int num)
{
return(num*num);
}
8/20/2019 Estrutura Dados Dovicchi UFSC
16/164
16 CAP ́ITULO 1. DADOS
Em C existem, basicamente 6 tipos, no padrão ANSI da linguagem, quedefinem o tipo de variável a ser manipulada pelo programa naquele endereçode memória, a saber: int, float, double, char, void e enum1.
1.6.1 O tipo int
O tipo int define uma variável do tipo “inteiro” que possue o tamanho de 16bits (2 bytes) e pode armazenar valores de −32767 a 32767. Por exemplo:
{
int Conta;
Conta = 5;
}
1.6.2 O tipo float
O tipo float define uma variável do tipo “real” (com ponto flutuante) quetem o tamanho de 32 bits (4 bytes) e pode armazenar valores reais com seisd́ıgitos de precisão. Por exemplo:
{
float quilos;
quilos = 8.123456;
}
1.6.3 O tipo double
O tipo double define uma variável real de maior precisão que tem o tamanhode 64 bits (8 bytes) e pode armazenar números reais com 10 d́ıgitos de precisão.Por exemplo:
{
double _Pi;
_Pi = 3.1415926536;
}
Nota: Esta questão de precisão pode variar de compilador para compiladorou de processador para processador. Voce podeŕa testar a precisão de seu
1Compiladores mais recentes reconhecem o tipo boolean.
8/20/2019 Estrutura Dados Dovicchi UFSC
17/164
1.6. DADOS EM C: TIPOS E MODIFICADORES 17
compilador/processador usando um programa que gere números e verificandoa precisão. Por exemplo, o programa:
#include
#include
int main (){
double rl;
rl = 4*atan(1.0);
fprintf(stdout, "%.10f\n", rl);
return 0;
}
imprime o valor de π com 10 casas depois da v́ırgula. Voce pode alterar oparâmetro %.10f para valores maiores que 10 e verificar a precis ão usando umvalor bem preciso de π conhecido. O valor com 50 casas depois da v́ırgula é:
π = 3.14159265358979323846264338327950288419716939937508
1.6.4 O tipo char
O tipo char define uma variável do tipo “caractere” com o tamanho de 8 bits(1 byte), que armazenha o valor ASCII do caractere em questão. Por exemplo:
{
char letra;
letra = ’x’;
}
Uma cadeia de caracteres é definida como um apontador para o endereçodo primeiro caractere e que tem um tamanho definido de um array .
1.6.5 O tipo enum
O tipo enum esta relacionado à diretiva #define e permite a definição de umalista de aliases que representa números inteiros, por exemplo, no lugar decodificar:
#define SEG 1
#define TER 2
8/20/2019 Estrutura Dados Dovicchi UFSC
18/164
18 CAP ́ITULO 1. DADOS
#define QUA 3
#define QUI 4
#define SEX 5
#define SAB 6
#define DOM 7
#define FALSE 0
#define TRUE 1
é posśıvel usar
enum semana { Seg=1, Ter, Qua, Qui, Sex Sab, Dom} dias;
enum boolean { FALSE = 0, TRUE };
1.7 Modificadores
Os tipos int, float e double podem ser redimensionados por modificadoreslong ou short; e signed ou unsigned. Tais modificadores definem a quanti-dade de bytes alocados na memória para as respectivas variáveis (veja tabela1.1).
Tipo Bytes Bits Valoresshort int 2 16 -32.768 → +32.767unsigned short int 2 16 0 → +65.535
unsigned int 2 16 0 → +65.535int 2 16 -32.768 → +32.767
long int 4 32 -2,147,483,648 → +2,147,483,647signed char 1 8 -128 → +127
unsigned char 1 8 0 → +255float 4 32
double 8 64long double 16 128
Tabela 1.1: Tipos de dados e tamanho das variáveis
O uso do modificador signed com int é redundante, no entanto é permitidoporque a declaração do tipo inteiro assume um número com sinal. O uso de
8/20/2019 Estrutura Dados Dovicchi UFSC
19/164
1.8. QUALIFICADORES DE DADOS 19
signed char pode ser feito em compiladores que não implementam este tipopor default, assim como o uso de unsigned double deve ser usado com cautelapois alguns compiladores não permitem esta modificação em números de pontoflutuante. Isto tudo deve ser levado em conta no caso da portabilidade docódigo.
Nos dias de hoje, o custo da memória é relativamente baixo, por isso poucosse preocupam com a quantidade utilizada, mas tudo isso é uma questão deconceito, uma vez que as linguagens de alto ńıvel que estão aparecendo seincumbem de dimensionar a memória. A questão é: será que o programaresultante é otimizado?
1.8 Qualificadores de dados
A linguagem C define dois tipos de qualificadores const e volatile que po-dem melhorar o desempenho, principalmente em cálculos matemáticos. Osqualificadores podem ser usados para definir constantes que são usadas emqualquer parte do programa. Por exemplo:
const float pi=3.14159;
O qualificador volatile é usado para propósitos dinâmicos, muito usadoem device drivers , para passar um dado por uma porta de hardware . Porexemplo:
#define TTYPORT 0x17755U
volatile char *port17 = (char)*TTYPORT;
*port17 = ’o’;
*port17 = ’N’;
na falta do qualificador volatile, o compilador pode interpretar a declaração*port 17 = ’o’; como redundante e removê-la do código objeto. A de-
claração previne a otimização do código pelo compilador.
8/20/2019 Estrutura Dados Dovicchi UFSC
20/164
20 CAP ́ITULO 1. DADOS
8/20/2019 Estrutura Dados Dovicchi UFSC
21/164
Caṕıtulo 2
Representação de dados
Já vimos como podemos representar dados de forma direta, referenciando-ospor meio de variáveis. Vamos, agora analisar a representação de dados quepodem ser referenciados por ı́ndices. Para isso, devemos, partir de algunsconceitos fundamentais que envolvem vetores e matrizes.
Primeiramente, vamos introduzir o conceito de refer̂encia indexada quepode ser de vários tipos:
1. Vetorial;
2. Matricial; e
3. Multidimensional.
Consideremos, por exemplo, que tenhamos de manipular dados referentes atemperaturas médias de 3 cidades, no peŕıodo de 4 meses. Estes dados podemser organizados em uma tabela onde as colunas se referem às temperaturasmédias em cada mês e as linhas se referem às temperaturas médias em cadacidade (veja tabela 2.1).
Cidade Janeiro Fevereiro Março AbrilCampinas 26 25 27 26
Campos do Jordão 22 23 21 20Ribeirão Preto 31 29 30 29
Tabela 2.1: Dados de temperatura média de três cidades paulistas no peŕıodode janeiro a abril de 2003.
21
8/20/2019 Estrutura Dados Dovicchi UFSC
22/164
22 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
De forma semelhante à tabela, estes dados podem ser representados emuma matriz, onde cada coluna representa as médias mensais e onde cada linharepresenta os dados de uma cidade. Por exemplo:
A =
a1,1 a1,2 a1,3 a1,4a2,1 a2,2 a2,3 a2,4a3,1 a3,2 a3,3 a3,4
=
26 25 27 2622 23 21 2031 29 30 29
A representação de dados por arranjo (array ) multidimensional é uma
forma comum de referenciar dados de um conjunto coerente. A dimensãon de um array pode ser qualquer valor inteiro. Assim,
• Se n = 1, o array é unidimensional e é chamado de vetor;
• Se n = 2, o array é bidimensional e é chamado de matriz;
• Para n = 3, o array é tridimensional e pode ser representado por umamatriz de matrizes; e
• Para n > 3, o array é multidimensional e podemos representá-los apenasformalmente.
Vamos estudar como é feita a representação de dados em array como tipode dado abstrato, sua utilização e as operações com arrays de dados numéricose literais.
2.1 Representação em array
Dados de um determinado conjunto podem ser representados como um tipode dado abstrato (TDA), que respeita algumas convenções. Por exemplo, umaseqüência pode ser descrita como na listagem 2.1
Assim, pode-se definir um TDA para um vetor como na listagem 2.2.
8/20/2019 Estrutura Dados Dovicchi UFSC
23/164
2.1. REPRESENTAÇ ˜ AO EM ARRAY 23
Listagem 2.1: TDA de uma seqüência/ * E xe mp lo G en ´ e r i c o :
a bs tr ac t t yp ed ef < t ip o1 , t ip o2 , . .. , t ip oN >
[ t i p o _ d a _s e q ]; * /
a b st r ac t t y pe d ef < < in t > > i n ts e q ;
/ * s eq . d e i nt ei ro s d e q ua lq ue r t am an ho * /
a b s t ra c t t y p e d ef < i n t eg e r , c h ar , f l o at > s e q 3 ;
/* s eq de t am an ho 3 c om um i nt ei ro ,
um c ar ac te re e u m f lo at */
a b st r ac t t y pe d ef < < in t , 10 > > i n ts e q ;
/* s eq de 1 0 i nt ei ro s */
Listagem 2.2: TDA de um vetor
a b st r ac t t y pe d ef < < ti po , t am > > A R RT Y PE ( t a m , t i p o );
c o nd i ti o n t ip o ( ta m ) = = i nt ;
a b st r ac t t i po e x tr a ct ( a , i ) ; / * w ri tt en a [i ] */
A R RT Y PE ( t a m , t i po ) a ;
i nt i ;
p re co nd it io n 0
8/20/2019 Estrutura Dados Dovicchi UFSC
24/164
24 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
Listagem 2.3: Programa exemplo de uso de array
# i n c lu d e < s t di o . h ># i n c lu d e < s t d li b . h >
# d e f in e N U ME R OS 1 0
i nt m ai n ( i nt a rg v , c ha r * a rg c [ ]) {/ + + } + + /
i nt n um [ N U M E RO S ] ; /* v e to r de n u me ro s * /
i nt i , t ot al ;
f l oa t m e di a ;
t ot al = 0;
f or ( i = 0 ; i < N U M E RO S ; i + + ) {/ + + } + + /s c an f ( " % d " , & n u m [ i ]) ;
t ot al + = n um [ i ];
}
media = ( float ) total / ( float ) NUMEROS ;
p r in t f ( " M e di a = % f \ n " , m e di a ) ;
r e tu r n 0 ;
}
/ + + ) ) + + /
Desta forma, pode-se usar a notação a[i], onde a representa uma variávele i um ı́ndice. Na prática temos que a referencia o endereço de memóriada primeira variável do vetor e i referencia o deslocamento dentro desta áreareservada, que depende do tipo de variável declarada.
Vamos, tomar um exemplo de uso de um vetor para manipulação de dados.Suponhamos que temos que entrar 10 números inteiros quaisquer e devemosefetuar algumas operações sobre eles, por exemplo, calcular sua média (vejalistagem 2.3).
Neste exemplo a variável num[i] representa um vetor do tamanho de 10elementos (definido na constante NUMEROS).
8/20/2019 Estrutura Dados Dovicchi UFSC
25/164
2.2. USANDO VETORES COMO PAR ̂AMETROS DE FUNÇ ˜ OES 25
Listagem 2.4: media2.h
/ * C a be c al h o p a r a o p ro gr am a m ed ia 2 . c * /
# d e f in e N U ME R OS 1 0
f lo at m ed ( in t a [] , i nt t );
Listagem 2.5: med.c
# i n c lu d e " m e d i a2 . h "
f lo at m ed ( i nt a [] , i nt t am ) {
i nt i , s om a;
f l oa t r e su l t ;
s om a = 0;
f or ( i =0 ; i < t am ; i + +) {
s om a + = a [ i ];
}
r es ul t = ( f lo at ) s om a / ( f lo at ) t am ;
r e tu r n ( r e s u lt ) ;
}
2.2 Usando vetores como parâmetros de funções
Programas em C podem ser modulares, ou seja, podemos especificar defini çõesem cabeçalhos (.h) e podemos colocar funções em subprogramas. Vamos, porexemplo, modularizar nosso programa de médias. Podemos colocar a constanteem um arquivo de cabeçalho e a função que calcula a média em um outroarquivo, deixando apenas o corpo principal para a função main. Assim, ocabeçalho poderia ser como na listagem 2.4.
A função que calcula a média (med.c) recebe um vetor como parâmetro eo tamanho deste vetor, conforme descrito no cabeçalho (listagem 2.5).
8/20/2019 Estrutura Dados Dovicchi UFSC
26/164
26 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
Listagem 2.6: media2.c
# i n c lu d e < s t di o . h ># i n c lu d e < s t d li b . h >
# i n c lu d e " m e d ia 2 . h "
i nt m ai n ( i nt a rg v , c ha r * a rg c [ ]) {/ + + } + + /
i nt n um [ N U M E RO S ] ; /* v e to r de n u me ro s * /
i nt i ;
f l oa t m e di a ;
f or ( i = 0 ; i < N U M E RO S ; i + + ) {/ + + } + + /
s c an f ( " % d " , & n u m [ i ]) ;
} media = med ( num , NUMEROS );
p r in t f ( " M e di a = % f \ n " , m e di a ) ;
r e tu r n 0 ;
}
/ + + ) ) + + /
Finalmente, o programa principal (media2.c) faz a chamada à função, pas-sando os parâmetros (listagem 2.6).
Neste caso, para compilar o programa, deve-se passar ao compilador oscódigos fonte a ser compilados para gerar o executável. Por exemplo:
gcc -O2 -Wall -ansi -pedantic -o
2.3 Operações com arrays
As operações sobre conjunto de dados representados em arrays podem ser dedois tipos: operações sobre dados numéricos e operações sobre dadosliterais. As operações sobre dados numéricos segue as regras da álgebra linear,uma vez que um array numérico é do tipo vetor, matriz ou multidimensional.As operações com dados literais são, via de regra, operações de manipulação
8/20/2019 Estrutura Dados Dovicchi UFSC
27/164
2.3. OPERAÇ ˜ OES COM ARRAYS 27
de caracteres ou cadeia de caracteres, tais como concatenação, segmentação,localização de um caractere na cadeia etc..
As operações sobre dados numéricos compreende:
• Multiplicação por escalares;
• Soma e subtração;
• Multiplicação entre arrays;
• Identidade;
• Inversibilidade; e
• Operações lógicas.
A multiplicação por escalares pode ser facilmente implementada, uma vezque a matriz resultante tem as mesmas dimensões da matriz de entrada (vejaexemplo na listagem 2.7).
As operações sobre dados literais podem ser:
• Recuperação;
• Ordenação;
• Inserção;
• Eliminação;
• Substituição;
• Concatenação; e
• Segmentação.
Em C, existem várias funções para manipulação de caracteres e cadeiasde caracteres (strings). Observe, no programa da listagem 2.8, como se podeatribuir este tipo de dado para variáveis. Se usarmos uma atribuição direta,do tipo:
a_linha = "Outra linha.";
8/20/2019 Estrutura Dados Dovicchi UFSC
28/164
28 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
Listagem 2.7: Multiplicação de matrizes: escmulmat.c
# i n c lu d e < s t di o . h ># i n c lu d e < s t d li b . h >
# d e fi ne L IN HA S 4
# d e fi ne C OL UN AS 5
i nt m ai n ( i nt a rg v , c ha r * a rg c [ ]) {/ + + } + + /
f l o a t M a t _ A [ L I N H A S ] [ C O L U N A S ] ; / * m at ri z de e nt ra da */
f l o a t M a t _ B [ L I N H A S ] [ C O L U N A S ] ; / * m at ri z r e su l ta n te * /
f l oa t f a to r ; / * f at or d e m u lt i pl i ca c ao * /
i nt i , j ;
f at or = 1 .0 ;
p ri nt f ( " En tr e o f at or d e m u lt i pl i ca c ao : " ) ;
s c an f ( " % f " , & f a t or ) ;
/ + + ) + + /
f or ( i = 0 ; i < L I N HA S ; i + + ) {
f or ( j = 0 ; j < C O L U NA S ; j + + ) {/ + + } } + + /
p ri nt f (" l in ha % d, c ol un a % d: " , i , j );
s c an f ( " % f " , & M a t _A [ i ] [ j ] );
M at _B [ i ][ j ] = M at _A [ i ][ j ] * f at or ;
}
}f or ( i = 0 ; i < L I N HA S ; i + + ) {
f or ( j = 0 ; j < C O L U NA S ; j + + ) {/ + + } } + + /
p ri nt f ( " %2 .2 f " , M a t_ A [ i ][ j ] );
}
p r i n t f ( " \ n " ) ;
}
/ + + ) ) ) + + /
p r i n t f ( " \ n \ n " ) ;
f or ( i = 0 ; i < L I N HA S ; i + + ) {
f or ( j = 0 ; j < C O L U NA S ; j + + ) {/ + + } } + + /
p ri nt f ( " %2 .2 f " , M a t_ B [ i ][ j ] );}
p r i n t f ( " \ n " ) ;
}
r e tu r n 0 ;
}
/ + + ) + + /
8/20/2019 Estrutura Dados Dovicchi UFSC
29/164
2.3. OPERAÇ ˜ OES COM ARRAYS 29
Listagem 2.8: Exemplo de manipulação de cadeias de caracteres: prtstr.c
/ * p rt st r . c - C om o a tr ib ui r c ad ei a d e c a ra c te r es
e m v a ri ´ a v ei s * /
# i n c lu d e < s t d io . h >
# i n c lu d e < s t d li b . h >
# i n c lu d e < s t r in g . h >
i nt m ai n ( in t a rg v , c ha r * a r gc [ ] ){
c ha r a _l in ha [ 80 ] , m ai s_ um a [ 80 ];
c h ar * s t r pt r ; / * P on te ir o p ar a o c on te ud o de a _l in ha */
/ * P ar a a tr ib ui r u ma c ad ei a d e c a ra c te r es */
s t rc p y ( a _l in ha , " O u t ra l i nh a . " ) ;
s t rc p y ( m a is _ um a , a _ li n ha ) ;
s tr pt r = a _l in ha ;
/* P ar a a d i ci on ar m ai s c ar ac te re s */
s t rc a t ( a _l in ha , " b la - b la " ) ;
p ri nt f ( " U ma l in ha d e t ex to . \ n" ) ;
p r in t f ( " V a r ia v el ’ a _ l in h a ’ : % s \ n " , a _ li n ha ) ;
p r in t f ( " V a r ia b le ’ m a i s_ u ma ’ : % s \ n " , m a is _ um a ) ;
p ri nt f ( " C o nt eu do d e ’ a _l in ha ’: % s \n " , s tr pt r );
r e tu r n 0 ;
/ + + ) ) ) + + /
}
8/20/2019 Estrutura Dados Dovicchi UFSC
30/164
30 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
Figura 2.1: Representação de dados em C
O compilador acusará um erro de tipo. Assim, devemos usar a funçãostrcpy. Para adicionar mais caracteres pode-se usar a função strcat, ambasdescritas no cabeçalho padrão do C “string.h”.
Neste exemplo dimensionamos as variáveis a linha e mais uma com o ta-manho de 80 caracteres. Neste caso, o programa reservará 80 posições do tipochar para cada uma, mesmo que nem todas sejam usadas (veja figura 2.1).
As posições de 0 a 12, cada uma com 1 byte, da cadeia de caracteresconterão as representações ASCII de cada letra, espaço, ponto e um caractere\0 no final:
45 75 74 72 61 20 6C 69 6E 68 61 2E 00
O restante conterá “zeros” representando o caractere NULL.
2.4 Linguagens funcionais e array
Embora o processamento de listas nas linguagens funcionais sejam extrema-mente fáceis, a implementação de array não o é. Na verdade, o conceito dearray é extremamente imperativo, uma vez que tal estrutura é tratada comouma coleção de variáveis relacionadas aos endereços de memória e está forte-mente vinculada à arquitetura da máquina de von Neumann.
Mesmo assim, é posśıvel implementar arrays em Haskell de forma funcional.Em Haskell, um array é do tipo:
Ix a => (a,a) -> [(a,b)] -> Array a b
Se a é do tipo ı́ndice e b é do tipo “any”, o array com ı́ndices em a eelementos em b é notado como Array a b. Assim,
array (1,3) [(1,20),(2,10),(3,15)]
corresponde ao vetor [20, 10, 15]T com ı́ndices (1, 2, 3) e
8/20/2019 Estrutura Dados Dovicchi UFSC
31/164
2.5. REPRESENTAÇ ˜ AO DE DADOS E MATRIZES 31
array (0,2) [(0,20),(1,10),(2,15)]
é o mesmo vetor com ı́ndices (0, 1, 2). Um array bidimensional pode ser escritocomo:
array((1,1),(2,2)) [((1,1),2),((1,2),2),((2,1),5),((2,2),8)]
que representa a matriz:
a1,1 a1,2a2,1 a2,2 =
2 25 8
2.5 Representação de dados e matrizesVimos que as matrizes podem ser representadas por estruturas como arranjode dados (array ). Aĺem disso, conceitos de estruturas relacionadas com algo-ritmos funcionais, tais como grafos e árvores dependem de conceitos um poucomais aprofundados de matrizes, principalmente os relacionados com álgebrabooleana (matrizes binárias) e matrizes esparsas.
As matrizes são entidades matemáticas usadas para representar dados emduas dimensões de ordenação. Uma matriz pode sofrer vários tipos de operações,tais como adição, multiplicação, inversão etc..
2.5.1 Matrizes: conceitos gerais
Denominamos matriz de ordem m × n à ordenação bidimensional de m por nelementos dispostos em m linhas e n colunas. Por exemplo:
A =
a1,1 a1,2 · · · a1,na2,1 a2,2 · · · a2,n
... ...
. . . ...
am,1 am,2 . . . am,n
1. A matriz onde m = n é denominada de matriz quadrada e é represen-tada por An ou A(n,n) e é dita de ordem n.
2. A matriz, onde m = n é chamada de matriz retangular e é de ordemm × n.
8/20/2019 Estrutura Dados Dovicchi UFSC
32/164
32 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
3. A matriz de ordem m×1 é chamada de matriz coluna ou vetor colunae a matriz de ordem 1 × n é chamada de matriz linha ou vetor linha,por exemplo:
A(4,1) =
3−2−54
; A(1,3) =
5 2 −3
4. Cada elemento de uma matriz é representado por ı́ndices i, j (por exem-plo: ai,j) onde o primeiro ı́ndice (i) representa a linha e o segundo ( j)representa a coluna do elemento da matriz.
5. Em uma matriz quadrada A = [ai,j ] de ordem n tem uma diagonal
principal que é dada pelos elementos ai,j onde i = j , ou seja, a diago-nal principal de uma matriz é dada pelos elementos (a1,1, a2,2, . . . an,n).Chama-se de diagonal secundária ao conjunto de elementos ai,j emque i + j = n + 1, ou seja, a diagonal secundária é dada pelos elementos(a1,n, a2,n−1, . . . , an,1).
6. Uma matriz em que os elementos a(i,j) são nulos quando i = j , é chamadade matriz diagonal. Exemplo:
A =
a1,1 0 0 · · · 00 a2,2 0 · · · 0
0 0 a3,3 · · · 0...
... ...
. . . ...
0 0 0 · · · an,n
7. A matriz diagonal de ordem n em que os elementos ai,j, para i = j , sãoiguais à unidade é chamada matriz unidade ou matriz identidade eé notada por I ou In.
8. Uma matriz m × n com todos os elementos nulos é chamada de matriznula e é notada por 0m,n.
9. Dada uma matriz A = [ai,j ] de ordem m × n, e a matriz B = [bi,j ],onde bi,j = −ai,j , dizemos que B é a matriz oposta de A, que pode serrepresentada por −A. Exemplo:
A =
5 9 −27 −6 3 ; B =
−5 −9 2−7 6 −3 ;e B = −A
8/20/2019 Estrutura Dados Dovicchi UFSC
33/164
2.5. REPRESENTAÇ ˜ AO DE DADOS E MATRIZES 33
10. Dada uma matriz A = [ai,j] de ordem m ×n, existe uma matriz B = [bi,j ]de ordem n × m em que bi,j = a j,i, então B é a mmatriz transpostade A que pode ser notada como AT ou At. Exemplo:
A =
1 −5 46 −3 23 1 1
−2 3 5
; B =
1 6 3 −2
−5 −3 1 34 2 1 5
;e B = AT
11. Uma matriz A = [ai,j] é denominada matriz simétrica se, e somentese, os elementos ai,j = a j,i para i = j .
12. A matriz quadrada A(n) é chamada de matriz triangular superior,
quando os termos ai,j da matriz, para i < j, são iguais a zero. Quandoos termos ai,j da matriz, para i > j, são nulos. a matriz é chamada dematriz triangular inferior.
2.5.2 Operações com matrizes
A manipulação de dados organizados em estruturas, uniões, array, listas elistas de listas podem ser do mesmo tipo de opera ções com as matrizes. Asprincipais operações com matrizes são: adição de matrizes, multiplicação porescalares, multiplicação de matrizes e transposição de matrizes.
Adição de matrizes
A adição de duas matrizes de mesma ordem é resultante da adição termo atermo de cada matriz. A adição de duas matrizes A e B de ordem m × n,definida como A + B, é uma matriz C de mesma ordem, onde ci,j = ai,j + bi,j.Por exemplo, seja: a1,1 a1,2a2,1 a2,2
+ b1,1 b1,2b2,1 b2,2
= a1,1 + b1,1 a1,2 + b1,2a2,1 + b2,1 a2,2 + b2,2
A subtração de duas matrizes A e B , definida por A − B pode ser expressa
pela diminuição termo a termo das duas matrizes ou pela soma da matriz Apela oposta de B, definida como A + (−B).
Propriedades da adição de matrizes: sejam A, B e C matrizes damesma ordem, então
1. A + (B + C ) = (A + B) + C ;
8/20/2019 Estrutura Dados Dovicchi UFSC
34/164
34 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
2. A + B = B + A;
3. Seja 0 uma matriz nula de mesma ordem, então A + 0 = A;
4. A + (−A) = 0.
Multiplicação por escalares
Seja A = [ai,j] e α um escalar, o produto αA é uma matriz B = [bi,j] tal quebi,j = αai,j. Por exemplo:
2 ×
4 −2 6−3 5 1
2 −1 4
=
8 −4 12−6 10 2
4 −2 8
Propriedades da multiplicação por escalares: sejam α e β dois esca-lares e A e B duas matrizes de mesma ordem, então
1. (αβ )A = α(βA);
2. (α + β )A = αA + βA;
3. α(A + B) = αA + αB; e
4. 1A = A.
Multiplicação de matrizes
Dadas uma matriz A de ordem m × n e B de ordem n × p, o produto das duasé uma matriz C de ordem m × p, tal que:
ci,j =n
k=1
ai,k bk,j
Por exemplo, considere as matrizes A(2×3) e B(3×4):
A =
2 −1 43 2 −2 e
3 1 2 −1
−2 2 1 34 −1 −3 0
O produto de A × B é uma matriz C (2×4), onde
8/20/2019 Estrutura Dados Dovicchi UFSC
35/164
2.5. REPRESENTAÇ ˜ AO DE DADOS E MATRIZES 35
c1,1 = a1,1 × b1,1 + a1,2 × b2,1 + a1,3 × b3,1
= 2 × 3 + (−1) × (−2) + 4 × 4= 24
c1,2 = a1,1 × b1,2 + a1,2 × b2,2 + a1,3 × b3,2= 2 × 1 + (−1) × 2 + 4 × (−1)= −4
c1,3 = a1,1 × b1,3 + a1,2 × b2,3 + a1,3 × b3,3= 2 × 2 + (−1) × 1 + 4 × (−3)= −9
c1,4 = a1,1 × b1,4 + a1,2 × b2,4 + a1,3 × b3,4= 2 × (−1) + (−1) × 3 + 4 × 0
= −5
c2,1 = a2,1 × b1,1 + a2,2 × b2,1 + a2,3 × b3,1= 3 × 3 + 2 × (−2) + (−2) × 4= −3
c2,2 = a2,1 × b1,2 + a2,2 × b2,2 + a2,3 × b3,2= 3 × 1 + 2 × 2 + (−2) × (−1)= 9
c2,3 = a2,1 × b1,3 + a2,2 × b2,3 + a2,3 × b3,3= 3 × 2 + 2 × 1 + (−2) × (−3)= 14
c2,4 = a2,1 × b1,4 + a2,2 × b2,4 + a2,3 × b3,4= 3 × (−1) + 2 × 3 + (−2) × 0= 3
resultando na matriz
C =
24 −4 −9 −5−3 9 14 3
Nota: As operações com matrizes ainda compreendem a inversão de matri-zes e o cálculo do determinante, que são operações importantes para a resolução
de sistemas lineares.
2.5.3 Matrizes booleanas
Matrizes booleanas são conjuntos de dados organizados sob a forma de ar-ranjo bidimensional de zeros e uns. Aĺem das operações normais da álgebra
8/20/2019 Estrutura Dados Dovicchi UFSC
36/164
36 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
sobre estas matrizes, elas podem sofrer operações da álgebra de Boole, ou seja,operações lógicas do tipo AND(∧) e OR (∨). Estas operações são denominadasde multiplicação lógica e soma lógica, respectivamente.
As operações lógicas (ou binárias) são efetuadas sobre os valores 0 e 1,sendo que a multiplicação lógica (∧) retorna o mı́nimo entre os operandos,ou seja, x ∧ y = min(x, y) e a soma lógica (∨) retorna o máximo entre osoperandos, ou seja, x ∨ y = max(x, y) (veja tabela 2.2).
x y x ∧ y0 0 00 1 01 0 0
1 1 1
x y x ∨ y0 0 00 1 11 0 1
1 1 1
Tabela 2.2: Tabelas lógicas AND e OR.
A multiplicação e soma lógicas de matrizes (operações AND e OR) segueas mesmas regras da soma de duas matrizes, ou seja, para duas matrizes demesma ordem, estas operações são feitas termo a termo. Entretanto o produtológico de duas matrizes de ordens apropriadas segue a regra da multiplicaçãode matrizes, com as operações lógicas (AND e OR. Assim, o produto lógico de
duas matrizes booleanas, notado por A × B, é dado por:
A × B = C | ci,j =mk=1
(ai,k ∧ bk,j)
ou seja, considere as matrizes:
A =
a1,1 a1,2 a1,3a2,1 a2,2 a2,3
e B =
b1,1 b1,2b2,1 b2,2b3,1 b3,2
o produto lógico de
A×B = C =
c1,1 c1,2c2,1 c2,2 ,onde
c1,1 = (a1,1 ∧ b1,1) ∨ (a1,2 ∧ b2,1) ∨ (a1,3 ∧ b3,1)c1,2 = (a1,1 ∧ b1,2) ∨ (a1,2 ∧ b2,2) ∨ (a1,3 ∧ b3,2)c2,1 = (a2,1 ∧ b1,1) ∨ (a2,2 ∧ b2,1) ∨ (a2,3 ∧ b3,1)c2,2 = (a2,1 ∧ b1,2) ∨ (a2,2 ∧ b2,2) ∨ (a2,3 ∧ b3,2)
8/20/2019 Estrutura Dados Dovicchi UFSC
37/164
2.5. REPRESENTAÇ ˜ AO DE DADOS E MATRIZES 37
Por exemplo, sejam:
A =
1 0 1 1
0 1 0 01 0 1 00 1 0 1
e B =
1 0 0 0
1 1 0 01 1 1 01 1 1 1
então, a soma, multiplicação e produto lógicos de A e B são, respectivamente:
A∧B =
1 0 0 00 1 0 01 0 1 00 1 0 1
, A∨B =
1 0 1 11 1 0 01 1 1 01 1 1 1
e A×B =
1 1 1 11 1 0 01 1 1 01 1 1 1
2.5.4 Matrizes esparsasMatrizes esparsas são conjuntos de dados organizados sob a forma de arranjobidimensional, onde grande parte dos valores são nulos. Tais matrizes podemser representadas na forma esparsa ou em uma forma compacta. A importânciado estudo das formas de representação destas matrizes nas formas esparsase compactas está na compactação de dados organizados de forma espalhada(esparsa).
Vamos tomar, por exemplo, uma matriz esparsa:
A =
1 0 0 5 0 0 0 0
0 −2 0 0 0 0 0 00 0 0 0 15 0 0 00 0 0 0 0 0 0 −70 0 0 0 −9 0 0 00 0 0 0 0 0 0 4
A matriz A(6×8) representa um conjunto esparsos de dados que podem ser
descritos como um array que ocupa 48 posições de memória:
int A[6][8] = {
{1,0,0,5,0,0,0},
{0,-2,0,0,0,0,0,0},{0,0,0,0,15,0,0,0},
{0,0,0,0,0,0,0,-7},
{0,0,0,0,-9,0,0,0},
{0,0,0,0,0,0,0,4}
}
8/20/2019 Estrutura Dados Dovicchi UFSC
38/164
38 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
Entretanto, esta matriz, por ser esparsa, pode ser representada de formamais racional e compacta. Para isso, é necessário estabelecer algumas regras.
Dada uma matriz esparsa A de ordem m × n, existe uma matriz compactaB de ordem (k + 1) × 3, onde k representa o número de elementos não-zero damatriz:
• O elemento da primeira linha e primeira coluna representa o número delinhas da matriz, ou seja, b1,1 = m;
• O elemento da primeira linha e segunda coluna representa o número decolunas da matriz, ou seja b1,2 = n;
• O elemento da primeira linha e terceira coluna representa o número deelementos não-zero da matriz, ou seja, b1,3 = k;
• A partir da segunda linha da matriz compacta, cada linha representa aposição de um elemento da matriz, ou seja, sua linha, sua coluna e opróprio elemento.
A matriz do exemplo acima (A(6×8)) tem 7 elementos não zero, logo, suaforma compacta deverá ser uma matriz B(8×3) e, portanto:
B =
6 8 71 1 1
1 4 52 2 −23 5 154 8 −75 5 −96 8 4
Assim, a primeira linha ([6 8 7]) indica que a matriz é de ordem 6 × 8e que possue 7 elementos não-zero. A segunda linha ([1 1 1]) indica quea1,1 = 1; a terceira indica que a1,4 = 5; a quarta que a2,2 = −2; e assim pordiante.
O array para representar esta matriz ocupará, portanto 24 posições dememória, ou seja, a metade da matriz esparsa:
int B[8][3] = {
{6,8,7},
{1,1,1},
8/20/2019 Estrutura Dados Dovicchi UFSC
39/164
2.6. TIPOS DE DADOS DEFINIDOS PELO USU ́ARIO 39
{1,4,5},
{2,2,-2},
{3,5,15},
{4,8,-7},
{5,5,-9},
{6,8,4}
}
Evidentemente, para matrizes muito maiores e mais esparsas (o que éfreqüente em imagens) pode-se economizar muita memória ou espaço de ar-mazenagem de dados.
2.6 Tipos de dados definidos pelo usuárioA linguagem C possui vários tipos de dados que podem ser definidos peloprogramador. Podemos ter um conjunto de registros, com suas etiquetas (la-bels ) definidas por tipos diferentes que podem ser referenciados sob um mesmonome (estruturas); por bits (campo de bits); por tipos em uma mesma porçãoda memória (uniões); por lista de śımbolos (enumeração) ou por novos tiposdefinidos pelo usuário (TDA) pelo uso de typedef.
Destes, duas formas são muito úteis para a representação de coleção dedados relacionados entre si. Uma delas é a declaração de um tipo estrutura(struct)e outra é do tipo união (union), onde os ı́tens são referenciados por
um identificador chamado membro.
2.6.1 Estruturas
Uma estrutura é um conjunto de dados organizados em uma declaração structonde cada dado é referenciado por um identificador. Comparativamente a umbanco de dados, uma estrutura é algo semelhante a um “registro” e cadamembro da estrutura pode ser comparado a um “campo”. Por exemplo:
struct nome {
char primeiro[10];
char meio[10];
char ultimo[20];
};
O exemplo acima cria uma estrutura chamada “nome” com os membros:“primeiro”, “meio” e “ultimo”. Pode-se, então, criar variáveis com o mesmo
8/20/2019 Estrutura Dados Dovicchi UFSC
40/164
40 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
tipo, usando-se a declaração struct nome n;. Nesta declaração é criada umavariável “n” do mesmo tipo da estrutura “nome”.
Observe que, quando uma estrutura é definida, está sendo definido ape-nas um tipo complexo de variável e não a variável, propriamente dita. Deforma semelhante, em uma linguagem SQL de banco de dados, tal estrutura éequivalente a:
CREATE TABLE nome (
primeiro char(10) default NULL,
meio char(10) default NULL,
ultimo char(20) default NULL,
);
Uma estrutura pode conter um membro do tipo de outra estrutura. Porexemplo, considere a seguinte estrutura:
struct agenda {
struct nome reg;
char endereco[60];
char cidade[20];
char uf[2];
char fone[16];
};
Neste caso, temos uma estrutura dentro de outra, ou seja, o primeiro mem-bro da estrutura “agenda” é uma variável chamada “reg” do tipo estrutura“nome”. O compilador vai alocar memória para todas os elementos da estru-tura, contendo:
nome → 40 bytesendereco → 60 bytes
cidade → 20 bytesuf → 2 bytes
fone → 16 bytes
A partir desta estrutura, pode-se, a qualquer momento, criar uma variáveldimensional para referenciar 200 registros do tipo “agenda”, por exemplo:
struct agenda ag[200];
8/20/2019 Estrutura Dados Dovicchi UFSC
41/164
2.6. TIPOS DE DADOS DEFINIDOS PELO USU ́ARIO 41
Qualquer membro da variável ag[200] pode ser referenciado por um cons-trutor “.” (ponto). Assim:
printf ("%s - %s\n", ag[2].reg.primeiro, ag[2].fone);
imprimirá o terceiro registro “primeiro” de “reg” da estrutura “ag” e seu res-pectivo “fone”.
A estrutura tamb́em pode ser declarada no mesmo momento em que édefinida, por exemplo:
s t r u c t ender {char nome [ 3 0 ] ;
c ha r r ua [ 4 0 ] ;c ha r c id a de [ 2 0 ] ;char estad o [ 3 ] ;u ns ig ne d l on g i n t c ep ;
} info ender , outra ender ;
neste caso as variáveis info ender e outra ender são variáveis declaradas dotipo ender. No caso de ser necessário apenas uma variável do tipo da estrutura,o nome da estrutura torna-se desnecessário, por exemplo:
s t r u c t {char nome [ 3 0 ] ;c ha r r ua [ 4 0 ] ;c ha r c id a de [ 2 0 ] ;char estad o [ 3 ] ;u ns ig ne d l on g i n t c ep ;
} info ender ;
que declara uma variável info ender do tipo da estrutura que a precede.Com a finalidade de compreender como uma estrutura ocupa a mem ória,
vamos considerar uma estrutura e verificar como os dados ficam armazenadosna memória (veja listagem 2.9).
8/20/2019 Estrutura Dados Dovicchi UFSC
42/164
42 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
Listagem 2.9: Exemplo de estrutura: est-ender.c
# i n c lu d e < s t di o . h >
# i n c lu d e < s t d li b . h >
# i n c lu d e < s t r in g . h >
s t ru c t m i st a {
i nt c a mp o 1 ;
d o ub l e c a mp o 2 ;c h ar c a mp o 3 [ 1 0] ;
f l oa t c a mp o 4 ;
i nt c a mp o 5 ;
};
i nt m ai n ( in t a rg v , c ha r * a rg c [ ]) {
s t r u ct m i s t a v a r 1 = { 2 , 3 . 65 , " a b c d e f g h i j k " , 9 2. 3 , 5 } ;
p ri nt f ( " c am po 1 ( i nt ) : % d \n " , v ar 1 . ca mp o1 ) ;
p r in t f ( " E n d er e co d e ’ c a m po 1 ’ : % x \ n " , & v a r1 . c a m po 1 ) ;p r in t f ( " \ n c am p o 2 ( d o u bl e ) : % f \ n " , v a r1 . c a m po 2 ) ;
p r in t f ( " E n d er e co d e ’ c a m po 2 ’ : % x \ n " , & v a r1 . c a m po 2 ) ;
p ri nt f ( " \ nc am po 3 ( c ha r * ): % s \n " , v ar 1 . ca mp o3 ) ;
p r in t f ( " E n d er e co d e ’ c a m po 3 ’ : % x \ n " , & v a r1 . c a m po 3 [ 0 ] );
p ri nt f ( " \ nc am po 4 ( f l oa t ): % f \n " , v ar 1 . ca mp o4 ) ;
p r in t f ( " E n d er e co d e ’ c a m po 4 ’ : % x \ n " , & v a r1 . c a m po 4 ) ;
p ri nt f ( " \ nc am po 5 ( i nt ) : % d \ n" , v ar 1 . ca mp o5 ) ;
p r in t f ( " E n d er e co d e ’ c a m po 5 ’ : % x \ n \ n" , & v a r 1 . c am p o5 ) ;
r e tu r n 0 ; / + + ) ) ) ) ) ) ) ) ) ) + + /
}
8/20/2019 Estrutura Dados Dovicchi UFSC
43/164
2.6. TIPOS DE DADOS DEFINIDOS PELO USU ́ARIO 43
Nesta estrutura temos vários tipos de membros (int, double, char, float)e, depois de compilado, o programa imprime os valores e endere ços de cadamembro. Desta forma pode-se observar o quanto cada membro ocupa namemória. A estrutura “mista” ocupa, na memória, o espaço somado de todosos seus membros.Nota: Observe que o campo3 tem 11 elementos e apenas 10 posições aloca-das. A compilação com ’-Wall -ansi -pedantic’ retornará as mensagensde warning mas o programa será compilado. Ao rodar o programa voce poderáobservar que o “k” foi desprezado.
As estruturas podem ser passadas para funções de duas formas. Uma delasé por valor e outra por referência. Veja, por exemplo, a listagem 2.10.
Listagem 2.10: Passando estruturas para funções: cards.c
# i n c lu d e < s t d io . h >
# i n c lu d e < s t d li b . h >
s tr uc t c ar ta s {
i n t i n di c e ;
c h ar n a ip e ;
};
v o id i m p r im e _ p or _ v a lo r ( s t r uc t c a rt a s q u al ) ;
v o id i m p r im e _ p or _ r e fe r ( s t r uc t c a rt a s * p ) ;
i nt m a in ( ) {
s tr uc t c ar ta s r ei _p au s = { 13 , ’ p ’ };
s tr uc t c ar ta s d a ma _ co p as = { 12 , ’ c ’ };
i m p r i m e _ p o r _ v a l o r ( r e i _ p a u s ) ;
i m p r i m e _ p o r _ r e f e r ( & d a m a _ c o p a s ) ;
r e tu r n 0 ;
}
v o id i m p r im e _ p or _ v a lo r ( s t r uc t c a rt a s q u al ) {
p r in t f ( " % i d e % c \ n " , q u al . i n di ce , q u al . n a i pe ) ;
} / + + ) + + /
v o id i m p r im e _ p or _ r e fe r ( s t r uc t c a rt a s * p ) {
p r in t f ( " % i d e % c \ n " , p - > i nd ic e , p - > n a i pe ) ;
}
/ + + ) } } + + /
8/20/2019 Estrutura Dados Dovicchi UFSC
44/164
44 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
c
´
struct s {short int s;long int l;double d;char c;
} r;
r.s = 10;r.l = 4832;r.d = 17.01;r.c = ´a´;
d
l
s
memoria
Figura 2.2: Estrutura e espaço de memória
A primeira função recebe por valor na variável “qual” como uma estruturado tipo “cartas”. Assim, a referência é feita pelos valores de qual.indice equal.naipe em relação à variável da chamada da função (no caso rei_paus).
Na segunda função, o valor é passado por referência pelo apontador (*p) doendereço da variável (&dama_copas) que é passada na chamada da função. Areferência é feita por p->indice e p->naipe. A notação p-> é correspondenteà (*p), ou seja, p->indice é equivalente a (*p).indice.
2.6.2 Uniões
Outro tipo de organização de dados, como as estruturas, são as uniões (union),que são representadas e referenciadas da mesma forma que elas. Entretanto, oconceito de união é fundamentalmente diferente do conceito de estrutura, noque se refere à organização dos membros na memória.
Em uma estrutura, o espaço de memória é ocupado seqüencialmente porcada um dos membros da estrutura, enquanto que no caso de uma união, omesmo espaço de memória pode ser ocupado por diversas variáveis de tama-
nhos diferentes. Por exemplo, na figura 2.2 temos um exemplo de como seorganizam os membros de uma estrutura na memória e na figura 2.3 os mem-bros de uma união na memória.
No tipo union, uma varíavel pode conter objetos de diferentes tipos etamanhos, mas não ao mesmo tempo. O compilador se incumbe de mantera refer̂encia dos requisitos de tamanho e alinhamento da memória. Assim,
8/20/2019 Estrutura Dados Dovicchi UFSC
45/164
2.6. TIPOS DE DADOS DEFINIDOS PELO USU ́ARIO 45
s
´
short int s;long int l;double d;char c;
} r;
r.s = 10;r.l = 4832;r.d = 17.01;r.c = ´a´;
union u {
c
d
l
memoria
Figura 2.3: Uniões e espaço de memória
este tipo de estrutura permite que se manipule tipos diferentes de dados emuma mesma área da memória, sem que se tenha que se preocupar com asdependências de arquitetura das máquinas no desenvolvimento do programa.
2.6.3 Campos de bits
Embora os tipos struct e union sejam os conceitos mais usados em estruturasde dados, existe ainda um outro tipo que tem uma determinada import ânciana comunicação entre portas de hardware. Por exemplo, um adaptador serialde comunicação entre dois equipamentos está organizado em uma estrutura decampo de bits de 1 byte, como:
Bit Se ligado0 clear-to-send alterado1 data-set-ready alterado2 pico de portadora3 rcpt alterado4 cts5 dsr
6 ring7 recepção de linha
A estrutura de bits para representar o estado de comunicação pode serexpressa da seguinte forma:
8/20/2019 Estrutura Dados Dovicchi UFSC
46/164
46 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
struct status_tipo{
unsigned var_cts :1;
unsigned var_dsr :1;
unsigned carrier :1;
unsigned var_rcpt :1;
unsigned cts :1;
unsigned dsr :1;
unsigned call :1;
unsigned line_rcp :1;
} status
A estrutura pode ser usada para determinar quando a aplicação pode ou
não enviar dados pelo canal de comunicação, por exemplo:
status = get_status();
if(status.cts){
printf ("livre para enviar\n");
}
if(status.dsr){
printf("dados prontos\n");
}
2.7 Exerćıcios
1. Em C, a função scanf é usada para ler dados de entrada do teclado egravar estes dados em variáveis. Por exemplo:
#include #include
#define NUMEROS 10
in t m ai n ( in t argv , char ∗ a r g c [ ] ) {i nt num [NUMEROS ] ; / ∗ v e t o r d e n um er os ∗/ i nt i , t o t a l ;f l o a t media ;
8/20/2019 Estrutura Dados Dovicchi UFSC
47/164
2.7. EXERC ́ICIOS 47
t o t a l = 0 ;for ( i =0; i
8/20/2019 Estrutura Dados Dovicchi UFSC
48/164
48 CAP ́ITULO 2. REPRESENTAÇ ˜ AO DE DADOS
8/20/2019 Estrutura Dados Dovicchi UFSC
49/164
Caṕıtulo 3
Listas
Alguns tipos de dados podem ser organizados em uma cadeia, seja de númerosou de caracteres que denominamos de lista. As listas podem ser implemen-tadas de várias maneiras, tanto em uma linguagem procedural como em umalinguagem funcional. As listas são estruturas dinâmicas, em oposição aos ve-tores (arrays) que são estáticas e contém um conjunto espećıfico de dados.Virtualmente, uma lista pode conter infinitos elementos.
As operações sobre listas são limitadas ao tipo de dados que uma listacontém. Por exemplo, listas de dados numéricos podem ser tratadas matema-ticamente, enquanto listas de caracteres podem ser ordenadas, concatenadasetc..
Elas podem ser classificadas em pilhas, filas e listas ligadas, dependendodo tipo de acesso que pode ser feito aos dados que ela cont́em:
• Listas LIFO (Last In, First Out ) ou pilhas;
• Listas FIFO (First In, First Out ) ou Filas; e
• Em qualquer posição (listas ligadas).
3.1 Definições e declarações
Podemos definir uma lista como um conjunto ordenado de elementos, geral-mente do mesmo tipo de dado. Por exemplo, [20,13,42,23,54] é uma listanumérica de inteiros; [‘a’,‘d’,‘z’,‘m’,‘w’,‘u’] é uma lista de caracteres;e ["banana","abacaxi","pera"] é uma lista de frutas.
Cada linguagem tem uma sintaxe espećıfica para organizar os dados emforma de listas. Em C/C++ uma lista pode ser descrita por uma estrutura
49
8/20/2019 Estrutura Dados Dovicchi UFSC
50/164
50 CAP ́ITULO 3. LISTAS
ou uma enumeração. Por exemplo, considere uma linha de texto como sendouma lista de caracteres:
/* Neste exemplo, "struct linebuffer" é uma estrutura que
* pode armazenar uma linha de texto. */
struct linebuffer{
long size;
char *buffer;
};
Nas linguagens funcionais, a declaração de listas usa os construtores: [ ]e : , onde [] representa uma lista vazia. Assim, uma lista pode ser declarada
como [1,2,3] ou (1:2:3:[]). Além disso, pode-se declarar uma lista usando-se uma expressão conhecida como list comprehension :
[x | x x) [1,2,3] que, em cálculo-λ é escrita como:
λx.x{1, 2, 3}
Liguagens como Haskell , Clean, CAML e Erlang, por exemplo, supor-tam tanto declarações expĺıcitas de listas, tais como [1,2,3,4,5] quantoimpĺıcitas, ou seja, [1..5]. Este último caso representa uma progressãoaritmética (PA) de razão 1. Assim, por exemplo:
[2,4..20] -- representa [2,4,6,8,10,12,14,,16,18,20] ou
-- uma PA de 2 a 20 de raz~ao 2
[1,4..15] -- representa [1,4,7,10,13], ou uma PA de 1 a
-- 15 de raz~ao 3.
As listas impĺıcitas podem ser declaradas de forma finita ([1..20], [2,4..100],[’a’..’m’] etc.) ou de forma infinita: ([1..], [2,4..] etc.).
Existe, ainda, uma maneira de representar uma lista por (x:xs)1 que éuma meta-estrutura onde x representa o primeiro elemento da lista (chamadode “cabeça”) e xs representa o restante da lista (chamado de “cauda”).
1Lê-se ’xis’ e ’xises’.
8/20/2019 Estrutura Dados Dovicchi UFSC
51/164
3.2. OPERAÇ ˜ OES COM LISTAS 51
3.2 Operações com listas
As linguagens funcionais implementam algumas funções para operações sobre
dados de uma lista. Por exemplo, a função map, em map f L aplica uma funçãof em uma lista L:
Prelude> map (^2) [1..10]
[1,4,9,16,25,36,49,64,81,100]
Prelude> map odd [1..10]
[True,False,True,False,True,False,True,False,True,False]
a função filter testa uma condição em uma lista:
Prelude> filter odd [1..10]
[1,3,5,7,9]
Prelude> filter (>10) [1..20]
[11,12,13,14,15,16,17,18,19,20]
Prelude> filter (>5) (filter ( :l Permuta
Permuta> perms "abcd"
["abcd","bacd","bcad","bcda","acbd","cabd","cbad","cbda","acdb",
"cadb","cdab","cdba","abdc","badc","bdac","bdca","adbc","dabc",
8/20/2019 Estrutura Dados Dovicchi UFSC
52/164
52 CAP ́ITULO 3. LISTAS
Função Descri̧cão Sintaxe Exemplo
concat Concatena duas lis-tas
concat [] []
concat [1..3] [6..8]
Resultado: [1,2,3,6,7,8]
filter Aplica uma condiçãoe retorna os elemen-tos que casam com opadrão
filter
[]
filter odd [1..10]
Resultado: [1,3,5,7,9]
map Aplica uma funçãoem todos os elemen-tos de uma lista
map
[]
map (*2) [1,2,3,4]
Resultado: [2,4,6,8]
take Toma n elementos de
uma lista
take n [] take 5 [10,20..]
Resultado:[10,20,30,40,50]
zip Forma duplas com oselementos de duas lis-tas
zip []
[]
zip [1,2,3] [’a’,’b’,’c’]
Resultado:[(1,’a’),(2,’b’),(3,’c’)]
Tabela 3.1: Exemplos de funções para operações sobre listas em Haskell .
Listagem 3.1: Programa Permuta.hs para explicar operações sobre listas emHaskell.
module P er m ut a (
perms
) where
p er ms :: [ a] - > [ [ a ]]
perms [] = [[]]
perms ( x: xs ) = c oncat ( map ( inter x ) ( perms x s))
inter x [] = [[ x ]]
i nt er x ys ’ @( y: ys ) = ( x: ys ’) : map ( y:) ( in te r x ys )
8/20/2019 Estrutura Dados Dovicchi UFSC
53/164
3.2. OPERAÇ ˜ OES COM LISTAS 53
"dbac","dbca","adcb","dacb","dcab","dcba"]
Permuta> perms [1..4]
[[1,2,3,4],[2,1,3,4],[2,3,1,4],[2,3,4,1],[1,3,2,4],[3,1,2,4],
[3,2,1,4],[3,2,4,1],[1,3,4,2],[3,1,4,2],[3,4,1,2],[3,4,2,1],
[1,2,4,3],[2,1,4,3],[2,4,1,3],[2,4,3,1],[1,4,2,3],[4,1,2,3],
[4,2,1,3],[4,2,3,1],[1,4,3,2],[4,1,3,2],[4,3,1,2],[4,3,2,1]]
A relação das linguagens funcionais com listas tem uma caracteŕıstica deeficîencia quando se trata de listas infinitas. Por exemplo:take 5 [1..] re-torna uma lista finita de 5 elementos ([1,2,3,4,5]). Isto se deve a um pro-cesso denominado de lazy evaluation que em inglês significa avaliação “pre-guiçosa”, mas que poderia ser melhor traduzida por avaliação “esperta”, ouavaliação sob demanda. Este processo gera a lista infinita até o ponto onde a
computação é necessária. Por exemplo:
Prelude> takeWhile ( a -> Boolprimo n = (verif n == [])
where
verif n = [ x | x [a] -> [a]
primos [] = []
primos (n:ns) = case (primo n) of True -> n : primos nsFalse -> primos ns
Usando-se a função takeWhile podemos recuperar uma lista de primos con-forme as condições. Neste caso, primos (takeWhile (
8/20/2019 Estrutura Dados Dovicchi UFSC
54/164
54 CAP ́ITULO 3. LISTAS
Listagem 3.2: Programa Primos.hs para encontrar os números primos em umalista.
module P r im os (
p ri mo , p r im o s
) where
p ri mo :: I nt eg ra l a = > a - > B oo l
p ri mo n = ( fa to r n == [])
where
fator n = [ x | x [ a ] - > [ a ]
primos [] = []p ri mo s ( n :ns ) = c as e ( p ri mo n ) o f T ru e - > n : pr im os ns
F al se - > p ri mo s n s
Prelude> :l Primos
Compiling Primos ( Primos.hs, interpreted )
Ok, modules loaded: Primos.
*Primos> primos (takeWhile (
8/20/2019 Estrutura Dados Dovicchi UFSC
55/164
3.3. PILHAS 55
1 2 3
1 1 1
2 2
3
Figura 3.1: Representação de uma pilha de bolas numeradas
uma posição denominada “topo da pilha”. Considere, por exemplo a figura3.1
Na figura um temos um tubo onde podemos empilhar as bolas numeradas.Neste caso, cada bola vai para o topo da pilha. É claro que, para se retirar asegunda bola, é necessário retirar antes a terceira. Ou seja, o último elementoa entrar em uma pilha é o primeiro a sair. Por isto, a pilha recebe o nome deLIFO, do inglês Last In First Out .
3.3.1 Operações e TDA
Existem duas primitivas (operações básicas) que podem ser efetuadas sobreuma estrutura em pilha. Uma delas adiciona um elemento a uma pilha (push)e a outra retira um elemento de uma pilha (pop). Por exemplo:
/* insere o elemento ’i’ em uma pilha ’s’ */
push (s,i);
/* passa o elemento no topo da pilha ’s’ para ’i’ */
i = pop (s);
Uma pilha não tem tamanho finito e definido, assim, a operação push podeser feita indefinidamente até que se esgote a memória, produzindo o que sedenomina “estouro da pilha” (stack overflow ). Ainda, a operação pop não podeser aplicada a uma pilha vazia, pois não há elemento para ser desempilhado.
8/20/2019 Estrutura Dados Dovicchi UFSC
56/164
56 CAP ́ITULO 3. LISTAS
Listagem 3.3: TDA de uma pilha
a b st r ac t t y pe d ef < < t _e le m > > S T AC K ( t _ e le m ) ;
a b st r ac t e m pt y ( s )
S TA CK ( t _ el em ) s ;
p o st c on d it i on e mp ty = = ( l e n ( s ) = = 0 );
a bs tr ac t t _e le m p op ( s )
S TA CK ( t _ el em ) s ;
p re co nd it io n e mp ty ( s) == F AL SE ;
p o st c on d it i on p op = = f ir st ( s ’ );
s == sub ( s’ , 1 , len (s ’) - 1);
a bs tr ac t p us h ( s , e le m )
S TA CK ( t _ el em ) s ;
t _ el e m e l em ;
p os tc on di ti on s == < elem > + s ’ ;
Esta operação, em uma pilha vazia, causa um erro denominado de “colapso dapilha” (stack underflow ).
Uma função empty (s) pode ser usada para testar e uma pilha está ou não
vazia. Esta função retornará TRUE se a pilha estiver vazia ou FALSE no casocontrário.Outra operação que se pode executar sobre pilhas é a função stacktop.
Esta função retorna o topo da pilha sem remover o elemento. Ou seja:
i = stacktop (s);
/* equivale a: */
i = pop (s);
push (s,i);
A listagem 3.3 representa o TDA de uma pilha. A pilha pode ser usada emqualquer situação que requeira uma rotina do tipo LIFO em um determinado
8/20/2019 Estrutura Dados Dovicchi UFSC
57/164
3.3. PILHAS 57
Listagem 3.4: Exemplo de pilha em C
/* D ef in e u ma p il ha de i nt ei ro s */
# d e f in e T A M _ PI L H A 1 00
s tr uc t p il ha {
i nt t op o ;
i n t e l e m s [ T A M _ P I L H A ] ;
};
padrão de agrupamento de dados como, por exemplo, chamada de rotina,
funções, operações com parênteses etc..
3.3.2 Implementação e Exemplos em C
Com a finalidade de implementar a solução de um problema que utilize umaestrutura de dados em pilhas, vamos ver como se pode representar uma pilhaem C. Antes, porém, é preciso ressaltar a diferença fundamental entre vetorese pilhas. Um vetor é um conjunto ordenado de elementos com um númerofixo, enquanto uma pilha é um conjunto dinâmico, cujo tamanho está sempremudando conforme se opera sobre sua estrutura.
Na prática, pode-se contornar esta caracteŕıstica declarado-se um espaçofinito reservado para uma pilha, desde que tenha tamanho sufuciente paraarmazenar o tamanho máximo necessário para os seus elementos. Uma ex-tremidade é o ińıcio da pilha, enquanto a outra é o topo da pilha. Assim, énecessário que se tenha um outro campo que indique em que ponto da pilhase encontra o topo durante a execução do programa (ver listagem 3.4).
O código da listagem 3.4 descreve uma pilha de inteiros de tamanho 100.Mas, se for necessáario descrever uma pilha com elementos diferentes de intei-
ros podemos especificar float elems[TAM PILHA] para números com pontoflutuante ou char elems[TAM PILHA] para caracteres, ou ainda qualquer ou-tro tipo. Mas, podemos criar uma pilha que possa armazenar qualquer tipo dedados (veja listagem 3.7).
8/20/2019 Estrutura Dados Dovicchi UFSC
58/164
58 CAP ́ITULO 3. LISTAS
Listagem 3.5: Exemplo de pilha genérica em C
/ * D ef in e u ma p il ha q ue p od e c on te r i nt ei ro s ,
* f lo at s e s tr in gs */
# d e f in e T A M _ P IL H A 1 00
# d e fi ne I NT EI RO 1
# d e fi ne D EC IM AL 2
# de fi ne C AD EI A 3
s tr uc t e l em _ pi l ha {
i nt e l e m _t i p o ; / * p od e s er i nt ei ro , f lo at o u s tr in g * /
u ni on {
i nt i v al ;
f l oa t f v al ;
c h ar * s v a l ; /* p on te ir o p ar a s tr in g * / } e le me nt o ;
};
s tr uc t p il ha {
i nt t o po ;
s t ru c t e l e m _ pi l h a e l em s [ T A M _ P IL H A ];
};
8/20/2019 Estrutura Dados Dovicchi UFSC
59/164
3.3. PILHAS 59
Listagem 3.6: pilha.h
# i n c lu d e < s t d li b . h ># i n c lu d e < s t d io . h >
t yp ed ef s tr uc t P il ha P L ;
s t ru c t P i lh a {
i nt t op , * e l em ;
in t max ; /* t am an ho m ´ a xi mo d a p il ha * /
};
v oi d P US H ( PL * P , in t A );
i nt P OP ( PL * P, i nt A );
As funções push e pop podem ser implementadas com facilidade. Por exem-plo, considere um cabeçalho (pilha.h) que defina uma estrutura de pilha deinteiros (listagem 3.8).
A função push pode ser descrita como:
#include "pilha.h"
void PUSH(PL *P,int A){
if (P->top < P->max - 1){
P->elem[++(P->top)] = A;
}
else{
printf("Pilha Cheia\n");}
}
E a função pop pode ser:
8/20/2019 Estrutura Dados Dovicchi UFSC
60/164
60 CAP ́ITULO 3. LISTAS
(d)
DCA B
A B C D E
B C D E
B C D E F
(a)
(b)
(c)
Figura 3.2: Exemplo inserção e remoção de elementos de uma estrutura emfila
#include "pilha.h"
int POP(PL *P, int A){
A=P->elem[--(P->top)];
return A;
}
3.4 Filas
Outro tipo de estruturas em listas são as filas. Filas são representações de umaestruturas seqüencial, como as pilhas, mas com a diferença de que os elementospodem ser inseridos na fila por uma extremidade chamada fim da fila e podem
ser retirados pela outra extremidade ou ińıcio da fila. Considere, por exemploa figura 3.2. A figura 3.2(a) representa uma fila; 3.2(b) a inserção de umelemento na fila; 3.2(c) a remoção de um elemento; e 3.2(d) outra inserção.
Pode-se notar que, após remover um elemento do ińıcio da fila, o novoińıcio é o segundo elemento. E a inserção de um novo elemento, no final dafila, passa a ser o novo final. Assim, o primeiro elemento a entrar em uma fila
8/20/2019 Estrutura Dados Dovicchi UFSC
61/164
3.4. FILAS 61
é o primeiro a sair. Por isto, a fila recebe o nome de FIFO, do inglês First In First Out .
3.4.1 Filas: operações e TDA
Assim como nas pilhas, existem duas operações básicas que podem ser efetua-das sobre uma estrutura de fila. Uma delas adiciona um elemento no final dafila (insere) e a outra retira um elemento do inı́cio de uma fila (remove). Porexemplo:
/* insere o elemento ’i’ em uma fila ’q’ */
insere (q,i);
/* passa o elemento no inı́cio da fila ’q’ para ’i’ */
i = remove (q);
De modo semelhante às pilhas, as filas não têm tamanho definido (dependede quanto queremos alocar para esta estrutura) logo, a operação insere podeser feita até que se atinja o limite de memória ou um tamanho pode ser es-tabelecido, provocando um “estouro da fila” (queue overflow ). Obviamente, aoperação remove não pode ser aplicada a uma fila vazia, pois não há elementopara ser removido. Esta operação causa um erro denominado de “colapso da
fila” (queue underflow ). Uma função empty (q), que já vimos para pilhas,pode ser usada para testar se uma fila está ou não vazia.A representação de uma fila como TDA é feita por meio de um t_elem, que
indica o tipo de elemento da fila, e a parametrização do tipo da fila, segundot_elem simples (veja listagem 3.7)
Uma pilha pode ser usada em qualquer situação que requeira uma rotinado tipo FIFO em um determinado padrão de agrupamento de dados.
3.4.2 Implementação em CPodemos implementar uma fila, usando uma estrutura, da mesma maneiracomo o fizemos com a pilha. Entretanto, esta estrutura deve conter variáveisque apontam para o inı́cio e o final da fila, como as pilhas as têm para indicaro topo da pilha. O cabeçalho (.h) de uma fila pode ser implementado comona listagem 3.8
8/20/2019 Estrutura Dados Dovicchi UFSC
62/164
62 CAP ́ITULO 3. LISTAS
Listagem 3.7: TDA para uma fila
a b st r ac t t y pe d ef < < t _e le m > > Q U EU E ( t _ e le m ) ;
a b st r ac t e m pt y ( q )
Q UE UE ( t _ el em ) q ;
p o st c on d it i on e mp ty = = ( l e n ( q ) = = 0 );
a b st r ac t t _ el e m r e mo v e ( q )
Q UE UE ( t _ el em ) q ;
p re co nd it io n e mp ty ( q) == F AL SE ;
p o st c on d it i on r em ov e = = f ir st ( q ’ );
q == sub ( q’ , 1 , len ( q’)