1

I am writing a program for a class assignment that tests 3 hashing functions with 3 different double hash functions (so 1/1, 1/2, 1/3, 2/1, 2/2, etc.), and the end goal is to output the test results of each pairing to a file via console command "exename > Results.txt" as per my professors instructions. I'm reaching final testing but my program will go into main, complete the nested for loop once, output the test results of the first hash function pairing, then the program ends with no error. I have messed with Visual Studio 12's debugger for hours and am no closer to finding a solution than I was when I started. When I run the program via console, it outputs "Unable to open data file. Program terminating", even though when stepping through the program it never once enters that for loop. Any ideas? Thanks!

P.S. I'm aware that some methods used in this program may be unconventional or not necessarily the easiest/best way to implement this, but I'm required to confine to my professor's standards.

UPDATE: I added a cout line in the getline for loop and can now see that the test completes once, then the next time around it repeats that for loop 41 times and exits instead of finishing all 50. Looks like we're getting somewhere.

Here is my output:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950ERROR1 Testing hash function 1 using double hash 1. Total collisions = 360. |||||||-------------------------------------|||||||||||||||-----|||||||||||||||--------|||||||||||||

1234567891011121314151617181920212223242526272829303132333435363738394041

#include <iostream>
#include <iomanip>
#include <fstream>
#include <stdlib.h>
#include <math.h>
#include <conio.h>
#include <string.h>

#define TABLESIZE     100
#define KEYSIZE       4
#define EMPTYKEY      "----"
#define DATAFILE      "P4DATA.txt"

using namespace std;

struct HashStruct
{
     char key[5];
     int data;
};

void InitTable(HashStruct hashT[], int TableSize);
int Hash_1(char *key);
int Hash_2(char *key);
int Hash_3(char *key);
int ProbeDec_1(char *key);
int ProbeDec_2(char *key);
int ProbeDec_3(char *key);
int HashInsert(HashStruct T[], char *key, int data, int hNum, int dhNum);

int main(void){

     int          hashNum, dHashNum, count;
     ifstream     *inFile;
     HashStruct   T[100];  // Hash table srray of 100 data structures
     char         line[64];// Array to hold lines read from file
     char         key[5];  // Array to hold 4-character keys
     int          data;    // Integer data
     char         filename[15];

     strcpy(filename, DATAFILE);

     for(hashNum = 0; hashNum < 3; hashNum++){
         for(dHashNum = 0; dHashNum < 3; dHashNum++){
             InitTable(T, TABLESIZE);
             inFile = new ifstream();
             inFile->open(filename, ifstream::in);
             if(!inFile->is_open()){
                 cout << "Unable to open data file. Program terminating\n";
                 return 0;
             }

             count = 0;
             for(int i = 0; i < 50; i++){
                 inFile->getline(line, 64, '\n');
                 sscanf(line, "%s %d", key, &data);
                 count += HashInsert(T, key, data, hashNum, dHashNum);
             }

             cout << "Testing hash function " << hashNum + 1 << " using double hash " << dHashNum + 1 << ".\n";
             cout << "Total collisions = " << count << ".\n";
             for(int i=0; i < 100; i++){
                 if(strcmp(T[i].key, EMPTYKEY))
                     cout << "|";
                 else
                     cout << "-";
             }
             cout << "\n\n";
             inFile->close();
             delete inFile;
         }
     }
     return 1;
}

int HashInsert(HashStruct T[], char *key, int data, int hNum, int dhNum){
    int  testNum = (hNum * 3) + dhNum;
    int  colCount = 0;
    int  hashIndex, probeDec;

    switch(testNum){
    case 0 :  // Hash function 1 -- Double hash 1 (linear probing)
        hashIndex = Hash_1(key);
        probeDec = ProbeDec_1(key); // Function just returns 1 
        break;
    case 1 :  // Hash function 1 -- Double hash 2  
        hashIndex = Hash_1(key);
        probeDec = ProbeDec_2(key);
        break;
    case 2 :  // Hash function 1 -- Double hash 3
        hashIndex = Hash_1(key);
        probeDec = ProbeDec_3(key);
        break;
    case 3 :  // Hash function 2 -- Double hash 1 (linear probing)
        hashIndex = Hash_2(key);
        probeDec = ProbeDec_1(key); // Function just returns 1
        break;
    case 4 :  // Hash function 2 -- Double hash 2  
        hashIndex = Hash_2(key);
        probeDec = ProbeDec_2(key);
        break;
    case 5 :  // Hash function 2 -- Double hash 3
        hashIndex = Hash_2(key);
        probeDec = ProbeDec_3(key);
        break;
    case 6 :  // Hash function 3 -- Double hash 1 (linear probing)
        hashIndex = Hash_3(key);
        probeDec = ProbeDec_1(key); // Function just returns 1
        break;
    case 7 :  // Hash function 3 -- Double hash 2  
        hashIndex = Hash_3(key);
        probeDec = ProbeDec_2(key);
        break;
    case 8 :  // Hash function 3 -- Double hash 3  
        hashIndex = Hash_3(key);
        probeDec = ProbeDec_3(key);
        break;
    }

    while(strcmp(T[hashIndex].key, EMPTYKEY) != 0){
        colCount++;
        hashIndex -= probeDec;  // Decrementing was chosen you could also choose to
        if(hashIndex < 0)    //  increment and wrap back to the beginning of the table.
            hashIndex = hashIndex + TABLESIZE;
    }   

    strcpy(T[hashIndex].key, key);
    T[hashIndex].data = data;
    return colCount;
}

