Commit 11c8af80 authored by Christophe Rhodes's avatar Christophe Rhodes
Browse files

updates to 06 07 08

parent 7eb1deda
#+TITLE: Algorithms & Data Structures: Lab 08
#+SUBTITLE: week of 26th November 2018
#+include: ../labsheet.org
* Setup
** Saving your work from last week
As with all previous weeks, you will use =git= to download a bundle
of lab code. You will probably 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 =08/=) alongside the existing directories.
* Hash tables
** Data structure
Implement a hash table, using \[ h_{a,c,m}(x) = (ax + c) \bmod m \]
as the hash and reduction function. The client of the hash table
will specify the parameters $a$ and $c$, and the capacity of the
storage table $m$. You *must* keep the ~buckets~ member variable
~public~ and use values of the hash function $h$ as indexes into
that array; in a real implementation ~buckets~ would be declared as
~private~, but it needs to be exposed for testing purposes. (You
may of course add other ~private~ member variables).
** Basic operations
Implement the ~insert~ and ~find~ operations, for *strictly
positive* (/i.e./ non-zero and non-negative) keys. Collision
resolution for this hash table implementation uses linear probing:
if a hash bucket is occupied on insert, move on to the next one
until there is an unoccupied one to store the key in.
Also, implement the ~loadFactor~ function, which should return as a
float the fraction of total hash buckets that are occupied.
Once these three methods are correctly implemented, the tests
distributed along with the lab bundle should pass.
** Further work
As it stands, your implementation of a hash table is incomplete
compared with a fully-functional one:
- it doesn't support ~delete~;
- it has a fixed capacity, rather than being able to expand beyond
its initial size;
- its collision resolution strategy is not best-of-breed.
Extend your implementation to rectify these or other problems. Be
aware that for the upcoming submission of this work, you will need
to be able to support the basic operations above precisely; any
work that you do here (including adapting the collision resolution
strategy) must not detract from being able to support ~find~,
~loadFactor~ and ~insert~ with a simple linear probing collision
strategy.
* List visualiser
** Submission
You must submit your =ListVisualiser= source code, along with any
auxiliary files it needs to build (/e.g./ a header file) but *not*
your =SLList= implementation, to the [[https://learn.gold.ac.uk/mod/workshop/view.php?id=613717][List Visualiser Activity on
learn.gold]] by *16:00* on *Friday 30th November*.
You should include in your submission, which can be a ZIP file, any
instructions for compilation or use of your code which would be
helpful to another member of the class, as they will need to be
able to compile and use your code in order to assess it and provide
you with feedback.
Failure to submit your source code will lead to an *automatic mark
of zero* for both the submission *and* the assessment portion of
this activity. There *no extensions* to the deadline of 16:00 on
Friday 30th November.
#include "HashTable.hpp"
HashTable::HashTable(long _a, long _c, long _m) {
}
HashTable::~HashTable() {
}
void HashTable::insert(int key) {
}
bool HashTable::find(int key) {
return false;
}
double HashTable::loadFactor() {
return 0.0;
}
#ifndef HASHTABLE_HPP
#define HASHTABLE_HPP
class HashTable {
public: // for testing purposes
int *buckets = 0;
public:
HashTable(long, long, long);
~HashTable();
void insert(int);
bool find(int);
double loadFactor();
};
#endif
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include "HashTable.hpp"
class HashTableFindTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(HashTableFindTest);
CPPUNIT_TEST(testFindOne);
CPPUNIT_TEST(testFindCollision);
CPPUNIT_TEST(testFindSequence);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() { };
void tearDown() { };
void testFindOne();
void testFindCollision();
void testFindSequence();
};
void HashTableFindTest::testFindOne() {
HashTable t = HashTable(29, 35, 256);
CPPUNIT_ASSERT_MESSAGE("buckets array is null", t.buckets != NULL);
t.insert(1);
CPPUNIT_ASSERT_MESSAGE("key 1 not found", t.find(1));
}
void HashTableFindTest::testFindCollision() {
HashTable t = HashTable(29, 35, 256);
CPPUNIT_ASSERT_MESSAGE("buckets array is null", t.buckets != NULL);
t.insert(1);
t.insert(257);
CPPUNIT_ASSERT_MESSAGE("key 1 not found", t.find(1));
CPPUNIT_ASSERT_MESSAGE("key 257 not found", t.find(257));
CPPUNIT_ASSERT_MESSAGE("key 513 found", !t.find(513));
}
void HashTableFindTest::testFindSequence() {
HashTable t = HashTable(29, 35, 256);
CPPUNIT_ASSERT_MESSAGE("buckets array is null", t.buckets != NULL);
int z[] = {64, 99, 90, 85, 196, 87, 254, 233, 136, 139};
for (int i = 0; i < 9; i++) {
t.insert(z[i]);
CPPUNIT_ASSERT_MESSAGE("key not found", t.find(z[i]));
}
}
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(HashTableFindTest, "Find");
CPPUNIT_REGISTRY_ADD_TO_DEFAULT("Find");
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include "HashTable.hpp"
class HashTableInsertTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(HashTableInsertTest);
CPPUNIT_TEST(testInsertOne);
CPPUNIT_TEST(testInsertCollision);
CPPUNIT_TEST(testInsertSequence);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() { };
void tearDown() { };
void testInsertOne();
void testInsertCollision();
void testInsertSequence();
};
void HashTableInsertTest::testInsertOne() {
HashTable t = HashTable(29, 35, 256);
CPPUNIT_ASSERT_MESSAGE("buckets array is null", t.buckets != NULL);
t.insert(1);
CPPUNIT_ASSERT_EQUAL_MESSAGE("key 1 not found in bucket 64", 1, t.buckets[64]);
}
void HashTableInsertTest::testInsertCollision() {
HashTable t = HashTable(29, 35, 256);
CPPUNIT_ASSERT_MESSAGE("buckets array is null", t.buckets != NULL);
t.insert(1);
t.insert(257);
CPPUNIT_ASSERT_EQUAL_MESSAGE("key 1 not found in bucket 64", 1, t.buckets[64]);
CPPUNIT_ASSERT_EQUAL_MESSAGE("key 257 not found in bucket 65", 257, t.buckets[65]);
}
void HashTableInsertTest::testInsertSequence() {
HashTable t = HashTable(29, 35, 256);
CPPUNIT_ASSERT_MESSAGE("buckets array is null", t.buckets != NULL);
int z[] = {64, 99, 90, 85, 196, 87, 254, 233, 136, 139};
for (int i = 0; i < 9; i++) {
t.insert(z[i]);
CPPUNIT_ASSERT_EQUAL_MESSAGE("key not found in right table bucket", z[i], t.buckets[z[i+1]]);
}
}
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(HashTableInsertTest, "Insert");
CPPUNIT_REGISTRY_ADD_TO_DEFAULT("Insert");
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include "HashTable.hpp"
class HashTableLoadFactorTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(HashTableLoadFactorTest);
CPPUNIT_TEST(testLoadFactorOne);
CPPUNIT_TEST(testLoadFactorCollision);
CPPUNIT_TEST(testLoadFactorSequence);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() { };
void tearDown() { };
void testLoadFactorOne();
void testLoadFactorCollision();
void testLoadFactorSequence();
};
void HashTableLoadFactorTest::testLoadFactorOne() {
HashTable t = HashTable(29, 35, 256);
CPPUNIT_ASSERT_MESSAGE("buckets array is null", t.buckets != NULL);
CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("load factor of empty table is not zero", 0.0, t.loadFactor(), 0.0);
t.insert(1);
CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("load factor of table with one element is not right", 1.0/256, t.loadFactor(), 0.0);
}
void HashTableLoadFactorTest::testLoadFactorCollision() {
HashTable t = HashTable(29, 35, 256);
CPPUNIT_ASSERT_MESSAGE("buckets array is null", t.buckets != NULL);
t.insert(1);
t.insert(257);
CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("load factor of table with two elements is not right", 2.0/256, t.loadFactor(), 0.0);
}
void HashTableLoadFactorTest::testLoadFactorSequence() {
HashTable t = HashTable(29, 35, 256);
CPPUNIT_ASSERT_MESSAGE("buckets array is null", t.buckets != NULL);
int z[] = {64, 99, 90, 85, 196, 87, 254, 233, 136, 139};
for (int i = 0; i < 9; i++) {
t.insert(z[i]);
CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("load factor is wrong", ((double) (i+1))/256, t.loadFactor(), 0.0);
}
}
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(HashTableLoadFactorTest, "LoadFactor");
CPPUNIT_REGISTRY_ADD_TO_DEFAULT("LoadFactor");
include ../../cpp.mk
HashTableTest: ../../00/cpp/RunTests.o HashTable.o HashTableInsertTest.o HashTableFindTest.o HashTableLoadFactorTest.o
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@
test: HashTableTest
./HashTableTest
.PHONY: test
public class HashTable {
// public for testing purposes
public int buckets[];
public HashTable(long _a, long _c, long _m) {
}
public void insert(int key) {
}
public boolean find(int key) {
return false;
}
public double loadFactor() {
return 0.0;
}
}
import static java.util.Arrays.asList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import java.util.Random;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
public class HashTableFindTest {
@Test
public void testFindOne() {
HashTable t = new HashTable(29, 35, 256);
t.insert(1);
assertTrue("key 1 not found", t.find(1));
}
@Test
public void testFindCollision() {
HashTable t = new HashTable(29, 35, 256);
t.insert(1);
t.insert(257);
assertTrue("key 1 not found", t.find(1));
assertTrue("key 257 not found", t.find(257));
assertTrue("key 513 found", !t.find(513));
}
@Test
public void testFindSequence() {
HashTable t = new HashTable(29, 35, 256);
int z[] = {64, 99, 90, 85, 196, 87, 254, 233, 136, 139};
for (int i = 0; i < 9; i++) {
t.insert(z[i]);
assertTrue("key " + z[i] + " not found", t.find(z[i]));
}
}
}
import static java.util.Arrays.asList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import java.util.Random;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
public class HashTableInsertTest {
@Test
public void testInsertOne() {
HashTable t = new HashTable(29, 35, 256);
t.insert(1);
assertEquals("key 1 not found in bucket 64", 1, t.buckets[64]);
}
@Test
public void testInsertCollision() {
HashTable t = new HashTable(29, 35, 256);
t.insert(1);
t.insert(257);
assertEquals("key 1 not found in bucket 64", 1, t.buckets[64]);
assertEquals("key 257 not found in bucket 65", 257, t.buckets[65]);
}
@Test
public void testInsertSequence() {
HashTable t = new HashTable(29, 35, 256);
int z[] = {64, 99, 90, 85, 196, 87, 254, 233, 136, 139};
for (int i = 0; i < 9; i++) {
t.insert(z[i]);
assertEquals("key not found in right table bucket", z[i], t.buckets[z[i+1]]);
}
}
}
import static java.util.Arrays.asList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import java.util.Random;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
public class HashTableLoadFactorTest {
@Test
public void testLoadFactorOne() {
HashTable t = new HashTable(29, 35, 256);
assertEquals("load factor of empty table is not zero", 0.0, t.loadFactor(), 0.0);
t.insert(1);
assertEquals("load factor of table with one element is not right", 1.0/256, t.loadFactor(), 0.0);
}
@Test
public void testLoadFactorCollision() {
HashTable t = new HashTable(29, 35, 256);
t.insert(1);
t.insert(257);
assertEquals("load factor of table with two elements is not right", 2.0/256, t.loadFactor(), 0.0);
}
@Test
public void testLoadFactorSequence() {
HashTable t = new HashTable(29, 35, 256);
int z[] = {64, 99, 90, 85, 196, 87, 254, 233, 136, 139};
for (int i = 0; i < 9; i++) {
t.insert(z[i]);
assertEquals("load factor is wrong", ((double)(i+1))/256, t.loadFactor(), 0.0);
}
}
}
include ../../java.mk
TESTCLASSFILES = HashTableInsertTest.class HashTableFindTest.class HashTableLoadFactorTest.class
CLASSFILES = HashTable.class $(TESTCLASSFILES)
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 $(CLASSFILES) test.xml
.PHONY: test all clean
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment