Your task is to define two classes HashTableOpen and HashTableClosed that are derived from the abstract base class HashTable: class HashTable { public: HashTable() {} virtual ~HashTable() {} virtual int insert(int uw_id, string const& info) = 0; virtual int remove(int uw_id) = 0; virtual string& operator[](int uw_id) = 0; virtual void print() const = 0; protected: static const int defaultSize = 100; int hash(int key, int buckets) const { return key % buckets; } }; The hash table uses an integer “uw_id” as the key and a string “name” as the data. HashTableOpen implements open hashing (each bucket points to a linked list of students) and HashTableClosed implements closed hashing (each bucket is a student). The following two structs are used to define the student: // for use in HashTableOpen struct Student { Student(int uw_id, string const& name) : uw_id(uw_id), name(name), next(NULL) {} int uw_id; string name; Student* next; }; // for use in HashTableClosed struct Student { Student() : uw_id(0) {} int uw_id; string name; bool valid; }; The HashTable class definition, the Student structs and a main function and the program output are provided in the code on the website. 1.HashTableOpen. Define class HashTableOpen which is derived from HashTable. The expected behaviour of the methods is as follows. HashTableOpen(): create vector of Student* of size HashTable::defaultSize and initialize entries to NULL HashTableOpen(int buckets): create vector of Student* of size buckets, or if buckets<1 of size HashTable::defaultSize, and initialize entries to NULL ~HashTableOpen(): delete nodes from linked lists; print “delete” followed by uw_ids as they are deleted to standard output insert(uw_id, name): insert student into table if uw_id not present and return number inserted (1 or 0) remove(uw_id): remove student from table if uw_id present and return number removed (1 or 0) operator[](uw_id): find student with specified uw_id or if not present, then insert student with uw_id and name=””; return a reference to the name string print(): traverse the buckets and their linked lists and print out (uw_id, name) pairs 2.HashTableClosed. Define class HashTableClosed which is derived from HashTable. The expected behaviour of the methods is as follows. HashTableClosed(): create vector of Student of size HashTable::defaultSize HashTableClosed(int buckets): create vector of Student of size buckets, or if buckets<1 of size HashTable::defaultSize • a destructor is not necessary for this class insert(uw_id, name): insert student into table if uw_id not present or not valid; if bucket that it hashes to is filled, search for an empty bucket (uw_id==0 or valid=false), wrapping around end of vector if necessary; if empty bucket found, insert student otherwise no insert is done; return number inserted (1 or 0) remove(uw_id): remove student from table if uw_id present; do not set uw_id=0, just set valid=false; return number removed (1 or 0) operator[](uw_id): find student with specified uw_id or if not present or valid, then insert student with uw_id and name=””; return a reference to the name string (if no space exists to insert missing uw_id, throw exception using this statement: throw string(”table full”); this will effectively return to the call in main and an error message will be printed) print(): traverse the buckets and print out (uw_id, name) pairs of valid students Tips: As with BST, I found a helper method useful for insert, remove and operator[]. The prototypes (for each derived class) are: int HashTableClosed::find(int uw_id); Student* HashTableOpen::find(int uw_id); •This is the hardest; it is not on the exam. This is only for interest