30
SOCIEDADE EDUCACIONAL DE SANTA CATARINA INSTITUTO SUPERIOR TUPY ENGENHARIA DE COMPUTAÇÃO RELATÓRIO DE DESENVOLVIMENTO DE ALGORITMOS DE ORDENAÇÃO EM C#.NET Aluno: Lorival Smolski Chapuis Turma: ECP-341 Professor: Glauco Vinicius Scheffel Joinville, 9 de abril de 2011

Algoritmos de ordenação

Embed Size (px)

DESCRIPTION

Relatório sobre o desenvolvimento dos seguintes algoritmos de ordenação:

Citation preview

Page 1: Algoritmos de ordenação

SOCIEDADE EDUCACIONAL DE SANTA CATARINA

INSTITUTO SUPERIOR TUPY

ENGENHARIA DE COMPUTAÇÃO

RELATÓRIO DE DESENVOLVIMENTO

DE ALGORITMOS DE ORDENAÇÃO EM C#.NET

Aluno: Lorival Smolski Chapuis

Turma: ECP-341

Professor: Glauco Vinicius Scheffel

Joinville, 9 de abril de 2011

Page 2: Algoritmos de ordenação

Sumário

1. Introdução ............................................................................................................................. 3

2. Ferramentas e métodos utilizados ........................................................................................ 4

3. Algoritmos de ordenação ...................................................................................................... 5

3.1. BubbleSort ..................................................................................................................... 6

3.2. SelectionSort ................................................................................................................. 9

3.3. InsertionSort ................................................................................................................ 12

3.4. MergeSort ................................................................................................................... 15

3.5. QuickSort ..................................................................................................................... 21

4. Execução dos testes automatizados ................................................................................... 24

5. Estatísticas entre os algoritmos de ordenação ................................................................... 27

6. Conclusão ............................................................................................................................ 30

Page 3: Algoritmos de ordenação

1. Introdução

Este relatório tem como objetivo detalhar o desenvolvimento dos algoritmos de

ordenação bubblesort, selectionsort, insertionsort, mergesort e quicksort.

Os algoritmos foram desenvolvidos em C# utilizando a IDE Visual Studio 2010, .Net

Framework 4.0, testes automatizados e orientação a aspectos.

A solução criada possui dois projetos. Um deles é responsável por implementar os

algoritmos de ordenação e o outro responsável apenas pelos testes.

Ao apresentar cada algoritmo de ordenação, é resumido seu funcionamento e

detalhado o código fonte em C#, que aparece logo em seguida, juntamente com os

códigos dos testes automatizados.

Ao final foram feitas estatísticas de desempenho comparando os algoritmos,

descritos acima, para ver o tempo de ordenação, de cada um, em um vetor de mil

posições.

Todos os códigos fontes estão em formas de texto exceto por duas imagens, prints

dos códigos. Isto acontece, pois foi utilizado um recurso chamado “region” que

permite separar e organizar melhor o código, podendo ocultar ou exibir trechos de

códigos. Os prints foram tirados para mostrar o código desejado juntamente com os

regions “fechados”, que serão “abertos” e explicados na sequência.

Page 4: Algoritmos de ordenação

2. Ferramentas e métodos utilizados

Para o desenvolvimento dos algoritmos foi utilizado o seguinte ambiente:

Microsoft Visual Studio 2010;

Microsoft .Net Framework 4.0 com a linguagem C#;

Testes automatizados;

Orientação a aspectos;

Os testes automatizados foram de dois tipos unitários e integrados. Isto devido à

complexidade de testar alguns métodos e de o autor não querer colocar mocks para

não complicar mais os programas.

A programação orientada a aspectos – POA – é um paradigma de desenvolvimento

que possibilita implementar funcionalidades que se encontram espalhadas por toda

aplicação (crosscutting concern) de forma encapsulada e modularizada.

Dentro do .Net Framework um dos princípios do POA é chamado de extension

