Programação de Computadores Ordenação de Arranjos

Documentos relacionados
BCC202 - Estrutura de Dados I

Métodos de Ordenação Parte I

BCC202 - Estrutura de Dados I

Ordenação. Prof. Jonas Potros

Carlos Eduardo Batista. Centro de Informática - UFPB

void subdivide (LISTA_ENC *pl, LISTA_ENC *pl1, LISTA_ENC *pl2) { int cont, k=1; for (cont=tam(*pl)/2;cont;cont--) {

Ordenação: MergeSort. Prof. Túlio Toffolo BCC202 Aula 14 Algoritmos e Estruturas de Dados I

Projeto e Análise de Algoritmos

Método BubbleSort. Estrutura de Dados II Prof Jairo Francisco de Souza

Introdução Métodos de Busca Parte 1

MC102 - Algoritmos e programação de computadores. Aula 16: Busca e Ordenação em vetores

Métodos de Ordenação

Algoritmos de Ordenação

ALGORITMOS DE ORDENAÇÃO

ORDENAÇÃO POR INTERCALAÇÃO

Algoritmos de Ordenação: Tempo Linear

Algoritmos de Ordenação. Profº Carlos Alberto T. Batista

Aula 3 Listas Lineares Sequenciais Ordenadas. prof Leticia Winkler

USP - ICMC - SSC SSC o. Semestre Disciplina de Linguagem de Programação e Aplicações [ Eng. Elétrica / Automação ]

INF111 Programação II Aulas 11, 12, 13 Ordenação

Estrutura de Dados. Algoritmos de Ordenação. Prof. Othon M. N. Batista Mestre em Informática

Algoritmos e Estruturas de Dados I1 Prof. Eduardo 1

Ordenação: Heapsort. Algoritmos e Estruturas de Dados II

Marcelo Keese Albertini Faculdade de Computação Universidade Federal de Uberlândia

Aula 18 Algoritmos básicos de busca e classificação

ALGORITMOS AVANÇADOS. UNIDADE III Algoritmo de Ordenação por Intercalação (Mergesort) Luiz Leão

BUSCA EM ARRAYS. Prof. André Backes. Ato de procurar por um elemento em um conjunto de dados

Extra- Algoritmos de Ordenação

Quicksort. David Menotti Algoritmos e Estruturas de Dados II DInf UFPR

Universidade Federal do ABC Avaliação Disciplina Turma Professor Data Instruções para a prova (leia antes de começar): SelectionSort selectonsortrec

Classificação por Intercalação

Ordenação - Motivação

Classificação por Seleção - selection sort

Ordenação em Memória Primária Estrutura de Dados II

Centro de Informá-ca Universidade Federal de Pernambuco. Vinicius Cardoso Garcia 2011 Vinicius Cardoso Garcia

5. Algoritmos de Ordenação

Métodos de Ordenação Parte 3

Programação II. Busca em Vetor (search) Bruno Feijó Dept. de Informática, PUC-Rio

Existem duas categorias de algoritmos de ordenação: Os algoritmos de ordenação são avaliados de acordo com os seguintes critérios:

Projeto e Análise de Algoritmos

INF1007: Programação 2 6 Ordenação de Vetores. 01/10/2015 (c) Dept. Informática - PUC-Rio 1

Métodos de ordenação. Bubble sort:

Universidade Estadual de Mato Grosso do Sul Bacharelado em Ciência da Computação Algoritmos e Estruturas de Dados II Prof. Fabrício Sérgio de Paula

Métodos de Classificação

Aula 1. Teoria da Computação III

Projeto e Análise de Algoritmos

Ordenação Externa. Ordenação Externa. Ordenação Externa. Ordenação Externa

Carlos Eduardo Batista. Centro de Informática - UFPB

Algoritmos e Estrutura de Dados. Algoritmos Prof. Tiago A. E. Ferreira

Mergesort. Aula 04. Algoritmo Mergesort. Divisão e Conquista. Divisão e Conquista- MergeSort

BCC202 - Estrutura de Dados I

MÉTODOS DE ORDENAÇÃO. Introdução à Programação SI2

Conteúdo. Busca Seqüencial. Busca Binária. Algoritmos de Ordenação e Busca e sua Análise de Complexidade. Alneu de Andrade Lopes Rosane Minghim

Algoritmos e Estruturas de Dados 2006/2007

Aula T19 BCC202 Pesquisa (Parte 1) Pesquisa Binária. Túlio Toffolo

Entrada: M ind

Pesquisa Linear. Adriano J. Holanda 15/3/2016

Classificação por Particionamento

Métodos de Classificação

Linguagem C: Ordenação

ESTRUTURAS DE DADOS E ALGORITMOS ALGORITMOS DE ORDENAÇÃO POR COMPARAÇÃO - II

Memória secundária. Memória secundária

Análise de Complexidade de Algoritmos. mario alexandre gazziro

Árvores B. Prof. Márcio Bueno. / Fonte: Material da Prof a Ana Eliza Lopes Moura

Projeto e Análise de Algoritmos Aula 4: Dividir para Conquistar ou Divisão e Conquista ( )

Departamento de Engenharia Rural Centro de Ciências Agrárias. Programação I

MÉTODOS DE CLASSIFICAÇÃO EM MEMÓRIA PRIMÁRIA. George Gomes Cabral

Classificação e Pesquisa Aula 6 Métodos de Ordenação: ShellSort e QuickSort. Prof. Esp. Pedro Luís Antonelli Anhanguera Educacional

Classes, Herança e Interfaces

Ordenação. Insertion Sort

Análise de Complexidade. Algoritmos e Estruturas de Dados Flavio Figueiredo (

Radix Sorting. Várias aplicações têm chaves que são inteiros, definidos dentro de um intervalo

O Problema da Ordenação Métodos de Ordenação Parte 1

Estruturas de Dados 2

DAINF - Departamento de Informática

Tabelas Hash O Que é uma Tabela Hash? O Que é uma Tabela Hash? O Que é uma Tabela Hash? Inserindo um Novo Registro. O Que é uma Tabela Hash?

Método de ordenação - objetivos:

Algoritmos de Busca em Vetores

Estrutura de Dados: Lista Linear. Parte I Introdução e Listas Sequenciais Estáticas

QuickSort. Algoritmos e Estruturas de Dados Verão Cátia Vaz 1

Classificação Externa: Geração de Partições Classificadas

Edital de Seleção 032/2016 PROPESP/UFAM. Prova de Conhecimento. Caderno de Questões

Algoritmos e Estruturas de Dados

Algoritmos de pesquisa. Tabelas de dispersão/hash

Pesquisa sequencial e pesquisa binária

Ordenação de Dados. Ordenação de Dados

Arquivos Sequenciais. Estruturas de Dados II Vanessa Braganholo

Métodos de Ordenação. Ordenação Interna. Ordenação Interna

Tabelas de hash Acabamos de estudar como implementar uma tabela hashing aberta e estudaremos agora como implementar uma tabela hashing fechada ou

Medida do Tempo de Execução de um Programa. David Menotti Algoritmos e Estruturas de Dados II DInf UFPR

Estrutura de Dados. ! Listas lineares. ! Como manipulá-las: ! estática. ! dinâmicas. ! pilhas. ! filas

6. Pesquisa e Ordenação

Árvores Binárias de Busca

Centro Federal de Educação Tecnológica de Minas Gerais Programa de Pós-Graduação em Modelagem Matemática e Computacional

Basicamente, os tipos de algoritmos de ordenação podem ser resumidos a: Por seleção: seleciona o menor elemento, o segundo menor e assim por diante

Comportamento Assintótico. Algoritmos e Estruturas de Dados Flavio Figueiredo (

Aula 15: Pesquisa em Memória Primária. Bruno Hott Algoritmos e Estruturas de Dados I DECSI UFOP

Complexidade de Algoritmos

Árvores Binárias de Busca (ABB) 18/11

Transcrição:

Programação de Computadores Ordenação de Arranjos Notação O Alan de Freitas Classes de algoritmos Busca em arranjo Busca sequencial Busca binária On) Olog n)

Ordenação de Arranjos Ordenação de Arranjos Como sabemos, buscas binárias em arranjos são mais eficientes que buscas sequenciais. Porém, estas buscas só podem ser feitas em arranjos ordenados É comum em programação a necessidade de se ordenar um arranjo Um motivo razoável para isto pode ser inclusive ordenação dos dados para facilitar sua visualização Pedro João Maria Roberto Manuel José Barbosa Joaquim Alberto Alberto Barbosa Joaquim João José Manuel Maria Pedro Roberto Ordenação de arranjos Conceitos de Ordenação Imagine um catálogo telefônico onde os nomes das pessoas não estão em ordem As estratégias para se ordenar um arranjo são diversas Neste curso, estudaremos algumas destas estratégias O processo de ordenação pode ser para colocar os itens em ordem crescente ou decrescente

Conceitos de Ordenação Como no caso da busca binária, os algoritmos são estendidos em situações práticas para ordenar structs por suas chaves Porém, para fins didáticos, os algoritmos de ordenação serão apresentados para ordenação de arranjos de tipos de dados fundamentais Ordenação Estável Uma ordenação estável é aquela que mantém a ordem relativa dos elementos antes da ordenação Ou seja, se dois elementos são iguais, o elemento que aparece antes no arranjo desordenado deve ainda aparecer antes no arranjo ordenado Suponha um arranjo a com os seguintes elementos. Suponha um arranjo a com os seguintes elementos. a 9 3 5 3 4 4 1 a 9 3 5 3 4 4 1 a 1 3 3 4 4 5 9 Este é o mesmo arranjo após a aplicação de um algoritmo de ordenação.

Se o resultado final ocorreu da seguinte maneira Note a procedência dos elementos 3 e 4. a 9 3 5 3 4 4 1 a 9 3 5 3 4 4 1 a 1 3 3 4 4 5 9 nosso algoritmo de ordenação teve comportamento estável. a 1 3 3 4 4 5 9 Perceba como mantiveram sua ordem relativa. Já este, poderia ser o resultado de um algoritmo instável Mas então qual a desvantagem de algoritmos instáveis? a 9 3 5 3 4 4 1 a 1 3 3 4 4 5 9 pois, apesar do resultado ser o mesmo, eles não se preocupam em manter a ordem relativa dos elementos. Imagine que queremos ordenar um arranjo com as cartas acima.

Estas cartas poderiam ser facilmente representadas pela seguinte estrutura: Utilizando uma ordenação qualquer, podemos ter um resultado como o abaixo: struct Carta int valor; int naipe; Nesta estrutura, valor seria um número de 1 a 13 e naipe seria um número de 1 a 4. As cartas estão ordenadas agora pelos números mas a ordem do naipes é arbitrária. Suponha que agora queremos que as cartas estejam ordenadas de acordo com seu naipe. Para esta segunda ordenação, podemos utilizar um algoritmo estável ou instável. Para isto precisamos de uma segunda ordenação das cartas.

Veja o que acontece quando ordenamos as cartas com um algoritmo instável. Veja o que aconteceria se houvéssemos ordenado as cartas com um algoritmo estável. Perdemos a ordem de valor das cartas ao ordenar pelos naipes. Claramente, isto não é o que queríamos. Agora temos as cartas ordenadas por seus naipes mas também mantivemos a ordenação anterior por seus valores. Ordenação Estável Para forçar a estabilidade, adicionamos um índice a cada elemento do arranjo. Alguns métodos mais eficientes não são estáveis 0 1 2 3 4 5 Porém, podemos forçar um método não estável a se comportar de forma estável

Para forçar a estabilidade, adicionamos um índice a cada elemento do arranjo. 0 1 2 3 4 5 1 < 2 True Agora, podemos utilizar o índice como fator de desempate caso os elementos tenham chave igual ou mesmo naipe em nosso exemplo) Ordenação Estável Apesar de possível, forçar um método não estável a se tornar estável diminui a eficiência dos algoritmos e faz com que o algoritmo gaste memória extra para armazenar todos os índices Como há um índice para cada elemento, este custo extra de memória é On) Complexidade de tempo Outro fator a se considerar é a complexidade de tempo dos algoritmos de ordenação A medida mais relevante de tempo é o número de comparações Cn) feitas por um algoritmo para ordenar o vetor Uma medida secundária é o número Mn) de movimentações, ou operações de atribuição Complexidade de tempo Em geral os métodos de ordenação simples: Requerem On 2 ) comparações São apropriados para arranjos pequenos Os métodos eficientes Requerem On log n) comparações Adequados para arranjos grandes

