diff --git a/labs/12_hash_tables/a.out b/labs/12_hash_tables/a.out deleted file mode 100755 index de6db89..0000000 Binary files a/labs/12_hash_tables/a.out and /dev/null differ diff --git a/labs/12_hash_tables/happy_number_separate_chaining_sol.cpp b/labs/12_hash_tables/happy_number_separate_chaining_sol.cpp deleted file mode 100644 index ff0c950..0000000 --- a/labs/12_hash_tables/happy_number_separate_chaining_sol.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// Solve the problem using separate chaining. - -#include - -// this table can have at most 1024 keys -#define TABLE_SIZE 1024 - -class Node { -public: - int number; - Node* next; -}; - -// search the hash table and see if we can find this num. -bool identify(int num, Node** table){ - int key = abs(num%TABLE_SIZE); - // search num in table[key]; - Node* node = table[key]; - while(node!=NULL){ - if(node->number == num){ - return true; - } - node = node->next; - } - // if not found, return false; - return false; -} - -// add num into the hash table -void add(int num, Node** table){ - int key = abs(num%TABLE_SIZE); - Node* node = new Node; - // insert num and index into table[key] - // if this is the first node - if(table[key]==NULL){ - node->number = num; - node->next = NULL; - table[key] = node; - }else{ - // if this is not the first node - node->number = num; - node->next = table[key]; - table[key] = node; - } -} - -int replace(int n){ - int digit; - int result=0; - while(n>0){ - digit = (n%10); - result += digit * digit; - n = n/10; - } - return result; -} - -bool isHappy(int n) { - int newN = n; - Node* hash_table[TABLE_SIZE]; - for(int i=0;i -#include - -int replace(int n){ - int digit; - int result=0; - while(n>0){ - digit = (n%10); - result += digit * digit; - n = n/10; - } - return result; -} - -bool isHappy(int n) { - int newN = n; - std::unordered_set set1; - while(1){ - newN = replace(newN); - if(newN==1){ - return true; - }else{ - // if we can find it, this is going to be an infinite loop - if(set1.find(newN)!=set1.end()){ - return false; - } - // can't find it, insert it in the set first - set1.insert(newN); - } - } -} - -int main() { - // Test cases - // 2, 4, 5, 6, 17, 18, 20 are not happy numbers. - // 1, 7, 10, 13, 19, 23, 28, 68 are not happy numbers. - - int testCases[] = {2,4,5,6,17,18,20,1,7,10,13,19,23,28,68}; - - for (int n : testCases) { - if (isHappy(n)) { - std::cout << n << " is a happy number." << std::endl; - } else { - std::cout << n << " is not a happy number." << std::endl; - } - } - - return 0; -} - diff --git a/labs/12_hash_tables/test/ds_hashset.h b/labs/12_hash_tables/test/ds_hashset.h deleted file mode 100644 index fe25a38..0000000 --- a/labs/12_hash_tables/test/ds_hashset.h +++ /dev/null @@ -1,260 +0,0 @@ -#ifndef ds_hashset_h_ -#define ds_hashset_h_ -// The set class as a hash table instead of a binary search tree. The -// primary external difference between ds_set and ds_hashset is that -// the iterators do not step through the hashset in any meaningful -// order. It is just the order imposed by the hash function. -#include -#include -#include -#include -#include - -// The ds_hashset is templated over both the type of key and the type -// of the hash function, a function object. -template < class KeyType, class HashFunc > -class ds_hashset { -private: - typedef typename std::list::iterator hash_list_itr; - -public: - // ================================================================= - // THE ITERATOR CLASS - // Defined as a nested class and thus is not separately templated. - - class iterator { - public: - friend class ds_hashset; // allows access to private variables - private: - - // ITERATOR REPRESENTATION - ds_hashset* m_hs; - int m_index; // current index in the hash table - hash_list_itr m_list_itr; // current iterator at the current index - - private: - // private constructors for use by the ds_hashset only - iterator(ds_hashset * hs) : m_hs(hs), m_index(-1) {} - iterator(ds_hashset* hs, int index, hash_list_itr loc) - : m_hs(hs), m_index(index), m_list_itr(loc) {} - - public: - // Ordinary constructors & assignment operator - iterator() : m_hs(0), m_index(-1) {} - iterator(iterator const& itr) - : m_hs(itr.m_hs), m_index(itr.m_index), m_list_itr(itr.m_list_itr) {} - iterator& operator=(const iterator& old) { - m_hs = old.m_hs; - m_index = old.m_index; - m_list_itr = old.m_list_itr; - return *this; - } - - // The dereference operator need only worry about the current - // list iterator, and does not need to check the current index. - const KeyType& operator*() const { return *m_list_itr; } - - // The comparison operators must account for the list iterators - // being unassigned at the end. - friend bool operator== (const iterator& lft, const iterator& rgt) - { return lft.m_hs == rgt.m_hs && lft.m_index == rgt.m_index && - (lft.m_index == -1 || lft.m_list_itr == rgt.m_list_itr); } - friend bool operator!= (const iterator& lft, const iterator& rgt) - { return lft.m_hs != rgt.m_hs || lft.m_index != rgt.m_index || - (lft.m_index != -1 && lft.m_list_itr != rgt.m_list_itr); } - // increment and decrement - iterator& operator++() { - this->next(); - return *this; - } - iterator operator++(int) { - iterator temp(*this); - this->next(); - return temp; - } - iterator & operator--() { - this->prev(); - return *this; - } - iterator operator--(int) { - iterator temp(*this); - this->prev(); - return temp; - } - - private: - // Find the next entry in the table - void next() { - ++ m_list_itr; // next item in the list - - // If we are at the end of this list - if (m_list_itr == m_hs->m_table[m_index].end()) { - // Find the next non-empty list in the table - for (++m_index; - m_index < int(m_hs->m_table.size()) && m_hs->m_table[m_index].empty(); - ++m_index) {} - - // If one is found, assign the m_list_itr to the start - if (m_index != int(m_hs->m_table.size())) - m_list_itr = m_hs->m_table[m_index].begin(); - - // Otherwise, we are at the end - else - m_index = -1; - } - } - - // Find the previous entry in the table - void prev() { - // If we aren't at the start of the current list, just decrement - // the list iterator - if (m_list_itr != m_hs->m_table[m_index].begin()) - m_list_itr -- ; - - else { - // Otherwise, back down the table until the previous - // non-empty list in the table is found - for (--m_index; m_index >= 0 && m_hs->m_table[m_index].empty(); --m_index) {} - - // Go to the last entry in the list. - m_list_itr = m_hs->m_table[m_index].begin(); - hash_list_itr p = m_list_itr; ++p; - for (; p != m_hs->m_table[m_index].end(); ++p, ++m_list_itr) {} - } - } - }; - // end of ITERATOR CLASS - // ================================================================= -private: - // ================================================================= - // HASH SET REPRESENTATION - std::vector< std::list > m_table; // actual table - HashFunc m_hash; // hash function - unsigned int m_size; // number of keys - -public: - // ================================================================= - // HASH SET IMPLEMENTATION - - // Constructor for the table accepts the size of the table. Default - // constructor for the hash function object is implicitly used. - ds_hashset(unsigned int init_size = 10) : m_table(init_size), m_size(0) {} - - // Copy constructor just uses the member function copy constructors. - ds_hashset(const ds_hashset& old) - : m_table(old.m_table), m_size(old.m_size) {} - - ~ds_hashset() {} - - ds_hashset& operator=(const ds_hashset& old) { - if (&old != this) { - this->m_table = old.m_table; - this->m_size = old.m_size; - this->m_hash = old.m_hash; - } - return *this; - } - - unsigned int size() const { return m_size; } - - - // Insert the key if it is not already there. - std::pair< iterator, bool > insert(KeyType const& key) { - const float LOAD_FRACTION_FOR_RESIZE = 1.25; - - if (m_size >= LOAD_FRACTION_FOR_RESIZE * m_table.size()) - this->resize_table(2*m_table.size()+1); - - // Implement this function for Lab 11, Checkpoint 1 - - - - - - - - - - - - - - } - - // Find the key, using hash function, indexing and list find - iterator find(const KeyType& key) { - unsigned int hash_value = m_hash(key); - unsigned int index = hash_value % m_table.size(); - hash_list_itr p = std::find(m_table[index].begin(), - m_table[index].end(), key); - if (p == m_table[index].end()) - return this->end(); - else - return iterator(this, index, p); - } - // Erase the key - int erase(const KeyType& key) { - // Find the key and use the erase iterator function. - iterator p = find(key); - if (p == end()) - return 0; - else { - erase(p); - return 1; - } - } - - // Erase at the iterator - void erase(iterator p) { - m_table[ p.m_index ].erase(p.m_list_itr); - } - - // Find the first entry in the table and create an associated iterator - iterator begin() { - - // Implement this function for Lab 11, Checkpoint 2, Part 1 - - - - - - - - } - - // Create an end iterator. - iterator end() { - iterator p(this); - p.m_index = -1; - return p; - } - - // A public print utility. - void print(std::ostream & ostr) { - for (unsigned int i=0; i -#include -#include -#include - -#include "ds_hashset.h" - - -// Wrapping a class around a function turns a function into a functor -// (We'll talk about this more in Lecture 21. You can just ignore -// this wrapper part for now.) -class hash_string_obj { -public: - - // ---------------------------------------------------------- - // EXPERIMENT WITH THE HASH FUNCTION FOR CHECKPOINT 1, PART 2 - - unsigned int operator() ( const std::string& key ) const { - // This implementation comes from - // http://www.partow.net/programming/hashfunctions/ - // - // This is a general-purpose, very good hash function for strings. - unsigned int hash = 1315423911; - for(unsigned int i = 0; i < key.length(); i++) - hash ^= ((hash << 5) + key[i] + (hash >> 2)); - return hash; - } - -}; - - -typedef ds_hashset ds_hashset_type; - - -int main() { - - // --------------------------------- - // CODE TO TEST CHECKPOINT 1, PART 1 - ds_hashset_type a; - ds_hashset_type set1; - std::pair< ds_hashset_type::iterator, bool > insert_result; - - std::string to_insert = std::string("hello"); - insert_result = set1.insert( to_insert ); - assert( insert_result.second ); - - insert_result = set1.insert( std::string("good-bye") ); - assert( insert_result.second ); - - insert_result = set1.insert( std::string("friend") ); - assert( insert_result.second ); - - insert_result = set1.insert( std::string("abc") ); - assert( insert_result.second ); - - insert_result = set1.insert( std::string("puppy") ); - assert( insert_result.second ); - - insert_result = set1.insert( std::string("zebra") ); - assert( insert_result.second ); - - insert_result = set1.insert( std::string("daddy") ); - assert( insert_result.second ); - - insert_result = set1.insert( std::string("puppy") ); - assert( !insert_result.second && * insert_result.first == std::string("puppy") ); - - std::cout << "The set size is " << set1.size() << '\n' - << "Here is the table: \n"; - set1.print( std::cout ); - - ds_hashset_type::iterator p; - p = set1.find( "foo" ); - if ( p == set1.end() ) - std::cout << "\"foo\" is not in the set\n"; - else - std::cout << "\"foo\" is in the set\n" - << "The iterator points to " << *p << std::endl; - - p = set1.find("puppy"); - if ( p == set1.end() ) - std::cout << "\"puppy\" is not in the set\n"; - else - std::cout << "\"puppy\" is in the set\n" - << "The iterator points to " << *p << std::endl; - - p = set1.find("daddy"); - if ( p == set1.end() ) - std::cout << "\"daddy\" is not in the set\n"; - else - std::cout << "\"daddy\" is in the set\n" - << "The iterator points to " << *p << std::endl; - - - // --------------------------------- - // CODE TO TEST CHECKPOINT 2, PART 1 - /* - p = set1.begin(); - std::cout << "\nHere is the result of iterating: \n"; - for ( p = set1.begin(); p != set1.end(); ++p ) - std::cout << *p << '\n'; - */ - - - // --------------------------------- - // CODE TO TEST CHECKPOINT 2, PART 2 - /* - ds_hashset_type set2( set1 ); - std::cout << "set1.size() = " << set1.size() << ", set2.size() = " << set2.size() << std::endl; - - // Now add more stuff to set2. This should trigger a resize given the default settings. - insert_result = set2.insert( std::string("ardvark") ); - assert( insert_result.second ); - insert_result = set2.insert( std::string("baseball") ); - assert( insert_result.second ); - insert_result = set2.insert( std::string("football") ); - assert( insert_result.second ); - insert_result = set2.insert( std::string("gymnastics") ); - assert( insert_result.second ); - insert_result = set2.insert( std::string("dance") ); - assert( insert_result.second ); - insert_result = set2.insert( std::string("swimming") ); - assert( insert_result.second ); - insert_result = set2.insert( std::string("track") ); - assert( insert_result.second ); - - std::cout << "\nAfter seven more inserts:\n" - << "set1.size() = " << set1.size() << ", set2.size() = " << set2.size() << "\n" - << "\nThe contents of set2:" << std::endl; - set2.print(std::cout); - std::cout << "The results of iterating:\n"; - for ( p = set2.begin(); p != set2.end(); ++p ) - std::cout << *p << '\n'; - */ - - // --------------- - // OTHER TEST CODE - /* - // Now test erase - int num = set2.erase( std::string("hello") ); - std::cout << "Tried erase \"hello\" and got num (should be 1) = " << num << std::endl; - num = set2.erase( std::string("abc") ); - std::cout << "Tried erase \"abc\" and got num (should be 1) = " << num << std::endl; - num = set2.erase( std::string("hello") ); - std::cout << "Tried erase \"hello\" and got num (should be 0) = " << num << std::endl; - num = set2.erase( std::string("football") ); - std::cout << "Tried erase \"football\" and got num (should be 1) = " << num << std::endl; - num = set2.erase( std::string("friend") ); - std::cout << "Tried erase \"friend\" and got num (should be 1) = " << num - << "\nHere are the final contents of set2:" << std::endl; - set2.print(std::cout); - */ - - return 0; -} diff --git a/labs/12_hash_tables/test2/a.out b/labs/12_hash_tables/test2/a.out deleted file mode 100755 index f7961d2..0000000 Binary files a/labs/12_hash_tables/test2/a.out and /dev/null differ diff --git a/labs/12_hash_tables/test2/happy_number_separate_chaining.cpp b/labs/12_hash_tables/test2/happy_number_separate_chaining.cpp deleted file mode 100644 index ff0c950..0000000 --- a/labs/12_hash_tables/test2/happy_number_separate_chaining.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// Solve the problem using separate chaining. - -#include - -// this table can have at most 1024 keys -#define TABLE_SIZE 1024 - -class Node { -public: - int number; - Node* next; -}; - -// search the hash table and see if we can find this num. -bool identify(int num, Node** table){ - int key = abs(num%TABLE_SIZE); - // search num in table[key]; - Node* node = table[key]; - while(node!=NULL){ - if(node->number == num){ - return true; - } - node = node->next; - } - // if not found, return false; - return false; -} - -// add num into the hash table -void add(int num, Node** table){ - int key = abs(num%TABLE_SIZE); - Node* node = new Node; - // insert num and index into table[key] - // if this is the first node - if(table[key]==NULL){ - node->number = num; - node->next = NULL; - table[key] = node; - }else{ - // if this is not the first node - node->number = num; - node->next = table[key]; - table[key] = node; - } -} - -int replace(int n){ - int digit; - int result=0; - while(n>0){ - digit = (n%10); - result += digit * digit; - n = n/10; - } - return result; -} - -bool isHappy(int n) { - int newN = n; - Node* hash_table[TABLE_SIZE]; - for(int i=0;i -#include - -int replace(int n){ - int digit; - int result=0; - while(n>0){ - digit = (n%10); - result += digit * digit; - n = n/10; - } - return result; -} - -bool isHappy(int n) { - int newN = n; - std::unordered_set set1; - while(1){ - newN = replace(newN); - if(newN==1){ - return true; - }else{ - // if we can find it, this is going to be an infinite loop - if(set1.find(newN)!=set1.end()){ - return false; - } - // can't find it, insert it in the set first - set1.insert(newN); - } - } -} - -int main() { - // Test cases - // 2, 4, 5, 6, 17, 18, 20 are not happy numbers. - // 1, 7, 10, 13, 19, 23, 28, 68 are not happy numbers. - - int testCases[] = {2,4,5,6,17,18,20,1,7,10,13,19,23,28,68}; - - for (int n : testCases) { - if (isHappy(n)) { - std::cout << n << " is a happy number." << std::endl; - } else { - std::cout << n << " is not a happy number." << std::endl; - } - } - - return 0; -} - diff --git a/labs/12_hash_tables/test4/a.out b/labs/12_hash_tables/test4/a.out deleted file mode 100755 index 3a2f665..0000000 Binary files a/labs/12_hash_tables/test4/a.out and /dev/null differ diff --git a/labs/12_hash_tables/test4/test_longest_consecutive_sequence.cpp b/labs/12_hash_tables/test4/test_longest_consecutive_sequence.cpp deleted file mode 100644 index 7dfd688..0000000 --- a/labs/12_hash_tables/test4/test_longest_consecutive_sequence.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include -#include - -#define TABLE_SIZE 1024 - -class Node{ -public: - int number; - Node* next; -}; - -// insert num into table -void insert(int num, Node** table){ - int key; - key = abs(num%TABLE_SIZE); // key will be something in between 0 and (TABLE_SIZE-1); num can be negative - if(table[key] == nullptr){ - // create the first node for this linked list - Node* node; - node = new Node; - node->number = num; - node->next = nullptr; - table[key] = node; - }else{ - // insert a node to the beginning of this linked list - Node* node; - node = new Node; - node->number = num; - node->next = table[key]; - table[key] = node; - } -} - -// search the hash table and see if we can find this num. -bool identify(int num, Node** table){ - int key = abs(num%TABLE_SIZE); - // search num in table[key]; - Node* node = table[key]; - while(node != nullptr){ - if(node->number == num){ - return true; - } - node = node->next; - } - // if not found, return false; - return false; -} - -// Question: why is this an O(n) solution when we have a nested loop? Because the inner while loop will only be used if *itr1 is the beginning of the sequence, which means each element will only be visited 2 or 3 times. -int longestConsecutive(std::vector& nums) { - int len=0; - Node* hash_table[TABLE_SIZE]; - // initialize the table - for(int i=0;inum-1) can't be found - if(identify(current->number - 1, hash_table)){ - int x = current->number + 1; - // now that current->num is the beginning of a sequence, how about current->num + 1? - while(identify(x, hash_table)){ - x++; - } - // when we get out of the above while loop, it's time to update len, if needed. - if( (x - current->number) > len){ - len = x - current->number; - } - } - current = current->next; - // we still need a while here, rather than an if. - // so that we can find the next non-empty bucket. - while(current == nullptr){ - i++; - if(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, 201, 202, 203, 205, 204, 1, 3, 2}; - int size = nums.size(); - std::cout<< "for vector {"; - for(int i=0;i -#include -#include - - // Question: why is this an O(n) solution when we have a nested loop? Because the inner while loop will only be used if *itr1 is the beginning of the sequence, which means each element will only be visited 2 or 3 times. - int longestConsecutive(std::vector& nums) { - int len=0; - std::unordered_set set1; - int size = nums.size(); - // store unique elements in nums in set1 - for(int i=0;i::iterator itr1 = set1.begin(); - while(itr1!=set1.end()){ - // clearly *itr1 is in the set, because that's the meaning of iteration; and if *itr1-1 is not in the set, then we know *itr1 is the beginning of a sequence. - if(!set1.count(*itr1-1)){ - int x = *itr1+1; - // now that *itr1 is the beginning of a sequence, how about *itr1+1? - while(set1.count(x)){ - x++; - } - if(x-*itr1>len){ - len = x-*itr1; - } - } - itr1++; - } - return len; - } - -int main() { - //std::vector 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, 201, 202, 203, 205, 204, 1, 3, 2}; - int size = nums.size(); - std::cout<< "for vector {"; - for(int i=0;i -#include - -#define TABLE_SIZE 1024 - -class Node{ -public: - int number; - Node* next; -}; - -// insert num into table -void insert(int num, Node** table){ - int key; - key = abs(num%TABLE_SIZE); // key will be something in between 0 and (TABLE_SIZE-1); num can be negative - if(table[key] == nullptr){ - // create the first node for this linked list - Node* node; - node = new Node; - node->number = num; - node->next = nullptr; - table[key] = node; - }else{ - // insert a node to the beginning of this linked list - Node* node; - node = new Node; - node->number = num; - node->next = table[key]; - table[key] = node; - } -} - -// search the hash table and see if we can find this num. -bool identify(int num, Node** table){ - int key = abs(num%TABLE_SIZE); - // search num in table[key]; - Node* node = table[key]; - while(node != nullptr){ - if(node->number == num){ - return true; - } - node = node->next; - } - // if not found, return false; - return false; -} - -// Question: why is this an O(n) solution when we have a nested loop? Because the inner while loop will only be used if *itr1 is the beginning of the sequence, which means each element will only be visited 2 or 3 times. -int longestConsecutive(std::vector& nums) { - int len=0; - Node* hash_table[TABLE_SIZE]; - // initialize the table - for(int i=0;inum-1) can't be found - if(!identify(current->number - 1, hash_table)){ - int x = current->number + 1; - // now that current->num is the beginning of a sequence, how about current->num + 1? - while(identify(x, hash_table)){ - x++; - } - // when we get out of the above while loop, it's time to update len, if needed. - if( (x - current->number) > len){ - len = x - current->number; - } - } - current = current->next; - // we still need a while here, rather than an if. - // so that we can find the next non-empty bucket. - while(current == nullptr){ - i++; - if(i 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}; - int size = nums.size(); - std::cout<< "for vector {"; - for(int i=0;i -#include - -#define TABLE_SIZE 1024 - -class Node{ -public: - int number; - Node* next; -}; - -// insert num into table -void insert(int num, Node** table){ - int key; - key = abs(num%TABLE_SIZE); // key will be something in between 0 and (TABLE_SIZE-1); num can be negative - if(table[key] == nullptr){ - // create the first node for this linked list - Node* node; - node = new Node; - node->number = num; - node->next = nullptr; - table[key] = node; - }else{ - // insert a node to the beginning of this linked list - Node* node; - node = new Node; - node->number = num; - node->next = table[key]; - table[key] = node; - } -} - -// search the hash table and see if we can find this num. -bool identify(int num, Node** table){ - int key = abs(num%TABLE_SIZE); - // search num in table[key]; - Node* node = table[key]; - while(node != nullptr){ - if(node->number == num){ - return true; - } - node = node->next; - } - // if not found, return false; - return false; -} - -// Question: why is this an O(n) solution when we have a nested loop? Because the inner while loop will only be used if *itr1 is the beginning of the sequence, which means each element will only be visited 2 or 3 times. -int longestConsecutive(std::vector& nums) { - int len=0; - Node* hash_table[TABLE_SIZE]; - // initialize the table - for(int i=0;inum-1) can't be found - if(!identify(current->number - 1, hash_table)){ - int x = current->number + 1; - // now that current->num is the beginning of a sequence, how about current->num + 1? - while(identify(x, hash_table)){ - x++; - } - // when we get out of the above while loop, it's time to update len, if needed. - if( (x - current->number) > len){ - len = x - current->number; - } - } - current = current->next; - // we still need a while here, rather than an if. - // so that we can find the next non-empty bucket. - while(current == nullptr){ - i++; - if(i 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