I'm trying to create a HashTable in C where each 'bucket' is a pointer to a LinkedList. That is, I need to create an array of LinkedList pointers.
As of now, SomeHashTable->Buckets[i] is returning a non-pointer LinkedList. I've been looking for answers everywhere and I just can't find anything. Perhaps I'm overlooking something? I've given my current code below.
HashTable.h
#include "LinkedList.h"
typedef struct HashTable
{
LinkedList* Buckets[1009];
} HashTable;
//Creates new hashtable
HashTable* HashTable_new();
//Hashes and adds a new entry
void HashTable_add(HashTable* Table, int data);
HashTable.c
#include "HashTable.h"
HashTable* HashTable_new()
{
HashTable* newTable = (HashTable*)malloc(sizeof(HashTable));
newTable->Buckets = malloc(1009 * sizeof(LinkedList*));
//Create linked lists
for (int i = 0; i < 1009; i++)
{
newTable->Buckets[i] = LinkedList_new();
}
return newTable;
}
void HashTable_add(HashTable* Table, int data)
{
int index = data % 1009;
//Get bucket to hash to
LinkedList* BucketHead = (Table->Buckets[index]);
//Hash it iiinnnn real good
LinkedList_add_at_end(BucketHead, data);
}
The linked List structs for reference:
typedef struct LinkedListNode {
int data;
struct LinkedListNode *next;
struct LinkedListNode *prev;
} LinkedListNode;
typedef struct LinkedList {
struct LinkedListNode *first;
struct LinkedListNode *last;
} LinkedList;
As H.S.'s comment mentions, there is no need to dynamically --and-- statically allocate the Buckets array.
This line:
newTable->Buckets = malloc(1009 * sizeof(LinkedList*));
is overwriting the pointer to the statically allocated array, which is probably not what you want. For scalability, I would ditch the static array and stick with malloc(). That way you could use an argument to HashTable_new() to specify the size of the buckets array, like so:
HashTable* HashTable_new(int nBuckets)
{
HashTable* newTable = (HashTable*)malloc(sizeof(HashTable));
newTable->Buckets = malloc(nBuckets * sizeof(LinkedList*));
newTable->nBuckets = nBuckets;
//Create linked lists
for (int i = 0; i < nBuckets; i++)
{
newTable->Buckets[i] = LinkedList_new();
}
return newTable;
}
Notice that newTable->Buckets is being allocated as a pointer to a pointer to LinkedList (LinkedList**). You'll need to keep track to the size of Buckets[], so add the variable to the struct as follows:
typedef struct HashTable
{
int nBuckets;
LinkedList **Buckets;
} HashTable;
You should be good as long as LinkedList_new()'s return type is LinkedList*, and don't forget to free() it all when you're done.
Related
I create in main.c an "hashmap" struct. it contains 6.000.000 "node" structs. i have to insert my elements by insert function. I didn't write it because it's not my trouble. If u need it I'll write it. Btw, the insert function is a generic function because data I need to insert every data type.In this case I insert a couple <key,value> of Integer. My trouble is : I have to make a function that return all key present in the hashmap t. In this function I have two parameters, both of them are void*. Key parameters in the hashmap are void*. The array that will contain all my keys, is void*. My aim is to put all my keys in this array and return it, but this is not possible ``` arr[j] = list->key; arr[j] = list->key;, the compiler gives me this error: incomplite type of void is not assignable*. Is there a way to resolve this thing?
library.c
struct node{
void* key;
void* val;
struct node *next;
struct node *prev;
};
struct hashmap{
int size;
struct node **list;
};
void recoverkey(struct hashmap *t, void *arr){
int j=0;
for (int i = 0; i < t->size; ++i) {
struct node *list = t->list[i];
while(list){
if(list->key!=NULL) {
arr[j] = list->key;
j++;
}
list = list->next;
}
}
}
main.c
#define SIZEFILE 6000000
int main(){
struct hashmap *t; // create hashmap
insert(); // I insert elements in the hashmap
int *arrRec;
arrRec = malloc(SIZEFILE*sizeof(int));
recoverkey(t,arrRec);
I'm trying to allocate memory for the code,of which i've only included excerpts from the actual program, that follows below, the problem I am having is that i don't know how to allocate memory to the type Key that lies within BStree_node this leads to the issue of segmentation errors when i try to assign values to variables within Key.
typedef int Data_Item;
typedef char* Sub_Key;
typedef struct {Sub_Key key1; Sub_Key key2;} Key;
struct BStree_node{
Key key;
Data_Item data;
struct BStree_node *left, *right;
}
typedef struct BStree_node BStree_node;
typedef BStree_node** BStree;
BStree bs_tree_ini(void){
BStree tempTreePointer;
tempTreePointer = malloc(sizeof(BStree_node*));
BStree_node *tempNode;
tempNode = malloc(sizeof(BStree_node));
tempNode = NULL;
tempTreePointer = &tempNode;
return tempTreePointer;
}
You could initialize your node like this, using calloc to zero the memory to initialize all the fields properly:
BStree_node *init_node()
{
BStree_node *rval = calloc(1,sizeof(BStree_node)); // so all data & pointers are zeroed
return rval;
}
use it like this: init main, and only left. right stays zeroed: no right node for that main node.
int main()
{
BStree_node *head = init_node();
head->left = init_node();
...
return 0;
}
typedef struct {
List *table;
unsigned int size;
} HashTable;
typedef struct node {
Data data;
struct node *next;
} NODE;
struct listptrs {
NODE *tail;
NODE *head;
NODE *prev;
NODE *current;
};
typedef struct listptrs List;
HashTable createHashTable(unsigned int size) {
//HashTable htable = { 0 };
//return htable;
int i;
HashTable *htable = NULL;
htable = malloc(sizeof(HashTable) * size);
for (i = 0; i < size; i++) {
htable[i].table = malloc(sizeof(List));
htable[i].table->current = NULL;
htable[i].table->head = NULL;
htable[i].table->prev = NULL;
htable[i].table->tail = NULL;
htable[i].size = size;
}
return *htable;//???
}
Then in main:
HashTable htable = createHashTable(tableSize);
htable doesn't act like an array at all. Any ideas how to solve it without changing any return value from the function and arguments for functions? This is part of a school assignment and only the contents of the function createHashTable may be changed. The rest of the program is not here because it isn't relevant to the question.
You maybe want this:
HashTable *createHashTable(unsigned int size)
{
//HashTable htable = { 0 };
//return htable;
int i;
HashTable* htable = NULL;
htable = malloc(sizeof(HashTable)* size);
for(i=0; i<size; i++)
{
htable[i].table = malloc(sizeof(List));
htable[i].table->current = NULL;
htable[i].table->head = NULL;
htable[i].table->prev = NULL;
htable[i].table->tail = NULL;
htable[i].size = size;
}
return htable;
}
As you allocate the array dynamically, you can simply return the newly allocated pointer. Returning a HashTable as you were trying doesn't make senses, because this would allow you to return one single HashTable, but you want to return a whole array of HashTables.
Usage:
Instead of:
HashTable htable = createHashTable(tableSize);
You need this:
HashTable *htable = createHashTable(100);
...
... // when done you need to delete the hashtable
deleteHashTable(htable);
The deleteHashTable is yet to be written, It essentially needs to free the table pointer and to free the table itself.
Now if you really are allowed to change only the contents of the createHashTable function but not the function signature, then your question doesn't make sense because with the function signature HashTable createHashTable(unsigned int size) you can only return one HashTable but not an array of HashTables.
But then maybe you actually want this:
HashTable createHashTable(unsigned int size)
{
HashTable htable = { 0 };
int i;
for(i=0; i<size; i++)
{
htable[i].table = malloc(sizeof(List));
htable[i].table->current = NULL;
htable[i].table->head = NULL;
htable[i].table->prev = NULL;
htable[i].table->tail = NULL;
htable[i].size = size;
}
return htable;
}
With this second solution, you still need to write the function that deletes the hash table.
The hash table itself isn't supposed to "behave like an array", and this:
return *htable;
makes no sense, it returns the first element from your array of hash tables.
You're not supposed to create an array of hash tables though, you're supposed to create a single hash table, which might contain an array (that's the table). It also has a size variable for instance, so there's more than the array itself to the hash table.
You should do
htable = malloc(sizeof *htable);
to allocate a single instance, then initialize that as needed and return it.
There seems to be some confusion here: createHashTable() is not supposed to allocate an array of hash tables, but a HashTable structure with an initial size for its embedded table member.
Furthermore, it is non standard practice to return the structure by value. You should instead return the pointer to the allocated HashTable or possibly take a pointer to HashTable structure allocated dynamically or statically by the caller and initialize that.
Here is a modified version of the code for this approach:
#include <stdlib.h>
typedef struct {
List *table;
unsigned int size;
} HashTable;
typedef struct node {
Data data;
struct node *next;
} NODE;
struct listptrs {
NODE *tail;
NODE *head;
NODE *prev;
NODE *current;
};
typedef struct listptrs List;
HashTable *createHashTable(unsigned int size) {
HashTable *htable = malloc(sizeof(*htable));
if (htable == NULL)
return NULL;
}
htable->size = size;
htable->table = NULL;
if (size == 0) {
return htable;
}
htable->table = malloc(sizeof(*htable->table) * size);
if (htable->table == NULL) {
free(htable);
return NULL;
}
for (unsigned int i = 0; i < size; i++) {
htable->table[i].head = NULL;
htable->table[i].tail = NULL;
htable->table[i].prev = NULL;
htable->table[i].current = NULL;
}
return htable;
}
Calling from main():
HashTable *htable = createHashTable(100);
So my data structure is supposed to be a hash table, an array of linked list. Inside each of those linked list holds a linked list. And inside those linked list is a Book. A book contains a book name, and a linked list of library IDs that hold that book.
I'm having trouble searching within the linked list to see if a book->name already exists.
I know how to access the so called "shelf" that it's on by:
int index = hashFunction(char* nameOfBook) % this->size;
and then searching within the hash array to find it like this:
this->chain[index]
But how can I access the Book struct once I'm inside the linked list?
In list.h
typedef struct NodeStruct {
void *data;
struct NodeStruct* next;
struct NodeStruct* prev;
} NodeStruct;
typedef struct ListStruct {
NodeStruct* first;
NodeStruct* last;
int elementType;
} ListStruct;
In hash.c:
typedef struct Book {
ListStruct* libID; // Each book has its own list of library IDs
char* name; // Each book has a name.
} Book;
// A hashset contains a linked list of books.
typedef struct HashStruct {
int size;
int load;
ListStruct **chain; //An array of Linked Lists.
} HashStruct;
Here are the constructors:
// Constructor for a new book.
Book *newBook(char* name) {
Book *this = malloc (sizeof (Book));
assert(this != NULL);
this->name = name;
this->libID = malloc(sizeof (ListStruct*));
this->libID = newList(sizeof(int));
return this;
}
HashHandle new_hashset(int size) {
HashHandle tempHash = malloc (sizeof (HashStruct));
assert (tempHash != NULL);
tempHash->size = size;
tempHash->load = 0;
tempHash->chain = malloc (sizeof (ListStruct));
assert(tempHash->chain != NULL);
// Each linked list holds a linked list.
for (int i = 0; i < size; ++i) {
tempHash->chain[i] = newList(sizeof(Book));
}
return tempHash;
}
EDIT: I think I got it to work. Haven't tested yet.
bool has_hashset (HashHandle this, char *item) {
//Finds the index to look at.
int index = strhash(item) % this->size;
NodeStruct *cur = this->chain[index]->first;
while (cur != NULL) {
Book *tmp = cur->data;
if (strcmp(tmp->name, item) == 0)
return true;
cur = cur->next;
}
return false;
}
Sorry if this was very confusing. By the way, the 'data' of a linked list is generic.
Thank you!
Because cur->data is a pointer to void, you need to assign it to a pointer of type Book (or cast it to that type). Otherwise, you will not be able to use -> to get a member because void is not a struct.
What you fixed in your edit should work fine.
i have a dynamic number of pointers all having the same size. i need to store all the addresses of my pointers in some place like a link List in order to fetch them later on.
my question is what structs should i use. is the following correct:
struct Node{
int *k;
Node*Next;
}
struct LS{
Node*first,*last;
void push(Node*n);
Node* GetFirst();
Node* GetLast();
}
the LS is the linked list that stores Nodes. and a Node is a struct that holds the address of my pointer and a pointer to the next Node.
am i using int *k to store the address of my pointer correctly? should i continue with this implementation or is there any easier way to do this?
this sample code may help you start...
#include <stdio.h>
struct Node{
int *k;
Node *Next;
}* Temp;
struct LS
{
Node *first,*last;
void push(Node *MyNode)
{
MyNode->Next=NULL;
if(empty())
{
first=MyNode;
last=MyNode;
}
else
{
last->Next = MyNode;
last=MyNode;
}
}
Node* front()
{
return first;
}
void pop()
{
free(first->k);
first=first->Next;
}
bool empty()
{
if(first==NULL) return true;
return false;
}
};
int N=10;
int main()
{
LS Q;Q.first=NULL;
for(int i=0;i<3;i++)
{
Node *NewNode= (Node*)malloc(sizeof(Node));
NewNode->k = (int*)malloc(sizeof(int)*N);
for(int k=0;k<N;k++) NewNode->k[k]=i;
Q.push(NewNode);
}
while(!Q.empty())
{
Temp=Q.front();
for(int i=0;i<N;i++) printf("%d ",Temp->k[i]);
printf("\n");
Q.pop();
}
return 1;
}
Yes, your Node struct is correct.
As to whether there is an easier way it depends. If there is a maximum number of pointers that you will need then an array of pointers would be easier. If you can do it in C++ then an STL vector (can use it like an array, but underneath the hood it can grow dynamically as needed) is easier. If you have to do it in C and it has to be dynamic, though, then no, there is not an easier way.
WDM.H (microsoft header) has a bunch of linked list stuff to look at ( http://msdn.microsoft.com/en-us/library/ff547799(VS.85).aspx ) , I've cut and pasted from that, and added a very simple example.
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY;
typedef struct _MY_THING
{
LIST_ENTRY ListEntry;
ULONG randomdata1;
ULONG randomdata2;
ULONG randomdata3;
ULONG randomdata4;
} MY_THING, *PMY_THING;
#define CONTAINING_RECORD(address, type, field) ((type *)( \
(PCHAR)(address) - \
(ULONG_PTR)(&((type *)0)->field)))
VOID
InsertHeadList(
IN PLIST_ENTRY ListHead,
IN PLIST_ENTRY Entry
)
{
PLIST_ENTRY Flink;
Flink = ListHead->Flink;
Entry->Flink = Flink;
Entry->Blink = ListHead;
Flink->Blink = Entry;
ListHead->Flink = Entry;
}
VOID
InitializeListHead(
IN PLIST_ENTRY ListHead
)
{
ListHead->Flink = ListHead->Blink = ListHead;
}
PLIST_ENTRY
RemoveHeadList(
IN PLIST_ENTRY ListHead
)
{
PLIST_ENTRY Flink;
PLIST_ENTRY Entry;
Entry = ListHead->Flink;
Flink = Entry->Flink;
ListHead->Flink = Flink;
Flink->Blink = ListHead;
return Entry;
}
void main()
{
LIST_ENTRY HeadOfMyList;
MY_THING Thing;
InitializeListHead(&Head);
// example of add thing to list.
InsertHeadList(&HeadOfMyList, &Thing.ListEntry);
// example of removing thing from the list
PLIST_ENTRY listEntry = RemoveHeadList(&HeadOfMyList);
PMY_THING pThing = (PMY_THING) CONTAINING_RECORD(listEntry, MY_THING, ListEntry);
}