From bb359c9fe78301fde75e55f179f619342b1e9837 Mon Sep 17 00:00:00 2001 From: JamesFlare Date: Wed, 9 Apr 2025 12:19:01 -0400 Subject: [PATCH] solve lab 9 --- labs/hash_tables/good_number.cpp | 138 ++++++++++++++++-- .../test_longest_consecutive_sequence.cpp | 120 +++++++++++++-- 2 files changed, 234 insertions(+), 24 deletions(-) diff --git a/labs/hash_tables/good_number.cpp b/labs/hash_tables/good_number.cpp index 8034056..731af84 100644 --- a/labs/hash_tables/good_number.cpp +++ b/labs/hash_tables/good_number.cpp @@ -1,23 +1,143 @@ #include +#include +#include +#include +#include -bool isGood(int n) { +// Compute the sum of the squares of a number's digits. +int sumOfSquaresOfDigits(int x) { + int sum = 0; + while (x > 0) { + int digit = x % 10; + sum += digit * digit; + x /= 10; + } + return sum; +} + +// std::unordered_set +bool isGood_unordered_set(int n) { + std::unordered_set visited; + while (n != 1 && visited.find(n) == visited.end()) { + visited.insert(n); + n = sumOfSquaresOfDigits(n); + } + return (n == 1); +} + +// std::unordered_map +bool isGood_unordered_map(int n) { + // We only need to mark that we have "seen" a number. + // The bool value is arbitrary; storing true is enough. + std::unordered_map visited; + while (n != 1 && visited.find(n) == visited.end()) { + visited[n] = true; // Mark n as visited + n = sumOfSquaresOfDigits(n); + } + return (n == 1); +} + +class MyHashSet { +private: + // store integers in a vector of lists + std::vector< std::list > table; + int num_elements; + static const int DEFAULT_SIZE = 16; + static const double LOAD_FACTOR_THRESHOLD; + + // A simple hash function for int + int hashFunction(int key) const { + // take abs value + int h = key < 0 ? -key : key; + return h % (int)table.size(); + } + + void rehash() { + int newSize = (int)table.size() * 2; // doubling + std::vector< std::list > newTable(newSize); + + // re-insert all existing elements into newTable + for (auto &chain : table) { + for (int val : chain) { + int h = (val < 0 ? -val : val) % newSize; + newTable[h].push_back(val); + } + } + table.swap(newTable); + } + + void rehashIfNeeded() { + // If load factor = num_elements / table.size() is too big, rehash + double load_factor = (double)num_elements / (double)table.size(); + if (load_factor > LOAD_FACTOR_THRESHOLD) { + rehash(); + } + } + +public: + // Constructor + MyHashSet(int initialSize = DEFAULT_SIZE) + : table(initialSize), num_elements(0) {} + + // Return true if key is found + bool find(int key) const { + int h = hashFunction(key); + // Search the list in bin h + for (int val : table[h]) { + if (val == key) return true; + } + return false; + } + + // Insert key if not already in the hash set + void insert(int key) { + if (!find(key)) { + int h = hashFunction(key); + table[h].push_back(key); + num_elements++; + rehashIfNeeded(); + } + } +}; + +const double MyHashSet::LOAD_FACTOR_THRESHOLD = 1.0; + +// The "isGood" function that uses MyHashSet +bool isGood_custom_hash(int n) { + MyHashSet visited; + while (n != 1 && !visited.find(n)) { + visited.insert(n); + n = sumOfSquaresOfDigits(n); + } + return (n == 1); } int main() { - // Test cases - // 2, 4, 5, 6, 17, 18, 20 are not good numbers. - // 1, 7, 10, 13, 19, 23, 28, 68 are good numbers. - int testCases[] = {2,4,5,6,17,18,20,1,7,10,13,19,23,28,68}; + std::cout << "=== Using std::unordered_set ===" << std::endl; for (int n : testCases) { - if (isGood(n)) { + if (isGood_unordered_set(n)) std::cout << n << " is a good number." << std::endl; - } else { + else + std::cout << n << " is not a good number." << std::endl; + } + + std::cout << "\n=== Using std::unordered_map ===" << std::endl; + for (int n : testCases) { + if (isGood_unordered_map(n)) + std::cout << n << " is a good number." << std::endl; + else + std::cout << n << " is not a good number." << std::endl; + } + + std::cout << "\n=== Using custom separate-chaining HashSet ===" << std::endl; + for (int n : testCases) { + if (isGood_custom_hash(n)) + std::cout << n << " is a good number." << std::endl; + else std::cout << n << " is not a good number." << std::endl; - } } return 0; } - diff --git a/labs/hash_tables/test_longest_consecutive_sequence.cpp b/labs/hash_tables/test_longest_consecutive_sequence.cpp index 3bcb50e..d287ee0 100644 --- a/labs/hash_tables/test_longest_consecutive_sequence.cpp +++ b/labs/hash_tables/test_longest_consecutive_sequence.cpp @@ -1,23 +1,113 @@ #include #include +#include + +// A minimal separate-chaining HashSet for integers. +class MyHashSet { +private: + std::vector< std::list > table; + int num_elements; + static const int DEFAULT_SIZE = 16; + static const double LOAD_FACTOR_THRESHOLD; + + int hashFunction(int key) const { + int h = key < 0 ? -key : key; // handle negative + return h % (int)table.size(); + } + + void rehash() { + int newSize = (int)table.size() * 2; + std::vector< std::list > newTable(newSize); + + for (auto &chain : table) { + for (int val : chain) { + int h = (val < 0 ? -val : val) % newSize; + newTable[h].push_back(val); + } + } + table.swap(newTable); + } + + void rehashIfNeeded() { + double load_factor = (double)num_elements / (double)table.size(); + if (load_factor > LOAD_FACTOR_THRESHOLD) { + rehash(); + } + } + +public: + MyHashSet(int initialSize = DEFAULT_SIZE) + : table(initialSize), num_elements(0) {} + + bool find(int key) const { + int h = hashFunction(key); + for (int val : table[h]) { + if (val == key) { + return true; + } + } + return false; + } + + void insert(int key) { + if (!find(key)) { + int h = hashFunction(key); + table[h].push_back(key); + num_elements++; + rehashIfNeeded(); + } + } +}; + +const double MyHashSet::LOAD_FACTOR_THRESHOLD = 1.0; int longestConsecutive(std::vector& nums) { + if (nums.empty()) return 0; + + // Insert all numbers into the custom hash set + MyHashSet set; + for (int n : nums) { + set.insert(n); + } + + int longestStreak = 0; + // For each number, only count a sequence if it's a "start" + // i.e., if (n-1) is NOT in the set + for (int n : nums) { + if (!set.find(n - 1)) { + // n is the start of a consecutive sequence + int currentNum = n; + int currentStreak = 1; + + while (set.find(currentNum + 1)) { + currentNum++; + currentStreak++; + } + if (currentStreak > longestStreak) { + longestStreak = currentStreak; + } + } + } + + return longestStreak; } int main() { - //std::vector nums = {100, 4, 200, 1, 3, 2}; - std::vector nums = {100, 4, 200, 1, 3, 2, 2, 2, 2, 3}; - //std::vector nums = {100, 4, 200, 1, 3, 2, 5, 6}; - //std::vector nums = {0,3,7,2,5,8,4,6,0,1}; - //std::vector nums = {100, 4, 200, 201, 202, 203, 205, 204, 1, 3, 2}; - //std::vector nums = {-3,0,1,2,3,-2,-1,-5}; - int size = nums.size(); - std::cout<< "for vector {"; - for(int i=0;i nums = {100, 4, 200, 1, 3, 2}; + //std::vector nums = {0,3,7,2,5,8,4,6,0,1}; + std::vector nums = {100, 4, 200, 1, 3, 2, 2, 2, 2, 3}; + + int size = nums.size(); + std::cout << "for vector {"; + for(int i = 0; i < size; i++){ + if(i < size - 1) std::cout << nums[i] << ","; + else std::cout << nums[i]; + } + std::cout << "}\n"; + + int length = longestConsecutive(nums); + std::cout << "The length of the longest consecutive sequence is: " + << length << std::endl; + return 0; }