Reputation: 435
I have been trying to implement a Set ADT using open addressing for the hash table and lazy deletion, however, I am having problems with the resizing of the Set. I can insert elements up to 75% of the total capacity of the Set, but when I resize it and try to access all of the elements again (all inserted elements are unique), I get this error:
==294546== Conditional jump or move depends on uninitialised value(s)
==294546== at 0x48D6AD6: __vfprintf_internal (vfprintf-internal.c:1516)
==294546== by 0x48C079E: printf (printf.c:33)
==294546== by 0x10FD3D: showDisciplineStatistics (simple.c:149)
==294546== by 0x109454: main (main.c:37)
==294546== Uninitialised value was created by a stack allocation
==294546== at 0x10FC00: showDisciplineStatistics (simple.c:127)
I know that is has something to do with how the elements are added back to the Set after resize, but I have no idea how to do it properly. In every single iteration I get the error precisely at index 128 and everything after. Here is how I am inserting the elements, v[] is a flag to check for the existence of all elements:
#include <stdlib.h>
#include <stdio.h>
#include "set.h"
int main() {
PtSet set = setCreate();
int v[200];
for(int i = 0; i < 200; i++) {
setAdd(set, i);
}
int elementsSize;
setSize(set, &elementsSize);
SetElem *elements = setValues(set);
for(int i = 0; i < elementsSize; i++) {
v[elements[i]] = 1;
}
for(int i = 0; i < 200; i++) {
printf("%d - %d\n", i, v[i]);
}
return EXIT_SUCCESS;
}
set.c, SetElem is typed as an integer:
#define LOAD_FACTOR_THRESHOLD 0.75
typedef struct setNode {
SetElem element; // Element present at this node.
int occupied; // Whether this node is occupied or not.
int deleted; // Whether this node has been deleted or not.
} SetNode;
typedef struct setImpl {
SetNode* nodes; // Nodes of the set.
int size; // Size of the set.
int deletedCount; // Number of nodes that have been deleted.
int index; // Determines the capacity (getPrime(index)) and multiplier (getPrime(index - 1)).
} SetImpl;
static int hashFunction(SetElem elem, int multiplier, int tableSize);
static bool ensureCapacity(PtSet set);
static int findPosition();
static int getPrime(int index);
PtSet setCreate() {
PtSet set = (PtSet) malloc(sizeof(SetImpl));
if(set == NULL) return NULL;
SetNode* newNodes = (SetNode*) calloc(getPrime(1), sizeof(SetNode));
if(newNodes == NULL) return NULL;
set->nodes = newNodes;
set->size = 0;
set->deletedCount = 0;
set->index = 1;
return set;
}
int setAdd(PtSet set, SetElem elem) {
if(set == NULL) return SET_NULL;
if(!ensureCapacity(set)) return SET_NO_MEMORY;
int position = findPosition(set, elem);
if(position == -1) return SET_ERROR;
int capacity = getPrime(set->index);
int firstDeletedIndex = -1;
bool added = false;
for(int i = 0; i < capacity; i++) {
if(set->nodes[position].occupied == 0 && set->nodes[position].deleted == 0) {
if(firstDeletedIndex != -1) {
position = firstDeletedIndex;
set->deletedCount--;
}
set->nodes[position].element = elem;
set->nodes[position].occupied = 1;
set->nodes[position].deleted = 0;
set->size++;
added = true;
break;
}
if(set->nodes[position].occupied == 1) {
if(setElemCompare(set->nodes[position].element, elem) == 0) {
return SET_DUPLICATE;
}
}
if(set->nodes[position].deleted == 1 && firstDeletedIndex == -1) {
firstDeletedIndex = position;
}
position = (position + 1) % capacity;
}
if(added == false) return SET_FULL;
else return SET_OK;
}
int setSize(PtSet set, int *ptSize) {
if(set == NULL) return SET_NULL;
*ptSize = set->size;
return SET_OK;
}
SetElem* setValues(PtSet set) {
if(set == NULL) return NULL;
SetElem *newValues = (SetElem*) calloc(set->size, sizeof(SetElem));
int j = 0;
for(int i = 0; i < getPrime(set->index); i++) {
if(set->nodes[i].occupied == 1) {
newValues[j++] = set->nodes[i].element;
}
}
return newValues;
}
static int hashFunction(SetElem elem, int multiplier, int tableSize) {
int len_bytes = sizeof(elem);
char *byte = (char*)&elem;
int c, hash = 5381;
for(int i=0; i < len_bytes; i++) {
c = *byte++;
hash = ((hash << 5) + hash) + c;
}
return abs((hash * multiplier) % tableSize);
}
static bool ensureCapacity(PtSet set) {
if(set == NULL) return false;
if((double) (set->size + set->deletedCount) / getPrime(set->index) >= LOAD_FACTOR_THRESHOLD) {
SetNode *newNodes = (SetNode*) calloc(getPrime(set->index + 1), sizeof(SetNode));
if(newNodes == NULL) return false;
int oldElementsSize;
setSize(set, &oldElementsSize);
SetElem *oldElements = setValues(set);
free(set->nodes);
set->nodes = newNodes;
set->size = 0;
set->deletedCount = 0;
set->index++;
for(int i = 0; i < oldElementsSize; i++) {
setAdd(set, oldElements[i]);
}
free(oldElements);
return true;
}
return true;
}
static int findPosition(PtSet set, SetElem elem) {
if(set == NULL) return -1;
int position = hashFunction(elem, getPrime(set->index - 1), getPrime(set->index));
return position;
}
static int getPrime(int index) {
// Useful prime numbers for setting table size.
int primeTable[] = {
53, 107, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917,
25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741
};
int primeSize = sizeof(primeTable) / sizeof(int);
if(index >= primeSize) return -1;
else return primeTable[index];
}
set.h:
#define SET_OK 0
#define SET_NULL 1
#define SET_NO_MEMORY 2
#define SET_EMPTY 3
#define SET_FULL 4
#define SET_ERROR 5
#define SET_DUPLICATE 6
#include "setElem.h"
#include <stdbool.h>
/** Forward declaration of the data structure. */
struct setImpl;
/** Definition of pointer to the data stucture. */
typedef struct setImpl *PtSet;
/**
* @brief Creates a new empty set.
*
* @return PtSet pointer to allocated data structure, or
* @return NULL if unsufficient memory for allocation.
*/
PtSet setCreate();
/**
* @brief Add an element to the set. If it already exists, then silently replace it.
*
* @param set [in] pointer to the set.
* @param elem [in] element to add.
*
* @return SET_OK if successful, or
* @return SET_FULL if no capacity available, or
* @return SET_NO_MEMORY if unsufficient memory for allocation, or
* @return SET_NULL if 'set' is NULL.
*/
int setAdd(PtSet set, SetElem elem);
/**
* @brief Gets the size of the set.
*
* @param set [in] pointer to the set.
* @param ptSize [out] size of the set.
*
* @return SET_OK if successful, or
* @return SET_FULL if no capacity available, or
* @return SET_NO_MEMORY if unsufficient memory for allocation, or
* @return SET_NULL if 'set' is NULL.
*/
int setSize(PtSet set, int *ptSize);
/**
* @brief Gets the values from a given set.
*
* The size of the dynamic array will be the size of the set.
*
* @param set [in] pointer to the set.
*
* @return array containing the values of the set, or
* @return NULL if the 'set' is empty or NULL
*/
SetElem* setValues(PtSet set);
setElemCompare() and setElemPrint():
void setElemPrint(SetElem elem) {
printf("%d\n", elem);
}
int setElemCompare(SetElem elem1, SetElem elem2) {
if(elem1 == elem2) return true;
else return false;
}
Valgrind settings:
valgrind --leak-check=full --show-reachable=yes --track-origins=yes ./prog
I really have no idea what's going on, I have been at it for longer than I would like to admit and can't seem to resize the hash table properly.
Upvotes: 1
Views: 66
Reputation: 435
I have fixed it, I don't know what's wrong with me, in the setAdd function:
if(set->nodes[position].occupied == 1) {
if(setElemCompare(set->nodes[position].element, elem) == 0) {
return SET_DUPLICATE;
}
}
should be:
if(set->nodes[position].occupied == 1) {
if(setElemCompare(set->nodes[position].element, elem) == true) {
return SET_DUPLICATE;
}
}
and setElemCompare should return a bool. Sorry for all the hassle, the set works as intended now.
Upvotes: 1