Complexidade de memória Ordenação por Seleção Mais um fator relevante é a memória extra que estes algoritmos utilizam para conseguir ordenar o arranjo Os métodos de ordenação que não precisam de memória extra são chamados de métodos in place ou in situ) Este é um dos algoritmos mais simples de ordenação É um algoritmo onde a cada passo de repetição: Se escolhe o menor elemento do arranjo Troca-o com o elemento da primeira posição Repete este procedimento para os outros n-1 elementos Considere um arranjo com os seguintes elementos A partir do primeiro elemento, procuramos o menor elemento do arranjo.

Este elemento é trocado com o elemento da primeira posição. Sabemos agora que o arranjo está ordenado até o primeiro elemento A partir do segundo elemento, procuramos o menor elemento do arranjo. Este é colocado na segunda posição e sabemos que os dois primeiros elementos do arranjo já estão ordenados.

A partir do terceiro elemento, procuramos o menor elemento e o colocamos na terceira posição. A partir do quarto elemento, procuramos o menor elemento e o colocamos na quarta posição. A partir do quinto elemento, procuramos o menor elemento e o colocamos na quinta posição. Como há apenas um elemento no arranjo não ordenado, já sabemos que ele está em sua posição correta então podemos encerrar o método.

Ordenação por Seleção Arranjo 7 5 4 6 9 8 Passo 1 4 5 7 6 9 8 Passo 2 4 5 7 6 9 8 Passo 3 4 5 6 7 9 8 Passo 4 4 5 6 7 9 8 Passo 5 4 5 6 7 8 9 Arranjo 4 5 6 7 8 9 Ordenação por seleção para um arranjo de inteiros void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; Troca Desordenado Ordenado A função ordena o arranjo a, que contém n elementos void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; Como sabemos que arranjos são passados por referência em C++, não precisamos retornar nada desta função. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; a 6 3 8 5 9 2 1 a 6 3 8 5 9 2 1

