From ac0b3d15c20d3f870e2f3a5d6eb5cab07d9463b6 Mon Sep 17 00:00:00 2001 From: David Nieder <post@davidnieder.de> Date: Sun, 1 Jan 2023 17:15:11 +0100 Subject: [PATCH] hashing/probing as function objects --- src/hashing.h | 63 +++++++++++++++++++++++++ tests/CMakeLists.txt | 3 ++ tests/test_hashing.cpp | 102 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 src/hashing.h create mode 100644 tests/test_hashing.cpp diff --git a/src/hashing.h b/src/hashing.h new file mode 100644 index 0000000..3551d68 --- /dev/null +++ b/src/hashing.h @@ -0,0 +1,63 @@ +#ifndef HASHING_H +#define HASHING_H + +#include <cmath> + + +/* + * hashing by division + */ +template<typename T> +struct DivHashing { + const size_t m; + DivHashing(size_t table_size) : m(table_size) {} + + size_t operator()(T key) { return key % m; } +}; + +/* + * hashing by multiplication + */ +template<typename T> +struct MulHashing { + const double gratio = 0.61803; + const size_t m; + MulHashing(size_t table_size) : m(table_size) {} + + size_t operator()(T key) { return m * (gratio*key - std::floor(gratio*key)); } +}; + +/* + * linear probing + */ +struct LinearProbing { + const size_t h; + const size_t m; + LinearProbing(size_t hash, size_t table_size) : h(hash), m(table_size) {} + + size_t operator()(size_t i) { return (h+i) % m; } +}; + +/* + * quadratic probing + */ +struct QuadraticProbing { + const size_t h; + const size_t m; + QuadraticProbing(size_t hash, size_t table_size) : h(hash), m(table_size) {} + + size_t operator()(size_t i) { return (h + i*i) % m; } +}; + +/* + * double hashing + */ +struct DoubleHashing { + const size_t h; + const size_t m; + DoubleHashing(size_t hash, size_t table_size) : h(hash), m(table_size) {} + + size_t operator()(size_t i) { return (h + i*(h+1)) % m; } +}; + +#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 47ef1cf..d02f383 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,12 +6,15 @@ include(CTest) # the executables that run the tests add_executable(test_main test_main.cpp) +add_executable(test_hashing test_hashing.cpp) add_executable(test_hashtable test_constructor.cpp test_hashtable.cpp) # link needed libraries target_link_libraries(test_main gtest gtest_main) +target_link_libraries(test_hashing gtest gtest_main) target_link_libraries(test_hashtable hashtable gtest gtest_main) # run with ctest add_test(NAME test_main COMMAND ${EXECUTABLE_OUTPUT_PATH}/test_main) +add_test(NAME test_hashing COMMAND ${EXECUTABLE_OUTPUT_PATH}/test_hashing) add_test(NAME test_hashtable COMMAND ${EXECUTABLE_OUTPUT_PATH}/test_hashtable) diff --git a/tests/test_hashing.cpp b/tests/test_hashing.cpp new file mode 100644 index 0000000..719b958 --- /dev/null +++ b/tests/test_hashing.cpp @@ -0,0 +1,102 @@ +#include <gtest/gtest.h> +#include "hashing.h" + + +TEST(hashing, DivHashing) { + DivHashing<unsigned> hash0(1); + DivHashing<unsigned> hash1(7); + DivHashing<unsigned> hash2(23); + DivHashing<unsigned> hash3(512); + DivHashing<unsigned> hash4(6899); + + for (unsigned i=0; i<65535; i++) { + EXPECT_EQ(i%1, hash0(i)); + EXPECT_EQ(i%7, hash1(i)); + EXPECT_EQ(i%23, hash2(i)); + EXPECT_EQ(i%512, hash3(i)); + EXPECT_EQ(i%6899, hash4(i)); + } +} + +TEST(hashing, MulHashing) { + const double a = 0.61803; + using std::floor; + #define H(k,m) (floor((m*((a*k)-floor(a*k))))) + + MulHashing<unsigned> hash0(1); + MulHashing<unsigned> hash1(7); + MulHashing<unsigned> hash2(23); + MulHashing<unsigned> hash3(512); + MulHashing<unsigned> hash4(6899); + + for (unsigned i=0; i<65535; i++) { + EXPECT_EQ(H(i,1), hash0(i)); + EXPECT_EQ(H(i,7), hash1(i)); + EXPECT_EQ(H(i,23), hash2(i)); + EXPECT_EQ(H(i,512), hash3(i)); + EXPECT_EQ(H(i,6899), hash4(i)); + } +} + +TEST(hashing, LinearProbing) { + LinearProbing p0(2, 1); + LinearProbing p1(4, 512); + LinearProbing p2(0, 8); + LinearProbing p3(7, 32); + LinearProbing p4(16, 6899); + + for (unsigned i=0; i<10000; i++) { + EXPECT_LT(p0(i), 1); + EXPECT_EQ(p0(i), (2+i)%1); + EXPECT_LT(p1(i), 512); + EXPECT_EQ(p1(i), (4+i)%512); + EXPECT_LT(p2(i), 8); + EXPECT_EQ(p2(i), (0+i)%8); + EXPECT_LT(p3(i), 32); + EXPECT_EQ(p3(i), (7+i)%32); + EXPECT_LT(p4(i), 6899); + EXPECT_EQ(p4(i), (16+i)%6899); + } +} + +TEST(hashing, QuadraticProbing) { + QuadraticProbing p0(2, 1); + QuadraticProbing p1(4, 512); + QuadraticProbing p2(0, 8); + QuadraticProbing p3(7, 32); + QuadraticProbing p4(16, 6899); + + for (unsigned i=0; i<10000; i++) { + EXPECT_LT(p0(i), 1); + EXPECT_EQ(p0(i), (2+i*i)%1); + EXPECT_LT(p1(i), 512); + EXPECT_EQ(p1(i), (4+i*i)%512); + EXPECT_LT(p2(i), 8); + EXPECT_EQ(p2(i), (0+i*i)%8); + EXPECT_LT(p3(i), 32); + EXPECT_EQ(p3(i), (7+i*i)%32); + EXPECT_LT(p4(i), 6899); + EXPECT_EQ(p4(i), (16+i*i)%6899); + } +} + +TEST(hashing, DoubleHashing) { + DoubleHashing p0(2, 1); + DoubleHashing p1(4, 512); + DoubleHashing p2(0, 8); + DoubleHashing p3(7, 32); + DoubleHashing p4(16, 6899); + + for (unsigned i=0; i<10000; i++) { + EXPECT_LT(p0(i), 1); + EXPECT_EQ(p0(i), (2+i*(2+1))%1); + EXPECT_LT(p1(i), 512); + EXPECT_EQ(p1(i), (4+i*(4+1))%512); + EXPECT_LT(p2(i), 8); + EXPECT_EQ(p2(i), (0+i*(0+1))%8); + EXPECT_LT(p3(i), 32); + EXPECT_EQ(p3(i), (7+i*(7+1))%32); + EXPECT_LT(p4(i), 6899); + EXPECT_EQ(p4(i), (16+i*(16+1))%6899); + } +} -- GitLab