lgoritmos e struturas de Dados 2013/14 Filas com rioridade - cervos Filas com prioridade - ntrodução (1) Filas com prioridade (riority Queues) usadas em diversas aplicações: Despacho (scheduler) de tarefas. Compressão de ficheiros. lgoritmos de ordenação. perações mais usuais em filas com prioridade: Criar fila, a partir de um conjunto de items nserir novo item emover o item com prioridade mais elevada emover um item odificar a prioridade de um item Juntar duas filas de prioridade 2
Filas com prioridade - ntrodução (2) nterface do tipo abstracto: void Qinit(int); /* inicializa fila com prioridade */ /* com número máximo de items */ B Qempty(); /* testa fila vazia */ void Qinsert(tem); /* insere item */ tem Qdelmax(); /* elimina item de maior prioridade */ as filas de prioridade, todos os elemento possuem uma chave, que pode ser usada para ordenar a fila Chave maior (ou menor) pode corresponder a maior prioridade 3 Filas com prioridade por tabela (1) mplementação por tabela não ordenada #include <stdlib.h> #include tem.h /* aqui o cliente define os dados */ static tem *queue; static int free; /* primeira posição livre */ static int qsize; /* tamanho da tabela */ void Qinit(unsigned ize) { queue = (tem *) malloc(ize * sizeof(tem)); qsize = ize; free = 0;} void Qinsert(tem ){ /* elemento inserido sempre na primeira posição livre */ if ((free+1) < qsize) queue[free++] = ; /* else error */} B smpty() { return free == 0? U : F;} Qinsert(i1); Qinsert(i3); Qinsert(i2); i2 i3 free=3 i1 4
Filas com prioridade por tabela (2) tem Qdelmax() { /* elimina elemento de maior chave; assume não vazio */ int dx, ax; /* procura elemento com maior chave */ for(dx=1, ax=0; dx<free; dx++) if(less(queue[ax], queue[dx])) ax = dx; } /* troca topo com o elemento de maior chave */ exch(queue[ax], queue[free-1]); return(queue[--free]); eja Key(i3)>Key(i2)>Key(i1) Qdelmax() dá: i2 i3 i2 free=3 i1 free=2 i1 5 Filas com prioridade por tabela (3) abela ordenada pela chave nserção e remoção de um elemento com prioridade qualquer, exige varrimento da tabela para deslocar items (no pior caso, toda a tabela). rocura e remoção do elemento com maior chave em tempo constante (acesso imediato ao topo). implementação das filas de prioridade por acervos (heaps) permite o melhor equilíbrio no desempenho da procura (e remoção) de elementos com maior e com prioridade qualquer. 6
Filas com prioridade por tabela (4) Complexidade, no pior caso, das operações das filas com prioridade (segundo algumas implementações) abela ordenada abela não ordenada nserção emover chave máxima emover ncontrar Chave máxima odificar rioridade Junção 1 1 1 1 1 cervo lg lg lg 1 lg 7 cervos (1) Definição Um acervo (heap) é uma representação, em tabela, de uma árvore que satisfaz a condição de acervo (heap condition): o valor da chave associada a cada nó é não inferior (ou não superior) ao valor das chaves associadas em todos os nós seus descendentes u seja, o valor da chave de um dado nó é sempre maior ou igual (ou menor ou igual) que o valor da chave de qualquer dos seus filhos (quando existam). ordenação dos acervos é parcial (heap-ordering) Vantagens da representação de árvores por tabela enor ocupação de memória cesso constante a qualquer elemento nconvenientes da representação de árvores por tabela ecessário conhecer tamanho à partida 8
cervos (2) Convenção (exemplo): nos acervos, a prioridade é maior quanto menor for o número. #define lessri(, B) (key() > key(b)) (pode ser exactamente o contrário; é uma convenção) criação de um acervo, a partir de uma árvore, é feita percorrendo a árvore em largura (breadht-first). e árvore não for completa, existem casas vazias. solução é impor que todos os nós intermédios sejam preenchidos. 9 cervos (3) xemplo 1: cervo de 12 posições 3 3 5 7 9 12 16 20 25 22 28 32 40 nó ascendente da posição i é (i-1)/2 5 7 xemplo: nó ascendente da posição 6 (prioridade 20), está na posição (6-1)/2 = 2 (prioridade 7) 9 25 22 12 16 28 32 40 20 s nós descendentes da posição i são 2i+1 e 2(i+1) xemplo: nós descendentes da posição 0 (prioridade 3), estão nas posições 1 (prioridade 5) e 2 (prioridade 7) xemplo: nós descendentes da posição 2 (prioridade 7), estão nas posições 5 (prioridade 16) e 6 (prioridade 20) ota! o livro do edgewick, os índices da tabela são considerados a partir de 1, qui usamos a convenção do C (a partir de 0) 10
cervos (4) lteração/inserção/remoção de um elemento pode quebrar a condição dos acervos. xemplo: se a prioridade for decrementada (valor substituído por outro maior), os descendentes podem passar a ter prioridades maiores (valores menores). ota: nos nossos exemplos decrementar a prioridade significa aumentar a chave perações a realizar para manter a condição de acervo e a prioridade for decrementada, verificar nós de alturas inferiores descendo num caminho até alguma folha e a prioridade for incrementada, verificar nós de alturas superiores subindo no caminho até à raiz 12 cervos (5) eposição da ordenação num acervo Caso e prioridade de um nó for aumentada, enquanto não for restabelecida a condição de acervo ou atingida a raiz, trocar com o nó ascendente. void FixUp(tem Heap[], int dx) { while (dx > 0 && lessri(heap[(dx-1)/2], Heap[dx])) { exch(heap[dx], Heap[(dx-1)/2]); dx = (dx-1)/2; } } Fácil verificar que FixUp é (lg) 13
cervos (6) xemplo 2: o exemplo 1, nó de prioridade 28 (posição 9) passa a ter prioridade 4 5 3 7 3 5 7 9 12 10 20 25 22 4 32 40 9 12 16 20 25 22 4 32 40 Heap[9]=4, Heap[(9-1)/2]=12 lessri(heap[4], Heap[9]): trocar e chamar FixUp sobre a posição 4 14 cervos (7) xemplo 2: o exemplo 1, nó de prioridade 28 (posição 9) passa a ter prioridade 4 5 3 7 3 5 7 9 4 10 20 25 22 12 32 40 9 4 16 20 25 22 12 32 40 Heap[4]=4, Heap[(4-1)/2]=5 lessri(heap[1], Heap[4]): trocar e chamar FixUp sobre a posição 1 15
cervos (8) xemplo 2: o exemplo 1, nó de prioridade 28 (posição 9) passa a ter prioridade 4 4 3 7 3 4 7 9 5 10 20 25 22 12 32 40 9 5 16 20 25 22 12 32 40 Heap[1]=4, Heap[(1-1)/2]=3!lessri(Heap[0], Heap[1]): condição de acervo satisfeita!! 16 cervos (9) xemplo 2: o exemplo 1, nó de prioridade 28 (posição 9) passa a ter prioridade 4 4 3 7 3 4 7 9 5 10 20 25 22 12 32 40 9 5 16 20 25 22 12 32 40 17
cervos (10) eposição da ordenação num acervo Caso B e prioridade de um nó for diminuída, enquanto não restabelecer a condição de acervo ou atingir uma folha, trocar com o maior descendente. void FixDown(tem Heap[], int dx, int ) { int Child; /* índice de um nó descendente */ } while((2*dx-1) < ) { /* enquanto não chegar às folhas */ Child = 2*dx+1; /* elecciona o maior descendente. */ /* ota: se índice Child é -1, então só há um descendente */ if (Child < (-1) && lessri(heap[child], Heap[Child+1])) Child++; if (!lessri(heap[dx], Heap[Child])) break; /* condição acervo */ /* satisfeita */ exch(heap[dx], Heap[Child]); /* continua a descer a árvore */ dx = Child; } Fácil verificar que FixDown é (lg) 18 cervos (11) xemplo 2: o exemplo 1, nó de prioridade 3 (posição 0) passa a ter prioridade 14 5 14 7 14 5 7 9 12 10 20 25 22 28 32 40 9 12 16 20 25 22 28 32 40 dx=0, Child=2*0+1=1!lessri(Heap[1],Heap[2]): foca na subárvore esq. lessri(heap[0],heap[1]): troca e chama FixDown sobre a posição 1 19
cervos (12) xemplo 2: o exemplo 1, nó de prioridade 3 (posição 0) passa a ter prioridade 14 14 5 7 5 14 7 9 12 10 20 25 22 28 32 40 9 12 16 20 25 22 28 32 40 dx=1, Child=2*1+1=3!lessri(Heap[3],Heap[4]): foca na subárvore esq. lessri(heap[1],heap[3]): troca e chama FixDown sobre a posição 3 20 cervos (13) xemplo 2: o exemplo 1, nó de prioridade 3 (posição 0) passa a ter prioridade 14 9 5 7 5 9 7 14 12 10 20 25 22 28 32 40 14 12 16 20 25 22 28 32 40 dx=3, Child=3*1+1=7 lessri(heap[7],heap[8]): foca na subárvore dir.!lessri(heap[3],heap[8]): condição de acervo satisfeita 21
cervos (14) xemplo 2: o exemplo 1, nó de prioridade 3 (posição 0) passa a ter prioridade 14 5 9 7 5 9 7 14 12 10 20 25 22 28 32 40 14 12 16 20 25 22 28 32 40 22 Filas com prioridade por acervo (1) #include tem.h /* aqui o cliente define os dados */ static tem *queue; static int free; /* número de elementos existentes no acervo */ static int hsize; void Qinit(unsigned ize) { queue = (tem *)malloc(ize*sizeof(tem)); hsize = ize; free = 0; } void Qinsert(tem ) { } /* insere novo elemento no fim e restabelece ordenação com FixUp */ if ((free+1) < hsize) { queue[free] = ; } FixUp(queue, free); free++; 23
Filas com prioridade por acervo (2) tem Qdelmax() { /* troca maior elemento com último da tabela e reordena com FixDown */ exch(queue[0], queue[free-1]); FixDown(queue, 0, free-1); /* ultimo elemento não considerado na reordenação */ return queue[--free]; } 24 rdenação por acervo (1) algoritmo de ordenação, usando uma fila com prioridade, é muito simples: nserir a tabela numa fila com prioridade, implementada por acervo. Chamar Qdelmax() para identificar a tabela inversamente ordenada. void Qsort(tem pable[], int, int ) { int ux; Qinit(-+1); for(ux = ; ux <= ; ux++) Qinsert(pable[ux]); for(ux = ; ux >= ; ux--) pable[ux] = Qdelmax(); } 25
rdenação por acervo (2) Complexidade do processamento: melhor que lg nicialização: (1) nserção: lg 1 + lg 2 +... + lg (< lg) etirada dos elementos do acervo: lg +... + lg 2 + lg 1 (< lg) Complexidade da memória extra:, para o acervo memória extra pode ser eliminada, se o acervo for construído na própria tabela a ordenar. rimeiro, constroi-se o acervo chamado FixDown na metade inicial da tabela. Depois, troca-se a raiz com o último elemento e faz-se o FixDown sobre a tabela de dimensão menos 1) 26 rdenação por acervo (3) void Heapsort(tem able[], int, int ) { int ux, op = ; /* Constroi acervo na própria tabela, executando FixDown na parte inferior */ for(ux = (+-1)/2; ux >= ; ux--) FixDown(able, ux, ); } /* eordena a tabela, trocando o topo e exercendo FixDown na tabela com */ /* dimensão 1 (na troca, o menor é já colocado na posição final) */ while(op > ){ exch(able[], able[op]); FixDown(able,, --op); } 27
xemplo de aplicação ransformação da tabela em acervo 28 xemplo de aplicação 29
xemplo de aplicação 30 xemplo de aplicação 31
xemplo de aplicação 32 xemplo de aplicação 33
xemplo de aplicação 34 xemplo de aplicação 35
xemplo de aplicação 36 xemplo de aplicação 37
xemplo de aplicação 38 xemplo de aplicação 39
xemplo de aplicação 40 xemplo de aplicação 41
xemplo de aplicação abela transformada em acervo 42 xemplo de aplicação rdenação da tabela a partir do acervo 43
xemplo de aplicação 44 xemplo de aplicação 45
xemplo de aplicação 46 xemplo de aplicação 47
xemplo de aplicação 48 xemplo de aplicação 49
xemplo de aplicação 50 xemplo de aplicação 51
xemplo de aplicação 52 xemplo de aplicação 53
xemplo de aplicação 54 xemplo de aplicação 55
xemplo de aplicação 56 xemplo de aplicação 57
xemplo de aplicação 58 xemplo de aplicação 59
xemplo de aplicação 60 xemplo de aplicação 61
xemplo de aplicação 62 xemplo de aplicação 63
xemplo de aplicação 64 xemplo de aplicação 65
xemplo de aplicação 66 xemplo de aplicação 67
xemplo de aplicação 68 xemplo de aplicação 69
xemplo de aplicação 70 xemplo de aplicação 71
xemplo de aplicação 72 xemplo de aplicação 73
xemplo de aplicação 74 xemplo de aplicação 75
xemplo de aplicação 76 xemplo de aplicação 77
xemplo de aplicação 78 xemplo de aplicação 79
xemplo de aplicação 80 xemplo de aplicação 81
xemplo de aplicação 82 xemplo de aplicação 83
xemplo de aplicação abela ordenada* * por ordem crescente de prioridade 84 nálise de complexidade Construção do acervo custa () É relativamente simples mostrar o resultado rdenação custa sempre ( lg), qualquer que seja o formato da entrada ver exemplos no edgewick.5 rimeiro constrói-se o acervo () e depois ordena-se a partir do acervo ( lg) elecção s k maiores elementos (k<<) podem ser identificados em (), bastando interromper o 2º ciclo ao fim de k iterações u seja, depois de construir o acervo, fazem-se k remoções do máximo () + (lg(-1)) + (lg(-2)) + (lg(-3)) +... + (lg(-k)) () + k (lg) () (quando k << ) 85
íntese da ula de Filas com rioridade ntrodução às filas com prioridade perações abstractas mplementação por tabelas não-ordenadas ntrodução aos acervos (heaps) eposição nos acervos scendente Descendente mplementação de filas, com prioridade, por acervos rdenação por acervo 86