Post

Algoritmos de ordenação

Resumo sobre Algoritmos de ordenação

AlgoritmoPior caso $O(n)$Caso Médio $\Theta(n)$Melhor caso $\Omega(n)$
Bubble sort$n^2$$n^2$$n$
Selection sort$n^2$$n^2$$n^2$
Insertion sort$n^2$$n^2$$n$
Shell sort$n^2$$n^2$$nlog_2n$ (depende do gap)
Quick sort$n^2$$log_2(n)$$log_2n$
Merge sort$log_2(n)$$log_2(n)$$log_2n$
Heap sort$log_2(n)$$log_2(n)$$log_2n$

Bubble sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def bubble_sort(a: list[int]) -> None:
    size = len(a)

     def swap(i: int, j: int):
         temp = a[i]
         a[i] = a[j]
         a[j] = temp

     def run_bubble() -> bool:
         swapped = False
         for i in range(size-1):
             if a[i] > a[i+1]:
                 swap(i, i+1)
                 swapped = True
         return swapped

     swapped = run_bubble()
     while swapped:
         swapped =run_bubble()

Selection sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def selection_sort(a: list[int]) -> None:
    size = len(a)

    def find_min(start_index: int):
        min = start_index
        for i in range(start_index, size):
            if a[i] < a[min]:
                min = i
        return min

    def swap(i: int, j: int):
        temp = a[i]
        a[i] = a[j]
        a[j] = temp

    for i in range(size):
        min_index = find_min(start_index=i)

        if min_index != i:
            swap(min_index, i)

Insertion sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def insertion_sort(a: list[int]) -> None:
    size = len(a)

    def move_itens_to_left(index: int, value: int) -> int:
        while index >= 0 and value < a[index]:
            a[index+1] = a[index]
            index -= 1
        return index

    def insert(index: int, value: int):
        a[index] = value

    for i in range(1, size):
        current_item = a[i]
        last_index = move_itens_to_left(i-1, current_item)

        if last_index != i:
            insert(last_index + 1, current_item)

Shell sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def shell_sort(a: list[int]) -> None:

    size = len(a)
    gap = _find_initial_gap(size)

    def swap(i: int, j: int):
        temp = a[i]
        a[i] = a[j]
        a[j] = temp

    def insert(i: int, gap: int):
        for index in range(i+gap, 0, -gap):
            if a[index] < a[index - gap]:
                swap(index - gap, index)

    while gap > 0:

        for i in range(0, size - gap):
            insert(i, gap)

        gap = gap // 2


def _find_initial_gap(size: int):
    gap = 1
    while gap < size:
        gap = gap*3 + 1

    return gap // 3

Quick sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def quick_sort(a: list[int]) -> None:

    def swap(i: int, j: int):
        temp = a[i]
        a[i] = a[j]
        a[j] = temp

    def partition(low: int, high: int) -> int:
        pivot_value = a[high]
        pivot_index = low - 1

        for i in range(low, high):

            if a[i] <= pivot_value:
                pivot_index += 1
                swap(pivot_index, i)

        pivot_index +=1
        swap(pivot_index, high)
        return pivot_index

    def _sort(low: int, high: int):

        if low >= high:
            return
        pivot = partition(low, high)
        _sort(low, pivot - 1)
        _sort(pivot + 1, high)

    size = len(a)
    low = 0
    high = size - 1

    _sort(low, high)

Merge sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import sys

def merge_sort(a: list[int]) -> None:

    def _split(begin: int, end: int):
        if end - begin <= 1:
            return

        split_size = (end + begin) // 2
        _split(begin, split_size)
        _split(split_size, end)
        _merge(begin, end, split_size)

    def _merge(begin: int, end: int, split_size: int):
        left = a[begin:split_size]
        right = a[split_size:end]
        # Quando acabar os elementos, de um dos arranjos
        # a comparação current_right <= current_left, sempre irá para o outro arranjo
        # que possui elementos, pois left[-1] ou right[-1] == infinito
        left.append(sys.maxsize)
        right.append(sys.maxsize)
        right_index = 0
        left_index = 0

        current_left = left[left_index]
        current_right = right[right_index]

        for i in range(begin, end):
            if current_left <= current_right:
                a[i] = current_left
                left_index += 1
                current_left = left[left_index]
            else:
                a[i] = current_right
                right_index += 1
                current_right = right[right_index]

    _split(begin=0, end=len(a))

Heap sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
def heap_sort(a: list[int]) -> None:

    build_max_heap(a)

    size = len(a)

    for i in range(size-1, 0, -1):
        __swap(a, 0, i)
        size -= 1
        heapify(heap=a, current_index=0, heap_size=size)



def build_max_heap(a: list[int]):

    size = len(a)
    for i in range(size//2, -1, -1):
        heapify(a, i, size)


def heapify(heap: list[int], current_index: int, heap_size: int):
    l = __left(current_index)
    r = __right(current_index)
    if l < heap_size and heap[l] > heap[current_index]:
        high = l
    else:
        high = current_index

    if r < heap_size and heap[r] > heap[high]:
        high = r

    if current_index != high:
        __swap(heap, current_index, high)
        heapify(heap, high, heap_size)


def __left(i: int) -> int:
    return 2*i + 1


def __right(i: int) -> int:
    return 2*(i + 1)


def __swap(heap: list[int], i: int, j: int):
    temp = heap[i]
    heap[i] = heap[j]
    heap[j] = temp

Comparação entre os Algoritmos

Algoritmos lentos

Algoritmos lentos

Algoritmos Rápidos

Algoritmos Rápidos

Códigos utilizados para a comparação: samuel-cavalcanti/sort_algorithms

This post is licensed under CC BY 4.0 by the author.