I've been actively engaged in C++ and C programming for over a year. Lately, I've been intrigued by the idea of implementing a map-like structure in C, and I've come across an approach to tackle this challenge. The strategy involves utilizing a set of Binary Search Trees (BST) for creating a map structure:
struct Map{ struct Tree **t; };
In this method, a tree is defined as follows:
struct Pair{
char *first;
int second;
};
struct Pair *make_pair(char *a,int b){
struct Pair *x=(struct Pair *)malloc(sizeof(struct Pair));
x->first=strdup(a);
x->second=b;
return x;
};
struct Nod{
struct Pair *val;
struct Nod *dr,*st;
};
struct Tree{
struct Nod *top;
};
Moreover, there is a need for a make_hash function to generate a hash for a char* and a compare function for "comparing" two "strings":
//create the hash
int make_hash(char *s,int size){
//use unsigned long long because it starts from 0 after going past the limit.
unsigned long long hash=5813;
for(int i=0;s[i];i++) hash=hash*33+s[i];
return (hash%size);
};
//compare two "strings"
//note: my compare function returns -1 if both "strings" are equal
int compare(char *a,char *b){
int i=0,x=0;
for(;a[i]&&b[i];i++){
if(b[i]>a[i]) return 0;
if(b[i]==a[i])x++;
}
if(a[i]&&!b[i])
return 1;
if(!a[i]&&b[i])
return 0;
if(!a[i]&&!b[i]&&x==i)
return -1;
};
Finally, the implementation requires functions for adding and finding a char* and its corresponding value in our program:
void addtotree(struct Tree *t,char *s,int val){
if(!t->top){
t->top=(struct Nod *)malloc(sizeof(struct Nod));
t->top->val=make_pair(s,val);
t->top->st=NULL;
t->top->dr=NULL;
return;
}
struct Nod *nod=t->top;
while(nod){
int x=compare(s,nod->val->first);
if(x==1){
if(nod->dr){
nod=nod->dr;
}
else{
nod->dr=(struct Nod *)malloc(sizeof(struct Nod));
nod->dr->val=make_pair(s,val);
nod->dr->dr=NULL;
nod->dr->st=NULL;
return;
}
}
else if(x==0){
if(nod->st){
nod=nod->st;
}
else{
nod->st=(struct Nod *)malloc(sizeof(struct Nod));
nod->st->val=make_pair(s,val);
nod->st->dr=NULL;
nod->st->st=NULL;
return;
}
}
else if(x==-1){
nod->val->second=val;
return;
}
}
}
struct Nod *findtotree(struct Tree *t,char *s){
struct Nod *nod=t->top;
while(nod){
int x=compare(s,nod->val->first);
if(x==1) nod=nod->dr;
else if(x==0) nod=nod->st;
else return nod;
}
return NULL;
};
void add(struct Map *m,char *s,int val){
int hash=make_hash(s,m->size);
if(!m->t[hash]){
m->t[hash]=(struct Tree *)malloc(sizeof(struct Tree));
m->t[hash]->top=NULL;
}
addtotree(m->t[hash],s,val);
};
int find(struct Map *m,char *s){
int hash=make_hash(s,m->size);
if(!m->t[hash]) return 0;
struct Nod *nod=findtotree(m->t[hash],s);
if(!nod) return 0;
return nod->val->second;
};
It's worth noting that there is room for improvement in this map implementation. With that in mind, let me now consolidate all the components:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Pair{
char *first;
int second;
};
struct Pair *make_pair(char *a,int b){
struct Pair *x=(struct Pair *)malloc(sizeof(struct Pair));
x->first=strdup(a);
x->second=b;
return x;
};
int make_hash(char *s,int size){
unsigned long long hash=5813;
for(int i=0;s[i];i++) hash=hash*33+s[i];
return (hash%size);
};
struct Nod{
struct Pair *val;
struct Nod *dr,*st;
};
struct Tree{
struct Nod *top;
};
int compare(char *a,char *b){
int i=0,x=0;
for(;a[i]&&b[i];i++){
if(b[i]>a[i]) return 0;
if(b[i]==a[i])x++;
}
if(a[i]&&!b[i])
return 1;
if(!a[i]&&b[i])
return 0;
if(!a[i]&&!b[i]&&x==i)
return -1;
};
void addtotree(struct Tree *t,char *s,int val){
if(!t->top){
t->top=(struct Nod *)malloc(sizeof(struct Nod));
t->top->val=make_pair(s,val);
t->top->st=NULL;
t->top->dr=NULL;
return;
}
struct Nod *nod=t->top;
while(nod){
int x=compare(s,nod->val->first);
if(x==1){
if(nod->dr){
nod=nod->dr;
}
else{
nod->dr=(struct Nod *)malloc(sizeof(struct Nod));
nod->dr->val=make_pair(s,val);
nod->dr->dr=NULL;
nod->dr->st=NULL;
return;
}
}
else if(x==0){
if(nod->st){
nod=nod->st;
}
else{
nod->st=(struct Nod *)malloc(sizeof(struct Nod));
nod->st->val=make_pair(s,val);
nod->st->dr=NULL;
nod->st->st=NULL;
return;
}
}
else if(x==-1){
nod->val->second=val;
return;
}
}
}
struct Nod *findtotree(struct Tree *t,char *s){
struct Nod *nod=t->top;
while(nod){
int x=compare(s,nod->val->first);
if(x==1) nod=nod->dr;
else if(x==0) nod=nod->st;
else return nod;
}
return NULL;
};
struct Map{
struct Tree **t;
int size;
};
struct Map *createMap(int size){
struct Map *m=(struct Map *)malloc(sizeof(struct Map));
m->size=size;
m->t=(struct Tree **)calloc(size,sizeof(struct Tree *));
for(int i=0;i<size;i++) m->t[i]=NULL;
return m;
};
void add(struct Map *m,char *s,int val){
int hash=make_hash(s,m->size);
if(!m->t[hash]){
m->t[hash]=(struct Tree *)malloc(sizeof(struct Tree));
m->t[hash]->top=NULL;
}
addtotree(m->t[hash],s,val);
};
int find(struct Map *m,char *s){
int hash=make_hash(s,m->size);
if(!m->t[hash]) return 0;
struct Nod *nod=findtotree(m->t[hash],s);
if(!nod) return 0;
return nod->val->second;
};
myHashTable.put(key,value)you'll need to sayputToHashTable(myHashTable,key,value)and so on. (Unless you want to really reinvent OO and start building method dispatch into your objects -- which is possible but overkill for this simple case.)