void InitTable(HashStruct hashT[], int TableSize){
    int i;

    for(i=0; i<TableSize; i++){
        strcpy(hashT[i].key, EMPTYKEY);
        hashT[i].data = 0;
    }
}

int Hash_1(char *key){
    int hash = 0;
    int prime = 29;
    int index = 0;

     for(int i = 0; i < 4; i++){
         hash = (key[i]-'0')*prime;
         for(int j = (3-i); j > 0; j--){
             hash *= prime;
         }
     }

     index = hash % TABLESIZE;
     return index;
}

int Hash_2(char *key){     // Folding
    int hash = 0;
    int index = 0;

    hash = (((key[0]-'0')+(key[1]-'0'))*37) + 
        (((key[1]-'0')+(key[2]-'0'))*47) + 
        (((key[2]-'0')+(key[3]-'0'))*67);

    index = hash % TABLESIZE;
    return index;
}

int Hash_3(char *key){     //Middle Squaring
    int hash = 0;
    int index = 0;

    hash = ((key[1]-'0') + (key[2]-'0'));
    hash *= hash;
    index = hash % TABLESIZE;
    return index;
}

int ProbeDec_1(char *key){
    return 1;
}

int ProbeDec_2(char *key){
    int dhash = 0;
    int index = 0;

    dhash = ((key[0]-'0')*97) + ((key[1]-'0')*83);
    index = dhash % TABLESIZE;
    return index;
}

int ProbeDec_3(char *key){
    int dhash = 0;
    int index = 0;

    dhash = (((key[0]-'0')*29) + ((key[1]-'0')*59) +
        ((key[2]-'0')*79) + ((key[3]-'0')*89));
    index = dhash % TABLESIZE;
    return index;
}
  • 1
    Welcome to stackoverflow.com. Please take some time to read [the help pages](http://stackoverflow.com/help), especially the sections named ["What topics can I ask about here?"](http://stackoverflow.com/help/on-topic) and ["What types of questions should I avoid asking?"](http://stackoverflow.com/help/dont-ask). Also please [take the tour](http://stackoverflow.com/tour) and [read about how to ask good questions](http://stackoverflow.com/help/how-to-ask). Lastly please learn how to create a [**Minimal**, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve). – Some programmer dude Jul 31 '18 at 08:57
  • Also please read [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/), and all of http://idownvotedbecau.se/ to learn some reasons your question might be down-voted. Finally, please [learn how to debug your programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). – Some programmer dude Jul 31 '18 at 08:57
  • And considering your bad mix of C++ with C, I suggest you [get a few good books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282#388282) to learn C++ properly. – Some programmer dude Jul 31 '18 at 09:00
  • @Someprogrammerdude this is how my professor requires we write our code, we aren't allowed to use the STL and must implement strings as character arrays. He's like 80 years old. – Alex McGowan Jul 31 '18 at 09:01
  • 360 collisions out of how many? and is that correct? – Surt Jul 31 '18 at 17:40
  • @Surt That is using the first double hash function which is just to increment by 1 when there is a collision, so this is a very inefficient hashing function but it's what my professor wants for the first test. – Alex McGowan Jul 31 '18 at 20:08

1 Answers1

1

There are a lot of bad checking in this code I'll just go for part of it.

for(int i = 0; i < 50; i++){
  inFile->getline(line, 64, '\n');
  sscanf(line, "%s %d", key, &data);
  count += HashInsert(T, key, data, hashNum, dHashNum);
}

Line 1+2: Too many magic numbers, if you mix up the 50, 64 and 4's you get errors.

Line 3: sscanf is very powerful but somewhat unsafe as you don't know how long the return values for strings are, one way is to make the string arrays as long as the read line.

Line 2+3 return values not checked.

char key[MAXLineLength];
const int LinesToRead = 100; // your hash array is 100, but you read only 50
const int NUMFIELDS = 2;
const int ERROR = -1; // there is a system return somewhere that is more correct.

for(int i = 0; i < LinesToRead ; i++){
  inFile->getline(line, MAXLineLength, '\n');
  if (!inFile->good())
    return ERROR;
  if (NUMFIELDS != sscanf(line, "%s %d", key, &data))
    return ERROR;
  if (strlen(key)!=4)
    return ERROR;
  count += HashInsert(T, key, data, hashNum, dHashNum);
}
Surt
  • 15,501
  • 3
  • 23
  • 39
  • Why would the 50 and 64 cause errors? The 50 is just the number of data lines in my file, I don't see why iterating this for loop 50 times would cause problems. Could you explain? – Alex McGowan Jul 31 '18 at 16:09
  • A majority of this code was provided by my instructor, including that which you have pointed out. The line array is set to 64 characters, which is why there is a 64 in the getline function – Alex McGowan Jul 31 '18 at 16:13
  • I do see that now that I have implemented these checks, I'm getting an error when checking for inFile->good(). Where should I go about hunting down the cause of that? I am quite a beginner and still have a lot to learn I apologize. – Alex McGowan Jul 31 '18 at 16:20
  • The problem is that when you change 50 to 100 later, you have to find all places where you at that time have written 50 to 100, its much easier to control when you store the value in a constant. You most likely have an End Of File (eof), you can check for that specific error. – Surt Jul 31 '18 at 17:37
  • And if you only have 50 lines and you have set the LinesToRead to 100 you will get the EOF, so change it to what it should be. – Surt Jul 31 '18 at 17:38
  • I am simply inserting 50 items into a hash table of size 100, it's not meant to be full. – Alex McGowan Jul 31 '18 at 20:07
  • Turns out the error was coming from my 2nd double hashing function, I changed the prime numbers I was using and the program now completes. Thanks for your help! – Alex McGowan Jul 31 '18 at 21:23