From 47901ec45becbfd1404f75868f3f89743d63c2b7 Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Sat, 29 Apr 2023 16:42:21 +0200 Subject: [PATCH 01/13] Add insertion sort --- sorts/insertion_sort.nim | 76 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 sorts/insertion_sort.nim diff --git a/sorts/insertion_sort.nim b/sorts/insertion_sort.nim new file mode 100644 index 00000000..8bda59b3 --- /dev/null +++ b/sorts/insertion_sort.nim @@ -0,0 +1,76 @@ +## Insertion Sort +#[ +This algorithm sorts a collection by comparing adjacent elements. +When it finds that order is not respected, it moves the element compared +backward until the order is correct. It then goes back directly to the +element's initial position resuming forward comparison. + +https://en.wikipedia.org/wiki/Insertion_sort +]# + +import std/[random, sequtils, algorithm] + +func insertionSortAllSwaps[T](l: var openArray[T]) = + ## First implementation swaps elements until the right position is found + var i = 1 + while i < len(l): + var + j = i + while j > 0 and l[j-1] > l[j]: + swap(l[j], l[j-1]) + j = j - 1 + i = i + 1 + +func insertionSort[T](l: var openArray[T]) = + ## Sort your array similar to how you would sort your cards in your hand. + ## You take a card `key` and insert it in the right position in your hand one + ## at a time. + for j in 1 .. l.high: + var + key = l[j] + i = j - 1 + while i >= 0 and l[i] > key: + l[i+1] = l[i] + i.dec + l[i+1] = key + +proc testSort[T: SomeNumber](mySort: proc (x: var openArray[T]), size: Positive = 15, + limit: SomeNumber = 100, verbose = true): bool = + ## Test the sort function with a random array + var limit = T(limit) + var arr = newSeqWith(size, rand(limit)) + if verbose: + echo "Before: ", arr + mySort(arr) + if verbose: + echo "After: ", arr + isSorted(arr) + +proc testSort(mySort: proc (x: var openArray[char]), size: Positive = 15, + limit: char = 'z', verbose = true): bool = + ## Test the sort function with a random array + var arr = newSeqWith[char](size, rand('a' .. limit)) + if verbose: + echo "Before: ", arr + mySort(arr) + if verbose: + echo "After: ", arr + isSorted(arr) + + + +when isMainModule: + randomize() + import std/unittest + + suite "Insertion Sort": + test "Sort": + check testSort(insertionSortAllSwaps[int]) + check testSort(insertionSort[int]) + test "Sort with limit 10": + check testSort(insertionSortAllSwaps[int], 15, 10) + check testSort(insertionSort[int], 15, 10) + test "Sort with floating-point numbers": + check testSort(insertionSort[float]) + test "Sort characters": + check testSort(insertionSort[char]) From 3da8127c1b6119ef827f93be632369e66fe2cfdc Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Sat, 29 Apr 2023 19:48:19 +0200 Subject: [PATCH 02/13] Remove tests from insertion sort file --- sorts/insertion_sort.nim | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/sorts/insertion_sort.nim b/sorts/insertion_sort.nim index 8bda59b3..c74847b2 100644 --- a/sorts/insertion_sort.nim +++ b/sorts/insertion_sort.nim @@ -8,7 +8,7 @@ element's initial position resuming forward comparison. https://en.wikipedia.org/wiki/Insertion_sort ]# -import std/[random, sequtils, algorithm] +import std/[random] func insertionSortAllSwaps[T](l: var openArray[T]) = ## First implementation swaps elements until the right position is found @@ -34,34 +34,10 @@ func insertionSort[T](l: var openArray[T]) = i.dec l[i+1] = key -proc testSort[T: SomeNumber](mySort: proc (x: var openArray[T]), size: Positive = 15, - limit: SomeNumber = 100, verbose = true): bool = - ## Test the sort function with a random array - var limit = T(limit) - var arr = newSeqWith(size, rand(limit)) - if verbose: - echo "Before: ", arr - mySort(arr) - if verbose: - echo "After: ", arr - isSorted(arr) - -proc testSort(mySort: proc (x: var openArray[char]), size: Positive = 15, - limit: char = 'z', verbose = true): bool = - ## Test the sort function with a random array - var arr = newSeqWith[char](size, rand('a' .. limit)) - if verbose: - echo "Before: ", arr - mySort(arr) - if verbose: - echo "After: ", arr - isSorted(arr) - - - when isMainModule: randomize() import std/unittest + import ./testSort.nim suite "Insertion Sort": test "Sort": From 7b59c7005e3641ae3fce8da3953f74f77499497f Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Sat, 29 Apr 2023 19:48:42 +0200 Subject: [PATCH 03/13] And add those tests in an external file --- sorts/testSort.nim | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 sorts/testSort.nim diff --git a/sorts/testSort.nim b/sorts/testSort.nim new file mode 100644 index 00000000..0a939018 --- /dev/null +++ b/sorts/testSort.nim @@ -0,0 +1,24 @@ +import std/[sequtils, random, algorithm] + +proc testSort*[T: SomeNumber](mySort: proc (x: var openArray[T]), size: Positive = 15, + limit: SomeNumber = 100, verbose = true): bool = + ## Test the sort function with a random array + var limit = T(limit) + var arr = newSeqWith(size, rand(limit)) + if verbose: + echo "Before: ", arr + mySort(arr) + if verbose: + echo "After: ", arr + isSorted(arr) + +proc testSort*(mySort: proc (x: var openArray[char]), size: Positive = 15, + limit: char = 'z', verbose = true): bool = + ## Test the sort function with a random array + var arr = newSeqWith[char](size, rand('a' .. limit)) + if verbose: + echo "Before: ", arr + mySort(arr) + if verbose: + echo "After: ", arr + isSorted(arr) From 24328c72ceb7aaacb6d694a3426ea89dcc34c3ee Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Sat, 29 Apr 2023 19:48:42 +0200 Subject: [PATCH 04/13] And add those tests in an external file --- sorts/testSort.nim | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 sorts/testSort.nim diff --git a/sorts/testSort.nim b/sorts/testSort.nim new file mode 100644 index 00000000..0a939018 --- /dev/null +++ b/sorts/testSort.nim @@ -0,0 +1,24 @@ +import std/[sequtils, random, algorithm] + +proc testSort*[T: SomeNumber](mySort: proc (x: var openArray[T]), size: Positive = 15, + limit: SomeNumber = 100, verbose = true): bool = + ## Test the sort function with a random array + var limit = T(limit) + var arr = newSeqWith(size, rand(limit)) + if verbose: + echo "Before: ", arr + mySort(arr) + if verbose: + echo "After: ", arr + isSorted(arr) + +proc testSort*(mySort: proc (x: var openArray[char]), size: Positive = 15, + limit: char = 'z', verbose = true): bool = + ## Test the sort function with a random array + var arr = newSeqWith[char](size, rand('a' .. limit)) + if verbose: + echo "Before: ", arr + mySort(arr) + if verbose: + echo "After: ", arr + isSorted(arr) From c07308e952a304af801f9e4a2fa226e667a6f6d3 Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Sat, 29 Apr 2023 20:24:01 +0200 Subject: [PATCH 05/13] [testSort] Set verbose to false by default --- sorts/testSort.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sorts/testSort.nim b/sorts/testSort.nim index 0a939018..4ca48b5c 100644 --- a/sorts/testSort.nim +++ b/sorts/testSort.nim @@ -1,7 +1,7 @@ import std/[sequtils, random, algorithm] proc testSort*[T: SomeNumber](mySort: proc (x: var openArray[T]), size: Positive = 15, - limit: SomeNumber = 100, verbose = true): bool = + limit: SomeNumber = 100, verbose = false): bool = ## Test the sort function with a random array var limit = T(limit) var arr = newSeqWith(size, rand(limit)) @@ -13,7 +13,7 @@ proc testSort*[T: SomeNumber](mySort: proc (x: var openArray[T]), size: Positive isSorted(arr) proc testSort*(mySort: proc (x: var openArray[char]), size: Positive = 15, - limit: char = 'z', verbose = true): bool = + limit: char = 'z', verbose = false): bool = ## Test the sort function with a random array var arr = newSeqWith[char](size, rand('a' .. limit)) if verbose: From 692e0cae5283c64decdb75a44d3894c1c2201e49 Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Sat, 29 Apr 2023 20:24:17 +0200 Subject: [PATCH 06/13] Add bubble sort --- sorts/bubble_sort.nim | 79 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 sorts/bubble_sort.nim diff --git a/sorts/bubble_sort.nim b/sorts/bubble_sort.nim new file mode 100644 index 00000000..dfb49ce5 --- /dev/null +++ b/sorts/bubble_sort.nim @@ -0,0 +1,79 @@ +# Bubble sort +#[ +Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the input list element by element, comparing the current element with the one after it, swapping their values if needed. These passes through the list are repeated until no swaps had to be performed during a pass, meaning that the list has become fully sorted. +# https://en.wikipedia.org/wiki/Bubble_sort +]# + +func bubbleSort[T](l: var openArray[T]) = + let n = l.len + for i in countDown(n - 1, 1): + for j in 0 ..< i: + if l[j] > l[j+1]: + swap(l[j], l[j+1]) + + +func bubbleSortOpt1[T](l: var openArray[T]) = + let n = l.len + for i in countDown(n - 1, 1): + var flag: bool = true # Optimisation + for j in 0 ..< i: + if l[j] > l[j+1]: + flag = false + swap(l[j], l[j+1]) + if flag: # We can return/break early + return + +func bubbleSortWhileLoop[T](l: var openArray[T]) = + ## The same optimization can be rewritten with + ## a while loop + let n = l.len + var swapped = true + while swapped: + swapped = false + for i in 1 ..< n: + if l[i-1] > l[i]: + swap l[i-1], l[i] + swapped = true + +func bubbleSortOpt2[T](l: var openArray[T]) = + ## The n-th pass finds the n-th largest element + ## So no need to look at the n last elements + ## during the (n+1)-th pass + var + n = l.len + swapped = true + while swapped: + swapped = false + for i in 1 ..< n: + if l[i-1] > l[i]: + swap l[i-1], l[i] + swapped = true + dec n + +when isMainModule: + import std/[unittest, random] + import ./testSort.nim + randomize() + + suite "Insertion Sort": + test "Sort": + check testSort(bubbleSort[int]) + check testSort(bubbleSortOpt1[int]) + check testSort(bubbleSortWhileLoop[int]) + check testSort(bubbleSortOpt2[int]) + test "Sort with limit 10": + check testSort(bubbleSort[int], 15, 10) + check testSort(bubbleSortOpt1[int], 15, 10) + check testSort(bubbleSortWhileLoop[int], 15, 10) + check testSort(bubbleSortOpt2[int], 15, 10) + test "Sort with floating-point numbers": + check testSort(bubbleSort[float]) + check testSort(bubbleSortOpt1[float]) + check testSort(bubbleSortWhileLoop[float]) + check testSort(bubbleSortOpt2[float]) + test "Sort characters": + check testSort(bubbleSort[char]) + check testSort(bubbleSortOpt1[char]) + check testSort(bubbleSortWhileLoop[char]) + check testSort(bubbleSortOpt2[char]) + From 2c971f290677b0ac99052682b702a5aa33c02ffc Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Fri, 2 Jun 2023 18:18:09 +0200 Subject: [PATCH 07/13] Add titles in DIRECTORY.md --- DIRECTORY.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 DIRECTORY.md diff --git a/DIRECTORY.md b/DIRECTORY.md new file mode 100644 index 00000000..8c99b32c --- /dev/null +++ b/DIRECTORY.md @@ -0,0 +1,22 @@ + + +# The Algorithms — Nim: Directory Hierarchy + +## Dynamic Programming + * [Catalan Numbers](dynamic_programming/catalan_numbers.nim) + * [Viterbi](dynamic_programming/viterbi.nim) + +## Maths + * [Area](maths/area.nim) + +## Sorts + * [Bubble sort](sorts/bubble_sort.nim) + * [Insertion Sort](sorts/insertion_sort.nim) + * [Merge Sort](sorts/merge_sort.nim) + * [Quick Sort](sorts/quick_sort.nim) + * [Selection Sort](sorts/selection_sort.nim) + * [Shell Sort](sorts/shell_sort.nim) + * [Test sorting algorithms](sorts/testSort.nim) + +## Strings + * [Check Anagram](strings/check_anagram.nim) From 98331f5b435fa68304984f617e798c91564f37cc Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Fri, 2 Jun 2023 18:52:29 +0200 Subject: [PATCH 08/13] Add sharp for titles --- sorts/bubble_sort.nim | 5 +-- sorts/counting_sort.nim | 80 ++++++++++++++++++++++++++++++++++++++++ sorts/merge_sort.nim | 2 +- sorts/quick_sort.nim | 2 +- sorts/selection_sort.nim | 2 +- sorts/shell_sort.nim | 2 +- sorts/testSort.nim | 1 + 7 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 sorts/counting_sort.nim diff --git a/sorts/bubble_sort.nim b/sorts/bubble_sort.nim index dfb49ce5..7108eb70 100644 --- a/sorts/bubble_sort.nim +++ b/sorts/bubble_sort.nim @@ -1,4 +1,4 @@ -# Bubble sort +## Bubble sort #[ Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the input list element by element, comparing the current element with the one after it, swapping their values if needed. These passes through the list are repeated until no swaps had to be performed during a pass, meaning that the list has become fully sorted. # https://en.wikipedia.org/wiki/Bubble_sort @@ -10,7 +10,7 @@ func bubbleSort[T](l: var openArray[T]) = for j in 0 ..< i: if l[j] > l[j+1]: swap(l[j], l[j+1]) - + func bubbleSortOpt1[T](l: var openArray[T]) = let n = l.len @@ -76,4 +76,3 @@ when isMainModule: check testSort(bubbleSortOpt1[char]) check testSort(bubbleSortWhileLoop[char]) check testSort(bubbleSortOpt2[char]) - diff --git a/sorts/counting_sort.nim b/sorts/counting_sort.nim new file mode 100644 index 00000000..34c913fe --- /dev/null +++ b/sorts/counting_sort.nim @@ -0,0 +1,80 @@ +## Counting Sort +#[ +Counting sort is an integer sorting algorithm. It sorts a collection of objects +according to their keys. It operates by counting the number of objects that possess distinct key values, +and applying prefix sum on those counts to determine the positions of each key value in the output sequence. +Its running time is linear in the number of items and the difference +between the maximum key value and the minimum key value +References: +https://en.wikipedia.org/wiki/Counting_sort +https://github.com/ringabout/data-structure-in-Nim/blob/master/countingSort.nim +]# + +import std/tables + +# proc countingSort*(x: openArray[int]): openArray[int] = +# ## `aid` is a count table +# let +# length = x.len +# smax = max(x) +# var aid = newSeq(smax + 1) +# result = newSeq(length) +# # Make `aid` a count table of x +# for i in 0 ..< length: +# aid[x[i]] += 1 + +# aid[0] -= 1 +# # `aid[i]` counts occurences of x[j] for all j <= i +# for i in 1 .. smax: +# aid[i] += aid[i-1] + +# for i in countdown(x.high, 0, 1): +# result[aid[x[i]]] = x[i] +# aid[x[i]] -= 1 + +# proc countingSortWithTable*[T](x: openArray[T]): openArray[T] = +# var +# length = x.len +# smax = max(x) +# frequenciesTable = toCountTable(x) +# dec frequenciesTable[0] +# for i in 1 .. smax: +# frequenciesTable[i] += frequenciesTable[i-1] +# result = newSeq[T](length) +# for i in countdown(x.high, 0, 1): +# result[frequenciesTable[x[i]]] = x[i] +# frequenciesTable[x[i]] -= 1 + +func countingSort*[T: SomeInteger](x: seq[T]): seq[T] = + ## https://github.com/ringabout/data-structure-in-Nim/blob/master/countingSort.nim + ## `aid` is a count table + let + length = x.len + smax = max(x) + var aid = newSeq[T](smax + 1) + result = newSeq[T](length) + # Make `aid` a count table of x + for i in 0 ..< length: + aid[x[i]] += 1 + + aid[0] -= 1 + # `aid[i]` counts occurences of x[j] for all j <= i + for i in 1 .. smax: + aid[i] += aid[i-1] + + for i in countdown(x.high, 0, 1): + result[aid[x[i]]] = x[i] + aid[x[i]] -= 1 + +when isMainModule: + import std/[unittest, random] + import ./testSort + randomize() + + suite "Counting Sort": + test "Integers": + check testSort countingSort[int] + # test "Float": + # check testSort countingSort[float] + # test "Char": + # check testSort countingSortWithTable[char] diff --git a/sorts/merge_sort.nim b/sorts/merge_sort.nim index d7e54623..1e03cdb5 100644 --- a/sorts/merge_sort.nim +++ b/sorts/merge_sort.nim @@ -1,4 +1,4 @@ -# Merge Sort +## Merge Sort ## Add Description {.push raises: [].} diff --git a/sorts/quick_sort.nim b/sorts/quick_sort.nim index c00dbbf4..ebd8e1f7 100644 --- a/sorts/quick_sort.nim +++ b/sorts/quick_sort.nim @@ -1,4 +1,4 @@ -# Quick Sort +## Quick Sort ## Add Description ## TODO: Need an out of place version of the test ## https://en.wikipedia.org/wiki/Shellsort diff --git a/sorts/selection_sort.nim b/sorts/selection_sort.nim index 5e17244b..2f7a74b0 100644 --- a/sorts/selection_sort.nim +++ b/sorts/selection_sort.nim @@ -1,4 +1,4 @@ -# Selection Sort +## Selection Sort ## Add description {.push raises: [].} diff --git a/sorts/shell_sort.nim b/sorts/shell_sort.nim index 825f424d..0634f238 100644 --- a/sorts/shell_sort.nim +++ b/sorts/shell_sort.nim @@ -1,4 +1,4 @@ -# Shell Sort +## Shell Sort #[ Shellsort, also known as Shell sort or Shell's method, is an in-place comparison sort. It can be seen as either a generalization diff --git a/sorts/testSort.nim b/sorts/testSort.nim index 4ca48b5c..33d42744 100644 --- a/sorts/testSort.nim +++ b/sorts/testSort.nim @@ -1,3 +1,4 @@ +## Test sorting algorithms import std/[sequtils, random, algorithm] proc testSort*[T: SomeNumber](mySort: proc (x: var openArray[T]), size: Positive = 15, From 51570f28d48506e44102c94d075baf8f3aeb65a0 Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Thu, 7 Sep 2023 15:53:53 +0200 Subject: [PATCH 09/13] Add comments and description of the quicksort algorithm --- sorts/quick_sort.nim | 53 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/sorts/quick_sort.nim b/sorts/quick_sort.nim index ebd8e1f7..1c07289b 100644 --- a/sorts/quick_sort.nim +++ b/sorts/quick_sort.nim @@ -1,7 +1,17 @@ ## Quick Sort -## Add Description -## TODO: Need an out of place version of the test -## https://en.wikipedia.org/wiki/Shellsort +## +## The Quick Sort is the first sort algorithm with a complexity less than quadratic +## and even reaching the optimal theoretical bound of a sorting algorithm. +## +## As a strategy, it selects an element (the pivot) which serves as +## a separation barrier. We put all elements higher than the pivot to its right, +## and all elements lower than the pivot to its left. +## We can operate recursively on the lists on each side. The base cases are lists +## of one or two elements (elements on the left and the right of the pivot are +## trivially sorted). +## +## complexity: O(n*log(n)) +## https://en.wikipedia.org/wiki/Quicksort ## https://github.com/ringabout/data-structure-in-Nim/blob/master/sortingAlgorithms/quickSort.nim {.push raises: [].} @@ -13,65 +23,84 @@ proc quickSort[T](list: var openArray[T], lo: int, hi: int) = if lo >= hi: return # Pivot selection - # Historically, the first element + # Historically, developers used the first element as pivot # let pivot = lo - # More performant: choose at random!!! + # The best choice is to select at random the pivot! let pivot = rand(lo..hi) var i = lo + 1 j = hi - # We place the pivot element at the + # We place temporarily the pivot element at the # lowest position swap(list[lo], list[pivot]) var running = true + + # We do not know in advance the number of swaps to do while running: + # Starting from the left, we select the first element that is superior to the pivot and ... while list[i] <= list[lo] and i < hi: i += 1 + # starting from the right, the first element that is inferior to the pivot. while list[j] >= list[lo] and j > lo: j -= 1 + # We swap them if they are not in increasing order if i < j: swap(list[i], list[j]) + # If no swaps have been done, all elements are positioned correctly + # compared to the pivot, so we can exit the loop + # If the pivot is the maximum then i=hi(=j) so we do not swap and + # end the loop directly. else: running = false + # If all elements are strictly superior to the pivot (i=lo+1, j=lo)(we selected the minimum!), we make two pass, one swapping the second element with the pivot, and one placing the pivot at the beginning again. + # The pivot element is actually the (j − lo + 1)-th smallest element of the sublist, since we found (i − lo) = (j - lo + 1) elements smaller than it, and all other elements are larger. swap(list[lo], list[j]) - # Recursive calls + # Recursive calls - the whole list is sorted if and only if + # both the upper and lower parts are sorted. quicksort(list, lo, j - 1) quicksort(list, j + 1, hi) proc quickSort*[T](list: var openArray[T]) = - ## Main function + ## Main function of the first quick sort implementation quicksort(list, list.low, list.high) proc QuickSort[T](list: openArray[T]): seq[T] = - ## Second quick sort implementation, out-of-place but making a lot of copies - ## Easier to memorize + ## Second quick sort implementation, out-of-place, making a lot of copies if len(list) == 0: return @[] + # We select the first element for simplicity var pivot = list[0] + # We explicitely create the left and right lists. + + # We can not guess the length in advance, so we have to use + # a container on the heap. var left: seq[T] = @[] var right: seq[T] = @[] + + # If elements have the same value as the pivot, they are omitted! for i in low(list)..high(list): if list[i] < pivot: left.add(list[i]) elif list[i] > pivot: right.add(list[i]) + + # We concatenate the results result = QuickSort(left) & pivot & QuickSort(right) when isMainModule: import std/[unittest] - import ./testSort + import test_sorts randomize() suite "Quick Sort": test "Integers": check testSort quickSort[int] - # check testSort QuickSort[int] test "Float": check testSort quickSort[float] test "Char": From 30d00e47cd1e4e74035fcc08409e331c0a3d2935 Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Thu, 7 Sep 2023 15:55:07 +0200 Subject: [PATCH 10/13] Rename testSort.nim -> test_sorts.nim --- sorts/bubble_sort.nim | 4 ++-- sorts/insertion_sort.nim | 17 ++++++++--------- sorts/merge_sort.nim | 2 +- sorts/selection_sort.nim | 2 +- sorts/{testSort.nim => test_sorts.nim} | 0 5 files changed, 12 insertions(+), 13 deletions(-) rename sorts/{testSort.nim => test_sorts.nim} (100%) diff --git a/sorts/bubble_sort.nim b/sorts/bubble_sort.nim index 7108eb70..50c6c60b 100644 --- a/sorts/bubble_sort.nim +++ b/sorts/bubble_sort.nim @@ -1,4 +1,4 @@ -## Bubble sort +## Bubble Sort #[ Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the input list element by element, comparing the current element with the one after it, swapping their values if needed. These passes through the list are repeated until no swaps had to be performed during a pass, meaning that the list has become fully sorted. # https://en.wikipedia.org/wiki/Bubble_sort @@ -52,7 +52,7 @@ func bubbleSortOpt2[T](l: var openArray[T]) = when isMainModule: import std/[unittest, random] - import ./testSort.nim + import ./test_sorts.nim randomize() suite "Insertion Sort": diff --git a/sorts/insertion_sort.nim b/sorts/insertion_sort.nim index c74847b2..3595e360 100644 --- a/sorts/insertion_sort.nim +++ b/sorts/insertion_sort.nim @@ -1,12 +1,11 @@ ## Insertion Sort -#[ -This algorithm sorts a collection by comparing adjacent elements. -When it finds that order is not respected, it moves the element compared -backward until the order is correct. It then goes back directly to the -element's initial position resuming forward comparison. - -https://en.wikipedia.org/wiki/Insertion_sort -]# +## +## This algorithm sorts a collection by comparing adjacent elements. +## When it finds that order is not respected, it moves the element compared +## backward until the order is correct. It then goes back directly to the +## element's initial position resuming forward comparison. +## +## https://en.wikipedia.org/wiki/Insertion_sort import std/[random] @@ -37,7 +36,7 @@ func insertionSort[T](l: var openArray[T]) = when isMainModule: randomize() import std/unittest - import ./testSort.nim + import test_sorts suite "Insertion Sort": test "Sort": diff --git a/sorts/merge_sort.nim b/sorts/merge_sort.nim index 1e03cdb5..da198352 100644 --- a/sorts/merge_sort.nim +++ b/sorts/merge_sort.nim @@ -50,7 +50,7 @@ func mergeSort[T](list: var openArray[T]) = when isMainModule: import std/[unittest, random] - import ./testSort + import test_sorts randomize() suite "Merge Sort": diff --git a/sorts/selection_sort.nim b/sorts/selection_sort.nim index 2f7a74b0..92b77fb3 100644 --- a/sorts/selection_sort.nim +++ b/sorts/selection_sort.nim @@ -17,7 +17,7 @@ func selectionSort[T](l: var openArray[T]) = when isMainModule: import std/[unittest, random] - import ./testSort + import test_sorts randomize() suite "Selection Sort": diff --git a/sorts/testSort.nim b/sorts/test_sorts.nim similarity index 100% rename from sorts/testSort.nim rename to sorts/test_sorts.nim From 0ba702407c543d5ce00a0177741fdcdd709e150d Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Thu, 7 Sep 2023 15:57:13 +0200 Subject: [PATCH 11/13] Fix tests in counting sort but ... --- sorts/counting_sort.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sorts/counting_sort.nim b/sorts/counting_sort.nim index 34c913fe..77e3e8d3 100644 --- a/sorts/counting_sort.nim +++ b/sorts/counting_sort.nim @@ -68,7 +68,7 @@ func countingSort*[T: SomeInteger](x: seq[T]): seq[T] = when isMainModule: import std/[unittest, random] - import ./testSort + import test_sorts randomize() suite "Counting Sort": From ca2237e6d5717158fb198e2e8a00d36659f0ece3 Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Thu, 7 Sep 2023 15:57:36 +0200 Subject: [PATCH 12/13] Remove counting sort --- sorts/counting_sort.nim | 80 ----------------------------------------- 1 file changed, 80 deletions(-) delete mode 100644 sorts/counting_sort.nim diff --git a/sorts/counting_sort.nim b/sorts/counting_sort.nim deleted file mode 100644 index 77e3e8d3..00000000 --- a/sorts/counting_sort.nim +++ /dev/null @@ -1,80 +0,0 @@ -## Counting Sort -#[ -Counting sort is an integer sorting algorithm. It sorts a collection of objects -according to their keys. It operates by counting the number of objects that possess distinct key values, -and applying prefix sum on those counts to determine the positions of each key value in the output sequence. -Its running time is linear in the number of items and the difference -between the maximum key value and the minimum key value -References: -https://en.wikipedia.org/wiki/Counting_sort -https://github.com/ringabout/data-structure-in-Nim/blob/master/countingSort.nim -]# - -import std/tables - -# proc countingSort*(x: openArray[int]): openArray[int] = -# ## `aid` is a count table -# let -# length = x.len -# smax = max(x) -# var aid = newSeq(smax + 1) -# result = newSeq(length) -# # Make `aid` a count table of x -# for i in 0 ..< length: -# aid[x[i]] += 1 - -# aid[0] -= 1 -# # `aid[i]` counts occurences of x[j] for all j <= i -# for i in 1 .. smax: -# aid[i] += aid[i-1] - -# for i in countdown(x.high, 0, 1): -# result[aid[x[i]]] = x[i] -# aid[x[i]] -= 1 - -# proc countingSortWithTable*[T](x: openArray[T]): openArray[T] = -# var -# length = x.len -# smax = max(x) -# frequenciesTable = toCountTable(x) -# dec frequenciesTable[0] -# for i in 1 .. smax: -# frequenciesTable[i] += frequenciesTable[i-1] -# result = newSeq[T](length) -# for i in countdown(x.high, 0, 1): -# result[frequenciesTable[x[i]]] = x[i] -# frequenciesTable[x[i]] -= 1 - -func countingSort*[T: SomeInteger](x: seq[T]): seq[T] = - ## https://github.com/ringabout/data-structure-in-Nim/blob/master/countingSort.nim - ## `aid` is a count table - let - length = x.len - smax = max(x) - var aid = newSeq[T](smax + 1) - result = newSeq[T](length) - # Make `aid` a count table of x - for i in 0 ..< length: - aid[x[i]] += 1 - - aid[0] -= 1 - # `aid[i]` counts occurences of x[j] for all j <= i - for i in 1 .. smax: - aid[i] += aid[i-1] - - for i in countdown(x.high, 0, 1): - result[aid[x[i]]] = x[i] - aid[x[i]] -= 1 - -when isMainModule: - import std/[unittest, random] - import test_sorts - randomize() - - suite "Counting Sort": - test "Integers": - check testSort countingSort[int] - # test "Float": - # check testSort countingSort[float] - # test "Char": - # check testSort countingSortWithTable[char] From ee6590ea0a8a7210f8f9f54a792a96586f7e6ce3 Mon Sep 17 00:00:00 2001 From: Dimitri LESNOFF Date: Thu, 7 Sep 2023 16:11:38 +0200 Subject: [PATCH 13/13] Run nimpretty --- sorts/quick_sort.nim | 10 +++++----- sorts/shell_sort.nim | 2 +- sorts/test_sorts.nim | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/sorts/quick_sort.nim b/sorts/quick_sort.nim index 1c07289b..f63a47a7 100644 --- a/sorts/quick_sort.nim +++ b/sorts/quick_sort.nim @@ -71,7 +71,7 @@ proc quickSort*[T](list: var openArray[T]) = proc QuickSort[T](list: openArray[T]): seq[T] = ## Second quick sort implementation, out-of-place, making a lot of copies if len(list) == 0: - return @[] + return @[] # We select the first element for simplicity var pivot = list[0] # We explicitely create the left and right lists. @@ -83,10 +83,10 @@ proc QuickSort[T](list: openArray[T]): seq[T] = # If elements have the same value as the pivot, they are omitted! for i in low(list)..high(list): - if list[i] < pivot: - left.add(list[i]) - elif list[i] > pivot: - right.add(list[i]) + if list[i] < pivot: + left.add(list[i]) + elif list[i] > pivot: + right.add(list[i]) # We concatenate the results result = QuickSort(left) & diff --git a/sorts/shell_sort.nim b/sorts/shell_sort.nim index 0634f238..045ae544 100644 --- a/sorts/shell_sort.nim +++ b/sorts/shell_sort.nim @@ -48,7 +48,7 @@ func shell3Sort*[T](x: var openArray[T]) = func shellSort[T](list: var openArray[T]) = ## A gap of 1 is an insertion sort algorithm ## Optimal gap sequence is referenced here: https://oeis.org/A102549 - const gaps = [701, 301, 132, 57, 23, 10, 4, 1] # Ciura gap sequence + const gaps = [701, 301, 132, 57, 23, 10, 4, 1] # Ciura gap sequence for gap in gaps: for i in gap .. list.high: var diff --git a/sorts/test_sorts.nim b/sorts/test_sorts.nim index 33d42744..0e74fe29 100644 --- a/sorts/test_sorts.nim +++ b/sorts/test_sorts.nim @@ -1,7 +1,8 @@ ## Test sorting algorithms import std/[sequtils, random, algorithm] -proc testSort*[T: SomeNumber](mySort: proc (x: var openArray[T]), size: Positive = 15, +proc testSort*[T: SomeNumber](mySort: proc (x: var openArray[T]), + size: Positive = 15, limit: SomeNumber = 100, verbose = false): bool = ## Test the sort function with a random array var limit = T(limit)