/*** Implementation of the Pagh–Rodler Cuckoo Hashing Algorithm (2001) ***/ /*** This version is slightly different from what is asked in the assignment ***/ #include #include #include #define INIT_T 3 #define MAX_ITER_CNT 10 #define MAX_REC_LEVEL 4 #define FAILURE 0 #define SUCCESS 1 #define PRESENT 2 #define DOUBLE_SIZE 3 #define CHANGE_PARAMS 4 typedef struct { unsigned int s; /* Allocation size */ unsigned int t; /* log2(s) */ unsigned int n; /* Number of elements stored */ unsigned int a, b; /* Parameters for generating two hash values */ char **data; /* One-dimensional table of strings */ } htbl; /* Function prototypes. Needed only for insert() and rehash() which call each other. */ htbl init ( ); unsigned int hash ( char *, unsigned int, unsigned int ); unsigned int search ( htbl, char *); htbl insertatpos ( htbl, char *, unsigned int, int * ); htbl insert ( htbl, char *, int *, int ); htbl rehash ( htbl, int, int * ); htbl delete ( htbl, char *, int * ); htbl readfile ( char *, int * ); /* Return an empty table with s = 8, t = 3, n = 0, a = 1, and b = 3 */ htbl init ( ) { htbl T; unsigned int i; T.s = (1U << INIT_T); T.t = INIT_T; T.n = 0; T.a = 1; T.b= 3; T.data = (char **)malloc((T.s) * sizeof(char *)); /* NULL pointer indicates empty location */ for (i=0; i> (32 - t); } /* Search at the two possible indices where str may stay */ unsigned int search ( htbl T, char *str ) { unsigned int h, status = FAILURE; h = hash(str, T.a, T.t); printf("(%u,", h); fflush(stdout); if ((T.data[h]) && (!strcmp(T.data[h],str))) status = SUCCESS; h = hash(str, T.b, T.t); printf("%u): ", h); fflush(stdout); if ((T.data[h]) && (!strcmp(T.data[h],str))) status = SUCCESS; return status; } /* Helper function for insert(). Assumes that T.data[h] is NULL, that is, it is allowed to insert str at the empty index h. */ htbl insertatpos ( htbl T, char *str, unsigned int h, int *status ) { T.data[h] = (char *)malloc((1 + strlen(str)) * sizeof(char)); /* Allocate memory */ strcpy(T.data[h],str); /* Store */ *status = SUCCESS; printf("insert at index %u: success\n", h); /* The number of elements increases by one. If the load factor exceeds half, rehashing is necessary in order to double the size of the data array. The call of rehash() sets the status (success/failure). */ ++T.n; if (T.n > (T.s >> 1)) { printf("\n+++ High load factor (n = %u, s = %u). Rehashing necessary...\n", T.n, T.s); T = rehash(T,DOUBLE_SIZE,status); } return T; } /* Insert str in T. PRESENT/SUCCESS/FAILURE is stored in *status. The recursion level indicates whether further rehashing attempt will be made if the main loop fails. */ htbl insert ( htbl T, char *str, int *status, int reclevel ) { unsigned int h1, h2, i; char *newstr, *tmpstr; printf("--- Insert(%s): ", str); fflush(stdout); /* If str is already present in T, do nothing. */ if (search(T,str) == SUCCESS) { printf("already present\n"); *status = PRESENT; return T; } /* Make a copy of str to newstr */ newstr = (char *)malloc((1 + strlen(str)) * sizeof(char)); strcpy(newstr,str); /* The main insertion loop */ for (i=0; i= 2) fname = argv[1]; else { printf("Input file name: "); fname = (char *)malloc(1024 * sizeof(char)); scanf("%s", fname); } /*** Initialize to empty table ***/ T = init(); fp = (FILE *)fopen(fname,"r"); if (fp == NULL) exit(1); /*** Insert ***/ fscanf(fp,"%d",&n); fscanf(fp,"%c",str); while (n--) { fgets(str,1024,fp); /* Read an entire line */ str[strlen(str)-1] = '\0'; /* Delete the trailing new line character */ T = insert(T,str,&status,0); /* Insert */ } /*** Search ***/ printf("\n"); fscanf(fp,"%d",&n); fscanf(fp,"%c",str); while (n--) { fgets(str,1024,fp); str[strlen(str)-1] = '\0'; printf("+++ Search(%s): ", str); status = search(T,str); printf("%s\n", status ? "SUCCESS" : "FAILURE"); } /*** Delete ***/ printf("\n"); fscanf(fp,"%d",&n); fscanf(fp,"%c",str); while (n--) { fgets(str,1024,fp); str[strlen(str)-1] = '\0'; printf("+++ Delete(%s): ", str); T = delete(T,str,&status); printf("%s\n", status ? "SUCCESS" : "FAILURE"); } fclose(fp); exit(0); }