Commit 80c1016f authored by Christophe Rhodes's avatar Christophe Rhodes

updates to 06

parent 4e53933d
#+TITLE: Algorithms & Data Structures: Lab 06
#+SUBTITLE: week of 12th November 2018
#+include: ../labsheet.org
* Setup
** Saving your work from last week
As with previous weeks, you will use =git= to download a bundle of
lab code. You might have made modifications in your downloaded
copy; if you have not already done so, you need to save those
modifications. First examine the changes present in your
downloaded copy by issuing the following commands from the labs
directory:
#+begin_example
git status
git diff
#+end_example
and if you are satisfied with the changes, store them in the git
version control system by doing
#+begin_example
git commit -a
#+end_example
and writing a suitable commit message
** Downloading this week's distribution
Once you have successfully saved your changes from last week, you
can get my updates by doing
#+begin_example
git pull
#+end_example
which /should/ automatically merge in new content. After the =git
pull= command, you should have a new directory containing this
week's material (named =05/=) alongside the existing directories.
* Linked lists (cont'd)
** Sublist
By adding to your existing ~SLList~ class from lab 04, implement a
~sublist~ method such that ~sublist(int start, int end)~ returns a
fresh list whose contents are the elements in positions between
~start~ (inclusive) and ~end~ (exclusive). You may assume that
~start~ is less than or equal to ~end~, and that ~end~ is less than
or equal to the length of the list.
For example, if ~x~ represents the three-element list ~(7, 9, 14)~,
~x.sublist(1,2)~ should return a fresh list ~(9)~ and
~x.sublist(2,2)~ should return ~NIL~.
** Merge
By adding to your existing ~SLList~ class from lab 04, implement a
~merge~ method such that ~merge(SLlist b)~ returns the result of
merging (in order) the contents of ~this~ with ~b~. You may assume
that the contents of ~this~ and ~b~ are already sorted in ascending
order.
** Merge sort
By adding to your existing ~SLList~ class, implement a ~mergesort~
method such that ~mergesort()~ returns a list of the sorted
contents.
If you divide the list as evenly as possible into two parts, how
many calls to ~mergesort()~ will there be for a list of length 8?
Of length 9? Of length 15?
Write down the recurrence relation for the number of calls to
~mergesort~ required to sort a list of length $N$. Do not forget
to include the first call to ~mergesort~.
Copy the following table into a spreadsheet (or similar document)
and fill in the blanks for the number of calls to ~mergesort~
required to complete the sorting operation. Check that your
answers are consistent with your recurrence relation. What is the
solution to the recurrence relation? (Use the master theorem).
| length | calls |
|--------+-------|
| 1 | 1 |
| 2 | 3 |
| 3 | |
| 4 | |
| 7 | |
| 8 | |
| 9 | |
| 15 | |
| 16 | |
| 32 | |
* Stacks and Queues
I have provided you with an implementation of stacks and queues,
based on the basic operations ~SLList~ class. Make sure that you
have implemented those four basic operations correctly, and read my
implementations of the data structures. What is the complexity of
the implementation of the ~enqueue~ and ~dequeue~ queue methods?
The ~StackQueue~ program prints some of the contents of a stack and
a queue, which are initialised and populated by ~prepare~. Write
code in ~prepare~ so that running the program (which you can do
using ~make sq~) prints your 8-digit student number and exits
without error.
* Submission
Submit your work for this lab to the [[https://learn.gold.ac.uk/mod/lti/view.php?id=613661][lab submission area]] on the
[[https://learn.gold.ac.uk/course/view.php?id=11491][module learn.gold page]]. The submission area will close at *16:00*
on *16th November 2018*.
include ../../cpp.mk
SLListTest: CPPFLAGS += -I ../../04/cpp
SLListTest: ../../04/cpp/SLList.o ../../00/cpp/RunTests.o SublistTest.o MergeTest.o MergesortTest.o
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@
test: SLListTest
./SLListTest
all: SLListTest
StackQueue: CPPFLAGS += -I ../../04/cpp
StackQueue: ../../04/cpp/SLList.o Stack.o Queue.o StackQueue.o
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@
sq: StackQueue
./StackQueue
.PHONY: test all
#include <cppunit/extensions/HelperMacros.h>
#include "SLList.hpp"
class MergeTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(MergeTest);
CPPUNIT_TEST(testMergeNILNIL);
CPPUNIT_TEST(testMergeNIL);
CPPUNIT_TEST(testNontrivialMerge);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() { };
void tearDown() { };
void testMergeNILNIL();
void testMergeNIL();
void testNontrivialMerge();
};
void MergeTest::testMergeNILNIL() {
SLList *r = SLList::NIL->merge(SLList::NIL);
CPPUNIT_ASSERT_EQUAL_MESSAGE("NIL merged with NIL should be NIL", SLList::NIL, r);
}
void MergeTest::testMergeNIL() {
SLList *r = SLList::NIL->merge(new SLList(10, SLList::NIL));
CPPUNIT_ASSERT_EQUAL_MESSAGE("Merging NIL with x should give x", 10, r->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Merging NIL with x should give x", SLList::NIL, r->rest());
SLList *r2 = (new SLList(20, SLList::NIL))->merge(SLList::NIL);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Merging NIL with x should give x", 20, r2->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("Merging NIL with x should give x", SLList::NIL, r2->rest());
}
void MergeTest::testNontrivialMerge() {
SLList *l1 = new SLList(4, new SLList(17, SLList::NIL));
SLList *l2 = new SLList(5, new SLList(29, SLList::NIL));
SLList *r11 = l1->merge(l1);
SLList *r12 = l1->merge(l2);
SLList *r21 = l2->merge(l1);
SLList *r22 = l2->merge(l2);
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (4 4 17 17)", 4, r11->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (4 4 17 17)", 4, r11->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (4 4 17 17)", 17, r11->rest()->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (4 4 17 17)", 17, r11->rest()->rest()->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (4 5 17 29)", 4, r12->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (4 5 17 29)", 5, r12->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (4 5 17 29)", 17, r12->rest()->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (4 5 17 29)", 29, r12->rest()->rest()->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (4 5 17 29)", 4, r21->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (4 5 17 29)", 5, r21->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (4 5 17 29)", 17, r21->rest()->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (4 5 17 29)", 29, r21->rest()->rest()->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (5 5 29 29)", 5, r22->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (5 5 29 29)", 5, r22->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (5 5 29 29)", 29, r22->rest()->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (5 5 29 29)", 29, r22->rest()->rest()->rest()->first());
}
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(MergeTest, "Merge");
CPPUNIT_REGISTRY_ADD_TO_DEFAULT("Merge");
#include <cppunit/extensions/HelperMacros.h>
#include "SLList.hpp"
class MergesortTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(MergesortTest);
CPPUNIT_TEST(testMergesortNIL);
CPPUNIT_TEST(testMergesortOne);
CPPUNIT_TEST(testNontrivialMergesort);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() { };
void tearDown() { };
void testMergesortNIL();
void testMergesortOne();
void testNontrivialMergesort();
};
void MergesortTest::testMergesortNIL() {
SLList *r = SLList::NIL->mergesort();
CPPUNIT_ASSERT_EQUAL_MESSAGE("mergesort of NIL should be NIL", SLList::NIL, r);
}
void MergesortTest::testMergesortOne() {
SLList *r = (new SLList(82, SLList::NIL))->mergesort();
CPPUNIT_ASSERT_EQUAL_MESSAGE("mergesort of (82) should be (82)", 82, r->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("mergesort of (82) should be (82)", SLList::NIL, r->rest());
}
void MergesortTest::testNontrivialMergesort() {
SLList *l = new SLList(2, new SLList(32, new SLList(8, new SLList(64, new SLList(1, SLList::NIL)))));
SLList *r = l->mergesort();
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (1 2 8 32 64)", 1, r->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (1 2 8 32 64)", 2, r->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (1 2 8 32 64)", 8, r->rest()->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (1 2 8 32 64)", 32, r->rest()->rest()->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("expected: (1 2 8 32 64)", 64, r->rest()->rest()->rest()->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("original: (2 32 8 64 1)", 2, l->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("original: (2 32 8 64 1)", 32, l->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("original: (2 32 8 64 1)", 8, l->rest()->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("original: (2 32 8 64 1)", 64, l->rest()->rest()->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("original: (2 32 8 64 1)", 1, l->rest()->rest()->rest()->rest()->first());
}
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(MergesortTest, "Mergesort");
CPPUNIT_REGISTRY_ADD_TO_DEFAULT("Mergesort");
#include "SLList.hpp"
#include "Queue.hpp"
using namespace std;
void Queue::enqueue(int o) {
if (tail == SLList::NIL) {
tail = new SLList(o, tail);
hd = tail;
} else {
tail->setRest(new SLList(o, SLList::NIL));
tail = tail->rest();
}
}
int Queue::dequeue() {
int r = hd->first();
SLList *newhd = hd->rest();
delete hd;
hd = newhd;
if (hd == SLList::NIL) {
tail = SLList::NIL;
}
return r;
}
int Queue::head() {
return hd->first();
}
bool Queue::empty() {
return hd == SLList::NIL;
}
#ifndef QUEUE_HPP
#define QUEUE_HPP
#include "SLList.hpp"
class Queue {
private:
SLList *hd = SLList::NIL;
SLList *tail = SLList::NIL;
public:
Queue() { };
void enqueue(int o);
int dequeue();
int head();
bool empty();
};
#endif
#include "SLList.hpp"
#include "Stack.hpp"
using namespace std;
void Stack::push(int o) {
head = new SLList(o, head);
}
int Stack::pop() {
int r = head->first();
SLList *newhead = head->rest();
delete head;
head = newhead;
return r;
}
int Stack::top() {
return head->first();
}
bool Stack::empty() {
return head == SLList::NIL;
}
#ifndef STACK_HPP
#define STACK_HPP
#include "SLList.hpp"
class Stack {
private:
SLList *head = SLList::NIL;
public:
Stack() { };
void push(int o);
int pop();
int top();
bool empty();
};
#endif
#include <iostream>
#include "Stack.hpp"
#include "Queue.hpp"
using namespace std;
static Stack *s;
static Queue *q;
void prepare() {
}
int main(int argc, char *argv[]) {
prepare();
cout << q->dequeue();
cout << s->pop();
cout << s->pop();
cout << q->dequeue();
s->pop();
q->dequeue();
cout << s->pop();
cout << q->dequeue();
cout << s->pop();
cout << q->dequeue() << endl;
s->pop();
q->dequeue();
}
#include <cppunit/extensions/HelperMacros.h>
#include "SLList.hpp"
class SublistTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(SublistTest);
CPPUNIT_TEST(testSublistOfNIL);
CPPUNIT_TEST(testEmptySublist);
CPPUNIT_TEST(testNonemptySublist);
CPPUNIT_TEST_SUITE_END();
private:
SLList *n, *ncirc;
public:
void setUp() {
n = new SLList(96, new SLList(172, new SLList(3, SLList::NIL)));
ncirc = new SLList(4, new SLList(17, SLList::NIL));
ncirc->rest()->setRest(ncirc);
};
void tearDown() {
/* in principle delete the SLLists */
};
void testSublistOfNIL();
void testEmptySublist();
void testNonemptySublist();
};
void SublistTest::testSublistOfNIL() {
SLList *r = SLList::NIL->sublist(0, 0);
CPPUNIT_ASSERT_EQUAL_MESSAGE("The sublist of NIL starting at 0 and ending at 0 should be NIL", SLList::NIL, r);
}
void SublistTest::testEmptySublist() {
SLList *r = n->sublist(0,0);
CPPUNIT_ASSERT_EQUAL_MESSAGE("The sublist of a list starting at 0 and ending at 0 should be NIL", SLList::NIL, r);
SLList *r2 = n->sublist(1,1);
CPPUNIT_ASSERT_EQUAL_MESSAGE("The sublist of a non-empty list starting at 1 and ending at 1 should be NIL", SLList::NIL, r2);
}
void SublistTest::testNonemptySublist() {
SLList *r = n->sublist(0,1);
CPPUNIT_ASSERT_MESSAGE("The list returned from sublist with start 0 and end 1 should not be NIL", SLList::NIL != r);
CPPUNIT_ASSERT_EQUAL_MESSAGE("The first element of the sublist with start 0 and end 1 should be 96", 96, r->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("The list returned from sublist with start 0 and end 1 should have length 1.", SLList::NIL, r->rest());
SLList *r2 = n->sublist(1,2);
CPPUNIT_ASSERT_MESSAGE("The list returned from sublist with start 1 and end 2 should not be NIL", SLList::NIL != r);
CPPUNIT_ASSERT_EQUAL_MESSAGE("The first element of the sublist with start 1 and end 2 should be 172", 172, r2->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("The list returned from sublist with start 1 and end 2 should have length 1.", SLList::NIL, r2->rest());
SLList *r3 = n->sublist(1,3);
CPPUNIT_ASSERT_MESSAGE("The list returned from sublist with start 1 and end 3 should not be NIL", SLList::NIL != r3);
CPPUNIT_ASSERT_EQUAL_MESSAGE("The first element of the sublist with start 1 and end 3 should be 172", 172, r3->first());
CPPUNIT_ASSERT_MESSAGE("The list returned from sublist with start 1 and end 3 should have length 2.", SLList::NIL != r3->rest());
CPPUNIT_ASSERT_EQUAL_MESSAGE("The second element of the sublist with start 1 and end 3 should be 3", 3, r3->rest()->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("The list returned from sublist with start 1 and end 3 should have length 2.", SLList::NIL, r3->rest()->rest());
SLList *r4 = ncirc->sublist(10,11);
CPPUNIT_ASSERT_EQUAL_MESSAGE("The sublist with start 10 and end 11 should be (4)", 4, r4->first());
CPPUNIT_ASSERT_EQUAL_MESSAGE("The sublist with start 10 and end 11 should be (4)", SLList::NIL, r4->rest());
}
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(SublistTest, "Sublist");
CPPUNIT_REGISTRY_ADD_TO_DEFAULT("Sublist");
include ../../java.mk
TESTCLASSFILES = SublistTest.class MergeTest.class MergesortTest.class
CLASSFILES = ../../04/java/SLList.class $(TESTCLASSFILES)
CLASSPATHS += ../../04/java
all: $(CLASSFILES)
test: all
(((($(JAVA) $(CP) $(CLASSPATH) org.junit.runner.JUnitCore $(subst .class,,$(TESTCLASSFILES)); echo $$? >&3) | egrep -v \(org.junit\|sun.reflect\|java.lang.reflect\) >&4) 3>&1) | (read xs; exit $$xs)) 4>&1
clean:
-rm -f $(TESTCLASSFILES) test.xml
sq: Stack.class Queue.class StackQueue.class
$(JAVA) $(CP) $(CLASSPATH) StackQueue
.PHONY: test all clean
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import org.junit.Test;
import org.junit.Before;
public class MergeTest {
@Test
public void testMergeNILNIL() {
SLList r = SLList.NIL.merge(SLList.NIL);
assertEquals("NIL merged with NIL should be NIL", SLList.NIL, r);
}
@Test
public void testMergeNIL() {
SLList r = SLList.NIL.merge(new SLList(10, SLList.NIL));
assertEquals("Merging NIL with x should give x", 10, r.first());
assertEquals("Merging NIL with x should give x", SLList.NIL, r.rest());
SLList r2 = new SLList(20, SLList.NIL).merge(SLList.NIL);
assertEquals("Merging x with NIL should give x", 20, r2.first());
assertEquals("Merging x with NIL should give x", SLList.NIL, r2.rest());
}
@Test
public void testNontrivialMerge() {
SLList l1 = new SLList(4, new SLList(17, SLList.NIL));
SLList l2 = new SLList(5, new SLList(29, SLList.NIL));
SLList r11 = l1.merge(l1);
SLList r12 = l1.merge(l2);
SLList r21 = l2.merge(l1);
SLList r22 = l2.merge(l2);
assertEquals("expected: (4 4 17 17)", 4, r11.first());
assertEquals("expected: (4 4 17 17)", 4, r11.rest().first());
assertEquals("expected: (4 4 17 17)", 17, r11.rest().rest().first());
assertEquals("expected: (4 4 17 17)", 17, r11.rest().rest().rest().first());
assertEquals("expected: (4 5 17 29)", 4, r12.first());
assertEquals("expected: (4 5 17 29)", 5, r12.rest().first());
assertEquals("expected: (4 5 17 29)", 17, r12.rest().rest().first());
assertEquals("expected: (4 5 17 29)", 29, r12.rest().rest().rest().first());
assertEquals("expected: (4 5 17 29)", 4, r21.first());
assertEquals("expected: (4 5 17 29)", 5, r21.rest().first());
assertEquals("expected: (4 5 17 29)", 17, r21.rest().rest().first());
assertEquals("expected: (4 5 17 29)", 29, r21.rest().rest().rest().first());
assertEquals("expected: (5 5 29 29)", 5, r22.first());
assertEquals("expected: (5 5 29 29)", 5, r22.rest().first());
assertEquals("expected: (5 5 29 29)", 29, r22.rest().rest().first());
assertEquals("expected: (5 5 29 29)", 29, r22.rest().rest().rest().first());
}
}
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import org.junit.Test;
import org.junit.Before;
public class MergesortTest {
@Test
public void testMergesortNIL() {
SLList r = SLList.NIL.mergesort();
assertEquals("mergesort of NIL should be NIL", SLList.NIL, r);
}
@Test
public void testMergesortOne() {
SLList r = new SLList(82, SLList.NIL).mergesort();
assertEquals("mergesort of (82) should be (82)", 82, r.first());
assertEquals("mergesort of (82) should be (82)", SLList.NIL, r.rest());
}
@Test
public void testNontrivialMergesort() {
SLList l = new SLList(2, new SLList(32, new SLList(8, new SLList(64, new SLList(1, SLList.NIL)))));
SLList r = l.mergesort();
assertEquals("expected: (1 2 8 32 64)", 1, r.first());
assertEquals("expected: (1 2 8 32 64)", 2, r.rest().first());
assertEquals("expected: (1 2 8 32 64)", 8, r.rest().rest().first());
assertEquals("expected: (1 2 8 32 64)", 32, r.rest().rest().rest().first());
assertEquals("expected: (1 2 8 32 64)", 64, r.rest().rest().rest().rest().first());
assertEquals("original: (2 32 8 64 1)", 2, l.first());
assertEquals("original: (2 32 8 64 1)", 32, l.rest().first());
assertEquals("original: (2 32 8 64 1)", 8, l.rest().rest().first());
assertEquals("original: (2 32 8 64 1)", 64, l.rest().rest().rest().first());
assertEquals("original: (2 32 8 64 1)", 1, l.rest().rest().rest().rest().first());
}
}
public class Queue {
private SLList head = SLList.NIL;
private SLList tail = SLList.NIL;
public Queue() { }
public void enqueue(Object o) {
if (tail == SLList.NIL) {
tail = new SLList(o, tail);
head = tail;
} else {
tail.setRest(new SLList(o, SLList.NIL));
tail = tail.rest();
}
}
public Object dequeue() {
Object r = head.first();
head = head.rest();
if (head == SLList.NIL) {
tail = SLList.NIL;
}
return r;
}
public Object head() {
return head.first();
}
public boolean empty() {
return head == SLList.NIL;
}
}
public class Stack {
private SLList head = SLList.NIL;
public Stack() { }
public void push(Object o) {
head = new SLList(o, head);
}
public Object pop() {
Object r = head.first();
head = head.rest();
return r;
}
public Object top() {
return head.first();
}
public boolean empty() {
return head == SLList.NIL;
}
}
public class StackQueue {
private static Stack s;
private static Queue q;
public static void main(String[] args) {
prepare();
System.out.print(q.dequeue());
System.out.print(s.pop());
System.out.print(s.pop());
System.out.print(q.dequeue());
s.pop();
q.dequeue();
System.out.print(s.pop());
System.out.print(q.dequeue());
System.out.print(s.pop());
System.out.println(q.dequeue());
s.pop();
q.dequeue();
}
private static void prepare() {
}
}
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import org.junit.Test;
import org.junit.Before;
public class SublistTest {
private SLList n;
private SLList ncirc;
@Test
public void testSublistOfNIL() {
SLList r = SLList.NIL.sublist(0, 0);
assertEquals("The sublist of NIL starting at 0 and ending at 0 should be NIL", SLList.NIL, r);
}
@Test
public void testEmptySublist() {
SLList r = n.sublist(0,0);
assertEquals("The sublist of a list starting at 0 and ending at 0 should be NIL", SLList.NIL, r);
SLList r2 = n.sublist(1,1);
assertEquals("The sublist of a non-empty list starting at 1 and ending at 1 should be NIL", SLList.NIL, r2);
}
@Test
public void testNonemptySublist() {
SLList r = n.sublist(0,1);
assertNotEquals("The list returned from sublist with start 0 and end 1 should not be NIL", SLList.NIL, r);
assertEquals("The first element of the sublist with start 0 and end 1 should be 96", 96, r.first());
assertEquals("The list returned from sublist with start 0 and end 1 should have length 1.", SLList.NIL, r.rest());
SLList r2 = n.sublist