Cod sursa(job #2727270)

Utilizator horiacoolNedelcu Horia Alexandru horiacool Data 21 martie 2021 18:27:57
Problema Hashuri Scor 100
Compilator c-64 Status done
Runda Arhiva educationala Marime 5.26 kb
/* Copyright 2021 Nedelcu Horia ([email protected]) */

#include <stdio.h>
#include <stdlib.h>


#ifndef UTILS_H
#define UTILS_H 

#include <errno.h>
#include <stdio.h>

#define DIE(assertion, call_description)				\
	do {								\
		if (assertion) {					\
			fprintf(stderr, "(%s, %d): ",			\
					__FILE__, __LINE__);		\
			perror(call_description);			\
			/* exit(errno); */				\
                        return errno;					\
		}							\
	} while (0)

#endif /* UTILS_H */


#ifndef LIST_H
#define LIST_H

#include <stddef.h>
#include <stdlib.h>
#include <string.h>


struct node {
	void *data_;
	struct node *link_;	
};

struct list {
	struct node *head_;
};


void init_list(struct list *list);
void delete_list(struct list *list);
int push_front(struct list *list, const void *data, size_t data_size);
void* get_data(const struct list *list, const void *data, size_t data_size);
int delete_data(struct list *list, const void *data, size_t data_size);

#endif /* LIST_H */

void init_list(struct list *list)
{
	list->head_ = NULL;
}

void delete_list(struct list *list)
{
	struct node *next_it, *it = list->head_;

	while (it != NULL) {
		next_it = it->link_;
		free(it->data_);
		free(it);
		it = next_it;
	}

	list->head_ = NULL;
}

int push_front(struct list *list, const void *data, size_t data_size)
{
	struct node *new_node = malloc(sizeof(struct node));
	DIE(new_node == NULL, "malloc failed");

	new_node->data_ = malloc(data_size);
	DIE(new_node->data_ == NULL, "malloc failed");

	memcpy(new_node->data_, data, data_size);
	new_node->link_ = list->head_;
	list->head_ = new_node;

	return 0;
}

void* get_data(const struct list *list, const void *data, size_t data_size)
{
	const struct node *it = list->head_;

	for (; it != NULL; it = it->link_) {
		if (memcmp(it->data_, data, data_size) == 0)
			return it->data_;
	}

	return NULL;
}

int delete_data(struct list *list, const void *data, size_t data_size)
{
	struct node *last_it = NULL, *it = list->head_;

	for (; it != NULL; it = it->link_) {
		if (memcmp(it->data_, data, data_size) == 0) {
			if (last_it != NULL) {
				last_it->link_ = it->link_;
			} else {
				list->head_ = it->link_;
			}

			free(it->data_);
			free(it);

			return 0;
		}

		last_it = it;
	}

	return 1;
}


#ifndef HASHMAP_H
#define HASHMAP_H

#define PRIME_BUCKETS_SIZE 1002797


struct hashmap {
	size_t key_size_, value_size_;
	struct list *buckets_;
	size_t (*hash_)(const char *, size_t);
};


size_t default_hash(const char *data, size_t key_size);
int init_hashmap(struct hashmap *hashmap, size_t key_size, size_t value_size,
	size_t (*hash)(const char *, size_t));
void delete_hashmap(struct hashmap *hashmap);
int insert(const struct hashmap *hashmap, const void *data);
void* get(const struct hashmap *hashmap, const void *data);
int delete(const struct hashmap *hashmap, const void *data);

#endif /* HASHMAP_H */

size_t default_hash(const char *data, size_t key_size)
{
	size_t hash, i;
	
	for(hash = i = 0; i < key_size; ++i) {
		hash += data[i];
		hash += (hash << 10);
		hash ^= (hash >> 6);
	}

	hash += (hash << 3);
	hash ^= (hash >> 11);
	hash += (hash << 15);

	return hash;
}

int init_hashmap(struct hashmap *hashmap, size_t key_size, size_t value_size,
	size_t (*hash)(const char *, size_t))
{
	hashmap->key_size_ = key_size;
	hashmap->value_size_ = value_size;

	/* (hashmap->buckets_[i].head = 0) == NULL */
	hashmap->buckets_ = calloc(PRIME_BUCKETS_SIZE, sizeof(struct list));
	DIE(hashmap->buckets_ == NULL, "calloc failed");

	hashmap->hash_ = (hash == NULL)? default_hash: hash;

	return 0;
}

void delete_hashmap(struct hashmap *hashmap)
{
	size_t i;

	for (i = 0; i < PRIME_BUCKETS_SIZE; ++i) {
		delete_list(&hashmap->buckets_[i]);
	}

	free(hashmap->buckets_);
	hashmap->buckets_ = NULL;
}

int insert(const struct hashmap *hashmap, const void *data)
{
	void *old_addr = get(hashmap, data);
	size_t ret, index = hashmap->hash_(data, hashmap->key_size_)
		% PRIME_BUCKETS_SIZE;

	if (old_addr == NULL) {
		ret = push_front(&hashmap->buckets_[index], data,
			hashmap->key_size_ + hashmap->value_size_);
		DIE(ret, "push_front list failed");
	} else {
		memcpy((char *) old_addr + hashmap->key_size_, (char *) data
			+ hashmap->key_size_, hashmap->value_size_);
	}

	return 0;
}

void* get(const struct hashmap *hashmap, const void *data)
{
	size_t index = hashmap->hash_(data, hashmap->key_size_)
		% PRIME_BUCKETS_SIZE;
	return get_data(&hashmap->buckets_[index], data, hashmap->key_size_);
}

int delete(const struct hashmap *hashmap, const void *data)
{
	size_t index = hashmap->hash_(data, hashmap->key_size_)
		% PRIME_BUCKETS_SIZE;
	return delete_data(&hashmap->buckets_[index], data, hashmap->key_size_);
}


int main() {
	FILE *fin, *fout;
	struct hashmap hashmap;
	int ret, n, q, x, i;

	ret = init_hashmap(&hashmap, sizeof(int), 0, NULL);
	DIE(ret, "init_hashmap failed");

	fin = fopen("./hashuri.in", "r");
	DIE(fin == NULL, "fopen failed");

	fout = fopen("./hashuri.out", "w");
	DIE(fout == NULL, "fopen failed");

	fscanf(fin, "%d", &n);

	for (i = 0; i < n; ++i) {
		fscanf(fin, "%d %d", &q, &x);

		switch (q)
		{
		case 1:
			insert(&hashmap, &x);
			break;
		
		case 2:
			delete(&hashmap, &x);
			break;

		case 3:
			fprintf(fout, "%d\n", get(&hashmap, &x) != NULL);
			break;
		default:
			break;
		}
	}

	delete_hashmap(&hashmap);
	fclose(fin);
	fclose(fout);

	return 0;
}