Hash Table or map implementation I'd like to get feedback on whether my hash table is correct or not. Also, any ideas on performance?

    template&lt;class J,class K&gt;
class List {
private:
    struct Node {
        J key;K data;

        Node * next;
        Node(J _key,K _data):key(_key),data(_data),next(nullptr) {}
    }*head;

public:
    List():head(nullptr){}
    ~List() {
        deleteNode();
    }
    void insert(J _key ,K _data) {
            Node * newNode = new Node(_key, _data);
            newNode-&gt;next = head;
            head = newNode;
    }

    void traverse() {
        for(Node * curr = head; curr != nullptr; curr = curr-&gt;next) {
            cout&lt;&lt; "( "&lt;&lt;curr-&gt;key &lt;&lt; ", " &lt;&lt; curr-&gt;data &lt;&lt; " )" &lt;&lt; " ";
        }
    }

    K search(J key) {
        if (!empty()){

            for(Node * curr = head;curr != nullptr;curr = curr-&gt;next) {
                if (curr-&gt;key == key) {
                    return curr-&gt;data;
                }
            }
        }

        return K(-1);
    }

    bool empty() { return (head == nullptr); }

    void deleteNode() {
        Node * tmp = nullptr;
        for(Node * curr = head; curr != nullptr;){
            tmp = curr-&gt;next;
            delete curr;
            curr = tmp;
        }
    }
};

template&lt;class KEY, class VALUE&gt;
class myHash {
private:

    struct bucket {
        List&lt;KEY,VALUE&gt; list_at_bucket;
    }*Buckets;

    int tableSize;
public:
    myHash(int size) {
        tableSize = size;
        Buckets = new bucket[tableSize];
    }

    ~myHash() {
        for(int i = 0; i &lt; tableSize; i++) {
            Buckets[i].list_at_bucket.deleteNode();
        }
    }



    void put(KEY k, VALUE value) {
        int getCode = hash(k);
         Buckets[getCode].list_at_bucket.insert(k,value);
    }


    VALUE getValue(KEY _key) {
        int getCode = hash(_key);
        return  Buckets[getCode].list_at_bucket.search(_key);
    }

    bool contains(KEY _key) {
        int getCode = hash(_key);
        if (Buckets[getCode].list_at_bucket.search(_key) != -1) {
            return  true;
        }
        return false;
    }

    // need a template hash function
    int hash(KEY key) const {
        int value = 0;
        for (char each: key) {
            value += each;
        }
        return  value % tableSize;
    }

    void traverse() {
        for (int index = 0; index &lt;tableSize; index++){
            cout&lt;&lt; "[" &lt;&lt; index &lt;&lt; " ]-&gt; ";
            Buckets[index].list_at_bucket.traverse();
        }
    }
};
Well, there's a lott to say:


K and V are the traditional template-arguments for keys and values in C++.
Why do you use J and K respectively KEY and VALUE instead?
List::Node is only instantiated at one place, where all three members are set. Why then does it have a constructor at all, and one setting the last one to nullptr at that?
Default copy- and move- construction and assignment are completely unsuited to your List, as it owns its nodes. Leaving them leads to double-deletes and abandoned nodes. Look at the rule of three.

Also worth a look are inclass-initializers (for head).
deleteNode looks more like reset, and should zero head or be inlined into the destructor. As-is, it leaves head dangling...
The same comments apply to copying / moving / assigning myHash as to List.
The myHash dtor leaks the array of buckets...
contains should return the condition directly, instead of putting it into an if-clause. if(somebool) return true; else return false; is a bit wordy.
Your traverse-functions would be more appropriately named dump or some such... Anyway, why don't you overload operator&gt;&gt;(std::ostream, yourtypehere) instead?
Your hash-function runs afool of the fact that only the type itself can know which parts are relevant and how to hash them. Take a look at the design of std::hash.
Next, I would suggest embracing auto, see Almost Always Auto.