Capítulo VIII – Técnicas de Ordenação

Slides:



Advertisements
Apresentações semelhantes
Complexidade de Algoritmos Recursivos
Advertisements

Katia S. Guimarães QUICKSORT Katia S. Guimarães
Listas encadeadas Prof. Rosana Palazon.
Algoritmos de Ordenação
Série de Exercícios.
1 MergeSort Seja uma lista A de n elementos. O algoritmo consiste das seguintes fases Dividir A em 2 sub-listas de tamanho n/2 Conquistar: ordenar cada.
Pesquisa em Memória Primária
David Menotti Algoritmos e Estruturas de Dados I DECOM – UFOP
HeapSort Filas de Prioridade – Heap
Pesquisa em Memória Primária – Árvores de Busca
Pesquisa em Memória Primária – Árvores de Busca
Pesquisa em Memória Primária
Ordenação Facilitar e aumentar a eficiência das operações de pesquisa sobre esses dados Pode ser crescente ou decrescente A seqüência de entrada, normalmente,
Classificação e Pesquisa de Dados
Prof. Ernesto Lindstaedt
Algoritmos de Ordenação
Algoritmos e Estruturas de Dados II
Pesquisa em Memória Primária
Árvores Binárias de Pesquisa
Heap Sort TPA – Prof. Mateus Costa
Estruturas de Dados e Ordenação
QuickSort Dividir: A[p…r] é particionado (reorganizado) em dois subvetores não vazios A[p…q] e A[q+1…r] tal que cada elemento de A[p…q] é menor ou igual.
Árvore Binária de Busca
Árvores Binárias Profa. Patrícia A. Jaques Luiz Gonzaga Jr
Estruturas de Dados Aula 15: Árvores
Capítulo VI – Variáveis Indexadas 6.1 – A necessidade de variáveis indexadas 6.2 – Vetores e matrizes 6.3 – Aplicações com vetores numéricos 6.4 – Aplicações.
ATAL – Prof. Jorge Figueiredo Ordenação AT AL Análise e Técnicas de Algoritmos Análise de Algoritmos de Ordenação.
Adriana Libório Fernandes Lins Arthur Cavalcanti Alem Átila Valgueiro Malta Moreira Flavio Juvenal da Silva Júnior Gustavo Cauê Silva.
Busca Sequencial Int pseq(int x, int n, int v[]){ for(i=0; i
USP – ICMC – SSC SSC0300 2º Semestre 2015
UNIVERSIDADE FEDERAL DE MINAS GERAIS Pilhas e Filas Cristiano Arbex Valle Vinicius Fernandes dos Santos
Campus Pau dos Ferros Disciplina de Algoritmos Prof. Demétrios Coutinho INFORMÁTICA BÁSICA Algoritmos de Ordenação.
INE5408 Estruturas de Dados Introdução a Árvores - Conceitos - Árvores Binárias - Métodos e algoritmos de percurso - Métodos e algoritmos de balanceamento.
1 Heap Sort Algoritmos e Estuturas de Dados Cátia Vaz.
Métodos de Pesquisa e Ordenação Estruturas de Dados Melissa Marchiani Palone Zanatta.
Listas de Prioridades Cinéticas Tese de Mestrado de: Guilherme Dias da Fonseca (bolsista CAPES) Orientadora: Celina M. H. de Figueiredo 03/2003.
Árvores Binárias Estruturas de Dados Melissa Marchiani Palone Zanatta.
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas – 2016
Ordenação dos Elementos de um Vetor - Bubble Sort e Quick Sort .
Márcio Soussa Estrutura de Dados Márcio Soussa
Programação em C Aula 8.
Ordenação: Terminologia
Métodos de Pesquisa: Seqüencial e Binária
Métodos de Pesquisa e Ordenação
INF1007: Programação 2 6 – Ordenação de Vetores
4. Complexidade média Este capítulo considera a complexidade média, examinando casos ilustrativos de análise de algoritmos e de projeto de estruturas.
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas
Métodos de Pesquisa e Ordenação
Capítulo IV – Árvores Gerais
Análise de Algoritmo Profº Me. Jeferson Bussula Pinheiro
FUNDAMENTO DE PROGRAMAÇÃO
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS
Pesquisa e Ordenação de Vetor
Estruturas de Dados aula 4
Complexidade de Algoritmos
RAZÃO E PROPORÇÃO (Aula 3)
EDA - Prof. Paulemir Campos
Árvores Binárias de Pesquisa e Balanceamento usando Árvores AVL
Prof. Rafael Mesquita Pilha Prof. Rafael Mesquita
Filas.
Algoritmos de ordenação
Prof. Rafael Mesquita Listas Encadeadas Prof. Rafael Mesquita
ALGORITMOS E SUA ANÁLISE: UMA INTRODUÇÃO À CIÊNCIA DA COMPUTAÇÃO
Ementário Noções de hardware e software. Conceitos Fundamentais.
INE5408 Estruturas de Dados
Aula 7 Professores: Conteúdo: Dante Corbucci Filho
Aula 8 Professores: Conteúdo: Dante Corbucci Filho
MATEMÁTICA.
Aula 10 Professores: Conteúdo: Dante Corbucci Filho
Transcrição da apresentação:

Capítulo VIII – Técnicas de Ordenação 8.1 – Introdução 8.2 – Métodos simples de ordenação 8.3 – O método Quick-Sort 8.4 – O método Heap-Sort 8.5 – O método Merge-Sort

8.3 – O Método Quick-Sort 8.3.1 – Generalidades e fundamentos Quick-Sort é provavelmente o algoritmo de ordenação mais usado por programadores em geral Durante muito tempo, pesquisadores de métodos de ordenação se dedicaram mais a aperfeiçoar o Quick-Sort do que a procurar novos métodos

No caso médio, Quick-Sort é O(n log2n) e no pior caso é O(n2) Quick-Sort é recursivo, mas pode ser transformado em não recursivo, mediante o uso de pilha Quick-Sort aplica a técnica denominada divisão e conquista, que reparte o vetor a ser ordenado em dois sub-vetores e os ordena independentemente

O método consiste em: Escolher, mediante um critério razoável, um pivô entre todos os elementos do vetor a ser ordenado Exemplo: seja o vetor Bom é quando tal pivô é a mediana de todos os elementos, ou seja, quando ele consegue dividir o vetor ao meio 5 1 4 3 9 2 8 V 6 Seja o maior entre os dois elementos distintos mais à esquerda escolhido como pivô (pivô = 5)

(para facilitar a elaboração do algoritmo) Dividir o vetor em 2 partes: sub-vetor baixo e sub-vetor alto, colocando no primeiro, todos os elementos menores que o pivô, e no segundo, os elementos restantes left right 5 1 4 3 9 2 8 V 6 pivô = 5 Incondicionalmente, trocar V[left] com V[right] (para facilitar a elaboração do algoritmo)

Dividir o vetor em 2 partes: sub-vetor baixo e sub-vetor alto, colocando no primeiro, todos os elementos menores que o pivô, e no segundo, os elementos restantes left right 6 5 1 4 3 9 2 8 V pivô = 5 Mover left para a direita até V[left]  pivô Mover right para a esquerda até V[right] < pivô

Dividir o vetor em 2 partes: sub-vetor baixo e sub-vetor alto, colocando no primeiro, todos os elementos menores que o pivô, e no segundo, os elementos restantes left right 6 5 1 4 3 9 2 8 V pivô = 5 Trocar V[left] com V[right]

Dividir o vetor em 2 partes: sub-vetor baixo e sub-vetor alto, colocando no primeiro, todos os elementos menores que o pivô, e no segundo, os elementos restantes left right 3 5 1 4 9 2 8 V 6 pivô = 5 Mover left para a direita até V[left]  pivô Mover right para a esquerda até V[right] < pivô

Dividir o vetor em 2 partes: sub-vetor baixo e sub-vetor alto, colocando no primeiro, todos os elementos menores que o pivô, e no segundo, os elementos restantes left right 3 5 1 4 9 2 8 V 6 pivô = 5 Trocar V[left] com V[right]

Dividir o vetor em 2 partes: sub-vetor baixo e sub-vetor alto, colocando no primeiro, todos os elementos menores que o pivô, e no segundo, os elementos restantes left right 3 1 4 9 2 5 8 V 6 pivô = 5 Mover left para a direita até V[left]  pivô Mover right para a esquerda até V[right] < pivô

Dividir o vetor em 2 partes: sub-vetor baixo e sub-vetor alto, colocando no primeiro, todos os elementos menores que o pivô, e no segundo, os elementos restantes left right 3 1 4 9 2 5 8 V 6 pivô = 5 Trocar V[left] com V[right]

Dividir o vetor em 2 partes: sub-vetor baixo e sub-vetor alto, colocando no primeiro, todos os elementos menores que o pivô, e no segundo, os elementos restantes left right 3 1 4 2 9 5 8 V 6 pivô = 5 Mover left para a direita até V[left]  pivô Mover right para a esquerda até V[right] < pivô

Dividir o vetor em 2 partes: sub-vetor baixo e sub-vetor alto, colocando no primeiro, todos os elementos menores que o pivô, e no segundo, os elementos restantes right left 3 1 4 2 9 5 8 V 6 pivô = 5 A divisão está completa pois left > right

Dividir o vetor em 2 partes: sub-vetor baixo e sub-vetor alto, colocando no primeiro, todos os elementos menores que o pivô, e no segundo, os elementos restantes 3 1 4 2 9 5 8 V 6 sub-vetor baixo sub-vetor alto pivô = 5 Pior caso: um dos sub-vetores com um só elemento e o outro com os restantes

Aplicar recursivamente os passos anteriores nos 2 sub-vetores formados Encerrar a recursividade quando, num dado sub-vetor, todos os seus elementos forem iguais Outros critérios para a escolha do pivô:   Um dos elementos extremos do vetor Média de três elementos aleatórios

8.3.2 – Programação V sub-vetor baixo sub-vetor alto i k j 3 1 4 2 9 5 void QuickSort (int i, j; vetor V) { int piv, pivind, k;   pivind = Pivo(i, j, V); if (pivind != -1) { piv = V[pivind]; k = Particao (i, j, piv, V); QuickSort (i, k-1, V); QuickSort (k, j, V); } QuickSort atua entre os índices i e j do vetor V Pivo retorna o índice do pivô no intervalo [i, j] do vetor V; Pivo retorna -1, caso o intervalo não tenha pivô (sem elementos distintos) Particao divide o intervalo [i, j] do vetor V nos sub-vetores baixo e alto, retornando o índice do 1º elemento no sub-vetor alto sub-vetor baixo sub-vetor alto i k j 3 1 4 2 9 5 8 V 6

Função Pivô: retorna -1, se o vetor no trecho considerado não possui elementos distintos; caso contrário retorna o índice do maior entre os dois elementos distintos mais à esquerda int Pivo (int i, j, vetor V) { int prim, k, indpiv; logic achou; prim = V[i]; achou = Falso; k = i+1; indpiv = -1; while (! achou && k <= j) if (V[k] == prim) k++; else { achou = Verdade; if (V[k] > prim) indpiv = k; else indpiv = i; } return indpiv;

Função Partição: faz a permutação dos elementos do vetor e acha o ponto de partição dos dois sub-vetores: int Particao (int i, j, piv; vetor V) { int left, right, aux; left = i; right = j; do { aux = V[left]; V[left] = V[right]; V[right] = aux; while (V[left] < piv) left++; while (V[right] >= piv) right--; } while (left <= right); return left; } left right 5 1 4 3 9 2 8 V 6

Capítulo VIII – Técnicas de Ordenação 8.1 – Introdução 8.2 – Métodos simples de ordenação 8.3 – O método Quick-Sort 8.4 – O método Heap-Sort 8.5 – O método Merge-Sort

8.4 – O Método Heap-Sort 8.4.1 – Definição de heap Árvore binária completa: tem todos os nós possíveis em cada nível; exemplos:

Heap: é uma árvore binária completa ou uma árvore binária: Que se torna completa, quando eliminadas as folhas do nível mais alto e Na qual as folhas de nível mais alto estão o mais à esquerda possível Exemplos:

A estrutura de um heap é única para um número fixo de nós Exemplo: o heap abaixo com 18 nós é único

Estrutura de dados para heap’s: vetor de n inteiros Declarações: typedef int Vetor[200]; struct heap {Vetor elem; int n;}; heap H1, H2; Observação: os nós são os índices do vetor; exemplo a seguir

Propriedades dessa representação:   nó i: iésima posição do vetor nó i tem como filhos 2i + 1 2i + 2 pai: (i-1) / 2 altura de um heap de n nós: log2n

8.4.2 – Fila de prioridades a) Definição: é um heap em que o valor de um nó é sempre menor ou igual aos de seus eventuais filhos Exemplos:

b) Operação de deletar o elemento mínimo duma fila de prioridades: Inicialmente: 3 5 9 8 6 9 10 10 18 12 9

Retira-se a raiz e coloca-se ali o último elemento: 3 5 9 8 6 9 10 10 18 12 9

trocar 9 5 9 8 6 9 10 10 18 12

5 trocar 9 9 8 6 9 10 10 18 12

Fim da operação 5 6 9 8 9 9 10 O número de troca nunca é maior que a altura da árvore – log2n 10 18 12

c) Operação de inserir um elemento numa fila de prioridades: Seja a inserção do 1: 3 5 9 6 8 9 10 10 18 9

Coloca-se o elemento a ser inserido na última posição: 3 5 9 trocar 6 8 9 10 10 18 9 1

3 trocar 5 9 6 1 9 10 10 18 9 8

trocar 3 1 9 6 5 9 10 10 18 9 8

Fim da operação 1 3 9 6 5 9 10 10 18 9 8 O número de troca nunca é maior que a altura da árvore – log2n

8.4.3 – Programação do Heap-Sort O método consiste em duas partes principais: Inserir elemento por elemento do vetor numa fila de prioridades Retirar pela raiz todos os elementos da fila de prioridades, retornando-os ao vetor

void HeapSort (int n, Vetor V) { int i; heap H; Anular (&H); for (i = 0; i < n; i++) Inserir (V[i], &H); V[i] = DeletaMin (&H); } rotina: Anular (heap *H) { H->n = 0;

void Inserir (int x, heap *H) { int i, temp; (H->n)++; i = H->n - 1; H->elem[i] = x; while (i > 0 && H->elem[i] < H->elem[(i-1)/2]) { temp = H->elem[i]; H->elem[i] = H->elem[(i-1)/2]; H->elem[(i-1)/2] = temp; i = (i-1)/2; }

int DeletaMin (heap *H) { int i, j, temp, ret; logic parou; ret = H->elem[0]; H->elem[0] = H->elem[H->n - 1]; (H->n)--; parou = FALSE; i = 0; while (! parou && 2*i+1 <= H->n - 1) { if (2*i+1 == H->n - 1 || H->elem[2*i+1] < H->elem[2*i+2]) j = 2*i+1; else j = 2*i+2; if (H->elem[i] > H->elem[j]) { temp = H->elem[i]; H->elem[i] = H->elem[j]; H->elem[j] = temp; i = j; } else parou = TRUE; return ret; Se i não tiver filhos, encerra a operação j terá o índice do menor dos filhos de i Troca entre os elementos de i e do menor de seus filhos

Observações: O método Heap-Sort é O(n log n) no caso médio e no pior caso Altura de um heap de n nós: log2n No caso médio, Quick-Sort leva alguma vantagem sobre Heap-Sort Nesta implementação, há um gasto maior de memória devido à variável auxiliar H A seguir uma implementação in place, ou seja, sem o uso da variável H

8.4.4 –Heap-Sort in place A distribuição dos elementos no vetor será invertida Exemplo de heap com 18 elementos:

Propriedades dessa representação:   nó j: jésima posição do vetor nó j tem como filhos 2j - n 2j - n - 1 pai: n - (n-j) / 2 altura de um heap de n nós: log2n

void HeapSort (int n, vetor V) { FormarFilaPrioridades (n, V); OrdenarFilaPrioridades (n, V); } void FormarFilaPrioridades (int n, vetor V) { int i, j, temp; for (i = n-2; i >= 0; i--) { j = i; while (j < n-1 && V[j] < V[n-(n-j)/2]) { temp = V[j]; V[j] = V[n-(n-j)/2]; V[n-(n-j)/2] = temp; j = n-(n-j)/2;

void OrdenarFilaPrioridades (int n, vetor V) { int i, j, k, temp, min; logic parou; for (i = 0; i < n-1; i++) { min = V[n-1]; V[n-1] = V[i]; V[i] = min; parou = FALSE; j = n-1; while (! parou && 2*j-n > i) { if (2*j-n == i+1 || V[2*j-n] < V[2*j-n-1]) k = 2*j-n; else k = 2*j-n-1; if (V[j] > V[k]) { temp = V[j]; V[j] = V[k]; V[k] = temp; j = k; } else parou = TRUE;

Capítulo VIII – Técnicas de Ordenação 8.1 – Introdução 8.2 – Métodos simples de ordenação 8.3 – O método Quick-Sort 8.4 – O método Heap-Sort 8.5 – O método Merge-Sort

8.5 – O Método Merge-Sort Merge: fundir num só dois vetores ordenados, mantendo a ordem Mas, se inicialmente o vetor está desordenado, como fazer fusão?

Idéia recursiva: Caso o vetor tenha dois ou mais elementos: Dividir o vetor ao meio, obtendo a metade da esquerda e a metade da direita Ordenar cada uma dessas metades pelo Merge-Sort Fundir as duas metades ordenadas

Fundir dois vetores ordenados: percorrê-los com cursores, comparando os elementos da posição dos mesmos; o menor é copiado num vetor temporário Exemplo: Fusão dos seguintes vetores: V1: 3, 5, 8, 8, 11, 13, 16 e V2: 4, 5, 6, 7, 8, 9

Fusão de 2 vetores: i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; 5 8 11 13 16 j V2 4 5 6 7 8 9 V3 k

Fusão de 2 vetores: i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; 5 8 11 13 16 j V2 4 5 6 7 8 9 V3 3 k

Fusão de 2 vetores: i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; 5 8 11 13 16 j V2 4 5 6 7 8 9 V3 3 4 k

Fusão de 2 vetores: i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; 5 8 11 13 16 j V2 4 5 6 7 8 9 V3 3 4 5 k

Fusão de 2 vetores: i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; 5 8 11 13 16 j V2 4 5 6 7 8 9 V3 3 4 5 k

Fusão de 2 vetores: i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; 5 8 11 13 16 j V2 4 5 6 7 8 9 V3 3 4 5 6 k

Fusão de 2 vetores: i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; 5 8 11 13 16 j V2 4 5 6 7 8 9 V3 3 4 5 6 7 k

Fusão de 2 vetores: i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; 5 8 11 13 16 j V2 4 5 6 7 8 9 V3 3 4 5 6 7 8 k

Fusão de 2 vetores: i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; 5 8 11 13 16 j V2 4 5 6 7 8 9 V3 3 4 5 6 7 8 k

Fusão de 2 vetores: i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; 5 8 11 13 16 j V2 4 5 6 7 8 9 V3 3 4 5 6 7 8 k

Fusão de 2 vetores: i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; 5 8 11 13 16 j V2 4 5 6 7 8 9 V3 3 4 5 6 7 8 9 k

Fusão de 2 vetores: i j k V3[k] = (V1[i] < V2[j]) ? V1[i] : V2[j]; 5 8 11 13 16 j V2 4 5 6 7 8 9 V3 3 4 5 6 7 8 9 11 13 16 k

No método Merge-Sort, os dois vetores são sub-vetores do vetor a ser ordenado 3 5 8 11 13 16 4 6 7 9

A seguir, ilustração do método Merge-Sort para o vetor: void MergeSort (int first, last; vetor V) { int med; if (first < last) { med = (first + last)/2; MergeSort (first, med, V); MergeSort (med+1, last, V); Merge (first, last, V); } A seguir, ilustração do método Merge-Sort para o vetor: 8, 6, 4, 6, 5, 7, 1, 2, 9, 7, 2

Merge é O(n) e MergeSort é O(n log n) void Merge (int first, last; vetor V) { int med, i, j, k; vetor T; med = (first + last)/2; i = 0; j = first; k = med + 1; while (j <= med && k <= last) { if (V[j] < V[k]) {T[i] = V[j]; j++;} else {T[i] = V[k]; k++;} i++; } while (j <= med) {T[i] = V[j]; j++; i++;} while (k <= last) {T[i] = V[k]; k++; i++;} for (j = first, i = 0; j <= last; j++, i++) V[j] = T[i]; Merge é O(n) e MergeSort é O(n log n)