Os índices i, j e min são utilizados para percorrermos o arranjo em um for aninhado e procurar seu menor elemento a cada passo. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; A variável x deve ser do mesmo tipo dos elementos do arranjos pois será uma variável temporária para fazer as trocas entre elementos. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; a 6 3 8 5 9 2 1 min i j a 6 3 8 5 9 2 1 min x i j Entramos em um for que, para cada posição do arranjo, colocará em seu lugar o elemento mínimo entre os elementos posteriores. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; Por exemplo, quando i é 0, supomos que o menor elemento entre as posições 0 e n está na posição 0 void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; a 6 3 8 5 9 2 1 min x i j a 6 3 8 5 9 2 1 a[min] min 0 x i 0 j

Percorremos então os elementos entre i+1 e n-1 atualizando a posição do menor elemento. Descobrimos que o menor elemento está em a[6]. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; Trocamos então os elementos da posição a[0] e a[6]. Precisamos da variável auxiliar x para fazer a troca. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; a 6 3 8 5 9 2 1 min 6 i 0 a 1 3 8 5 9 2 6 min 6 i 0 a[min] x j 7 a[min] x 1 j 7 Ao fim do primeiro passo, procuramos então o menor elemento entre a[0] e a[n-1] e colocamos no lugar de a[0]. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; Atualizamos i para 1 e fazemos mais um passo. Sabemos que o vetor até já está ordenado. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; a 1 3 8 5 9 2 6 min 6 i 0 a 1 3 8 5 9 2 6 min 6 i 1 a[min] x 1 j 7 a[min] x 1 j 7

Esta iteração procura o menor elemento entre e a[n-1]. Este elemento a[min] é trocado com. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; a 1 3 8 5 9 2 6 min 5 i 1 a 1 2 8 5 9 3 6 min 5 i 1 a[min] x 1 j 7 a[min] x 2 j 7 Atualizamos novamente i para 2 e sabemos agora que o arranjo até já está ordenado. Achamos o menor entre e a[n-1]. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; a 1 2 8 5 9 3 6 min 5 i 2 a 1 2 8 5 9 3 6 min 5 i 2 a[min] x 2 j 7 a[min] x 2 j 7

Trocamos com a[min]. Incrementamos i. Sabemos que o arranjo está ordenado até a posição. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; a 1 2 3 5 9 8 6 min 5 i 2 a 1 2 3 5 9 8 6 min 5 i 3 a[min] x 3 j 7 a[min] x 3 j 7 Encontramos o menor elemento entre e a[n-1]. Trocamos o elemento com o elemento a[min]. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; a 1 2 3 5 9 8 6 min 3 i 3 a 1 2 3 5 9 8 6 min 3 i 3 a[min] x 3 j 7 a[min] x 5 j 7

Na próxima iteração, colocamos o menor em a[4]. Na última iteração, colocamos o menor em a[5]. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; a 1 2 3 5 6 8 9 min 6 i 4 a 1 2 3 5 6 8 9 min 5 i 5 a[min] x 6 j 7 a[min] x 8 j 7 Veja que não precisamos de uma iteração para o último elemento. Se há apenas um elemento, sabemos que ele seria o menor. void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; Assim, terminamos a função com todos os elementos do arranjo a ordenados void selecaoint a[], int n) int i, j, min; // índices // para cada posição for i = 0; i < n - 1; i++) // procuramos o menor entre i+1 e n e colocamos em i min = i; //mínimo é o i for j = i + 1; j < n; j++) if < a[min]) min = j; //mínimo é o j // troca com a[min] x = a[min]; a[min] = ; = x; a 1 2 3 5 6 8 9 min 5 i 5 a 1 2 3 5 6 8 9 min 5 i 5 a[min] x 8 j 7 a[min] x 8 j 7

Análise No laço interno, sempre que procuramos o menor elemento entre i e n, fazemos n-i comparações No laço mais externo, estas n-i comparações são feitas n-1 vezes Somatório: nx 1 n i=1 i = n2 2 = On2 ) Assim, no total, o algoritmo faz On 2 ) comparações Análise Em relação ao número de atribuições, cada troca envolve 3 atribuições. Como são feitas n-1 trocas, temos 3n-1) = On) atribuições de movimentação. Além destas, temos a atualização da posição do menor Esta ocorre em média n log n vezes Com estas, o custo total de atribuições é On log n) Análise - Vantagens Em relação ao custo de movimentação, temos um custo linear On) É então um bom algoritmo onde estas movimentações por algum motivo custem muito O algoritmo é interessante para arranjos pequenos Análise - Desvantagens Se o arranjo já estiver ordenado, isto não ajuda o algoritmo, pois o custo de comparações continua On 2 ) Dizemos que o método não é adaptável. O algoritmo não é estável pois a troca entre elementos pode destruir a ordem relativa destes

