451 lines
No EOL
16 KiB
C
451 lines
No EOL
16 KiB
C
// header files
|
|
#include "GeneralUtility.h"
|
|
#include "HashUtility.h"
|
|
#include "StateDataUtility.h"
|
|
|
|
// constants
|
|
const int MINIMUM_HASH_LETTER_COUNT = 7;
|
|
const int ITEM_NOT_FOUND = -1;
|
|
const bool USED_NODE = true;
|
|
const bool UNUSED_NODE = false;
|
|
|
|
/* Data Structures
|
|
typedef struct HashStruct
|
|
{
|
|
StateDataType *array;
|
|
|
|
int tableSize;
|
|
|
|
ProbeType probeStrategy;
|
|
} ProbingHashType;
|
|
Data Structures */
|
|
|
|
// function definitions
|
|
|
|
/*
|
|
Name: addItemFromData
|
|
Process: adds item to hash table using data input,
|
|
sets node to used state
|
|
Function input/parameters: hash data (ProbingHashType *),
|
|
state name (const char *),
|
|
average, lowest, and highest temperatures (double),
|
|
Function output/parameters: updated hash table data (ProbingHashType *)
|
|
Function output/returned: result of operation (bool)
|
|
Device input/---: none
|
|
Device output/monitor: probing process displayed (in called function)
|
|
Dependencies: setDataNodeFromData, addItemFromStruct
|
|
*/
|
|
bool addItemFromData( ProbingHashType *hashTable, const char *stateName,
|
|
double avgTemp, double lowTemp, double highTemp )
|
|
{
|
|
StateDataType createState;
|
|
// sets a node from the data using the function
|
|
setDataNodeFromData(&createState, stateName, avgTemp,
|
|
lowTemp, highTemp, UNUSED_NODE);
|
|
// uses add item from struct to add the data and do the calling.
|
|
// return addItemFromStruct
|
|
return addItemFromStruct(hashTable, createState);
|
|
}
|
|
|
|
/*
|
|
Name: addItemFromStruct
|
|
Process: adds item to hash table using struct input,
|
|
uses probing as specified in hashTable data,
|
|
either LINEAR_PROBING or QUADRATIC_PROBING,
|
|
may probe as many as tableSize times
|
|
Function input/parameters: hash data (ProbingHashType *),
|
|
new item (StateDataType)
|
|
Function output/parameters: updated hash table data (ProbingHashType *)
|
|
Function output/returned: result of operation (bool)
|
|
Device input/---: none
|
|
Device output/monitor: probing process displayed
|
|
Dependencies: getHashIndex, privateToPower, printf, stateDataToString,
|
|
setDataNodeFromStruct
|
|
*/
|
|
bool addItemFromStruct( ProbingHashType *hashTable, StateDataType newItem )
|
|
{
|
|
// initialize function/variables
|
|
char stateString[MAX_STR_LEN];
|
|
// create offset variable
|
|
int hashOffset = 0;
|
|
// get hash value, assign to hashIndex variable
|
|
int hashIndex = getHashIndex(*hashTable, newItem);
|
|
// set a temp node with index
|
|
StateDataType currentNode;
|
|
int workingIndex = hashIndex;
|
|
setDataNodeFromStruct(¤tNode, newItem);
|
|
// loop until location found
|
|
// iterate no more than HT size AND element is in use
|
|
printf("\nIndices Probed: %d", workingIndex);
|
|
while(workingIndex <= hashTable->tableSize &&
|
|
hashTable->array[workingIndex].inUse)
|
|
{
|
|
// increment the offset variable
|
|
hashOffset = hashOffset + 1;
|
|
// check for linear probe type
|
|
if(hashTable->probeStrategy == LINEAR_PROBING)
|
|
{
|
|
// set working variable to the hash index plus the offset
|
|
workingIndex = hashIndex + hashOffset;
|
|
printf(", %d", workingIndex % hashTable->tableSize);
|
|
}
|
|
// otherwise, assume quadratic probe type
|
|
else
|
|
{
|
|
// set working variable to the hash index plus the offset squared
|
|
workingIndex = hashIndex + privateToPower(hashOffset, 2);
|
|
printf(", %d", workingIndex % hashTable->tableSize);
|
|
}
|
|
// mod by table size to keep index in bounds
|
|
workingIndex = workingIndex % hashTable->tableSize;
|
|
// set temp node to the new index
|
|
}
|
|
printf("\n");
|
|
stateDataToString(stateString, currentNode);
|
|
printf("%s, %d -> %d\n", stateString, hashIndex, workingIndex);
|
|
// end index loop
|
|
// check for failed correct index
|
|
if(hashOffset == hashTable->tableSize)
|
|
{
|
|
// return false
|
|
return false;
|
|
}
|
|
// complete the data - set the temp value's inUse to true
|
|
currentNode.inUse = USED_NODE;
|
|
// assign to array (use setDataNodeFromStruct)
|
|
setDataNodeFromStruct(&hashTable->array[workingIndex], currentNode);
|
|
// return true
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
Name: clearHashTable
|
|
Process: clear hash table array, deallocates hash struct
|
|
Function input/parameters: hash data (ProbingHashType *)
|
|
Function output/parameters: updated hash table data (ProbingHashType *)
|
|
Function output/returned: none
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: free
|
|
*/
|
|
void clearHashTable( ProbingHashType *hashTable )
|
|
{
|
|
// free the internal array
|
|
free(hashTable->array);
|
|
// free the rest of the structure
|
|
free(hashTable);
|
|
// no return, void.
|
|
}
|
|
|
|
/*
|
|
Name: displayHashTable
|
|
Process: array data dump of numbered data to screen,
|
|
shows data where used, shows "Unused" where not
|
|
Function input/parameters: provided hashTable data (const ProbingHashType *)
|
|
Function output/parameters: none
|
|
Function output/returned: none
|
|
Device input/---: none
|
|
Device output/monitor: displayed as specified
|
|
Dependencies: printf, stateDataToString
|
|
*/
|
|
void displayHashTable( const ProbingHashType *hashTable )
|
|
{
|
|
int dispIterator;
|
|
char dispState[MAX_STR_LEN];
|
|
// print out the 'title card' for the display
|
|
printf("\nHASH TABLE ARRAY DUMP:\n");
|
|
// iterate through the array
|
|
for(dispIterator = 0; dispIterator < hashTable->tableSize; dispIterator++)
|
|
{
|
|
if(hashTable->array[dispIterator].inUse)
|
|
{
|
|
// print the state data using stateDataToString
|
|
stateDataToString(dispState, hashTable->array[dispIterator]);
|
|
printf("%2d) %s\n", dispIterator + 1, dispState);
|
|
}
|
|
else
|
|
{
|
|
// print "Unused" in the table
|
|
printf("%2d) Unused\n", dispIterator + 1);
|
|
}
|
|
}
|
|
// no return, void.
|
|
}
|
|
|
|
/*
|
|
Name: findItem
|
|
Process: finds item in hash table, returns
|
|
Function input/parameters: provided search data (const StateDataType),
|
|
hashTable (const ProbingHashType *)
|
|
Function output/parameters: none
|
|
Function output/returned: state data set to struct (StateDataType),
|
|
or search parameter set to empty node if not found
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: findItemIndex, setEmptyDataNode
|
|
*/
|
|
StateDataType findItem( const ProbingHashType *hashTable,
|
|
StateDataType searchItem )
|
|
{
|
|
int indexFound;
|
|
StateDataType foundItem;
|
|
// set the return item to empty as default
|
|
setEmptyDataNode(&foundItem);
|
|
// use findItemIndex to search for the item
|
|
indexFound = findItemIndex(hashTable, searchItem);
|
|
if (indexFound != ITEM_NOT_FOUND)
|
|
{
|
|
// return the hashTable at index data.
|
|
return hashTable->array[indexFound];
|
|
}
|
|
// return foundItem with blank data
|
|
return foundItem;
|
|
}
|
|
|
|
/*
|
|
Name: findItemIndex
|
|
Process: finds item index, using probing strategy provided in hashTable data,
|
|
otherwise,
|
|
returns ITEM_NOT_FOUND if search fails after tableSize attempts,
|
|
displays index probing attempts
|
|
Function input/parameters: provided search data (const StateDataType),
|
|
hashTable (const ProbingHashType *)
|
|
Function output/parameters: none
|
|
Function output/returned: index or ITEM_NOT_FOUND (int) as specified
|
|
Device input/---: none
|
|
Device output/monitor: displays probing action, provided in sample run file
|
|
Dependencies: getHashIndex, printf, privateCompareStrings, privateToPower,
|
|
setDataNodeFromStruct
|
|
*/
|
|
int findItemIndex( const ProbingHashType *hashTable, StateDataType searchItem )
|
|
{
|
|
// initialize function/variables
|
|
int findIterator;
|
|
// set hash index to getHashIndex
|
|
int hashIndex = getHashIndex(*hashTable, searchItem);
|
|
// declare added value, set to zero
|
|
int addedVal = 0;
|
|
// declare working index
|
|
int workingIndex = hashIndex;
|
|
// set the value into a temp
|
|
// test the value, set compare to int var
|
|
int strCompare = privateCompareStrings(hashTable->array[workingIndex].name,
|
|
searchItem.name);
|
|
// print indices probed, with hash index
|
|
printf("\nIndices Probed: %d", workingIndex);
|
|
// loop up to table size with added value AND value not found
|
|
// value not found => test for equality of name
|
|
for(findIterator = 0; findIterator < hashTable->tableSize && strCompare != 0;
|
|
findIterator++)
|
|
{
|
|
// increment the added value
|
|
addedVal = addedVal + 1;
|
|
// check for linear probing type
|
|
if(hashTable->probeStrategy == LINEAR_PROBING)
|
|
{
|
|
// get a working index from the hash index plus the added value
|
|
workingIndex = hashIndex + addedVal;
|
|
}
|
|
// otherwise, assume quadratic
|
|
else
|
|
{
|
|
// get a working index from the hash index
|
|
// plus the added value squared
|
|
workingIndex = hashIndex + privateToPower(addedVal, 2);
|
|
}
|
|
// process the working index to set it within array indices
|
|
workingIndex = workingIndex % hashTable->tableSize;
|
|
// print index probed, with comma delimiter
|
|
printf(", %d", workingIndex);
|
|
// set the value into a temp
|
|
// test the value, set compare to int var
|
|
strCompare = privateCompareStrings(hashTable->array[workingIndex].name,
|
|
searchItem.name);
|
|
}
|
|
// end of loop
|
|
// print an endline
|
|
printf("\n");
|
|
// check for item not found (added value is up at hash table size)
|
|
if(addedVal == hashTable->tableSize)
|
|
{
|
|
// return item not found
|
|
return ITEM_NOT_FOUND;
|
|
}
|
|
// return working index
|
|
return workingIndex;
|
|
}
|
|
|
|
/*
|
|
Name: getHashIndex
|
|
Process: finds hashed index for given data item,
|
|
sums integer values of state name characters,
|
|
if state name length is less than MINIMUM_HASH_LETTER_COUNT,
|
|
repeats going over the state letters as needed to meet this minimum
|
|
Function input/parameters: provided search data (const StateDataType),
|
|
hashTable (const ProbingHashType)
|
|
Function output/parameters: none
|
|
Function output/returned: array index generated from state name (int)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: privateGetStringLength
|
|
*/
|
|
int getHashIndex( const ProbingHashType hashTable, const StateDataType state )
|
|
{
|
|
int hashIndex = 0, hashDiff = 0, hashIterator;
|
|
// check to see if the state name length is less than MIN HASH LETTER COUNT
|
|
// if it is, take a difference of the minimum letter count, then loop
|
|
if(privateGetStringLength(state.name) < MINIMUM_HASH_LETTER_COUNT)
|
|
{
|
|
// set the hash difference
|
|
hashDiff = MINIMUM_HASH_LETTER_COUNT - privateGetStringLength(state.name);
|
|
}
|
|
// otherwise, for loop through the name of the state
|
|
for(hashIterator = 0; hashIterator < privateGetStringLength(state.name);
|
|
hashIterator++)
|
|
{
|
|
// loop through the state's characters, add them up.
|
|
hashIndex = hashIndex + (int)state.name[hashIterator];
|
|
}
|
|
// if the state does not meet the minimum, then loop through the difference.
|
|
for(hashIterator = 0; hashIterator < hashDiff; hashIterator++)
|
|
{
|
|
// since the requirement wasn't met, and if the difference is greater than
|
|
// zero, then this loop will fill in the gap.
|
|
hashIndex = hashIndex + (int)state.name[hashIterator];
|
|
}
|
|
// since the hash index is now a number, must mod by table size in order to
|
|
// get an index value that is range fitted.
|
|
hashIndex = hashIndex % hashTable.tableSize;
|
|
// return hashIndex
|
|
return hashIndex;
|
|
}
|
|
|
|
/*
|
|
Name: initializeHashTable
|
|
Process: creates dynamically allocated hashTable,
|
|
creates dynamically allocated array of empty StateDataType items,
|
|
initializes tableSize to given capacity,
|
|
initializes probe strategy to given strategy
|
|
Function input/parameters: provided capacity (int),
|
|
provided probe strategy (ProbeType)
|
|
Function output/parameters: none
|
|
Function output/returned: pointer to created hashTable (ProbingHashType *)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: malloc, setEmptyDataNode,
|
|
*/
|
|
ProbingHashType *initializeHashTable( int capacity, ProbeType probe )
|
|
{
|
|
int initIterator;
|
|
// use malloc to initialize the table
|
|
ProbingHashType *createdHashTable =
|
|
(ProbingHashType *) malloc(sizeof(ProbingHashType));
|
|
// use malloc to create the array
|
|
createdHashTable->array =
|
|
(StateDataType *) malloc(sizeof(StateDataType) * capacity);
|
|
// iterate through the entire array, set to empty data
|
|
for(initIterator = 0; initIterator < capacity; initIterator++)
|
|
{
|
|
// set the array's items to empty.
|
|
setEmptyDataNode(&createdHashTable->array[initIterator]);
|
|
}
|
|
// define the size of the table to capacity.
|
|
createdHashTable->tableSize = capacity;
|
|
// define the probing strategy given.
|
|
createdHashTable->probeStrategy = probe;
|
|
// return the created hash table
|
|
return createdHashTable;
|
|
}
|
|
|
|
/*
|
|
Name: removeState
|
|
Process: finds item in hash table, removes,
|
|
sets array location to unused (but does not set any other data),
|
|
returns removed state
|
|
Function input/parameters: provided search data (const StateDataType),
|
|
hashTable (const ProbingHashType)
|
|
Function output/parameters: returned state (StateDataType *)
|
|
Function output/returned: Boolean result of action (bool)
|
|
Device input/---: none
|
|
Device output/---: none
|
|
Dependencies: findItemIndex, setDataNodeFromStruct
|
|
*/
|
|
bool removeState( StateDataType *removedState,
|
|
const StateDataType toBeRemoved, const ProbingHashType hashTable )
|
|
{
|
|
int removeIndex;
|
|
// get the index of the item
|
|
removeIndex = findItemIndex(&hashTable, toBeRemoved);
|
|
// check to see if the item was not found
|
|
// if the item was found, then 'remove' it by setting to unused.
|
|
if(removeIndex != ITEM_NOT_FOUND)
|
|
{
|
|
// set the removed state to where the item is in array
|
|
setDataNodeFromStruct(removedState, hashTable.array[removeIndex]);
|
|
// set the state to unused in the array to let overwriting possible
|
|
hashTable.array[removeIndex].inUse = UNUSED_NODE;
|
|
// return true since operation success
|
|
return true;
|
|
}
|
|
// return false since item not found
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
Name: showHashTableStatus
|
|
Process: displays array <D>ata values and <U>unused values
|
|
as a string of letters,
|
|
displays number of items in hashTable,
|
|
displays minimum number of contiguous data items,
|
|
displays maximum number of contiguous data items,
|
|
displays number of empty/unused array elements
|
|
Function input/parameters: hashTable (const ProbingHashType)
|
|
Function output/parameters: none
|
|
Function output/returned: none
|
|
Device input/---: none
|
|
Device output/monitor: hash data status displayed as specified
|
|
Dependencies: sprintf, printf
|
|
*/
|
|
void showHashTableStatus( const ProbingHashType hashTable)
|
|
{
|
|
int itemCount = 0, statusIterator, maxContig = 0, minContig = 0;
|
|
int unusedCount = 0;
|
|
// display the hash table status, then iterate through either used/unused
|
|
printf("\nHash Table Status: ");
|
|
for(statusIterator = 0; statusIterator < hashTable.tableSize;
|
|
statusIterator++)
|
|
{
|
|
// check to see if inUse
|
|
if(hashTable.array[statusIterator].inUse)
|
|
{
|
|
// print 'D'
|
|
printf("D");
|
|
// increment the item count actual
|
|
itemCount = itemCount + 1;
|
|
// increment the minimum number of contiguous elements
|
|
minContig = minContig + 1;
|
|
// check to see if the min exceeds max
|
|
if(minContig > maxContig)
|
|
{
|
|
// assign the max to min since it exceeded
|
|
maxContig = minContig;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// reset the minimum value to zero.
|
|
minContig = 0;
|
|
// print 'U'
|
|
printf("U");
|
|
// keep count of the actual unused values.
|
|
unusedCount = unusedCount + 1;
|
|
}
|
|
}
|
|
// print out the table of important values.
|
|
printf("\nD => Data, U => Unused\n\n");
|
|
printf(" Items in Hash Table: %d\n", itemCount);
|
|
printf(" Minimum contiguous bins: %d\n", minContig);
|
|
printf(" Maximum contiguous bins: %d\n", maxContig);
|
|
printf(" Number of empty bins: %d\n", unusedCount);
|
|
// no return, void.
|
|
} |