Tipos de Dados Abstractos Estruturas Lineares Pilhas e Filas FEUP - MIEEC Programação - 008/009 Tipo de Dados Abstractos: Pilha (stack) Pilha estrutura de dados linear em que: inserção e a remoção de elementos se faz pela mesma extremidade, designada por topo da pilha uma pilha pode ser considerada como uma restrição de lista porque é uma estrutura de dados mais simples que a lista, é possível obter implementações mais eficazes não usa iteradores estrutura do tipo LIFO (Last-In-First-Out) Exemplos de utilização tabuleiro de recepção de serviço de um administrativo! zona de memória auxiliar da execução de rotina de programação
TAD: Pilhas Operações mais usuais: criar uma pilha vazia adicionar/remover um elemento à pilha verificar qual o topo da pilha (último elemento adicionado) push() push() push() push() push() pop() pop() pop() pop() Classe stack (STL) Alguns métodos da classe stack (STL): stack() stack(const stack &) bool empty() const size_type size() const T & top() void push(const T &) void pop() stack & operator =(const stack &) Funções globais (não membros da classe stack): bool operator ==(const stack &, const stack &) bool operator <(const stack &, const stack &) http://www.sgi.com/tech/stl/stack.html http://www.cppreference.com/cppstack
Pilhas: aplicação Notação RPN (Reverse Polish Notation) expressões matemáticas onde os operadores surgem a seguir aos operandos (notação posfixa) ex: + vantagem: não requer parêntesis nem regras de precedência outras notações: Notação infixa (comum): os operadores surgem entre os operandos ex: + Notação prefixa: os operadores surgem antes dos operandos ex: + exemplo: Notação infixa: * ( + ) / Notação RPN: + * / Pilhas: aplicação Avaliação de expressões RPN : algoritmo. Processar sequencialmente os elementos da expressão. Para cada elemento:. Se o elemento for um número (operando), colocá-lo na pilha.. Se o elemento for um operador... Retirar os dois elementos do topo da pilha... Processar os elementos de acordo com o operador... Colocar o resultado na pilha. Retirar o (único) elemento da pilha. É o resultado 6
Pilhas: aplicação class Elemento public: float valor; // valor=0 se elemento é operador char op; // op=? se elemento é operando Elemento(float v=0, char o='?'): valor(v), op(o) ; ; float calcop(float v, float v, char op) switch(op) case '+' : return v+v; case '-' : return v-v; case '*' : return v*v; case '/' : return v/v; default: cout << operação inválida <<endl; 7 Pilhas: aplicação float avaliarpn(string expressao) // simplificação: números de dígito apenas stack<elemento> pilha; for ( int i=0; i<expressao.length(); i++ ) if ( expressao[i]>='0' && expressao[i]<='9') // é numero pilha.push(elemento(expressao[i]-8,'?')); else float num = pilha.top().valor; pilha.pop(); float num = pilha.top().valor; pilha.pop(); float res = calcop(num, num, expressao[i]); pilha.push(elemento(res,'?')); float res = pilha.top().valor; pilha.pop(); return res; 8
Tipo de Dados Abstractos: Fila (queue) Fila estrutura de dados linear em que: inserção de elementos se faz por uma extremidade, designada por cauda remoção de elementos se faz por extremidade oposta à cauda, designada por cabeça uma fila pode ser considerada como uma restrição de lista não usa iteradores estrutura do tipo FIFO (First-In-First-Out) Exemplo fila de atendimento numa caixa de supermercado 9 TAD: Filas Operações mais usuais: criar uma fila vazia adicionar/remover um elemento a uma fila verificar qual o elemento da cabeça/cauda da fila (mais antigo/recente) front back front back front back front back push() push() push() push() front back front back front back front back pop() pop() pop() 0
Classe queue (STL) Alguns métodos da classe queue (STL): queue() queue(const queue &) bool empty() const size_type size() const T & front() T & back() void push(const T &) void pop() queue & operator =(const queue &) Funções globais (não membros da classe queue): bool operator ==(const queue &, const queue &) bool operator <(const queue &, const queue &) http://www.sgi.com/tech/stl/queue.html http://www.cppreference.com/cppqueue Filas: aplicação Pretende-se implementar uma classe para gerir a fila de impressão de uma impressora de rede. a impressora de rede, quando recebe um ficheiro para impressão, adiciona-o numa fila de espera do tipo FIFO. class Documento string nome; string utilizador; int tamanho; int nfolhas; public: Document(string n, string ut, int t, int f): nome(n), utilizador(ut), tamanho(t), nfolhas(f) string getutil() const return utilizador; string getnome() const return nome; int gettamanho() const return tamanho; int getnfolhas() const return nfolhas; void setnfolhas(int n) nfolhas=n; ;
Filas: aplicação class Impressora queue<documento> filaimpressao; int maxmemoria; int folhasrestantes; // nº folhas existentes na impressora public: Impressora(int m, int f): maxmemoria(m), folhasrestantes(f) void adicionardocumento(documento doc); Documento imprimirdocumento(); void trocartoner(int numerofolhas); // a implementar void listardocumentos(ostream& os); // a implementar void excluirdocumento(string n, string o); ; Filas: aplicação // adiciona um novo documento à fila de impressão. Se o tamanho do documento é superior à memória // disponível na impressora, o documento é ignorado. void Impressora::adicionarDocumento(Documento doc) //calcula memória consumida int memoriaconsumida = 0; queue<documento> temp(filaimpressao); while(!temp.empty()) memoriaconsumida += temp.front().gettamanho(); temp.pop(); //adiciona documento if( (maxmemoria - memoriaconsumida) >= doc.gettamanho() ) filaimpressao.push(doc); cout << nº docs na fila: << filaimpressao.size() << endl;
Filas: aplicação // imprime o próximo documento na lista de impressão. Se o documento for impresso na // totalidade, sai da fila. Caso não haja toner na impressora suficiente para imprimir todas as páginas do // documento, imprime as páginas que forem possíveis, deixando o restante para ser impresso mais tarde Documento Impressora::imprimirDocumento() Documento d = filaimpressao.front(); if( folhasrestantes >= d.getnfolhas() ) folhasrestantes -= d.getnfolhas(); filaimpressao.pop(); else int nfolhasdoc= d.getnfolhas()-folhasrestantes; filaimpressao.front().setnfolhas(nfolhasdoc); folhasrestantes = 0; cout << não foram impressas todas as folhas << endl; return d; Filas: aplicação // retira da fila de impressão o documento de nome n, pertencente ao utilizador ut. Caso encontre // mais do que um documento, todos devem ser retirados da fila de impressão. void Impressora::excluirDocumento(string n, string ut) queue<documento> temp; //apaga todos os documentos com nome n e utilizador ut while(!filaimpressao.empty()) if( (filaimpressao.front().getnome() == n) && (filaimpressao.front().getutil() == ut) ) filaimpressao.pop(); else temp.push( filaimpressao.front() ); filaimpressao.pop(); filaimpressao = temp; 6