Skip to content

Commit 5c39fc6

Browse files
[#726] New practice exercise satellite (#756)
Co-authored-by: Angelika Tyborska <angelikatyborska@fastmail.com>
1 parent b742431 commit 5c39fc6

File tree

10 files changed

+229
-0
lines changed

10 files changed

+229
-0
lines changed

config.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2380,6 +2380,24 @@
23802380
],
23812381
"difficulty": 9
23822382
},
2383+
{
2384+
"slug": "satellite",
2385+
"name": "Satellite",
2386+
"uuid": "a07e01e6-7cea-4db9-a514-7c95788e90a9",
2387+
"prerequisites": [
2388+
"pattern-matching",
2389+
"tuples",
2390+
"cond",
2391+
"recursion",
2392+
"atoms",
2393+
"lists",
2394+
"enum"
2395+
],
2396+
"practices": [
2397+
"recursion"
2398+
],
2399+
"difficulty": 6
2400+
},
23832401
{
23842402
"slug": "zebra-puzzle",
23852403
"name": "Zebra Puzzle",
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Description
2+
3+
Imagine you need to transmit a binary tree to a satellite approaching Alpha
4+
Centauri and you have limited bandwidth. Since the tree has no repeating
5+
items it can be uniquely represented by its [pre-order and in-order traversals][wiki].
6+
7+
Write the software for the satellite to rebuild the tree from the traversals.
8+
9+
A pre-order traversal reads the value of the current node before (hence "pre")
10+
reading the left subtree in pre-order. Afterwards the right subtree is read
11+
in pre-order.
12+
13+
An in-order traversal reads the left subtree in-order then the current node and
14+
finally the right subtree in-order. So in order from left to right.
15+
16+
For example the pre-order traversal of this tree is [a, i, x, f, r].
17+
The in-order traversal of this tree is [i, a, f, x, r]
18+
19+
```
20+
a
21+
/ \
22+
i x
23+
/ \
24+
f r
25+
```
26+
27+
Note: the first item in the pre-order traversal is always the root.
28+
29+
[wiki]: https://en.wikipedia.org/wiki/Tree_traversal
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Used by "mix format"
2+
[
3+
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
4+
]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"blurb": "Rebuild binary trees from pre-order and in-order traversals.",
3+
"authors": [
4+
"jiegillet"
5+
],
6+
"contributors": [
7+
"angelikatyborska"
8+
],
9+
"files": {
10+
"solution": [
11+
"lib/satellite.ex"
12+
],
13+
"test": [
14+
"test/satellite_test.exs"
15+
],
16+
"example": [
17+
".meta/example.ex"
18+
]
19+
}
20+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
defmodule Satellite do
2+
@typedoc """
3+
A tree, which can be empty, or made from a left branch, a node and a right branch
4+
"""
5+
@type tree :: {} | {tree, any, tree}
6+
7+
@doc """
8+
Build a tree from the elements given in a pre-order and in-order style
9+
"""
10+
@spec build_tree(preorder :: [any], inorder :: [any]) :: {:ok, tree} | {:error, String.t()}
11+
12+
def build_tree(preorder, inorder) do
13+
p_length = length(preorder)
14+
i_length = length(inorder)
15+
p_set = MapSet.new(preorder)
16+
i_set = MapSet.new(inorder)
17+
18+
cond do
19+
p_length != i_length -> {:error, "traversals must have the same length"}
20+
p_set != i_set -> {:error, "traversals must have the same elements"}
21+
p_length != MapSet.size(p_set) -> {:error, "traversals must contain unique items"}
22+
true -> {:ok, build_tree(preorder, inorder, :safe)}
23+
end
24+
end
25+
26+
def build_tree([], [], :safe), do: {}
27+
28+
def build_tree([root | preorder], inorder, :safe) do
29+
{in_left, in_right, pre_left, pre_right} = split(root, inorder, preorder)
30+
31+
{build_tree(pre_left, in_left, :safe), root, build_tree(pre_right, in_right, :safe)}
32+
end
33+
34+
defp split(root, [root | inorder], preorder), do: {[], inorder, [], preorder}
35+
36+
defp split(root, [i | inorder], [p | preorder]) do
37+
{in_left, in_right, pre_left, pre_right} = split(root, inorder, preorder)
38+
39+
{[i | in_left], in_right, [p | pre_left], pre_right}
40+
end
41+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# This is an auto-generated file. Regular comments will be removed when this
2+
# file is regenerated. Regenerating will not touch any manually added keys,
3+
# so comments can be added in a "comment" key.
4+
5+
[8df3fa26-811a-4165-9286-ff9ac0850d19]
6+
description = "Empty tree"
7+
8+
[f945ccfc-05e3-47d7-825b-0270559d43ad]
9+
description = "Tree with one item"
10+
11+
[a0121d5f-37b0-48dd-9c64-cba4c4464135]
12+
description = "Tree with many items"
13+
14+
[6074041f-4891-4d81-a128-401050c2a3b0]
15+
description = "Reject traversals of different length"
16+
17+
[27916ce4-45f3-4d8b-8528-496fedc157ca]
18+
description = "Reject inconsistent traversals of same length"
19+
20+
[d86a3d72-76a9-43b5-9d3a-e64cb1216035]
21+
description = "Reject traversals with repeated items"
22+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
defmodule Satellite do
2+
@typedoc """
3+
A tree, which can be empty, or made from a left branch, a node and a right branch
4+
"""
5+
@type tree :: {} | {tree, any, tree}
6+
7+
@doc """
8+
Build a tree from the elements given in a pre-order and in-order style
9+
"""
10+
@spec build_tree(preorder :: [any], inorder :: [any]) :: {:ok, tree} | {:error, String.t()}
11+
12+
def build_tree(preorder, inorder) do
13+
end
14+
end

exercises/practice/satellite/mix.exs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
defmodule Satellite.MixProject do
2+
use Mix.Project
3+
4+
def project do
5+
[
6+
app: :satellite,
7+
version: "0.1.0",
8+
# elixir: "~> 1.8",
9+
start_permanent: Mix.env() == :prod,
10+
deps: deps()
11+
]
12+
end
13+
14+
# Run "mix help compile.app" to learn about applications.
15+
def application do
16+
[
17+
extra_applications: [:logger]
18+
]
19+
end
20+
21+
# Run "mix help deps" to learn about dependencies.
22+
defp deps do
23+
[
24+
# {:dep_from_hexpm, "~> 0.3.0"},
25+
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
26+
]
27+
end
28+
end
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
defmodule SatelliteTest do
2+
use ExUnit.Case
3+
4+
# @tag :pending
5+
test "Empty tree" do
6+
preorder = []
7+
inorder = []
8+
tree = {}
9+
assert Satellite.build_tree(preorder, inorder) == {:ok, tree}
10+
end
11+
12+
@tag :pending
13+
test "Tree with one item" do
14+
preorder = [:a]
15+
inorder = [:a]
16+
tree = {{}, :a, {}}
17+
assert Satellite.build_tree(preorder, inorder) == {:ok, tree}
18+
end
19+
20+
@tag :pending
21+
test "Tree with many items" do
22+
preorder = ~w(a i x f r)a
23+
inorder = ~w(i a f x r)a
24+
tree = {{{}, :i, {}}, :a, {{{}, :f, {}}, :x, {{}, :r, {}}}}
25+
assert Satellite.build_tree(preorder, inorder) == {:ok, tree}
26+
end
27+
28+
@tag :pending
29+
test "Reject traversals of different length" do
30+
preorder = [:a, :b]
31+
inorder = [:b, :a, :r]
32+
error = {:error, "traversals must have the same length"}
33+
assert Satellite.build_tree(preorder, inorder) == error
34+
end
35+
36+
@tag :pending
37+
test "Reject inconsistent traversals of same length" do
38+
preorder = [:x, :y, :z]
39+
inorder = [:a, :b, :c]
40+
error = {:error, "traversals must have the same elements"}
41+
assert Satellite.build_tree(preorder, inorder) == error
42+
end
43+
44+
@tag :pending
45+
test "Reject traversals with repeated items" do
46+
preorder = [:a, :b, :a]
47+
inorder = [:b, :a, :a]
48+
error = {:error, "traversals must contain unique items"}
49+
assert Satellite.build_tree(preorder, inorder) == error
50+
end
51+
end
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ExUnit.start()
2+
ExUnit.configure(exclude: :pending, trace: true)

0 commit comments

Comments
 (0)