[Error] Tabla Hashing

Iniciado por Zodiak98, 16 Febrero 2017, 01:59 AM

0 Miembros y 1 Visitante están viendo este tema.

Zodiak98

Verán, estoy intentando representar una Tabla Hash, pero por alguna razón me dice que existe un error de enlace o algo así.

Estoy trabajando en Visual Studio 2015, esto es lo que llevo:
Nodo.h
Código (cpp) [Seleccionar]

#pragma once

template<class T>
class Nodo {
private:
Nodo<T>* siguiente;
Nodo<T>* anterior;
T clave;
public:
inline Nodo();
inline Nodo(T clave);

inline Nodo<T>* getSiguiente();
inline Nodo<T>* getAnterior();
inline T getClave();

inline void setSiguiente(Nodo<T>* siguiente);
inline void setAnterior(Nodo<T>* anterior);
inline void setClave(T clave);
};


Nodo.cpp
Código (cpp) [Seleccionar]

#include "Nodo.h"

template <class T>
inline Nodo<T>::Nodo() {
siguiente = nullptr;
anterior = nullptr;
clave = 0;
}

template <class T>
inline Nodo<T>::Nodo(T clave) {
siguiente = nullptr;
anterior = nullptr;
this->clave = clave;
}

template <class T>
inline Nodo<T>* Nodo<T>::getSiguiente() {
return siguiente;
}

template <class T>
inline Nodo<T>* Nodo<T>::getAnterior() {
return anterior;
}

template <class T>
inline T Nodo<T>::getClave() {
return clave;
}

template <class T>
inline void Nodo<T>::setAnterior(Nodo<T>* anterior) {
this->anterior = anterior;
}

template <class T>
inline void Nodo<T>::setSiguiente(Nodo<T>* siguiente) {
this->siguiente = siguiente;
}

template <class T>
inline void Nodo<T>::setClave(T clave) {
this->clave = clave;
}


ListaDoble.h
Código (cpp) [Seleccionar]

#pragma once
#include "Nodo.h"

template <class T>
class ListaDoble {
private:
Nodo<T>* inicio;
public:
inline ListaDoble();

void agregar(Nodo<T>* n);
void eliminar(Nodo<T>* n);
void listar();

inline Nodo<T>* getInicio();
};


ListaDoble.cpp
Código (cpp) [Seleccionar]

#include "ListaDoble.h"

template <class T>
inline ListaDoble<T>::ListaDoble() {
inicio = nullptr;
}

template <class T>
void ListaDoble<T>::agregar(Nodo<T>* n) {
n->setSiguiente(inicio);

if (inicio != nullptr) {
inicio->setAnterior(n);
}

n->setAnterior(nullptr);
inicio = n;
}

template <class T>
void ListaDoble<T>::eliminar(Nodo<T>* n) {
if (n->getAnterior() != nullptr) {
n->getAnterior()->setSiguiente(n->getSiguiente());
} else {
inicio = n;
}

if (n->getSiguiente() != nullptr) {
n->getSiguiente()->setAnterior(n->getAnterior());
}

delete n;
}

template <class T>
inline Nodo<T>* ListaDoble<T>::getInicio() {
return inicio;
}

template <class T>
void ListaDoble<T>::listar() {
for (Nodo<T>* aux = inicio; aux != nullptr; aux = aux->getSiguiente()) {
cout << "Clave: " << aux->getClave() << endl;
}
}


TablaHash.h
Código (cpp) [Seleccionar]

#pragma once
#include "ListaDoble.h"

#define TAM 701

template <class T>
class TablaHash {
private:
ListaDoble<T>* H[TAM];
public:
TablaHash();

void agregar(Nodo<T>* n);
void eliminar(Nodo<T>* n);
Nodo<T>* buscar(T clave);

inline int h(int clave);

void listar();
};


TablaHash.cpp
Código (cpp) [Seleccionar]

#include "TablaHash.h"

template<class T>
TablaHash<T>::TablaHash() {
for (int h = 0; h < TAM; h++) {
H[h] = nullptr;
}
}

template<class T>
inline int TablaHash<T>::h(int clave) {
return (clave % TAM);
}