de perda de estabilidade Suponha um passo onde trocaremos o elemento 6) com o elemento 1). de perda de estabilidade Ao fazer esta troca, o elemento 6) perde sua ordem relativa entre qualquer elemento entre a[i+1] e a[j-1]. a 6 3 8 6 9 2 1 a 1 3 8 6 9 2 6 Neste caso, o elemento perdeu sua ordem relativa com o elemento a[3], que tem o mesmo valor. Ordenação por Inserção Este é o algoritmo preferido dos jogadores de cartas É um algoritmo onde a cada passo de repetição: Temos um arranjo ordenado até um certo ponto Pegamos o próximo elemento Colocamos este elemento na posição correta entre o primeiro e ele mesmo Considere um arranjo com os seguintes elementos

Ordenado Desordenado Sabemos que o arranjo até o segundo elemento já está ordenado pois um arranjo de apenas um elemento está sempre ordenado. Colocamos então o próximo elemento na posição correta do arranjo ordenado. Sabemos agora então que os dois primeiros elementos estão ordenados. O próximo elemento deverá ser colocado em sua posição correta.

Sabemos agora que os três primeiros elementos estão ordenados. O próximo elemento deverá ser colocado em sua posição correta. Sabemos agora que os quatro primeiros elementos estão ordenados. O próximo elemento deverá ser colocado em sua posição correta.

Sabemos agora que os cinco primeiros elementos estão ordenados. O próximo elemento deverá ser colocado em sua posição correta. Ordenação por Inserção Arranjo 7 5 4 6 9 8 Passo 1 7 5 4 6 9 8 Passo 2 5 7 4 6 9 8 Passo 3 4 5 7 6 9 8 Passo 4 4 5 6 7 9 8 Passo 5 4 5 6 7 9 8 Arranjo 4 5 6 7 8 9 Sabemos agora que todos os elementos estão ordenados. Movimentação Desordenado Ordenado

Ordenação por inserção para um arranjo de inteiros A função ordena o arranjo a, que contém n elementos void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 6 3 8 5 9 2 1 Como sabemos que arranjos são passados por referência em C++, não precisamos retornar nada desta função. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; Os índices i e j são utilizados para percorrermos o arranjo em um for aninhado e colocar cada elemento em sua posição no arranjo ordenado. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 6 3 8 5 9 2 1 a 6 3 8 5 9 2 1 i j

A variável x deve ser do mesmo tipo dos elementos do arranjo pois será uma variável temporária para fazer as trocas entre elementos. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; Entramos em um for que, para cada posição i do arranjo, colocará o elemento em seu lugar correto do arranjo ordenado de a[0] até a[i-1] void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 6 3 8 5 9 2 1 x i a 6 3 8 5 9 2 1 x i j j Inicialmente, quando i é 1, sabemos que o arranjo até a[0] já está ordenado. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; A variável x recebe um cópia do elemento. Esta cópia será colocada em sua posição correta no arranjo ordenado. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 6 3 8 5 9 2 1 a 6 3 8 5 9 2 1 x i 1 x 3 i 1 j j

O índice j, recebe i-1. É a partir de a[i-1] que procuraremos a posição correta de. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; No while aninhado, deslocamos os elementos anteriores a. Isso até encontrarmos a posição de x ou até que todos os elementos tenham sido deslocados. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 6 3 8 5 9 2 1 a 6 3 8 5 9 2 1 x 3 i 1 x 3 i 1 j 0 j 0 Na primeira iteração temos que a[0] é deslocado. O valor de ainda está salvo em x. Saímos deste loop pois todos os elementos foram deslocados. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 6 6 8 5 9 2 1 a 6 6 8 5 9 2 1 x 3 i 1 x 3 i 1 j -1 j -1

O elemento x, que saiu de, é então inserido em sua posição correta a[j+1]. Incrementamos i para 2, e sabemos agora que o arranjo até a[1] já está ordenado. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 3 6 8 5 9 2 1 a 3 6 8 5 9 2 1 x 3 i 1 x 3 i 2 j -1 j -1 Repetindo o processo, x guarda uma cópia do elemento em questão A partir de a[i-1] agora ) procuraremos a posição correta para o elemento. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 3 6 8 5 9 2 1 a 3 6 8 5 9 2 1 x 8 i 2 x 8 i 2 j -1 j 1

Como o elemento guardado x não é menor que o elemento, já achamos a posição correta para ele. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; O elemento x é colocado na posição a[j+1], que já era sua posição original. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 3 6 8 5 9 2 1 a 3 6 8 5 9 2 1 x 8 i 2 x 8 i 2 j 1 j 1 Sabemos que o vetor até a[2] está ordenado e incrementamos i para 3 A variável x recebe uma cópia de void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 3 6 8 5 9 2 1 a 3 6 8 5 9 2 1 x 8 i 3 x 5 i 3 j 1 j 1

O índice j marca que procuraremos a posição a partir de a[i-1] Enquanto não achamos a posição do elemento ou não deslocamos todos os elementos void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 3 6 8 5 9 2 1 a 3 6 8 5 9 2 1 x 5 i 3 x 5 i 3 j 2 j 2 Deslocamos o elemento em uma posição Decrementamos j para testar o próximo elemento void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 3 6 8 8 9 2 1 a 3 6 8 8 9 2 1 x 5 i 3 x 5 i 3 j 2 j 1

Ainda não achamos a posição correta de x nem deslocamos todos os elementos. Deslocamos o elemento em uma posição. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 3 6 8 8 9 2 1 a 3 6 6 8 9 2 1 x 5 i 3 x 5 i 3 j 1 j 1 Decrementamos j para testar a próxima posição. Como o elemento x não é menor que, encontramos sua posição correta. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 3 6 6 8 9 2 1 a 3 6 6 8 9 2 1 x 5 i 3 x 5 i 3 j 0 j 0

O elemento guardado em x é então colocado em sua posição correta. Sabemos que o arranjo está ordenado até a[3] e incrementamos i para 4. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 3 5 6 8 9 2 1 a 3 5 6 8 9 2 1 x 5 i 3 x 5 i 4 j 0 j 0 Como vimos neste trecho de código, elementos maiores que serão deslocados no arranjo ordenado e será inserido em sua posição correta. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; Sabemos que o arranjo está ordenado até a[4] e incrementamos i para 5. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 3 5 6 8 9 2 1 a 3 5 6 8 9 2 1 x 9 i 4 x 9 i 5 j 3 j 3

