// 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 ata values and 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. }