template<class T>
void TablaHash<T>::agregar(Nodo<T>* n) {
int slot = h((int)n->getClave());

if (H[slot] == nullptr) {
H[slot] = new ListaDoble<T>;
}

H[slot]->agregar(n);
}

template <class T>
Nodo<T>* TablaHash<T>::buscar(T clave) {
int slot = h((int)clave);

if (H[slot] != nullptr) {
for (Nodo<T>* aux = H[slot]->getInicio(); aux != nullptr; aux = aux->getSiguiente()) {
if (aux->getClave() == clave) {
return aux;
}
}
}

return nullptr;
}

template <class T>
void TablaHash<T>::eliminar(Nodo<T>* n) {
int slot = h((int)n->getClave());
Nodo<T>* aux = buscar(n->getClave());

if (aux != nullptr) {
H[slot]->eliminar(aux);
}

if (H[slot]->getInicio() == nullptr) {
H[slot] = nullptr;
delete H[slot];
}
}

template <class T>
void TablaHash<T>::listar() {
for (int i = 0; i < TAM; i++) {
if (H[i] != nullptr) {
H[i]->listar();
}
}
}


main.cpp
Código (cpp) [Seleccionar]

#include <iostream>
#include "TablaHash.h"

using namespace std;

int main() {
TablaHash<int> myHashTable;

Nodo<int>* nodo1 = new Nodo<int>(25);
Nodo<int>* nodo2 = new Nodo<int>(35);
Nodo<int>* nodo3 = new Nodo<int>(45);


return 0;
}


El error que me da es el siguiente:

- Error LNK2019 unresolved external symbol "public: __thiscall TablaHash<int>::TablaHash<int>(void)" (??0?$TablaHash@H@@QAE@XZ) referenced in function _main
- Error LNK2019 unresolved external symbol "public: __thiscall Nodo<int>::Nodo<int>(int)" (??0?$Nodo@H@@QAE@H@Z) referenced in function _main

- Error LNK1120 2 unresolved externals


Supongo que tiene algo que ver con las cabeceras, ¿alguien podría decirme que estoy haciendo mal?

Gracias de antemano. :)

engel lex

tienes un error del linker

no tu puedo ayudar mucho, pero estas son posibles soluciones

https://msdn.microsoft.com/en-us/library/799kze2z.aspx
El problema con la sociedad actualmente radica en que todos creen que tienen el derecho de tener una opinión, y que esa opinión sea validada por todos, cuando lo correcto es que todos tengan derecho a una opinión, siempre y cuando esa opinión pueda ser ignorada, cuestionada, e incluso ser sujeta a burla, particularmente cuando no tiene sentido alguno.

Zodiak98

#2
Gracias por responder, aún no he logrado solucionarlo. Verifiqué algunas de esas posibles soluciones y nada de nada.

-- EDIT --
Si cambio en el main el include del header para incluir el .cpp, sí funciona. O sea, por alguna razón no me está reconociendo los .cpp donde están las definiciones de los .h

ivancea96

No puedes definir templates en un .cpp y usarlos desde fuera.
El cpp se compila antes que el main. Por tanto, los templates que no uses ahí (TablaHash<int>, por ejemplo), no se va a compilar.

Tendrás que pioner esos templates en el hpp, sin el cpp.

Zodiak98

#4
¿Podrías explicarte un poco mejor, por favor? Aún no me ha quedado del todo claro.

Yo creé los templates en el hpp, y luego le di cuerpo a esas clases en archivos .cpp, ¿eso no es válido? Sólo estoy dándole cuerpo a los métodos de esas clases.

¿Te refieres a que sólo debo crear el .hpp y darle cuerpo donde tengo el main (cuando hago uso de plantillas)?

ivancea96

El cuerpo debes dárselo en el hpp.

Los templates se compilan por cada combinación de tipos que le des. Si no se le da ningun tipo (como ocurre en el .cpp, por ejemplo), no se compila. Entonces, cuando compilas el main, no encuentra el template <int> en ningún lado (porque no ha sido compilado).

Poniéndolo en el .hpp se compila en cada lugar en que hagas el include, y por tanto, se compila todo lo que se necesita.

Zodiak98

Oh, wow. Ojalá mi profesor de la universidad fuese como tú. Jajajaj Muchas gracias.  ;D ;D