Elementos maiores que serão deslocados no arranjo ordenado e será inserido em sua posição correta. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; Sabemos que o arranjo está ordenado até a[5] e incrementamos i para 6. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 2 3 5 6 8 9 1 a 2 3 5 6 8 9 1 x 2 i 5 x 2 i 6 j -1 j -1 Elementos maiores que serão deslocados no arranjo ordenado e será inserido em sua posição correta. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; Sabemos agora que todo o arranjo está ordenado e o critério de parada é então atingido quando i chega a 7, encerrando a função. void insercaoint a[], int n) int i, j; // Índices // para cada posição a partir de i = 1 for i = 1; i < n; i++) // coloca o elemento na posição correta entre 0 e i - 1 x = ; j = i - 1; while x < && j >= 0) a[j+1] = ; j--; a[j+1] = x; a 1 2 3 5 6 8 9 a 1 2 3 5 6 8 9 x 1 i 6 x 1 i 7 j -1 j -1

Análise Há duas condições que podem terminar o laço mais interno do algoritmo: A posição do elemento já ter sido encontrada Todas as posições já terem sido testadas Análise Em relação aos casos possíveis para o laço interno, temos: Melhor caso: quando é feita apenas uma comparação pois o elemento já está sempre na posição correta O1) Pior caso: i comparações são feitas até testarmos todas as posições i = Oi) Caso médio - probabilidade 1/i em cada caso: 1 ix i 1 + 2 + 3 + i) =1 j = i +1 = Oi) i 2 j=1 Análise Como temos n-1 iterações do laço mais externo, temos: Melhor caso 1+1+ +1= Pior caso 2+3+ + n = Caso médio 3+4+5...n+1 2 = nx i=2 nx i=2 nx 1=n 1=On) i=2 i = n + n2 2 2 i +1 2 = 3n + n2 4 4 = On 2 ) = On 2 ) Análise No algoritmo de ordenação por inserção, o número de movimentações é proporcional ao número de comparações. Isso porque os elementos são movimentados até que uma comparação indique que a posição correta foi encontrada

Análise Assim, em relação ao número de movimentações, temos também: Melhor caso: On) Pior caso: On 2 ) Caso médio: On 2 ) Análise - Vantagens O algoritmo tem um melhor caso que ocorre quando os elementos já estão ordenados Uma ordenação prévia é aproveitada pelo algoritmo. Dizemos que o método é adaptável. É um bom método para se adicionar alguns poucos elementos a um arranjo ordenado, pois terá um custo baixo em um arranjo "quase ordenado" Este algoritmo de ordenação é estável, pois a ordem relativa dos elementos é mantida no deslocamento dos elementos. Análise - Desvantagens Apesar de pouco provável na maior parte das aplicações práticas, o custo máximo do algoritmo ocorre quando os elementos estão em ordem reversa Se o número de movimentações é o fator mais relevante, ele se torna ineficiente em relação à ordenação por seleção Seleção X Inserção Algoritmo Seleção Inserção Pior caso On 2 ) On 2 ) Melhor caso On 2 ) On) Caso médio On 2 ) On 2 ) Estabilidade Não Sim Adaptabilidade Não Sim Movimentações On) Mesmo que comparações

Testes reais Como os dois algoritmos são On 2 ) no caso médio, podemos fazer comparações reais de tempo para ver a performance em segundos dos algoritmos. Para as comparações apresentadas a seguir, foram utilizadas versões mais eficientes dos algoritmos. Tempo segundos) 2 1 x 10 4 Seleção Inserção Testes reais Arranjos em ordem inicial aleatória 0 0 100 200 300 400 500 600 700 Tamanho do arranjo Tempo segundos) 5 4.5 4 3.5 3 2.5 2 1.5 1 0.5 Seleção Inserção 0 0 1 2 3 4 5 6 7 8 9 10 Tamanho do arranjo x 10 4 Testes reais Em proporção, a seleção chega a ser quase 18 vezes mais lenta que a inserção. Testes reais Arranjos em ordem inicial decrescente pior caso da inserção) 6 Seleção Inserção 18 16 Seleção Inserção x 10 4 Seleção Inserção 4.5 4 Seleção Inserção Tempo em proporção à ordenação por seleção) 5 4 3 2 Tempo em proporção à ordenação por seleção) 14 12 10 8 6 4 Tempo segundos) 2 1 Tempo segundos) 3.5 3 2.5 2 1.5 1 1 2 0.5 0 0 100 200 300 400 500 600 700 Tamanho do arranjo 0 0 1 2 3 4 5 6 7 8 9 10 Tamanho do arranjo x 10 4 0 0 100 200 300 400 500 600 700 Tamanho do arranjo 0 0 1 2 3 4 5 6 7 8 9 10 Tamanho do arranjo x 10 4

Testes reais Em proporção, a seleção chega a ser quase 9 vezes mais lenta que a inserção, mesmo em seu pior caso. Testes reais Arranjos em ordem inicial crescente melhor caso da inserção) 8 7 Seleção Inserção 9 8 Seleção Inserção x 10 4 Seleção Inserção 5 4.5 Seleção Inserção Tempo em proporção à ordenação por seleção) 6 5 4 3 2 Tempo em proporção à ordenação por seleção) 7 6 5 4 3 2 Tempo segundos) 2 1 Tempo segundos) 4 3.5 3 2.5 2 1.5 1 1 1 0.5 0 0 100 200 300 400 500 600 700 Tamanho do arranjo 0 0 1 2 3 4 5 6 7 8 9 10 Tamanho do arranjo x 10 4 0 0 100 200 300 400 500 600 700 Tamanho do arranjo 0 0 1 2 3 4 5 6 7 8 9 10 Tamanho do arranjo x 10 4 Testes reais Em proporção, a seleção chega a ser quase 2500 vezes mais lenta que a inserção, em seu melhor caso. Testes reais Como o melhor caso da inserção é On), em comparação a On 2 ) seleção, isto era esperado. 30 Seleção Inserção 2500 Seleção Inserção 30 Seleção Inserção 2500 Seleção Inserção Tempo em proporção à ordenação por seleção) 25 20 15 10 5 Tempo em proporção à ordenação por seleção) 2000 1500 1000 500 Tempo em proporção à ordenação por seleção) 25 20 15 10 5 Tempo em proporção à ordenação por seleção) 2000 1500 1000 500 0 0 100 200 300 400 500 600 700 Tamanho do arranjo 0 0 1 2 3 4 5 6 7 8 9 10 Tamanho do arranjo x 10 4 0 0 100 200 300 400 500 600 700 Tamanho do arranjo 0 0 1 2 3 4 5 6 7 8 9 10 Tamanho do arranjo x 10 4

