Estrutura Dados Dovicchi UFSC

download Estrutura Dados Dovicchi UFSC

of 56

Transcript of Estrutura Dados Dovicchi UFSC

  • 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’)