-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
213 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
name: CI | ||
on: | ||
pull_request: | ||
push: | ||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/[email protected] | ||
- name: Setup JDK | ||
uses: actions/[email protected] | ||
with: | ||
java-version: 17 | ||
distribution: temurin | ||
cache: sbt | ||
- name: Build | ||
run: sbt rebuild |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/.bsp | ||
/.idea | ||
/project/target | ||
/project/project/target | ||
/target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
version = 3.8.0 | ||
runner.dialect = scala3 | ||
|
||
rewrite.trailingCommas.style = multiple |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
ThisBuild / version := "0.1.0-SNAPSHOT" | ||
|
||
ThisBuild / scalaVersion := "3.3.1" | ||
|
||
ThisBuild / scalacOptions ++= Seq( | ||
"-encoding", | ||
"utf8", | ||
"--release:17", | ||
"-deprecation", | ||
"-Xfatal-warnings", | ||
) | ||
|
||
lazy val root = (project in file(".")) | ||
.settings( | ||
name := "algorithms", | ||
libraryDependencies ++= Seq( | ||
"org.scalatest" %% "scalatest" % "3.2.19" % Test | ||
), | ||
) | ||
|
||
commands ++= Seq( | ||
Command.command("build") { state => | ||
"scalafmtCheckAll" :: | ||
"scalafmtSbtCheck" :: | ||
"test" :: | ||
state | ||
}, | ||
Command.command("rebuild") { state => | ||
"clean" :: "build" :: state | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
sbt.version=1.9.9 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2") |
74 changes: 74 additions & 0 deletions
74
src/main/scala/com/github/skozlov/algorithms/sort/InsertionSort.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package com.github.skozlov.algorithms.sort | ||
|
||
import scala.annotation.tailrec | ||
import scala.collection.mutable | ||
import scala.math.Ordered.orderingToOrdered | ||
|
||
object InsertionSort { | ||
|
||
/** Sorts the input sequence putting elements to the output sequence. | ||
* | ||
* The sequences may be independent (then the input sequence isn't modified) | ||
* or be the same sequence (then in-place sort is performed). | ||
* | ||
* This sort is stable. | ||
* | ||
* Time consumption: O(n<sup>2</sup>). | ||
* | ||
* Memory consumption: O(1). | ||
* @param in | ||
* input sequence which contains elements to sort | ||
* @param out | ||
* output sequence to put sorted elements into | ||
* @throws IllegalArgumentException | ||
* if the input and output sequences have different sizes | ||
*/ | ||
def sort[A: Ordering]( | ||
in: collection.IndexedSeq[A], | ||
out: mutable.IndexedSeq[A], | ||
): Unit = { | ||
require( | ||
in.size == out.size, | ||
s"in and out have different sizes: ${in.size} and ${out.size}", | ||
) | ||
|
||
if (in.nonEmpty) { | ||
|
||
/** Assuming that out[0:index-1] contains sorted in[0:index-1], inserts | ||
* in[index] into out[0:index-1] so that out[0:index] contains sorted | ||
* in[0:index]. | ||
*/ | ||
def insert(index: Int): Unit = { | ||
val elementToInsert = in(index) | ||
|
||
/** In out sequence, shifts elements which are greater than | ||
* elementToInsert one position to the right, going right to left | ||
* starting from startIndex. | ||
* @return | ||
* the index to insert elementToInsert into after the shift | ||
*/ | ||
@tailrec | ||
def shiftGreaterReturningTargetIndex(startIndex: Int): Int = { | ||
val elementToCompare = out(startIndex) | ||
if (elementToCompare > elementToInsert) { | ||
out(startIndex + 1) = elementToCompare | ||
if (startIndex == 0) { | ||
0 | ||
} else { | ||
shiftGreaterReturningTargetIndex(startIndex - 1) | ||
} | ||
} else startIndex + 1 | ||
} | ||
|
||
val targetIndex = | ||
shiftGreaterReturningTargetIndex(startIndex = index - 1) | ||
out(targetIndex) = elementToInsert | ||
} | ||
|
||
out(0) = in(0) | ||
for (i <- 1 until in.size) { | ||
insert(i) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.github.skozlov.algorithms | ||
|
||
import org.scalatest.funsuite.AnyFunSuite | ||
import org.scalatest.matchers.should.Matchers | ||
|
||
abstract class Test extends AnyFunSuite with Matchers |
73 changes: 73 additions & 0 deletions
73
src/test/scala/com/github/skozlov/algorithms/sort/SortTest.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package com.github.skozlov.algorithms.sort | ||
|
||
import com.github.skozlov.algorithms.Test | ||
|
||
class SortTest extends Test { | ||
private val cases: Seq[Seq[(Int, Int)]] = { | ||
Seq( | ||
Seq.empty[Int], | ||
Seq(1), | ||
Seq(1, 2, 3), | ||
Seq(1, 3, 2), | ||
Seq(2, 1, 3), | ||
Seq(2, 3, 1), | ||
Seq(3, 1, 2), | ||
Seq(3, 2, 1), | ||
Seq(1, 3, 2, 3, 1), | ||
) map { _.zipWithIndex } | ||
} | ||
|
||
private implicit val ordering: Ordering[(Int, Int)] = | ||
Ordering.by[(Int, Int), Int](_._1) | ||
|
||
private val commonExpectedResults: Seq[Seq[Int]] = cases map { | ||
_.map { _._1 }.sorted | ||
} | ||
|
||
private val stableSortExpectedResults: Seq[Seq[(Int, Int)]] = cases map { | ||
_.sorted(Ordering.by[(Int, Int), Int](_._1).orElseBy(_._2)) | ||
} | ||
|
||
private def checkResults( | ||
results: Seq[Seq[(Int, Int)]], | ||
stableSort: Boolean, | ||
): Unit = { | ||
if (stableSort) { | ||
results shouldBe stableSortExpectedResults | ||
} else { | ||
(results map { _ map { _._1 } }) shouldBe commonExpectedResults | ||
} | ||
} | ||
|
||
private def testInPlaceSort( | ||
sort: InsertionSort.type, | ||
stable: Boolean, | ||
): Unit = { | ||
val arrays: Seq[Array[(Int, Int)]] = cases map { _.toArray } | ||
val results: Seq[Seq[(Int, Int)]] = for (array <- arrays) yield { | ||
sort.sort(in = array, out = array) | ||
array.toSeq | ||
} | ||
checkResults(results, stable) | ||
} | ||
|
||
private def testImmutableInputSort( | ||
sort: InsertionSort.type, | ||
stable: Boolean, | ||
): Unit = { | ||
val inputsAndOutputsAfterSort: Seq[(Array[(Int, Int)], Array[(Int, Int)])] = | ||
for { | ||
_case: Seq[(Int, Int)] <- cases | ||
input: Array[(Int, Int)] = _case.toArray | ||
output: Array[(Int, Int)] = Array.ofDim[(Int, Int)](_case.size) | ||
_ = sort.sort(input, output) | ||
} yield (input, output) | ||
checkResults(inputsAndOutputsAfterSort map { _._2.toSeq }, stable) | ||
(inputsAndOutputsAfterSort map { _._1.toSeq }) shouldBe cases | ||
} | ||
|
||
test("insertion sort") { | ||
testInPlaceSort(InsertionSort, stable = true) | ||
testImmutableInputSort(InsertionSort, stable = true) | ||
} | ||
} |