re order 11 and 12
This commit is contained in:
89
labs/12_hash_tables/README.md
Normal file
89
labs/12_hash_tables/README.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Lab 12 — Hash Tables
|
||||
|
||||
<!--In this lab, you will first experiment with our hash table implementation of a set. The key differences between the ds_set class (based on a binary search tree) and the ds_hashset class (based on a hash table, of course), are the performance of insert/find/erase: O(log n) vs. O(1), and the order that the elements are traversed using iterators: the set was in order, while the hashset is in no apparent order.-->
|
||||
|
||||
In this lab, you will practice using std::unordered_set, std::unordered_map, and construct your own separate-chaining-based hash table.
|
||||
|
||||
<!--Provided code for checkpoint 1 and checkpoint 2: [ds_hashset.h](ds_hashset.h) and [test_ds_hashset.cpp](test_ds_hashset.cpp).-->
|
||||
|
||||
## Checkpoint 1: Using std::unordered_set and std::unordered_map
|
||||
|
||||
*estimate: 15-30 minutes*
|
||||
|
||||
Complete the *isHappy* function in this [program](happy_number.cpp). This function determines if a number n is happy or not. You can assume 1<=n<50000. You must write two versions of the function, one version uses std::unordered_set, the other version uses std::unordered_map.
|
||||
|
||||
A happy number is a number defined by the following process:
|
||||
|
||||
- Starting with any positive integer, replace the number by the sum of the squares of its digits.
|
||||
- Repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1.
|
||||
- Those numbers for which this process ends in 1 are happy.
|
||||
|
||||
Return true if n is a happy number, and false if not. Here are some examples:
|
||||
|
||||
```console
|
||||
Example 1:
|
||||
|
||||
Input: n = 19
|
||||
Output: true
|
||||
|
||||
Explanation:
|
||||
1^2 + 9^2 = 82
|
||||
8^2 + 2^2 = 68
|
||||
6^2 + 8^2 = 100
|
||||
1^2 + 0^2 + 0^2 = 1
|
||||
```
|
||||
|
||||
```console
|
||||
Example 2:
|
||||
|
||||
Input: n = 2
|
||||
Output: false
|
||||
```
|
||||
|
||||
<!--For the first part of this checkpoint, implement and test the *insert* function for the hashset. The *insert* function must first determine in which bin the new element belongs (using the hash function), and then insert the element into that bin but only if it isn’t there already. The *insert* function returns a pair containing an iterator pointing at the element, and a bool indicating whether it was successfully inserted (true) or already there (false).
|
||||
|
||||
For the second part of this checkpoint, experiment with the hash function. In the provided code we include the implementation of a good hash function for strings. Are there any collisions for the small example? Now write some alternative hash functions. First, create a trivial hash function that is guaranteed to have many, many collisions. Then, create a hash function that is not terrible, but will unfortunately always place anagrams (words with the same letters, but rearranged) in the same bin. Test your alternate functions and be prepared to show the results to your TA.
|
||||
|
||||
**To complete this checkpoint**: Show a TA your debugged implementation of *insert* and your experimentation with alternative hash functions.-->
|
||||
|
||||
**To complete this checkpoint**: Show a TA the two versions of your program and the test results.
|
||||
|
||||
## Checkpoint 2: Separate Chaining Hash Table
|
||||
|
||||
*estimate: 30-40 minutes*
|
||||
|
||||
<!--Next, implement and test the *begin* function, which initializes the iteration through a hashset. Confirm that the elements in the set are visited in the same order they appear with the *print* function (which we have implemented for debugging purposes only).
|
||||
|
||||
Finally, implement and test the *resize* function. This function is automatically called from the *insert* function when the set gets “too full”. This function should make a new top level vector structure of the requested size and copy all the data from the old structure to the new structure. Note that the elements will likely be shuffled around from the old structure to the new structure.-->
|
||||
|
||||
Complete the *isHappy* function using separate chaining. Do not use any of these: std::unordered_map, std::unordered_set, std::map, std::set.
|
||||
|
||||
**To complete this checkpoint**: Show a TA these additions and the test output.
|
||||
|
||||
## Checkpoint 3,4,5,6: Separate Chaining Hash Table (Yes, it's Checkpoint 3,4,5,6, as there are 3 extra credits for making this program work.)
|
||||
|
||||
*estimate: 30-40 minutes*
|
||||
|
||||
Form a team of two members. Complete the *longestConsecutive* function in this [program](test_longest_consecutive_sequence.cpp). You must use a separate-chaining-based hash table. Do not use any of these: std::unordered_map, std::unordered_set, std::map, std::set.
|
||||
|
||||
The *longestConsecutive* function takes an unsorted std::vector of integers, and returns the length of the longest consecutive elements sequence.
|
||||
|
||||
```console
|
||||
Example 1:
|
||||
|
||||
Input: nums = [100,4,200,1,3,2]
|
||||
Output: 4
|
||||
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
|
||||
```
|
||||
|
||||
```console
|
||||
Example 2:
|
||||
|
||||
Input: nums = [0,3,7,2,5,8,4,6,0,1]
|
||||
Output: 9
|
||||
Explanation: The longest consecutive elements sequence is [0, 1, 2, 3, 4, 5, 6, 7, 8]. Therefore its length is 9.
|
||||
```
|
||||
|
||||
**To complete checkpoint (3,4,5,6)**: Show a TA your program and the test results.
|
||||
|
||||
**Note**: checkpoint (3,4,5,6) is very challenging, if you can't get it work during your lab period, make sure you understand it completely after the lab period, because one of the four problems on Test 3, will be about separate-chaining-based hash tables. It's 100% certain.
|
||||
BIN
labs/12_hash_tables/a.out
Executable file
BIN
labs/12_hash_tables/a.out
Executable file
Binary file not shown.
90
labs/12_hash_tables/find_max_average.cpp
Normal file
90
labs/12_hash_tables/find_max_average.cpp
Normal file
File diff suppressed because one or more lines are too long
23
labs/12_hash_tables/happy_number.cpp
Normal file
23
labs/12_hash_tables/happy_number.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <iostream>
|
||||
|
||||
bool isHappy(int n) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Test cases
|
||||
// 2, 4, 5, 6, 17, 18, 20 are not happy numbers.
|
||||
// 1, 7, 10, 13, 19, 23, 28, 68 are 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;
|
||||
}
|
||||
|
||||
95
labs/12_hash_tables/happy_number_separate_chaining_sol.cpp
Normal file
95
labs/12_hash_tables/happy_number_separate_chaining_sol.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// Solve the problem using separate chaining.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// 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<TABLE_SIZE;i++){
|
||||
hash_table[i]=NULL;
|
||||
}
|
||||
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(identify(newN, hash_table)){
|
||||
return false;
|
||||
}
|
||||
// can't find it, push it in the map first
|
||||
add(newN, hash_table);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
50
labs/12_hash_tables/happy_number_set_sol.cpp
Normal file
50
labs/12_hash_tables/happy_number_set_sol.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <iostream>
|
||||
#include <unordered_set>
|
||||
|
||||
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<int> 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;
|
||||
}
|
||||
|
||||
260
labs/12_hash_tables/test/ds_hashset.h
Normal file
260
labs/12_hash_tables/test/ds_hashset.h
Normal file
@@ -0,0 +1,260 @@
|
||||
#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 <iostream>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
// 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<KeyType>::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<KeyType> > 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<KeyType, HashFunc>& old)
|
||||
: m_table(old.m_table), m_size(old.m_size) {}
|
||||
|
||||
~ds_hashset() {}
|
||||
|
||||
ds_hashset& operator=(const ds_hashset<KeyType,HashFunc>& 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<m_table.size(); ++i) {
|
||||
ostr << i << ": ";
|
||||
for (hash_list_itr p = m_table[i].begin(); p != m_table[i].end(); ++p)
|
||||
ostr << ' ' << *p;
|
||||
ostr << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// resize the table with the same values but twice as many buckets
|
||||
void resize_table(unsigned int new_size) {
|
||||
|
||||
// Implement this function for Lab 11, Checkpoint 2, Part 2
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
#endif
|
||||
155
labs/12_hash_tables/test/test_ds_hashset.cpp
Normal file
155
labs/12_hash_tables/test/test_ds_hashset.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
|
||||
#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<std::string, hash_string_obj> 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;
|
||||
}
|
||||
BIN
labs/12_hash_tables/test2/a.out
Executable file
BIN
labs/12_hash_tables/test2/a.out
Executable file
Binary file not shown.
95
labs/12_hash_tables/test2/happy_number_separate_chaining.cpp
Normal file
95
labs/12_hash_tables/test2/happy_number_separate_chaining.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// Solve the problem using separate chaining.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
// 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<TABLE_SIZE;i++){
|
||||
hash_table[i]=NULL;
|
||||
}
|
||||
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(identify(newN, hash_table)){
|
||||
return false;
|
||||
}
|
||||
// can't find it, push it in the map first
|
||||
add(newN, hash_table);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
BIN
labs/12_hash_tables/test3/a.out
Executable file
BIN
labs/12_hash_tables/test3/a.out
Executable file
Binary file not shown.
50
labs/12_hash_tables/test3/happy_number_set_sol.cpp
Normal file
50
labs/12_hash_tables/test3/happy_number_set_sol.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <iostream>
|
||||
#include <unordered_set>
|
||||
|
||||
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<int> 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;
|
||||
}
|
||||
|
||||
BIN
labs/12_hash_tables/test4/a.out
Executable file
BIN
labs/12_hash_tables/test4/a.out
Executable file
Binary file not shown.
117
labs/12_hash_tables/test4/test_longest_consecutive_sequence.cpp
Normal file
117
labs/12_hash_tables/test4/test_longest_consecutive_sequence.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#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<int>& nums) {
|
||||
int len=0;
|
||||
Node* hash_table[TABLE_SIZE];
|
||||
// initialize the table
|
||||
for(int i=0;i<TABLE_SIZE;i++){
|
||||
hash_table[i] = nullptr;
|
||||
}
|
||||
int size = nums.size();
|
||||
if(size == 0){
|
||||
return 0;
|
||||
}
|
||||
// store unique elements in nums in set1
|
||||
for(int i=0;i<nums.size();i++){
|
||||
insert(nums[i], hash_table);
|
||||
}
|
||||
|
||||
int i=0;
|
||||
Node* current = hash_table[i];
|
||||
// if we reach here, then there is at least one Node in the hash table.
|
||||
// find the first non-NULL Node.
|
||||
while(current == nullptr){
|
||||
i++;
|
||||
current = hash_table[i];
|
||||
}
|
||||
// traverse the hash table
|
||||
while(current!=nullptr){
|
||||
// if (current->num-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<TABLE_SIZE){
|
||||
// move to the next bucket
|
||||
current = hash_table[i];
|
||||
}else{
|
||||
// this means we have visited every element in the whole hash table.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int main() {
|
||||
//std::vector<int> nums = {100, 4, 200, 1, 3, 2};
|
||||
std::vector<int> nums = {0,3,7,2,5,8,4,6,0,1};
|
||||
//std::vector<int> 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<size-1;i++){
|
||||
std::cout<< nums[i] << ",";
|
||||
}
|
||||
std::cout<< nums[size-1] << "}" <<std::endl;
|
||||
int length = longestConsecutive(nums);
|
||||
std::cout << "The length of the longest consecutive sequence is: " << length << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
// 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<int>& nums) {
|
||||
int len=0;
|
||||
std::unordered_set<int> set1;
|
||||
int size = nums.size();
|
||||
// store unique elements in nums in set1
|
||||
for(int i=0;i<nums.size();i++){
|
||||
set1.insert(nums[i]);
|
||||
}
|
||||
std::unordered_set<int>::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<int> nums = {100, 4, 200, 1, 3, 2};
|
||||
std::vector<int> nums = {0,3,7,2,5,8,4,6,0,1};
|
||||
//std::vector<int> 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<size-1;i++){
|
||||
std::cout<< nums[i] << ",";
|
||||
}
|
||||
std::cout<< nums[size-1] << "}" <<std::endl;
|
||||
int length = longestConsecutive(nums);
|
||||
std::cout << "The length of the longest consecutive sequence is: " << length << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#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<int>& nums) {
|
||||
int len=0;
|
||||
Node* hash_table[TABLE_SIZE];
|
||||
// initialize the table
|
||||
for(int i=0;i<TABLE_SIZE;i++){
|
||||
hash_table[i] = nullptr;
|
||||
}
|
||||
int size = nums.size();
|
||||
if(size == 0){
|
||||
return 0;
|
||||
}
|
||||
// store unique elements in nums in set1
|
||||
for(int i=0;i<nums.size();i++){
|
||||
insert(nums[i], hash_table);
|
||||
}
|
||||
|
||||
int i=0;
|
||||
Node* current = hash_table[i];
|
||||
// if we reach here, then there is at least one Node in the hash table.
|
||||
// find the first non-NULL Node.
|
||||
while(current == nullptr){
|
||||
i++;
|
||||
current = hash_table[i];
|
||||
}
|
||||
// traverse the hash table
|
||||
while(current!=nullptr){
|
||||
// if (current->num-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<TABLE_SIZE){
|
||||
// move to the next bucket
|
||||
current = hash_table[i];
|
||||
}else{
|
||||
// this means we have visited every element in the whole hash table.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int main() {
|
||||
//std::vector<int> nums = {100, 4, 200, 1, 3, 2};
|
||||
std::vector<int> nums = {100, 4, 200, 1, 3, 2, 2, 2, 2, 3};
|
||||
//std::vector<int> nums = {100, 4, 200, 1, 3, 2, 5, 6};
|
||||
//std::vector<int> nums = {0,3,7,2,5,8,4,6,0,1};
|
||||
//std::vector<int> 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<size-1;i++){
|
||||
std::cout<< nums[i] << ",";
|
||||
}
|
||||
std::cout<< nums[size-1] << "}" <<std::endl;
|
||||
int length = longestConsecutive(nums);
|
||||
std::cout << "The length of the longest consecutive sequence is: " << length << std::endl;
|
||||
return 0;
|
||||
}
|
||||
23
labs/12_hash_tables/test_longest_consecutive_sequence.cpp
Normal file
23
labs/12_hash_tables/test_longest_consecutive_sequence.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
int longestConsecutive(std::vector<int>& nums) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
//std::vector<int> nums = {100, 4, 200, 1, 3, 2};
|
||||
std::vector<int> nums = {100, 4, 200, 1, 3, 2, 2, 2, 2, 3};
|
||||
//std::vector<int> nums = {100, 4, 200, 1, 3, 2, 5, 6};
|
||||
//std::vector<int> nums = {0,3,7,2,5,8,4,6,0,1};
|
||||
//std::vector<int> nums = {100, 4, 200, 201, 202, 203, 205, 204, 1, 3, 2};
|
||||
//std::vector<int> nums = {-3,0,1,2,3,-2,-1,-5};
|
||||
int size = nums.size();
|
||||
std::cout<< "for vector {";
|
||||
for(int i=0;i<size-1;i++){
|
||||
std::cout<< nums[i] << ",";
|
||||
}
|
||||
std::cout<< nums[size-1] << "}" <<std::endl;
|
||||
int length = longestConsecutive(nums);
|
||||
std::cout << "The length of the longest consecutive sequence is: " << length << std::endl;
|
||||
return 0;
|
||||
}
|
||||
120
labs/12_hash_tables/test_longest_consecutive_sequence_sol.cpp
Normal file
120
labs/12_hash_tables/test_longest_consecutive_sequence_sol.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#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<int>& nums) {
|
||||
int len=0;
|
||||
Node* hash_table[TABLE_SIZE];
|
||||
// initialize the table
|
||||
for(int i=0;i<TABLE_SIZE;i++){
|
||||
hash_table[i] = nullptr;
|
||||
}
|
||||
int size = nums.size();
|
||||
if(size == 0){
|
||||
return 0;
|
||||
}
|
||||
// store unique elements in nums in set1
|
||||
for(int i=0;i<nums.size();i++){
|
||||
insert(nums[i], hash_table);
|
||||
}
|
||||
|
||||
int i=0;
|
||||
Node* current = hash_table[i];
|
||||
// if we reach here, then there is at least one Node in the hash table.
|
||||
// find the first non-NULL Node.
|
||||
while(current == nullptr){
|
||||
i++;
|
||||
current = hash_table[i];
|
||||
}
|
||||
// traverse the hash table
|
||||
while(current!=nullptr){
|
||||
// if (current->num-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<TABLE_SIZE){
|
||||
// move to the next bucket
|
||||
current = hash_table[i];
|
||||
}else{
|
||||
// this means we have visited every element in the whole hash table.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int main() {
|
||||
//std::vector<int> nums = {100, 4, 200, 1, 3, 2};
|
||||
//std::vector<int> nums = {100, 4, 200, 1, 3, 2, 2, 2, 2, 3};
|
||||
//std::vector<int> nums = {100, 4, 200, 1, 3, 2, 5, 6};
|
||||
//std::vector<int> nums = {0,3,7,2,5,8,4,6,0,1};
|
||||
//std::vector<int> nums = {100, 4, 200, 201, 202, 203, 205, 204, 1, 3, 2};
|
||||
std::vector<int> nums = {-3,0,1,2,3,-2,-1,-5};
|
||||
int size = nums.size();
|
||||
std::cout<< "for vector {";
|
||||
for(int i=0;i<size-1;i++){
|
||||
std::cout<< nums[i] << ",";
|
||||
}
|
||||
std::cout<< nums[size-1] << "}" <<std::endl;
|
||||
int length = longestConsecutive(nums);
|
||||
std::cout << "The length of the longest consecutive sequence is: " << length << std::endl;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user