diff --git a/lectures/20_hash_tables_I/README.md b/lectures/20_hash_tables_I/README.md index f20afb5..89b2bbd 100644 --- a/lectures/20_hash_tables_I/README.md +++ b/lectures/20_hash_tables_I/README.md @@ -225,7 +225,7 @@ configuration tweaks) to access these more recent pieces of STL. (And this will in future years!) Also, for many types STL has a good default hash function, so you may not always need to specify both template parameters! -## 20.13 Our Copycat Version: A Set As a Hash Table + -## 20.22 Leetcode Exercises +## 20.13 Leetcode Exercises - [Leetcode problem 1: Two Sum](https://leetcode.com/problems/two-sum/). Solution: [p1_twosum_hash_table.cpp](../../leetcode/p1_twosum_hash_table.cpp). - [Leetcode problem 128: Longest Consecutive Sequence](https://leetcode.com/problems/longest-consecutive-sequence/). Solution: [p128_longest_consecutive_sequence.cpp](../../leetcode/p128_longest_consecutive_sequence.cpp). diff --git a/lectures/20_hash_tables_I/ds_hashset_start.h b/lectures/20_hash_tables_I/ds_hashset_start.h deleted file mode 100644 index 5099ab2..0000000 --- a/lectures/20_hash_tables_I/ds_hashset_start.h +++ /dev/null @@ -1,253 +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 - -// 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 = old; - } - - 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); - - // implemented in lecture or lab - - - - - - - - - - - - - - } - - // 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() { - // implemented in lecture or lab - - - - - - - - } - - // 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