Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,14 @@
"prerequisites": [],
"difficulty": 5
},
{
"slug": "linked-list",
"name": "Linked List",
"uuid": "c9a57acf-9f9f-4973-b22e-252bdef18ed1",
"practices": [],
"prerequisites": [],
"difficulty": 5
},
{
"slug": "nth-prime",
"name": "Nth Prime",
Expand Down
26 changes: 26 additions & 0 deletions exercises/practice/linked-list/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Instructions

Your team has decided to use a doubly linked list to represent each train route in the schedule.
Each station along the train's route will be represented by a node in the linked list.

You don't need to worry about arrival and departure times at the stations.
Each station will simply be represented by a number.

Routes can be extended, adding stations to the beginning or end of a route.
They can also be shortened by removing stations from the beginning or the end of a route.

Sometimes a station gets closed down, and in that case the station needs to be removed from the route, even if it is not at the beginning or end of the route.

The size of a route is measured not by how far the train travels, but by how many stations it stops at.

~~~~exercism/note
The linked list is a fundamental data structure in computer science, often used in the implementation of other data structures.
As the name suggests, it is a list of nodes that are linked together.
It is a list of "nodes", where each node links to its neighbor or neighbors.
In a **singly linked list** each node links only to the node that follows it.
In a **doubly linked list** each node links to both the node that comes before, as well as the node that comes after.

If you want to dig deeper into linked lists, check out [this article][intro-linked-list] that explains it using nice drawings.

[intro-linked-list]: https://medium.com/basecs/whats-a-linked-list-anyway-part-1-d8b7e6508b9d
~~~~
6 changes: 6 additions & 0 deletions exercises/practice/linked-list/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Introduction

You are working on a project to develop a train scheduling system for a busy railway network.

You've been asked to develop a prototype for the train routes in the scheduling system.
Each route consists of a sequence of train stations that a given train stops at.
21 changes: 21 additions & 0 deletions exercises/practice/linked-list/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"authors": [
"IsaacG"
],
"files": {
"solution": [
"linked_list.gd"
],
"test": [
"linked_list_test.gd",
"run_tests",
"lib/test_runner.gd",
"project.godot"
],
"example": [
".meta/example.gd"
]
},
"blurb": "Implement a doubly linked list.",
"source": "Classic computer science topic"
}
73 changes: 73 additions & 0 deletions exercises/practice/linked-list/.meta/example.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
class ListNode:

var _prev = null
var _next = null
var _val = null

func _init(value):
_val = value

func add_prev(value):
var new = ListNode.new(value)
link(_prev, new, self)
return new

func add_next(value):
var new = ListNode.new(value)
link(self, new, _next)
return new

func link(a, b, c):
a._next = b
b._next = c
c._prev = b
b._prev = a

func remove():
_next._prev = _prev
_prev._next = _next
return _val


class LinkedList:

var _head = null
var _tail = null
var _len = 0

func _init():
_head = ListNode.new(null)
_tail = ListNode.new(null)
_head._next = _tail
_tail._prev = _head

func push(value):
_tail.add_prev(value)
_len += 1

func unshift(value):
_head.add_next(value)
_len += 1

func delete(value):
var cur = _head._next
while cur != _tail and cur._val != value:
cur = cur._next
if cur._val != value:
return
cur.remove()
_len -= 1

func remove(node):
var val = node.remove()
_len -= 1
return val

func pop():
return remove(_tail._prev)

func shift():
return remove(_head._next)

func count():
return _len
26 changes: 26 additions & 0 deletions exercises/practice/linked-list/.meta/template.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{% for case in cases %}
func test_{{ case.func_name }}(solution_script):
var linked_list = solution_script.LinkedList.new()
var res = 0
{% for op in case.input.operations %}
{%- if op.operation == "count" %}
res = linked_list.count()
if res != {{ op.expected }}:
return [false, "count() = %d; expected %d" % [res, {{ op.expected }}]]
{%- elif (op.operation == "pop" or op.operation == "shift") and "expected" in op %}
res = linked_list.{{ op.operation }}()
if res != {{ op.expected }}:
return [false, "{{ op.operation }}() = %d; expected %d" % [res, {{ op.expected }}]]
{%- elif op.operation == "pop" or op.operation == "shift" %}
linked_list.{{ op.operation }}()
{%- elif op.operation == "push" or op.operation == "unshift" %}
linked_list.{{ op.operation }}({{ op.value }})
{%- elif op.operation == "delete" %}
linked_list.{{ op.operation }}({{ op.value }})
{%- else %}
{{ "Invalid op" | raise_error }}
{%- endif %}
{% endfor %}
return [true, true]

{% endfor %}
67 changes: 67 additions & 0 deletions exercises/practice/linked-list/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[7f7e3987-b954-41b8-8084-99beca08752c]
description = "pop gets element from the list"

[c3f67e5d-cfa2-4c3e-a18f-7ce999c3c885]
description = "push/pop respectively add/remove at the end of the list"

[00ea24ce-4f5c-4432-abb4-cc6e85462657]
description = "shift gets an element from the list"

[37962ee0-3324-4a29-b588-5a4c861e6564]
description = "shift gets first element from the list"

[30a3586b-e9dc-43fb-9a73-2770cec2c718]
description = "unshift adds element at start of the list"

[042f71e4-a8a7-4cf0-8953-7e4f3a21c42d]
description = "pop, push, shift, and unshift can be used in any order"

[88f65c0c-4532-4093-8295-2384fb2f37df]
description = "count an empty list"

[fc055689-5cbe-4cd9-b994-02e2abbb40a5]
description = "count a list with items"

[8272cef5-130d-40ea-b7f6-5ffd0790d650]
description = "count is correct after mutation"

[229b8f7a-bd8a-4798-b64f-0dc0bb356d95]
description = "popping to empty doesn't break the list"

[4e1948b4-514e-424b-a3cf-a1ebbfa2d1ad]
description = "shifting to empty doesn't break the list"

[e8f7c600-d597-4f79-949d-8ad8bae895a6]
description = "deletes the only element"

[fd65e422-51f3-45c0-9fd0-c33da638f89b]
description = "deletes the element with the specified value from the list"

[59db191a-b17f-4ab7-9c5c-60711ec1d013]
description = "deletes the element with the specified value from the list, re-assigns tail"

[58242222-5d39-415b-951d-8128247f8993]
description = "deletes the element with the specified value from the list, re-assigns head"

[ee3729ee-3405-4bd2-9bad-de0d4aa5d647]
description = "deletes the first of two elements"

[47e3b3b4-b82c-4c23-8c1a-ceb9b17cb9fb]
description = "deletes the second of two elements"

[7b420958-f285-4922-b8f9-10d9dcab5179]
description = "delete does not modify the list if the element is not found"

[7e04828f-6082-44e3-a059-201c63252a76]
description = "deletes only the first occurrence"
Loading
Loading