methods que consiste em desenvolver um algoritmo separado de seu objeto de uso e

armazená-lo junto aos demais métodos do Framework, para ser usado a qualquer

momento de qualquer lugar da solução que utilize a biblioteca em questão.

Um exemplo de extension method, seria criar um método chamado ToShortString()

para conversão de um datetime (1/12/2999 00:00:00) para uma data curta

(01/12/20999). Ao criar este método informamos que será aplicado ao tipo datetime,

logo os objetos datetime terão mais um método (ToShortString()) podendo ser usado

de qualquer parte da solução e a qualquer momento. Exemplo de uso do método

acima:

DateTime date = DateTime.Now;

String shortDate = date.ToShortString();

Se não utilizar um extension method, o modo convencional seria criar um método

que recebe-se como parâmetro um datetime e retorna-se uma string. Como é apenas

um algoritmo de conversão, poderia estar em uma classe estática chamada

DateConvertionHelper. Veja um exemplo de uso:

DateTime date = DateTime.Now;

String shortDate = DateConvertionHelper.ToShortString(date);

Usar um extension method torna muito mais simples a utilização final.

Page 5: Algoritmos de ordenação

3. Algoritmos de ordenação

Para não tornar o relatório longo e ser o mais objetivo possível, cada tópico de

algoritmo será dividido em 3 partes:

Objetivo;

Algoritmo;

Testes.

Para mais informações sobre os testes, veja o item “4. Execução dos testes

automatizados”.

Foi criada uma classe chamada SortingAlgorithms que contém os 6 algoritmos de

ordenação. O escopo desta classe está abaixo e o conteúdo dos “regions” estão

detalhados em cada algoritmo.

Page 6: Algoritmos de ordenação

3.1. BubbleSort

Objetivo: Percorrer o vetor diversas vezes e a cada passagem fazer flutuar para o final

do vetor o item de maior valor. A cada passagem é analisado a quantidade de itens do

vetor menos um, pois o último já estará ordenado.

Algoritmo:

#region BubbleSort

public static void BubbleSort(this IList<int> list)

{

int lastListPosition = list.Count - 1;

bool hasChanged = true;

while (hasChanged)

{

hasChanged = false;

for (int i = 0; i < lastListPosition; i++)

{

if (list[i] > list[i + 1])

{

var aux = list[i];

list[i] = list[i + 1];

list[i + 1] = aux;

hasChanged = true;

}

}

lastListPosition--;

}

}

#endregion

Page 7: Algoritmos de ordenação

Testes:

