Skip to content

Commit 2266b5b

Browse files
committed
adding new exercises
1 parent 7767311 commit 2266b5b

File tree

8 files changed

+291
-5
lines changed

8 files changed

+291
-5
lines changed

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11

22
# Algorithms and Data Structures
33

4-
[![Build Status](https://travis-ci.org/arcuri82/algorithms.svg?branch=master)](https://travis-ci.org/arcuri82/pg4200)
5-
4+
![CI](https://github.com/arcuri82/algorithms/workflows/CI/badge.svg)
65

76
Slides, code examples and exercises (with solutions) for the PG4200 course:
87
Algoritmer og datastrukturer (Algorithms and Data Structures).

docs/exercises/ex02.md

+19-3
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,28 @@ On the other hand, when `index > size()/2` it would be more efficient to start f
4545

4646
Write a `MyBidirectionalLinkedListTest` that extends `MyListTestTemplate`.
4747
If your implementation is correct, all tests should pass.
48-
Run the tests with code coverage enabled, and verify that all of the instructions in your
49-
code are covered. If not, add new tests to `MyBidirectionalLinkedListTest`.
50-
48+
5149

5250

5351
## Part D
52+
53+
Write a new class `MyMiddleBidirectionalLinkedList` that extends `MyList`, using `MyBidirectionalLinkedList` as starting point.
54+
However, besides having a link to the `head` and the `tail` of the list, you need to have a 3rd link, pointing to the `middle` of the list.
55+
When you need to access an element (e.g., with a get), then you need to minimize the number of nodes to traverse.
56+
For example, assume a list with 100 elements, and you need to delete the element at position 40.
57+
Then, the most efficient way would be to start from the `middle` link, and go backwards following the previous links till position 40.
58+
On the other hand, if accessing at position 20, it would be more efficient to start from head and follow the next links.
59+
In other words, all indices in the range 25%-75% of the size of the list should be accessed starting from the `middle` link.
60+
61+
Pay particular attention at the fact that, at each `delete` and `add` operation, the value of `middle` will likely need to be updated.
62+
Note: in case of list with an even number of elements, the middle could have 2 values, choose the lower.
63+
For example: `length=1` and `length=2` would have middle at position `0`, whereas `length=3` and `length=4` would have it at position `1`, `length=5` at `2`, and so on.
64+
65+
Write a `MyMiddleBidirectionalLinkedListTest` that extends `MyListTestTemplate`.
66+
If your implementation is correct, all tests should pass.
67+
68+
69+
## Part E
5470

5571
Study the source code of `MyLinkedList`, `MyStackLinkedList` and `MyQueueArray`.
5672
Once you think you fully understand them, write their implementation

exercises/src/main/java/org/pg4200/ex09/PatternExamples.java

+11
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,15 @@ public interface PatternExamples {
3030
* - a final domain code, which is at least 2 letters (upper or lower case), and no digits
3131
*/
3232
String emailRegex();
33+
34+
/**
35+
* Need match the following sentence:
36+
*
37+
* Is this an out of season april fools joke?
38+
*
39+
* However, the regex should be general enough to also match for further string variants following these properties:
40+
* a) there can be any number of spaces between the words
41+
* b) each letter can be either in lower or upper case
42+
*/
43+
String isItAJoke();
3344
}

exercises/src/test/java/org/pg4200/ex09/PatternExamplesTestTemplate.java

+16
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,20 @@ public void testEmail(){
7777
assertTrue("[email protected]".matches(regex));
7878
assertTrue("[email protected]".matches(regex));
7979
}
80+
81+
@Test
82+
public void testIsItAJoke(){
83+
84+
String regex = getNewInstance().isItAJoke();
85+
86+
assertFalse("".matches(regex));
87+
assertFalse("Is this an out of season april fools jok".matches(regex));
88+
assertFalse("Is this an out of season april fools joke".matches(regex));
89+
assertFalse("a b c d e f g h i?".matches(regex));
90+
assertFalse("i S THIS AN oUT of sEason APRIL FOOLs joKe?".matches(regex));
91+
assertFalse("this Is an out of season april fools joke?".matches(regex));
92+
93+
assertTrue("Is this an out of season april fools joke?".matches(regex));
94+
assertTrue("iS THIS AN oUT of sEason APRIL FOOLs joKe?".matches(regex));
95+
}
8096
}

lessons/src/test/java/org/pg4200/les02/list/MyListTestTemplate.java

+14
Original file line numberDiff line numberDiff line change
@@ -262,4 +262,18 @@ public void testInsertMiddle(){
262262
assertEquals("b", data.get(2));
263263
assertEquals("c", data.get(3));
264264
}
265+
266+
@Test
267+
public void testInsertAndGetMany(){
268+
269+
MyList<Integer> data = getNewInstance(Integer.class);
270+
271+
for(int i=0; i<100; i++){
272+
data.add(i*2);
273+
}
274+
275+
for(int i=0; i<100; i++){
276+
assertEquals(i*2, data.get(i));
277+
}
278+
}
265279
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
package org.pg4200.sol02;
2+
3+
import org.pg4200.les02.list.MyList;
4+
5+
/**
6+
* Created by arcuri82 on 05-Jun-19.
7+
*/
8+
public class MyMiddleBidirectionalLinkedList<T> implements MyList<T> {
9+
10+
/*
11+
Is this better than MyBidirectionalLinkedList?
12+
As usual, it all depends...
13+
The get(i) in the 25%-75% range will be faster, but each add/delete becomes
14+
more expensive, as need to update the middle link
15+
*/
16+
17+
private class ListNode{
18+
T value;
19+
ListNode next;
20+
ListNode previous;
21+
}
22+
23+
private ListNode head;
24+
private ListNode tail;
25+
private ListNode middle;
26+
private int size;
27+
28+
29+
private int expectedIndexOfMiddle(){
30+
if(isEmpty()){
31+
return -1;
32+
}
33+
34+
/*
35+
we do not keep track of the index of middle, as that always
36+
can be inferred by the size of the list
37+
*/
38+
return (int) (Math.ceil(size() / 2.0) - 1);
39+
}
40+
41+
@Override
42+
public void delete(int index) {
43+
44+
if(index < 0 || index >= size()){
45+
throw new IndexOutOfBoundsException();
46+
}
47+
48+
if(index == 0){
49+
if(head.next != null){
50+
head = head.next;
51+
head.previous = null;
52+
} else {
53+
head = null;
54+
tail = null;
55+
}
56+
} else if(index == (size-1)){
57+
58+
tail.previous.next = null;
59+
tail = tail.previous;
60+
61+
} else {
62+
63+
ListNode target = getNode(index);
64+
65+
target.previous.next = target.next;
66+
target.next.previous = target.previous;
67+
}
68+
69+
int previous = expectedIndexOfMiddle();
70+
if(index <= previous){
71+
previous--;
72+
}
73+
size--;
74+
updateMiddle(previous);
75+
}
76+
77+
private void updateMiddle(int previousIndex){
78+
79+
int current = expectedIndexOfMiddle();
80+
if(current == previousIndex){
81+
//nothing to do
82+
return;
83+
}
84+
85+
if(previousIndex < 0){
86+
//from empty to 1 element
87+
assert size() == 1;
88+
middle = head;
89+
} else if(current < 0){
90+
//from 1 element to empty
91+
assert size() == 0;
92+
middle = null;
93+
} else if(current < previousIndex){
94+
//move backwards
95+
middle = middle.previous;
96+
} else {
97+
//move forward
98+
middle = middle.next;
99+
}
100+
}
101+
102+
private ListNode getNode(int index){
103+
104+
if(index < 0 || index >= size()){
105+
throw new IndexOutOfBoundsException();
106+
}
107+
108+
ListNode current = null;
109+
int counter = -1;
110+
boolean forwards = false;
111+
112+
if(index <= size() * 0.25){
113+
//start from head
114+
current = head;
115+
counter = 0;
116+
forwards = true;
117+
118+
} else if(index > size() * 0.25 && index < size() * 0.75){
119+
//from middle, either backwards or forwards
120+
current = middle;
121+
counter = expectedIndexOfMiddle();
122+
forwards = index >= size() * 0.5;
123+
124+
} else {
125+
//start from tail
126+
current = tail;
127+
counter = size -1;
128+
forwards = false;
129+
}
130+
131+
if(forwards){
132+
while(counter <= index){
133+
134+
if(counter == index){
135+
return current;
136+
}
137+
138+
current = current.next;
139+
counter++;
140+
}
141+
} else {
142+
//backward
143+
while(counter >= index){
144+
145+
if(counter == index){
146+
return current;
147+
}
148+
149+
current = current.previous;
150+
counter--;
151+
}
152+
}
153+
154+
assert false;
155+
return null;
156+
}
157+
158+
@Override
159+
public T get(int index) {
160+
return getNode(index).value;
161+
}
162+
163+
@Override
164+
public void add(int index, T value) {
165+
166+
if(index < 0 || index > size){
167+
throw new IndexOutOfBoundsException();
168+
}
169+
170+
ListNode node = new ListNode();
171+
node.value = value;
172+
173+
if(head == null){
174+
head = node;
175+
tail = node;
176+
177+
} else if(index == 0){
178+
head.previous = node;
179+
node.next = head;
180+
head = node;
181+
182+
} else if(index == size) {
183+
tail.next = node;
184+
node.previous = tail;
185+
tail = node;
186+
187+
} else {
188+
189+
ListNode target = getNode(index);
190+
ListNode beforeTarget = target.previous;
191+
192+
beforeTarget.next = node;
193+
node.previous = beforeTarget;
194+
195+
node.next = target;
196+
target.previous = node;
197+
}
198+
199+
int previous = expectedIndexOfMiddle();
200+
if(index <= previous){
201+
previous++;
202+
}
203+
size++;
204+
updateMiddle(previous);
205+
}
206+
207+
@Override
208+
public int size() {
209+
return size;
210+
}
211+
}

solutions/src/main/java/org/pg4200/sol09/PatternExamplesImp.java

+5
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,9 @@ public String telephoneNumberRegex() {
2222
public String emailRegex() {
2323
return "[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})";
2424
}
25+
26+
@Override
27+
public String isItAJoke() {
28+
return "[iI][sS] +[tT][hH][iI][sS] +[aA][nN] +[oO][uU][tT] +[oO][fF] +[sS][eE][aA][sS][oO][nN] +[aA][pP][rR][iI][lL] +[fF][oO][oO][lL][sS] +[jJ][oO][kK][eE]\\?";
29+
}
2530
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.pg4200.sol02;
2+
3+
import org.pg4200.les02.list.MyList;
4+
import org.pg4200.les02.list.MyListTestTemplate;
5+
6+
import static org.junit.jupiter.api.Assertions.*;
7+
8+
class MyMiddleBidirectionalLinkedListTest extends MyListTestTemplate {
9+
10+
@Override
11+
protected <T> MyList<T> getNewInstance(Class<T> klass) {
12+
return new MyMiddleBidirectionalLinkedList<>();
13+
}
14+
}

0 commit comments

Comments
 (0)