Exercício Criar um arranjo com 10 elementos aleatórios entre 1 e 50 Desenhar o arranjo várias vezes demonstrando os passos de uma ordenação por: Seleção Inserção Colocar um círculo nos elementos movimentados. Colocar um traço entre os elementos ordenados e os desordenados. Ordenação por Seleção Arranjo 7 5 4 6 9 8 Passo 1 4 5 7 6 9 8 Passo 2 4 5 7 6 9 8 Passo 3 4 5 6 7 9 8 Passo 4 4 5 6 7 9 8 Passo 5 4 5 6 7 8 9 Arranjo 4 5 6 7 8 9 Troca Desordenado Ordenado Ordenação por Inserção Arranjo 7 5 4 6 9 8 Passo 1 7 5 4 6 9 8 Passo 2 5 7 4 6 9 8 Passo 3 4 5 7 6 9 8 Passo 4 4 5 6 7 9 8 Passo 5 4 5 6 7 9 8 Arranjo 4 5 6 7 8 9 Movimentação Desordenado Ordenado Merge sort O merge sort ordenação por intercalação) é um método que utiliza uma técnica de dividir para conquistar É um algoritmo onde a cada passo: Divide o arranjo em 2 arranjos menores até que tenhamos vários arranjos de tamanho 1 Então, iniciamos uma repetição onde: 2 arranjos são fundidos em um arranjo maior ordenado até que tenhamos o arranjo original ordenado

Considere um arranjo com os seguintes elementos Já inicialmente, temos um arranjo de 8 elementos Dividimos este arranjo em dois arranjos com a metade do tamanho Redividimos cada arranjo na metade

Este processo continua até que tenhamos arranjos de 1 elemento cada Sabemos que cada um destes arranjos de 1 elemento é um arranjo ordenado. Iniciaremos agora a fase de intercalação. Os dois primeiros arranjos ordenados são intercalados em um novo arranjo ordenado. Fazemos isto com todos os arranjos menores.

Fazemos isto com todos os arranjos menores. Fazemos isto com todos os arranjos menores. O interessante é que o custo de se intercalar dois arranjos ordenados em um arranjo ordenado é menor que o custo de se colocar dois arranjos desordenados em um arranjo ordenado Fazemos a intercalação para os arranjos de tamanho 2

Fazemos a intercalação para os arranjos de tamanho 2 Na última intercalação, temos todo o arranjo original ordenado 7 5 3 4 6 2 9 8 7 5 3 4 6 2 9 8 7 5 3 4 6 2 9 8 7 5 3 4 6 2 9 8 Esta é a etapa de conquista. Temos como resultado o arranjo original ordenado. 7 5 3 4 6 2 9 8 7 5 3 4 6 2 9 8 7 5 3 4 6 2 9 8 7 5 3 4 6 2 9 8 Esta é a etapa de divisão. Temos como resultado n arranjos ordenados de tamanho 1. 5 7 3 4 2 6 8 9 3 4 5 7 2 6 8 9 2 3 4 5 6 7 8 9 Desordenado Ordenado Desordenado Ordenado

Divisão 7 5 3 4 6 2 9 8 7 5 3 4 6 2 9 8 7 5 3 4 6 2 9 8 Etapa de intercalação Intercalação 7 5 3 4 6 2 9 8 5 7 3 4 2 6 8 9 3 4 5 7 2 6 8 9 2 3 4 5 6 7 8 9 Desordenado Ordenado 5 7 3 4 3 4 5 7 Para a implementação de maneira mais usual, a etapa de intercalação de dois arranjos requer um arranjo auxiliar, onde serão colocados os itens. Etapa de intercalação Etapa de intercalação 5 7 3 4 5 7 3 4 3 4 5 7 3 4 5 7 3 4 5 7 3 4 5 7 Os elementos são intercalados em um arranjo auxiliar e então são transferidos de volta para o arranjo de onde vieram: o arranjo sendo ordenado. Assim, para intercalar n elementos, precisamos de uma memória extra On)