using System.Linq; using Lorival.Collections; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Tester { [TestClass] public class BubbleSortTestar : AbstractTester { [TestMethod] public void BubbleSortTestar_SortTwoItems() { //-- Arrange int[] expected = { 1, 2 }; int[] actual = { 2, 1 }; //-- Act actual.BubbleSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void BubbleSortTestar_SortFiveItemsNeedTwoSteps() { //-- Arrange int[] expected = { 1, 2, 3, 4, 5 }; int[] actual = { 2, 1, 4, 5, 3 }; //-- Act actual.BubbleSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void BubbleSortTestar_SortFiveItemsNeedThreeSteps() { //-- Arrange int[] expected = { 10, 12, 35, 43, 101 }; int[] actual = { 101, 35, 12, 10, 43 }; //-- Act actual.BubbleSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void BubbleSortTestar_SortTenItems() { //-- Arrange

Page 8: Algoritmos de ordenação

int[] expected = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; int[] actual = { 14, 10, 20, 12, 4, 8, 2, 16, 18, 6 }; //-- Act actual.BubbleSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void BubbleSortTestar_SortTenItemsWithRepetedValues() { //-- Arrange int[] expected = { 2, 4, 4, 8, 10, 12, 14, 16, 18, 20 }; int[] actual = { 14, 10, 20, 12, 4, 8, 2, 16, 18, 4 }; //-- Act actual.BubbleSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void BubbleSortTestar_SortOneHumdredItems() { //-- Arrange NumericListCreator numericListCreator = new NumericListCreator(100); int[] actual = numericListCreator.UnorderedList.ToArray<int>(); //-- Act actual.BubbleSort(); //-- Assert CollectionAssert.AreEqual(numericListCreator.OrderedList, actual); } } }

Page 9: Algoritmos de ordenação

3.2. SelectionSort

Objetivo: Percorrer o vetor diversas vezes e a cada passagem trazer para a primeira

posição do vetor o item de menor valor. A cada passagem é analisado a quantidade de

itens do vetor menos um, pois o primeiro já estará ordenado. A grande diferença do

selectionsort para o bubblesort é que o bubble faz varias trocas a cada passagem e a

seleção procura o menor valor e faz apenas uma troca no final da passagem.

Algoritmo:

#region SelectionSort

public static void SelectionSort(this IList<int> list)

{

int lowestValuePosition = 0;

for (int lastPosition = 0; lastPosition < list.Count; lastPosition++)

{

lowestValuePosition = lastPosition;

for (int currentPosition = lastPosition; currentPosition < list.Count; currentPosition++)

{

if (list[currentPosition] < list[lowestValuePosition])

lowestValuePosition = currentPosition;

}

if (lowestValuePosition > lastPosition)

{

var aux = list[lastPosition];

list[lastPosition] = list[lowestValuePosition];

list[lowestValuePosition] = aux;

}

}

}

#endregion

Page 10: Algoritmos de ordenação

Testes:

using System.Linq; using Lorival.Collections; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Tester { [TestClass] public class SelectionSortTester : AbstractTester { [TestMethod] public void SelectionSortTester_SortTwoItems() { //-- Arrange int[] expected = { 1, 2 }; int[] actual = { 2, 1 }; //-- Act actual.SelectionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void SelectionSortTester_SortFiveItems() { //-- Arrange int[] expected = { 1, 2, 3, 4, 5 }; int[] actual = { 2, 1, 4, 5, 3 }; //-- Act actual.SelectionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void SelectionSortTester_SortFiveItemsInOtherOrder() { //-- Arrange int[] expected = { 10, 12, 35, 43, 101 }; int[] actual = { 101, 35, 12, 10, 43 }; //-- Act actual.SelectionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void SelectionSortTester_SortTenItems() { //-- Arrange

Page 11: Algoritmos de ordenação

int[] expected = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; int[] actual = { 14, 10, 20, 12, 4, 8, 2, 16, 18, 6 }; //-- Act actual.SelectionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void SelectionSortTester_SortTenItemsWithRepetedValues() { //-- Arrange int[] expected = { 2, 4, 4, 8, 10, 12, 14, 16, 18, 20 }; int[] actual = { 14, 10, 20, 12, 4, 8, 2, 16, 18, 4 }; //-- Act actual.SelectionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void SelectionSortTester_SortOneHumdredItems() { //-- Arrange NumericListCreator numericListCreator = new NumericListCreator(100); int[] actual = numericListCreator.UnorderedList.ToArray<int>(); //-- Act actual.SelectionSort(); //-- Assert CollectionAssert.AreEqual(numericListCreator.OrderedList, actual); } } }

Page 12: Algoritmos de ordenação

3.3. InsertionSort

Objetivo: Percorrer o vetor da esquerda para a direita e à medida que avança vai

deixando os elementos mais a esquerda ordenados. A cada passagem vai abrindo

espaço para o item corrente e procurando, mais a esquerda qual é o lugar daquele

item. Ao encontrar empurra todos os itens para a direita e insere o item selecionado

no seu respectivo local.

Algoritmo:

#region InsertionSort

public static void InsertionSort(this IList<int> list)

{

int valueWillBeInserted, lastPosition;

for (int currentPosition = 1; currentPosition < list.Count; currentPosition++)

{

valueWillBeInserted = list[currentPosition];

lastPosition = currentPosition - 1;

while (lastPosition >= 0 && list[lastPosition] > valueWillBeInserted)

{

list[lastPosition + 1] = list[lastPosition];

lastPosition--;

}

list[lastPosition + 1] = valueWillBeInserted;

}

}

#endregion

Page 13: Algoritmos de ordenação

Testes:

using System.Linq; using Lorival.Collections; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Tester { [TestClass] public class InsertionSortTester : AbstractTester { [TestMethod] public void InsertionSortTester_SortTwoItems() { //-- Arrange int[] expected = { 1, 2 }; int[] actual = { 2, 1 }; //-- Act actual.InsertionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void InsertionSortTester_SortFiveItems() { //-- Arrange int[] expected = { 1, 2, 3, 4, 5 }; int[] actual = { 2, 1, 4, 5, 3 }; //-- Act actual.InsertionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void InsertionSortTester_SortFiveItemsInOtherOrder() { //-- Arrange int[] expected = { 10, 12, 35, 43, 101 }; int[] actual = { 101, 35, 12, 10, 43 }; //-- Act actual.InsertionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void InsertionSortTester_SortTenItems() { //-- Arrange

Page 14: Algoritmos de ordenação

int[] expected = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; int[] actual = { 14, 10, 20, 12, 4, 8, 2, 16, 18, 6 }; //-- Act actual.InsertionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void InsertionSortTester_SortTenItemsWithRepetedValues() { //-- Arrange int[] expected = { 2, 4, 4, 8, 10, 12, 14, 16, 18, 20 }; int[] actual = { 14, 10, 20, 12, 4, 8, 2, 16, 18, 4 }; //-- Act actual.InsertionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void InsertionSortTester_SortOneHumdredItems() { //-- Arrange NumericListCreator numericListCreator = new NumericListCreator(100); int[] actual = numericListCreator.UnorderedList.ToArray<int>(); //-- Act actual.InsertionSort(); //-- Assert CollectionAssert.AreEqual(numericListCreator.OrderedList, actual); } } }

Page 15: Algoritmos de ordenação

3.4. MergeSort

Objetivo: Criar uma sequência ordenada baseada em outras duas também ordenadas.

Para isto é necessário dividir a sequência original até chegar a um limite ordenável por

um insertionSort (100 itens neste exemplo) ou até sobrarem pares para ordenar.

Depois vai agrupando todas as sequências divididas até formar a sequência ordenada.

Modo com InsertionSort e sem InsertionSort

Foi desenvolvido dois métodos de chamada. Um para mergeSort com

InsertionSort e outro sem InsertionSort. Ambos utilizam o mesmo algoritmo para

ordenação com a diferença de um parâmetro que informa se irá usar o algoritmo

InsertionSort quando chegar nos 100 itens ou não.

Page 16: Algoritmos de ordenação

Algoritmo:

#region Private Methods private static IList<int> ExecuteMergeSort(IList<int> list, bool sortWithInsertionSort) { if (sortWithInsertionSort) { if (list.Count <= 100) { list.InsertionSort(); return list; } } else if (list.Count <= 1) return list; int midlePosition = list.Count / 2; IList<int> leftSide = new List<int>(); IList<int> rightSide = new List<int>(); for (int i = 0; i < midlePosition; i++) leftSide.Add(list[i]); for (int i = midlePosition; i < list.Count; i++) rightSide.Add(list[i]); return ExecuteMergeSort(ExecuteMergeSort(leftSide, sortWithInsertionSort), ExecuteMergeSort(rightSide, sortWithInsertionSort)); } private static IList<int> ExecuteMergeSort(IList<int> left, IList<int> right) { IList<int> listToBeReturned = new List<int>(); while (left.Count > 0 && right.Count > 0) if (left[0] > right[0]) { listToBeReturned.Add(right[0]); right.RemoveAt(0); } else { listToBeReturned.Add(left[0]); left.RemoveAt(0); } for (int i = 0; i < left.Count; i++) listToBeReturned.Add(left[i]); for (int i = 0; i < right.Count; i++) listToBeReturned.Add(right[i]); return listToBeReturned; } #endregion

Page 17: Algoritmos de ordenação

Testes:

using System.Linq; using Lorival.Collections; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Tester { [TestClass] public class MergeTester : AbstractTester { #region WithOutInsertionSort [TestMethod] public void MergeTester_SortTwoItems() { //-- Arrange int[] expected = { 1, 2 }; int[] actual = { 2, 1 }; //-- Act actual.MergeSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void MergeTester_SortFiveItems() { //-- Arrange int[] expected = { 1, 2, 3, 4, 5 }; int[] actual = { 2, 1, 4, 5, 3 }; //-- Act actual.MergeSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void MergeTester_SortFiveItemsInOtherOrder() { //-- Arrange int[] expected = { 10, 12, 35, 43, 101 }; int[] actual = { 101, 35, 12, 10, 43 }; //-- Act actual.MergeSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void MergeTester_SortTenItems() {

Page 18: Algoritmos de ordenação

//-- Arrange int[] expected = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; int[] actual = { 14, 10, 20, 12, 4, 8, 2, 16, 18, 6 }; //-- Act actual.MergeSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void MergeTester_SortTenItemsWithRepetedValues() { //-- Arrange int[] expected = { 2, 4, 4, 8, 10, 12, 14, 16, 18, 20 }; int[] actual = { 14, 10, 20, 12, 4, 8, 2, 16, 18, 4 }; //-- Act actual.MergeSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void MergeTester_SortOneHumdredItems() { //-- Arrange NumericListCreator numericListCreator = new NumericListCreator(100); int[] actual = numericListCreator.UnorderedList.ToArray<int>(); //-- Act actual.MergeSort(); //-- Assert CollectionAssert.AreEqual(numericListCreator.OrderedList, actual); } #endregion #region WithInsertionSort [TestMethod] public void MergeTester_SortTwoItems_WithInsertionSort() { //-- Arrange int[] expected = { 1, 2 }; int[] actual = { 2, 1 }; //-- Act actual.MergeSortWithInsertionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void MergeTester_SortFiveItems_WithInsertionSort()

Page 19: Algoritmos de ordenação

{ //-- Arrange int[] expected = { 1, 2, 3, 4, 5 }; int[] actual = { 2, 1, 4, 5, 3 }; //-- Act actual.MergeSortWithInsertionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void MergeTester_SortFiveItemsInOtherOrder_WithInsertionSort() { //-- Arrange int[] expected = { 10, 12, 35, 43, 101 }; int[] actual = { 101, 35, 12, 10, 43 }; //-- Act actual.MergeSortWithInsertionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void MergeTester_SortTenItems_WithInsertionSort() { //-- Arrange int[] expected = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; int[] actual = { 14, 10, 20, 12, 4, 8, 2, 16, 18, 6 }; //-- Act actual.MergeSortWithInsertionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void MergeTester_SortTenItemsWithRepetedValues_WithInsertionSort() { //-- Arrange int[] expected = { 2, 4, 4, 8, 10, 12, 14, 16, 18, 20 }; int[] actual = { 14, 10, 20, 12, 4, 8, 2, 16, 18, 4 }; //-- Act actual.MergeSortWithInsertionSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void MergeTester_SortOneHumdredItems_WithInsertionSort() {

Page 20: Algoritmos de ordenação

//-- Arrange NumericListCreator numericListCreator = new NumericListCreator(100); int[] actual = numericListCreator.UnorderedList.ToArray<int>(); //-- Act actual.MergeSortWithInsertionSort(); //-- Assert CollectionAssert.AreEqual(numericListCreator.OrderedList, actual); } #endregion } }

Page 21: Algoritmos de ordenação

3.5. QuickSort

Objetivo: Ordena o vetor dividindo-o recursivamente, através de um pivô, colocando

os itens menores que o pivô de um lado e maiores do outro. Ao final os itens estarão

ordenados. Este é o algoritmo mais rápido e eficiente para ordenação para vetores

grandes.

Algoritmo:

#region QuickSort public static void QuickSort(this IList<int> list) { Sort(list, 0, list.Count - 1); } #region Private Methods private static void Sort(IList<int> list, int startPosition, int endPosition) { if (startPosition < endPosition) { int pivotPosition = Partition(list, startPosition, endPosition); Sort(list, startPosition, pivotPosition - 1); Sort(list, pivotPosition + 1, endPosition); } } private static int Partition(IList<int> list, int startPosition, int endPosition) { int pivo = list[startPosition]; int startPartitionPosition = startPosition + 1, endPartitionPosition = endPosition; while (startPartitionPosition <= endPartitionPosition) { if (list[startPartitionPosition] <= pivo) startPartitionPosition++; else if (pivo < list[endPartitionPosition]) endPartitionPosition--; else { int troca = list[startPartitionPosition]; list[startPartitionPosition] = list[endPartitionPosition]; list[endPartitionPosition] = troca; startPartitionPosition++; endPartitionPosition--; } } list[startPosition] = list[endPartitionPosition]; list[endPartitionPosition] = pivo; return endPartitionPosition; } #endregion #endregion

Page 22: Algoritmos de ordenação

Testes:

using System.Linq; using Lorival.Collections; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Tester { [TestClass] public class QuickSortTester : AbstractTester { [TestMethod] public void QuickSortTester_SortTwoItems() { //-- Arrange int[] expected = { 1, 2 }; int[] actual = { 2, 1 }; //-- Act actual.QuickSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void QuickSortTester_SortFiveItems() { //-- Arrange int[] expected = { 1, 2, 3, 4, 5 }; int[] actual = { 2, 1, 4, 5, 3 }; //-- Act actual.QuickSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void QuickSortTester_SortFiveItemsInOtherOrder() { //-- Arrange int[] expected = { 10, 12, 35, 43, 101 }; int[] actual = { 101, 35, 12, 10, 43 }; //-- Act actual.QuickSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void QuickSortTester_SortTenItems() { //-- Arrange

Page 23: Algoritmos de ordenação

int[] expected = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; int[] actual = { 14, 10, 20, 12, 4, 8, 2, 16, 18, 6 }; //-- Act actual.QuickSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void QuickSortTester_SortTenItemsWithRepetedValues() { //-- Arrange int[] expected = { 2, 4, 4, 8, 10, 12, 14, 16, 18, 20 }; int[] actual = { 14, 10, 20, 12, 4, 8, 2, 16, 18, 4 }; //-- Act actual.QuickSort(); //-- Assert CollectionAssert.AreEqual(expected, actual); } [TestMethod] public void QuickSortTester_SortOneHumdredItems() { //-- Arrange NumericListCreator numericListCreator = new NumericListCreator(100); int[] actual = numericListCreator.UnorderedList.ToArray<int>(); //-- Act actual.QuickSort(); //-- Assert CollectionAssert.AreEqual(numericListCreator.OrderedList, actual); } } }

Page 24: Algoritmos de ordenação

4. Execução dos testes automatizados

Para facilitar os testes automatizados para grandes vetores foi criado uma classe chamada

NumericListCreator que tem como objetivo criar dois vetores iguais com a diferença que um

está ordenado e o outro não. Quando criamos a instância desta classe informamos o tamanho

do vetor que queremos e ela disponibiliza duas propriedades, cada uma sendo um vetor.

Para criar os dois vetores com os mesmos valores, foi utilizado um recurso do .Net

Framework. Na verdade é um objeto chamado SortedList, que nada mais é do que uma lista

que se ordena conforme vai incluindo os itens. Esta classe gera os vetores com no máximo cem

mil posições.

Veja abaixo a codificação desta classe:

using System.Collections; using System.Collections.Generic; using Lorival.Collections; using System; namespace Tester { internal class NumericListCreator { internal IList OrderedList { get; private set; } internal IList<int> UnorderedList { get; private set; } private const int limitGeneratedLists = 100000; internal NumericListCreator(int listSize) { OrderedList = new List<int>(); UnorderedList = new List<int>(); if (listSize > limitGeneratedLists) listSize = limitGeneratedLists; SortedList sortedList = new SortedList(); while(sortedList.Count < listSize) { int randowNumber = new Random().Next(limitGeneratedLists); if (!sortedList.ContainsKey(randowNumber)) { sortedList.Add(randowNumber, null); UnorderedList.Add(randowNumber); } } OrderedList = sortedList.GetKeyList(); } } }

Page 25: Algoritmos de ordenação

Todos os testes foram escritos seguindo um pouco de babysteps. Começam com

vetores de duas posições e vai aumentando até um vetor de 100 posições, gerado através do

objeto gerador de vetores já citado.

Foi criada uma classe abstrata para os testes. Esta tem como único objetivo armazenar

informações pertinentes ao framework de testes. Veja abaixo:

using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Tester { public abstract class AbstractTester { /// <summary> ///Gets or sets the test context which provides ///information about and functionality for the current test run. ///</summary> public TestContext TestContext { get;set;} #region Additional test attributes // // You can use the following additional attributes as you write your tests: // // Use ClassInitialize to run code before running the first test in the class // [ClassInitialize()] // public static void MyClassInitialize(TestContext testContext) { } // // Use ClassCleanup to run code after all tests in a class have run // [ClassCleanup()] // public static void MyClassCleanup() { } // // Use TestInitialize to run code before running each test // [TestInitialize()] // public void MyTestInitialize() { } // // Use TestCleanup to run code after each test has run // [TestCleanup()] // public void MyTestCleanup() { } // #endregion } }

Page 26: Algoritmos de ordenação

Abaixo segue o resultado da execução de todos os 36 testes.

Page 27: Algoritmos de ordenação

5. Estatísticas entre os algoritmos de ordenação

Abaixo segue tabelas comparando o tempo de execução dos algoritmos ordenando

vetores. Para a realização dos testes foi gerado um vetor com valores aleatórios e utilizado o

mesmo vetor para todos os algoritmos. O programa utilizado será explicado após as tabelas de

comparação.

Ordenando vetores com 10 itens

BubbleSort {00:00:00}

SelectionSort {00:00:00.0010001}

InsertionSort {00:00:00}

MergeSort {00:00:00.0020002}

MergeSortWithInsertionSort {00:00:00}

QuickSort {00:00:00.0010001}

Ordenando vetores com 100 itens

BubbleSort {00:00:00.0012501}

SelectionSort {00:00:00.0010001}

InsertionSort {00:00:00.0012501}

MergeSort {00:00:00.0012501}

MergeSortWithInsertionSort {00:00:00.0012501}

QuickSort {00:00:00.0012500}

Ordenando vetores com 1000 itens

BubbleSort {00:00:00.0179982}

SelectionSort {00:00:00.0109989}

InsertionSort {00:00:00.0069993}

MergeSort {00:00:00.0029997}

MergeSortWithInsertionSort {00:00:00.0019998}

QuickSort {00:00:00.0019998}

Ordenando vetores com 10000 itens

BubbleSort {00:00:01.6988304}

SelectionSort {00:00:01.0148985}

InsertionSort {00:00:00.6489351}

MergeSort {00:00:00.0749925}

MergeSortWithInsertionSort {00:00:00.0569943}

QuickSort {00:00:00.0059994}

Page 28: Algoritmos de ordenação

Ordenando vetores com 50000 itens

BubbleSort {00:00:41.9553894}

SelectionSort {00:00:28.3195700}

InsertionSort {00:00:16.4596458}

MergeSort {00:00:01.2951295}

MergeSortWithInsertionSort {00:00:01.1681168}

QuickSort {00:00:00.0280028}

Para implementar os extensions methods (orientação a aspectos) é necessário utilizar

classes estáticas. Estas por sua vez não permite herdar de interfaces o que inviabiliza a

aplicação do command pattern.

Pela ótica de como foi desenvolvido, o projeto responsável por contemplar o programa

que gera as estatísticas foi o projeto de testes, visto que as estatísticas, neste caso, fazem

parte dos testes de avaliação do software.

Abaixo segue a classe que gerou as estatísticas apresentadas:

using System; using System.Linq; using Lorival.Collections; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Tester { [TestClass] public class SpeedTester : AbstractTester { [TestMethod] public void EffectTest() { DateTime startTime; DateTime endTime; startTime = DateTime.Now; NumericListCreator numericListCreator = new NumericListCreator(50000); endTime = DateTime.Now; TimeSpan numericListCreatorSpeedTime = endTime - startTime; startTime = DateTime.Now; int[] bubble = numericListCreator.UnorderedList.ToArray<int>(); bubble.BubbleSort(); endTime = DateTime.Now; TimeSpan bubbleSpeedTime = endTime - startTime; //-- startTime = DateTime.Now; int[] selection = numericListCreator.UnorderedList.ToArray<int>(); selection.SelectionSort(); endTime = DateTime.Now; TimeSpan selectionSpeedTime = endTime - startTime; //-- startTime = DateTime.Now;

Page 29: Algoritmos de ordenação

int[] insertion = numericListCreator.UnorderedList.ToArray<int>(); insertion.InsertionSort(); endTime = DateTime.Now; TimeSpan insertionSpeedTime = endTime - startTime; //-- startTime = DateTime.Now; int[] merge = numericListCreator.UnorderedList.ToArray<int>(); merge.MergeSort(); endTime = DateTime.Now; TimeSpan mergeSpeedTime = endTime - startTime; //-- startTime = DateTime.Now; int[] mergeWithInsertion = numericListCreator.UnorderedList.ToArray<int>(); mergeWithInsertion.MergeSortWithInsertionSort(); endTime = DateTime.Now; TimeSpan mergeWithInsertionSpeedTime = endTime - startTime; //-- startTime = DateTime.Now; int[] quick = numericListCreator.UnorderedList.ToArray<int>(); quick.QuickSort(); endTime = DateTime.Now; TimeSpan quickSpeedTime = endTime - startTime; } } }

Page 30: Algoritmos de ordenação

6. Conclusão

Os objetivos do trabalho foram alcançados com sucesso, ou seja, foi possível construir

todos os algoritmos e apresenta-los neste relatório juntamente com estatísticas de

desempenho de cada um.

O tempo aproximado total utilizado para desenvolvimento e geração deste relatório

foi de doze horas.

Os testes unitários foram imprescindíveis para a perfeita conclusão de todos os

algoritmos. Mesmo depois de concluído cada um, foi necessário passar por uma fase de

revisão e refinação o que permitiu serem feitas de forma muito mais rápidas e assertivas, visto

que existiam testes validando a ordenação de todos os algoritmos.

O maior problema encontrado foi na geração de um vetor não ordenado com valores

aleatórios para a realização dos testes. Como esta era uma responsabilidade do projeto de

testes foi possível utilizar o “SortedList” para facilitar o desenvolvimento, porém o tempo para

geração de um vetor de 50 mil posições sem valores repetidos foi de quase 20 minutos.

Existem várias outras formas de gerar este vetor, porém como não fazia parte dos objetivos

propostos e fazia parte apenas dos testes foi utilizada a forma mais rápida de desenvolver, que

implicou unicamente em ter maior tempo de espera na geração das estatísticas.

Por fim o trabalho foi de grande valia para entendimento, principalmente, das

diferenças de desempenho entre os algoritmos de ordenação e compreender que sempre

existem métodos mais eficientes de resolver um problema recorrente.