user2206227 user2206227 - 1 month ago 19
C++ Question

Implementing with quadratic probing

I have this code and I am suppose to re implement it using a quadratic probing method, the algorithm I have is

i = (i + count) % CAPACITY;
. I'm not sure how I am supposed to do this, so help would be nice. I'm thinking you would just change the hash function and the next_index function, I'm not too sure. Here is the code I need to re-implement. Header file on top template on bottom.

#ifndef TABLE1_H
#define TABLE1_H
#include <cstdlib> // Provides size_t

namespace main_savitch_12A
{
template <class RecordType>
class table
{
public:
// MEMBER CONSTANT -- See Appendix E if this fails to compile.
static const std::size_t CAPACITY = 811;
// CONSTRUCTOR
table( );
// MODIFICATION MEMBER FUNCTIONS
void insert(const RecordType& entry);
void remove(int key);
// CONSTANT MEMBER FUNCTIONS
bool is_present(int key) const;
void find(int key, bool& found, RecordType& result) const;
std::size_t size( ) const { return used; }
private:
// MEMBER CONSTANTS -- These are used in the key field of special records.
static const int NEVER_USED = -1;
static const int PREVIOUSLY_USED = -2;
// MEMBER VARIABLES
RecordType data[CAPACITY];
std::size_t used;
// HELPER FUNCTIONS
std::size_t hash(int key) const;
std::size_t next_index(std::size_t index) const;
void find_index(int key, bool& found, std::size_t& index) const;
bool never_used(std::size_t index) const;
bool is_vacant(std::size_t index) const;
};
}
#include "table1.template" // Include the implementation.
#endif
//End Of Header




#include <cassert> // Provides assert
#include <cstdlib> // Provides size_t

namespace main_savitch_12A
{
template <class RecordType>
const std::size_t table<RecordType>::CAPACITY;

template <class RecordType>
const int table<RecordType>::NEVER_USED;

template <class RecordType>
const int table<RecordType>::PREVIOUSLY_USED;

template <class RecordType>
table<RecordType>::table( )
{
std::size_t i;

used = 0;
for (i = 0; i < CAPACITY; ++i)
data[i].key = NEVER_USED; // Indicates a spot that's never been used.
}

template <class RecordType>
void table<RecordType>::insert(const RecordType& entry)
// Library facilities used: cassert
{
bool already_present; // True if entry.key is already in the table
std::size_t index; // data[index] is location for the new entry

assert(entry.key >= 0);

// Set index so that data[index] is the spot to place the new entry.
find_index(entry.key, already_present, index);

// If the key wasn't already there, then find the location for the new entry.
if (!already_present)
{
assert(size( ) < CAPACITY);
index = hash(entry.key);
while (!is_vacant(index))
index = next_index(index);
++used;
}

data[index] = entry;
}

template <class RecordType>
void table<RecordType>::remove(int key)
// Library facilities used: cassert
{
bool found; // True if key occurs somewhere in the table
std::size_t index; // Spot where data[index].key == key

assert(key >= 0);

find_index(key, found, index);
if (found)
{ // The key was found, so remove this record and reduce used by 1.
data[index].key = PREVIOUSLY_USED; // Indicates a spot that's no longer in use.
--used;
}
}

template <class RecordType>
bool table<RecordType>::is_present(int key) const
// Library facilities used: assert.h
{
bool found;
std::size_t index;

assert(key >= 0);

find_index(key, found, index);
return found;
}

template <class RecordType>
void table<RecordType>::find(int key, bool& found, RecordType& result) const
// Library facilities used: cassert.h
{
std::size_t index;

assert(key >= 0);

find_index(key, found, index);
if (found)
result = data[index];
}

template <class RecordType>
inline std::size_t table<RecordType>::hash(int key) const
{
return (key % CAPACITY);
}

template <class RecordType>
inline std::size_t table<RecordType>::next_index(std::size_t index) const
// Library facilities used: cstdlib
{
return ((index+1) % CAPACITY);
}

template <class RecordType>
void table<RecordType>::find_index(int key, bool& found, std::size_t& i) const
// Library facilities used: cstdlib
{
std::size_t count; // Number of entries that have been examined

count = 0;
i = hash(key);
while((count < CAPACITY) && (data[i].key != NEVER_USED) && (data[i].key != key))
{
++count;
i = next_index(i);
}
found = (data[i].key == key);
}

template <class RecordType>
inline bool table<RecordType>::never_used(std::size_t index) const
{
return (data[index].key == NEVER_USED);
}

template <class RecordType>
inline bool table<RecordType>::is_vacant(std::size_t index) const
{
return (data[index].key == NEVER_USED) || (data[index].key == PREVIOUSLY_USED);
}
}

Answer

With this code you are doing linear probing

    index = hash(entry.key);
    while (!is_vacant(index))
        index = next_index(index);

template <class RecordType>
inline std::size_t table<RecordType>::next_index(std::size_t index) const
// Library facilities used: cstdlib
{
    return ((index+1) % CAPACITY);
}

Say your map is nearly full and hash returns 23, then the next slots you are going to test will be 24, 25, 26, 27, etc.

All that is different about quadratic probing is the pattern of slots to test when a slot is full. Again suppose hash returns 23, then the next slot to test will be 23 + 1 = 24, the next will be 23 + 4 = 27, the next will be 23 + 9 = 32, the next will be 23 + 16 = 39. See the pattern? Each time you are testing 23 + n*n. That is quadratic probing. Of course all values should be mod CAPACITY, like you are doing now.

In other words you don't need to change the hash function, just the while loop inside insert.