O algoritmo de intercalação é organizado em algumas etapas Primeiramente, um arranjo temporário é criado e os índices são inicializados void intercalaint a[], int n) int *tmp = new int[n]; // Arranjo temporário para intercalação int meio = n / 2; // Índice que marca o meio do arranjo int i, j, k; // Índices para a estrutura de repetição i = 0; // Índice i marca itens intercalados do primeiro arranjo j = meio; // Índice j marca itens intercalados do segundo arranjo k = 0; // Índice k marca itens já intercalados no arranjo temporário // Enquanto os índices i e j não tenham chegado ao fim de seus arranjos while i < meio && j < n) // colocamos o menor item entre e no arranjo temporário if < ) tmp[k] = ; else tmp[k] = ; // se o índice i chegou ao fim de seu arranjo primeiro if i == meio) // os outros elementos do segundo arranjo vão para o arranjo temporário while j < n) tmp[k] = ; // se foi o índice j que chegou ao fim de seu arranjo primeiro else // os outros elementos do primeiro arranjo vão para o arranjo temporário void intercalaint a[], int n) int *tmp = new int[n]; // Arranjo temporário para intercalação int meio = n / 2; // Índice que marca o meio do arranjo int i, j, k; // Índices para a estrutura de repetição i = 0; // Índice i marca itens intercalados do primeiro arranjo j = meio; // Índice j marca itens intercalados do segundo arranjo k = 0; // Índice k marca itens já intercalados no arranjo temporário // Enquanto os índices i e j não tenham chegado ao fim de seus arranjos while i < meio && j < n) // colocamos o menor item entre e no arranjo temporário if < ) tmp[k] = ; else tmp[k] = ; // se o índice i chegou ao fim de seu arranjo primeiro if i == meio) // os outros elementos do segundo arranjo vão para o arranjo temporário while j < n) tmp[k] = ; // se foi o índice j que chegou ao fim de seu arranjo primeiro else // os outros elementos do primeiro arranjo vão para o arranjo temporário void intercalaint a[], int n) int *tmp = new int[n]; // Arranjo temporário para intercalação int meio = n / 2; // Índice que marca o meio do arranjo int i, j, k; // Índices para a estrutura de repetição i = 0; // Índice arranjo i marca itens intercalados temporário do primeiro arranjo j = meio; // Índice j marca itens intercalados do segundo arranjo k = 0; // Índice k marca itens já intercalados no arranjo temporário // Enquanto os índices i e j não tenham chegado ao fim de seus arranjos while i < meio && j < n) // colocamos o menor item entre e no arranjo temporário if < ) tmp[k] = ; else tmp[k] = ; // se o índice i chegou ao fim de seu arranjo primeiro if i == meio) // os outros elementos do segundo arranjo vão para o arranjo temporário while j < n) tmp[k] = ; // se foi o índice j que chegou ao fim de seu arranjo primeiro else // os outros elementos do primeiro arranjo vão para o arranjo temporário while i < meio) tmp[k] = ; // neste ponto, o arranjo temporário tem todos os elementos intercalados // estes elementos são copiados de volta para o arranjo int a[] Logo após, os elementos de a são intercalados neste // colocamos o menor item entre e no arranjo temporário if < ) tmp[k] = ; else tmp[k] = ; // se o índice i chegou ao fim de seu arranjo primeiro if i == meio) // os outros elementos do segundo arranjo vão para o arranjo temporário while j < n) tmp[k] = ; // se foi o índice j que chegou ao fim de seu arranjo primeiro else // os outros elementos do primeiro arranjo vão para o arranjo temporário while i < meio) tmp[k] = ; // neste ponto, o arranjo temporário tem todos os elementos intercalados // estes elementos são copiados de volta para o arranjo int a[] for i = 0; i < n; ++i) = tmp[i]; // o arranjo temporário pode então ser desalocado da memória delete [] tmp; Então, os elementos intercalados no arranjo temporário são transferidos de volta para o arranjo a

void intercalaint a[], int n) int *tmp = new int[n]; // Arranjo temporário para intercalação int meio = n / 2; // Índice que marca o meio do arranjo int i, j, k; // Índices para a estrutura de repetição i = 0; // Índice i marca itens intercalados do primeiro arranjo j = meio; // Índice j marca itens intercalados do segundo arranjo k = 0; // Índice k marca itens já intercalados no arranjo temporário // Enquanto os índices i e j não tenham chegado ao fim de seus arranjos while i < meio && j < n) // colocamos o menor item entre e no arranjo temporário if < ) tmp[k] = ; else tmp[k] = ; A função intercalará os elementos de a[] // se o índice i chegou ao fim de seu arranjo primeiro if i == meio) // os outros elementos do segundo arranjo vão para o arranjo temporário while j < n) tmp[k] = ; // se foi o índice j que chegou ao fim de seu arranjo primeiro else // os outros elementos do primeiro arranjo vão para o arranjo temporário a 3 4 5 7 2 6 8 9 while i < meio) tmp[k] = ; // neste ponto, o arranjo temporário tem todos os elementos intercalados // estes elementos são copiados de volta para o arranjo int a[] n 8 void intercalaint a[], int n) int *tmp = new int[n]; // Arranjo temporário para intercalação int meio = n / 2; // Índice que marca o meio do arranjo int i, j, k; // Índices para a estrutura de repetição i = 0; // Índice i marca itens intercalados do primeiro arranjo j = meio; // Índice j marca itens intercalados do segundo arranjo k = 0; // Índice k marca itens já intercalados no arranjo temporário // Enquanto os índices i e j não tenham chegado ao fim de seus arranjos while i < meio && j < n) // colocamos o menor item entre e no arranjo temporário if < ) tmp[k] = ; else tmp[k] = ; Os elementos de a[0] até a[3] serão intercalados com os elementos de a[4] a a[7] // se o índice i chegou ao fim de seu arranjo primeiro if i == meio) // os outros elementos do segundo arranjo vão para o arranjo temporário while j < n) tmp[k] = ; // se foi o índice j que chegou ao fim de seu arranjo primeiro else // os outros elementos do primeiro arranjo vão para o arranjo temporário a 3 4 5 7 2 6 8 9 while i < meio) tmp[k] = ; // neste ponto, o arranjo temporário tem todos os elementos intercalados // estes elementos são copiados de volta para o arranjo int a[] n 8 void intercalaint a[], int n) int *tmp = new int[n]; // Arranjo temporário para intercalação int meio = n / 2; // Índice que marca o meio do arranjo int i, j, k; // Índices para a estrutura de repetição i = 0; // Índice i marca itens intercalados do primeiro arranjo j = meio; // Índice j marca itens intercalados do segundo arranjo k = 0; // Índice k marca itens já intercalados no arranjo temporário // Enquanto os índices i e j não tenham chegado ao fim de seus arranjos while i < meio && j < n) // colocamos o menor item entre e no arranjo temporário if < ) tmp[k] = ; else tmp[k] = ; Um arranjo temporário é criado para guardar os elementos intercalados // se o índice i chegou ao fim de seu arranjo primeiro if i == meio) // os outros elementos do segundo arranjo vão para o arranjo temporário while j < n) tmp[k] = ; a 3 4 5 7 2 6 8 9 0 1 2 3 4 5 6 7 // se foi o índice j que chegou ao fim de seu arranjo primeiro else // os outros elementos do primeiro arranjo vão para o arranjo temporário while tmpi < meio) tmp[k] = ; 0 1 2 3 4 5 6 7 // neste ponto, o arranjo temporário tem todos os elementos intercalados // estes elementos são copiados de volta para o arranjo int a[] n 8 void intercalaint a[], int n) int *tmp = new int[n]; // Arranjo temporário para intercalação int meio = n / 2; // Índice que marca o meio do arranjo int i, j, k; // Índices para a estrutura de repetição i = 0; // Índice i marca itens intercalados do primeiro arranjo j = meio; // Índice j marca itens intercalados do segundo arranjo k = 0; // Índice k marca itens já intercalados no arranjo temporário // Enquanto os índices i e j não tenham chegado ao fim de seus arranjos while i < meio && j < n) // colocamos o menor item entre e no arranjo temporário if < ) tmp[k] = ; else tmp[k] = ; Um índice meio marca onde está a metade do arranjo. Ou onde começa o segundo arranjo a ser intercalado. // se o índice i chegou ao fim de seu arranjo primeiro if i == meio) // os outros elementos do segundo arranjo vão para o arranjo temporário while j < n) tmp[k] = ; a 3 0 4 1 5 2 7 3 2 4 6 5 8 6 9 7 // se foi o índice j que chegou ao fim de seu arranjo primeiro else a[meio] // os outros elementos do primeiro arranjo vão para o arranjo temporário while tmpi < meio) tmp[k] = ; 0 1 2 3 4 5 6 7 // neste ponto, o arranjo temporário tem todos os elementos intercalados // estes elementos são copiados de volta para o arranjo int a[] n 8 meio 4

