I am trying the following code for Hash table implementation in C++. The program compiles and accepts input and then a popup appears saying " the project has stopped working and windows is checking for a solution to the problem. I feel the program is going in the infinite loop somewhere. Can anyone spot the mistake?? Please help!
#include <iostream>
#include <stdlib.h>
#include <string>
#include <sstream>
using namespace std;
/* Definitions as shown */
typedef struct CellType* Position;
typedef int ElementType;
struct CellType{
ElementType value;
Position next;
};
/* *** Implements a List ADT with necessary functions.
You may make use of these functions (need not use all) to implement your HashTable ADT */
class List{
private:
Position listHead;
int count;
public:
//Initializes the number of nodes in the list
void setCount(int num){
count = num;
}
//Creates an empty list
void makeEmptyList(){
listHead = new CellType;
listHead->next = NULL;
}
//Inserts an element after Position p
int insertList(ElementType data, Position p){
Position temp;
temp = p->next;
p->next = new CellType;
p->next->next = temp;
p->next->value = data;
return ++count;
}
//Returns pointer to the last node
Position end(){
Position p;
p = listHead;
while (p->next != NULL){
p = p->next;
}
return p;
}
//Returns number of elements in the list
int getCount(){
return count;
}
};
class HashTable{
private:
List bucket[10];
int bucketIndex;
int numElemBucket;
Position posInsert;
string collision;
bool reportCol; //Helps to print a NO for no collisions
public:
HashTable(){ //constructor
int i;
for (i=0;i<10;i++){
bucket[i].setCount(0);
}
collision = "";
reportCol = false;
}
int insert(int data){
bucketIndex=data%10;
int col;
if(posInsert->next==NULL)
bucket[bucketIndex].insertList(data,posInsert);
else { while(posInsert->next != NULL){
posInsert=posInsert->next;
}
bucket[bucketIndex].insertList(data,posInsert);
reportCol=true;}
if (reportCol==true) col=1;
else col=0;
numElemBucket++;
return col ;
/*code to insert data into
hash table and report collision*/
}
void listCollision(int pos){
cout<< "("<< pos<< "," << bucketIndex << "," << numElemBucket << ")"; /*codeto generate a properly formatted
string to report multiple collisions*/
}
void printCollision();
};
int main(){
HashTable ht;
int i, data;
for (i=0;i<10;i++){
cin>>data;
int abc= ht.insert(data);
if(abc==1){
ht.listCollision(i);/* code to call insert function of HashTable ADT and if there is a collision, use listCollision to generate the list of collisions*/
}
//Prints the concatenated collision list
ht.printCollision();
}}
void HashTable::printCollision(){
if (reportCol == false)
cout <<"NO";
else
cout<<collision;
}
The output of the program is the point where there is a collision in the hash table, thecorresponding bucket number and the number of elements in that bucket.
After trying dubbuging, I come to know that, while calling a constructor you are not emptying the bucket[bucketIndex].
So your Hash Table constructor should be as follow:
HashTable(){ //constructor
int i;
for (i=0;i<10;i++){
bucket[i].setCount(0);
bucket[i].makeEmptyList(); //here we clear for first use
}
collision = "";
reportCol = false;
}
//Creates an empty list
void makeEmptyList(){
listHead = new CellType;
listHead->next = NULL;
}
what you can do is you can get posInsert using
bucket[bucketIndex].end()
so that posInsert-> is defined
and there is no need to
while(posInsert->next != NULL){
posInsert=posInsert->next;
because end() function is doing just that so use end() function
Related
So I'm trying to build a linear linked list that takes info from users and saves the info in two sorted lists by name (alphabetically) and by birthdate. So far I have
struct node{
char* name;
int birthDate;
node *nameNext;
node * dateNext;
};
where each node will have two pointers pointing to the appropriate list. The problem I'm having is how to direct the head pointer node *head. How do I set head when there are two different lists? I'm thinking something like head->nameNext and head->dateNext but that would point to the second node of the lists if it work. Please help! Thanks in advance.
if i got your question right, you're simply looking to sort your list
in two ways (alphabetically and birthdate)
note: i will use bubble sort to simplify the algorithm but you can use better one as you know
#include <iostream>
struct node{
const char* name;
int birthdate;
node*next;
};
struct sort_data{
private:
node *name_root = nullptr; // alphabetically head/root pointer
node *date_root = nullptr; // birthdate head/root pointer
public:
void push(const char*name,int birthdate); // push data;
void sort_by_birth(); // sort the birth linked list
void sort_by_alphabet(); // sort the alphabet linked list
void print_birth(); // print the data of the birth linked list
void print_alph(); // print of the data of the alphabet linked list
};
void sort_data::push(const char*name,int birthdata) {
node*Name = new node; // allocate a node for the alphabet list
node*Date = new node; // allocate a node for the date list
Name->name = Date->name = name;
Name->birthdate = Date->birthdate = birthdata;
Name->next = name_root;
Date->next = date_root;
name_root = Name;
date_root = Date;
}
void sort_data::sort_by_birth() {
node*i = date_root;
node*j;
if(!i) // if i == nullptr
return;
while(i){ // while(i!=nullptr)
j = i->next;
while(j){
if(i->birthdate > j->birthdate){
std::swap(i->birthdate,j->birthdate);
std::swap(i->name,j->name);
}
j = j->next;
}
i = i->next;
}
}
void sort_data::sort_by_alphabet() {
node*i = name_root;
node*j;
if(!i)
return;
while(i){
j = i->next;
while(j){
if(i->name[0] > j->name[0]){
std::swap(i->birthdate,j->birthdate);
std::swap(i->name,j->name);
}
j = j->next;
}
i = i->next;
}
}
void sort_data:: print_birth(){
node*temp = date_root;
while(temp){
std::cout << temp->name << " " << temp->birthdate << std::endl;
temp = temp->next;
}
}
void sort_data::print_alph() {
node*temp = name_root;
while(temp){
std::cout << temp->name << " " << temp->birthdate << std::endl;
temp = temp->next;
}
}
int main(){
sort_data obj;
obj.push("jack",1997);
obj.push("daniel",1981);
obj.push("maria",1995);
obj.push("john",2008);
obj.sort_by_alphabet();
obj.sort_by_birth();
std::cout << "alphabetically : \n" ;
obj.print_alph();
std::cout << "by birthdate : \n";
obj.print_birth();
}
note: because you're using C++ don't use char* to store string literals
use std::string or const char *. as the chars in string literals are const char so you don't want to point on const char with char
if you're using a C++ compiler that support C++11 your compiler should generate a warning about such thing
I am writing my own HashTable class in C++ and need to output to the user the number of occurrences of each string in the table. For example, if this is the input: testing, 1, 2, testing, and this is the hash table (done with chaining, and node pointers):
[0]->testing, testing
[1]->2
[2]->1
this would be the output to the user (the count, followed by the word):
2 testing
1 2
1 1
The problem I'm having is how to keep track of how many of each word is in the Hash Table, or how to find it. I started with this question but was unable to implement another array in my code.
I also tried the solution in this question, but it didn't work because of my use of pointers/chained hashing.
My question is, do I need to use a separate array of strings to keep track of what's already been used, or is there an easy way to recursively go through each index of the Hash Table and print out the number of occurrences of each string? I think I need to accomplish this in either my insert function or my printData function.
For reference, here is my code:
HashTable.h:
#include <string>
#include <iostream>
using namespace std;
struct Entry {
string word;
Entry* next;
};
class HashTable {
public:
HashTable();
HashTable(int);
int hash(string);
void insert(string);
void printData();
int getCapacity() const;
private:
//Member variables
int CAPACITY; // The initial capacity of the HashTable
Entry **data; // The array to store the data of strings (Entries)
};
HashTable.cpp:
#include "HashTable.h"
HashTable::HashTable()
{
CAPACITY = 0;
data = new Entry*[0];
}
HashTable::HashTable(int _cap)
{
CAPACITY = _cap;
data = new Entry*[_cap];
for (int i = 0; i < CAPACITY; i++) {
data[i] = new Entry;
data[i]->word = "empty";
data[i]->next = nullptr;
}
}
int HashTable::hash(string key)
{
int hash = 0;
for (unsigned int i = 0; i < key.length(); i++) {
hash = hash + (int)key[i];
}
return hash % CAPACITY;
}
void HashTable::insert(string entry)
{
int index = hash(entry);
if (data[index]->word == "empty") {
data[index]->word = entry;
} else {
Entry* temp = data[index];
Entry* e = new Entry;
e->word = entry;
e->next = nullptr;
while (temp->next != nullptr) {
temp = temp->next;
}
temp->next = e;
}
}
void HashTable::printData()
{
for (int i = 0; i < CAPACITY; i++) {
if (data[i]->next != nullptr) {
while(data[i]->next != nullptr) {
cout << data[i]->word << " -> ";
data[i] = data[i]->next;
}
cout << data[i]->word << endl;
} else {
cout << data[i]->word << endl;
}
}
}
int HashTable::getCapacity() const
{
return CAPACITY;
}
NOTE: I can't use any function/data structure from the standard C++ Library.
I only see two options here
Traverse entire linked list to count occurances. Use a map< string, int > to count occurances for each string.
You should make your linked list sorted. So when you insert a new node, you will insert it in its exact place. You can use strcmp for comparison. This way you can count every word exactly in one traverse and using just one integer variable, but your insert time and complexity will increase.
I'm implementing a basic hashtable. My logic for the table makes sense (at least to me), but I'm a bit rusty with my C++. My program returns a free memory error when I run it, but I can't seem to figure out where my problem is. I think is has to do with how I call the pointers in the various class functions.
#include <iostream>
#include <unordered_map>
#include <string>
#include <cmath>
#include <exception>
using namespace std;
int hashU(string in/*, int M*/){ //hThe hash function that utilizes a smal pseusorandom number
char *v = new char[in.size() + 1]; //generator to return an number between 0 and 50. (I arbitrarily chose 50 as the upper limit)
copy(in.begin(), in.end(), v); //First the input string is turned into a char* for use in the the function.
v[in.size()] = '\0';
int h, a = 31415, b = 27183;
for(h=0;*v!=0;v++,a=a*b%(49-1))
h = (a*h + *v)%50;
delete[] v; //Delete the char* to prevent leaky memory.
return (h<0) ? (h+50) : h; //Return number
}
struct hashNode{ //The node that will store the key and the values
string key;
float val;
struct hashNode *next;
};
struct hashLink{ //The linked list that will store additional keys and values should there be a collision.
public:
struct hashNode *start; //Start pointer
struct hashNode *tail; //Tail pointer
hashLink(){ //hashLink constructor
start=NULL;
tail=NULL;
}
void push(string key, float val); //Function to push values to stack. Used if there is a collision.
};
void hashLink::push(string key, float val){
struct hashNode *ptr;
ptr = new hashNode;
ptr->key = key;
ptr->val = val;
ptr->next = NULL;
if(start != NULL){
ptr->next = tail;
}
tail = ptr;
return;
}
struct hashTable{ //The "hash table." Creates an array of Linked Lists that are indexed by the values returned by the hash function.
public:
hashLink hash[50];
hashTable(){ //Constructor
}
void emplace(string in, float val); //Function to insert a new key and value into the table.
float fetch(string in); //Function to retrieve a stored key.
};
void hashTable::emplace(string in, float val){
int i = hashU(in); //Retrieve index of key from hash function.
hashNode *trav; //Create node traveler
trav = hash[i].start; //Set the traveler to the start of the desired linked list
while(trav!=hash[i].tail){ //Traverse the list searching to see if the input key already exists
if(trav->key.compare(in)==0){ //If the input key already exists, its associated value is updated, and the function returns.
trav->val = val;
return;
}
else //Travler moves to next node if the input key in not found.
trav = trav->next;
}
hash[i].push(in,val); //If the traveler does not see the input key, the request key must not exist and must be created by pushing the input key and associated value to the stack.
return;
}
float hashTable::fetch(string in){
int i = hashU(in); //Retrieve index of key
hashNode *trav; //Create node traveler and set it to the start of the appropriate list.
trav = hash[i].start;
while(trav!=hash[i].tail){ //Traverse the linked list searching for the requested key.
if(trav->key.compare(in)==0){ //If the the requested key is found, return the associated value.
return trav->val;
}
else
trav = trav->next; //If not found in the current node, move to the next.
}
return false; //If the requested key is not found, return false.
}
int main(){
hashTable vars; //initialize the hash table
float num = 5.23; //create test variable
vars.emplace("KILO",num);
cout<<vars.fetch("KILO")<<endl;
return 0;
}
The problem is that when you call delete[] v, you have advanced v such that it is pointing to the 0 at the end of the string, which is the wrong address to delete.
Also, you're wasting a lot of code unnecessarily copying the string out of where it is already available as a c-string.
unsigned int hashU(string in/*, int M*/) {
const char* v = in.c_str();
unsigned int h, a = 31415, b = 27183;
for(h=0;*v!=0;v++,a=a*b%(49-1))
h = (a*h + *v);
return h % 50;
}
for(h=0;*v!=0;v++,a=a*b%(49-1))
h = (a*h + *v)%50;
delete[] v; //Delete the char* to prevent leaky
You are incrementing v, then deleting an invalid memory location.
I have been working on this for a while and cannot seem to understand what is happening. I am trying to take the values in istr, put them in a linked list and sort them alphabetically. Eventually I will print them out. I am not sure where my problem is but I thought it was in the function InsertAfter. Is this not my problem and if so do you know what may be causing my linked list to not link? The last bit of code only outputs the headObj and not all of them, so I assumed that my list wasn't linking properly in nextNodePtr in each object but I am not sure. Thank you for your help!
void WordNode::InsertAfter(WordNode* nodeLoc) {
WordNode* tmpNext = 0;
tmpNext = this->nextNodePtr; // Remember next
this->nextNodePtr = nodeLoc; // this -- node -- ?
nodeLoc->nextNodePtr = tmpNext; // this -- node -- next
return;
}
wordNode.hpp
#ifndef wordNode_hpp
#define wordNode_hpp
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class WordNode {
public:
WordNode(string wordval = "", int count = 0, WordNode* nextLoc = 0);
void InsertAfter(WordNode* nodePtr);
WordNode* GetNext();
void PrWordNodeData();
string GetWord();
private:
string word;
WordNode* nextNodePtr;
int wordCount;
};
wordNode.cpp
#include "wordNode.hpp"
// Constructor
WordNode::WordNode(string wordval,int count, WordNode* nextLoc) {
this->word = wordval;
this->wordCount = count;
this->nextNodePtr = nextLoc;
return;
}
/* Insert node after this node.
* Before: this -- next
* After: this -- node -- next
*/
void WordNode::InsertAfter(WordNode* nodeLoc) {
WordNode* tmpNext = 0;
tmpNext = this->nextNodePtr; // Remember next
this->nextNodePtr = nodeLoc; // this -- node -- ?
nodeLoc->nextNodePtr = tmpNext; // this -- node -- next
return;
}
// Print dataVal
void WordNode::PrWordNodeData() {
cout << this->word <<": count=" <<this->wordCount << endl;
return;
}
// Grab location pointed by nextNodePtr
WordNode* WordNode::GetNext() {
return this->nextNodePtr;
}
//Returns word
string WordNode::GetWord()
{
return word;
}
main.cpp
#include <iostream>
#include <sstream>
#include <string>
#include "wordNode.hpp"
int main() {
WordNode* headObj = 0; // Create WordNode objects
WordNode* currObj = 0;
WordNode* nextObj = 0;
string istr ="555 999 777 333 111";
istringstream instring(istr);
string temp;
//Assigns first word to the head object
if (!instring.eof()){
instring >> temp;
headObj=new WordNode(temp,1);
}
currObj=headObj;
while (!instring.eof()){
instring >> temp;
nextObj=new WordNode(temp,1);
//swaps values if currObj is greater than the next word
if(currObj > nextObj) {
currObj->InsertAfter(nextObj);
}
currObj=nextObj;
}
// Print linked list
currObj = headObj;
while (currObj != 0) {
currObj->PrWordNodeData();
currObj = currObj->GetNext();
}
string i;
cin >> i;
return 0;
}
In the very first iteration of the loop (using the string you gave as example) you loose the reference to the head object and hence subsequent iterations will add nodes to a "headless list".
currObj=headObj;
while (!instring.eof()){
instring >> temp;
nextObj = new WordNode(temp,1);
//swaps values if currObj is greater than the next word
if(currObj->GetWord() > nextObj->GetWord()) {
currObj->InsertAfter(nextObj);
}
// And what happens if it is not greater?
currObj = nextObj; // Loose reference to head here if not greater
}
To fix your code you will either just have to add all nodes to the list and then sort it with a sorting algorithm or insert them on the fly as you intend to do now. However, to do the latter you will have to modify your insertion logic, i.e. insert node at the beginning (if new node is alphabetically lower than the first element) or at the end. I recommend reading this nice article about singly linked lists. It has examples and code for the insertions mentioned.
Been wracking my mind all day trying to hammer out the underlying data structures for a challenge assignment in one of my programming classes.
The problem is as follows:
Given an assortment of objects (each of which includes an identifier and a weight) and a supply of containers (which have a fixed weight capacity), pack all the items using as few containers as possible without overloading any of them.
I have the logic aspects hammered out using a hodgepodge of arrays, but the dynamic nature of this assignment has me wanting to optimize things by using vectors and/or linked lists.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <math.h>
#include <time.h>
#include <conio.h>
#include <vector>
#include <algorithm>
using namespace std;
struct Item
{
int number;
double weight;
bool operator < (const Item& str) const
{
return (weight < str.weight);
}
};
class Node
{
int number;
double weight;
Node* next;
public:
Node()
{};
void SetID(int iNum)
{
number = iNum;
};
void SetWeight(double iWeight)
{
weight = iWeight;
};
void SetNext(Node* iNext)
{
next = iNext;
}
int GetID()
{
return number;
};
double GetWeight()
{
return weight;
};
Node* Next()
{
return next;
};
};
class List
{
Node* head;
double weight;
public:
List()
{
head = NULL;
weight = 0;
};
int Size()
{
Node* tmp;
int count = 0;
for (tmp = head; tmp != NULL; tmp = tmp->Next())
{
count++;
}
return count;
};
double Weight()
{
return weight;
};
void Print()
{
Node *tmp = head;
if ( tmp == NULL )
{
cout << " E M P T Y" << endl;
return;
}
do
{
cout << setw(8) << tmp->GetID() << " | " << setw(8) << tmp->GetWeight() << endl;
tmp = tmp->Next();
} while ( tmp != NULL );
};
void Append(int iNum, double iWeight)
{
Node* newNode = new Node();
newNode->SetID(iNum);
newNode->SetWeight(iWeight);
newNode->SetNext(NULL);
Node *tmp = head;
if ( tmp != NULL )
{
while ( tmp->Next() != NULL )
{
tmp = tmp->Next();
}
tmp->SetNext(newNode);
}
else
{
head = newNode;
}
weight += iWeight;
};
};
double ItemWeights(vector<Item> iVect)
{
double total = 0;
for(int i = 0; i < iVect.size(); i++)
{
total += iVect[i].weight;
}
return total;
}
int main()
{
const double MAX_WEIGHT = 20;
vector< Item > source;
//
// Segment of code which propagates the vector data
// works fine, but is excluded for the sake of brevity
//
double totalWeight = ItemWeights(source);
// Duplicate vector of items
vector< Item > items(source);
for(int i = 0; i < items.size(); i++)
{
cout << setw(8) << items[i].number << setw(8) << items[i].weight << endl;
}
cout << "\n Total weight = " << totalWeight << endl;
cout << "\n\n Press any key to continue... ";
getch();
// Solution A-Original
// vector< vector< Item > > boxesAO( vector< Item >);
// boxesAO[0].push_back({items[items.size()].number, items[items.size()].weight});
vector< List > boxesAO;
// boxesAO[0].Append(items[items.size()].number, items[items.size()].weight);
return 0;
}
I've left some of the methods I've tried in the code (commented out) - none of which worked. As I mentioned above, I've got it working with arrays of linked lists and with 2D arrays, but the vast range of potential input makes these problematic at best. Either a bunch of empty lists taking up space or, worse, not having enough.
I'm thinking that vector< List > is my best option, but I can't figure out how I'm supposed to access any of the List functionality.
If someone would be so helpful as to offer a suggestion for how to create a "dynamic 2D array" as well as a code example of how to access it, I would be most greatly appreciative. My deepest thanks in advance.
EDIT:
#jaredad7 ~ That's what I've been trying, but it keeps causing the program to crash.
List box;
box.Append(items[items.size()].number, items[items.size()].weight);
This works just fine - no problems whatsoever.
The earlier code propagates a 1D vector of Item structs, which also works properly.
vector< List > boxes;
boxes[0].Append(items[items.size()].number, items[items.size()].weight);
This compiles fine but crashes during execution, no matter what index is used. (I'm also using couts for debugging, and the issue most definitely lies with trying to access the List functions.)
I'm suspecting that .push_back or somesuch may be needed, but I haven't been able to find much information concerning vectors of List objects.
If you can, my first suggestion would be to go with the vector (if that is allowed). As for accessing functions/attributes of a member of a vector, it's done the same way as an array, that is:
vectorname[i].functionname(a,b,c);
The best way to do this without vectors would be to use your nodes as the item container (a struct), and handle node-creation, deletion, etc. in your list class. Then, you would only really need one container for as many objects of one type as you need. You can make the type dynamic (although it appears you only need doubles for this project) by adding a class template (use google if you are unfamiliar with templates in C++). This will allow your user to make a container for each type of data (much like a vector).