void intercalaint a[], int n) int *tmp = new int[n]; // Arranjo temporário para intercalação int meio = n / 2; // Índice que marca o meio do arranjo int i, j, k; // Índices para a estrutura de repetição i = 0; // Índice i marca itens intercalados do primeiro arranjo j = meio; // Índice j marca itens intercalados do segundo arranjo k = 0; // Índice k marca itens já intercalados no arranjo temporário // Enquanto os índices i e j não tenham chegado ao fim de seus arranjos while i < meio && j < n) // colocamos o menor item entre e no arranjo temporário if < ) tmp[k] = ; else tmp[k] = ; Índices i, j e k marcam onde intercalaremos no primeiro, segundo arranjo e no arranjo temporário // se o índice i chegou ao fim de seu arranjo primeiro if i == meio) // os outros elementos do segundo arranjo vão para o arranjo temporário while j < n) tmp[k] = ; a 3 0 4 1 5 2 7 3 2 4 6 5 8 6 9 7 i 0 // se foi o índice j que chegou ao fim de seu arranjo primeiro else a[meio] j 4 // os outros elementos do primeiro arranjo vão para o arranjo temporário while tmpi < meio) tmp[k] = ; 0 1 2 3 4 5 6 7 k 0 tmp[k] // neste ponto, o arranjo temporário tem todos os elementos intercalados // estes elementos são copiados de volta para o arranjo int a[] n 8 meio 4 int meio = n / 2; // Índice que marca o meio do arranjo int i, j, k; // Índices para a estrutura de repetição i = 0; // Índice i marca itens intercalados do primeiro arranjo j = meio; // Índice j marca itens intercalados do segundo arranjo k = 0; // Índice k marca itens já intercalados no arranjo temporário // Enquanto os índices i e j não tenham chegado ao fim de seus arranjos while i < meio && j < n) // colocamos o menor item entre e no arranjo temporário if < ) tmp[k] = ; else tmp[k] = ; Se i é menor que meio e j é menor que n, não atingimos o fim de nenhum arranjo sendo intercalados // se o índice i chegou ao fim de seu arranjo primeiro if i == meio) // os outros elementos do segundo arranjo vão para o arranjo temporário while j < n) tmp[k] = ; // se foi o índice j que chegou ao fim de seu arranjo primeiro else a // os outros 3 elementos 4 5 do 7primeiro 2 arranjo 6 8 vão 9para o arranjo i temporário 0 while i < meio) tmp[k] 0 = ; 1 2 3 4 5 6 7 n 8 a[meio] a[n] j 4 tmp // neste ponto, o arranjo temporário tem todos os elementos intercalados meio 4 // estes elementos são copiados de volta para o arranjo int a[] 0 1 2 3 4 5 6 7 for i = 0; i < n; ++i) k 0 = tmp[k] tmp[i]; // o arranjo temporário pode então ser desalocado da memória int meio = n / 2; // Índice que marca o meio do arranjo int i, j, k; // Índices para a estrutura de repetição i = 0; // Índice i marca itens intercalados do primeiro arranjo j = meio; // Índice j marca itens intercalados do segundo arranjo k = 0; // Índice k marca itens já intercalados no arranjo temporário // Enquanto os índices i e j não tenham chegado ao fim de seus arranjos while i < meio && j < n) // colocamos o menor item entre e no arranjo temporário if < ) tmp[k] = ; else tmp[k] = ; Como não atingimos o final de um dos arranjos, comparamos com // se o índice i chegou ao fim de seu arranjo primeiro if i == meio) // os outros elementos do segundo arranjo vão para o arranjo temporário while j < n) tmp[k] = ; // se foi o índice j que chegou ao fim de seu arranjo primeiro else a // os outros 3 elementos 4 5 do 7primeiro 2 arranjo 6 8 vão 9para o arranjo i temporário 0 while i < meio) tmp[k] 0 = ; 1 2 3 4 5 6 7 n 8 a[meio] a[n] j 4 tmp // neste ponto, o arranjo temporário tem todos os elementos intercalados meio 4 // estes elementos são copiados de volta para o arranjo int a[] 0 1 2 3 4 5 6 7 for i = 0; i < n; ++i) k 0 = tmp[k] tmp[i]; // o arranjo temporário pode então ser desalocado da memória int meio = n / 2; // Índice que marca o meio do arranjo int i, j, k; // Índices para a estrutura de repetição i = 0; // Índice i marca itens intercalados do primeiro arranjo j = meio; // Índice j marca itens intercalados do segundo arranjo k = 0; // Índice k marca itens já intercalados no arranjo temporário // Enquanto os índices i e j não tenham chegado ao fim de seus arranjos while i < meio && j < n) // colocamos o menor item entre e no arranjo temporário if < ) tmp[k] = ; else tmp[k] = ; O menor é colocado no arranjo temporário // se o índice i chegou ao fim de seu arranjo primeiro if i == meio) // os outros elementos do segundo arranjo vão para o arranjo temporário while j < n) tmp[k] = ; // se foi o índice j que chegou ao fim de seu arranjo primeiro else a // os outros 3 elementos 4 5 do 7primeiro 2 arranjo 6 8 vão 9para o arranjo i temporário 0 while i < meio) tmp[k] 0 = ; 1 2 3 4 5 6 7 a[meio] a[n] j 4 tmp 2 // neste ponto, o arranjo temporário tem todos os elementos intercalados // estes elementos são copiados de volta para o arranjo int a[] 0 1 2 3 4 5 6 7 for i = 0; i < n; ++i) k 0 = tmp[k] tmp[i]; // o arranjo temporário pode então ser desalocado da memória n 8 meio 4