I'm trying to implement hash table with Separate chaining collision resolution and I have a problem.
This is my code (little modified to simplify, but error still same):
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
using namespace std;
int ascii(char character)
{
return character;
}
int hashFunction(string word, int num)
{
char* str = new char[word.length() + 1];
strcpy(str, word.c_str());
return ((3 * ascii(str[0]) + 5 * ascii(str[1]))) % num;
}
typedef struct tab
{
string data;
struct tab* next;
}Node;
typedef struct link
{
Node* head;
Node* tail;
}List;
List* createList()
{
List* list = new List();
if (list)
{
list->head = NULL;
list->tail = NULL;
}
return list;
}
void insert(List* list, string data)
{
//if list is empty
if (list->head == NULL) //!!!!!!!!!!!!!!!!ERROR OCCURE HERE !!!!!!!!!!!!!!!
{
list->head = new Node();
list->head->data = data;
list->head->next = NULL;
list->tail = list->head;
}
//if list already contains some data
else
{
list->tail->next = new Node();
list->tail->next->data = data;
list->tail = list->tail->next;
list->tail->next = NULL;
}
}
int main(int argc, char* argv[])
{
int size = 8; //Size of hash table (number of indexes)
List* table[12];
string A[8] = { "hello","world","car","notebook","science","starwars","lollypop","anything" };
//Insert elements from array A into a hash table
int index;
for (int i = 0; i < size; i++)
{
index = hashFunction(A[i], size);
if (table[index] == NULL)
table[index] = createList();
insert(table[index], A[i]);
}
return 0;
}
When I run the .exe file (or start from cmd), program ends up with message that app.exe has stopped working. I tried debug the program and got this:
http://imgur.com/a/yOhRV
Can anyone help me how to fix this? I've figured out problem must be in insert() function, probably in the condition, but I don't know what is wrong.
you derefernce a pointer without checking it: if (list->head == NULL)...
What you are doing here, is taking list and cheking if the value pointed by it is NULL, but since you haven't checked if (list) then it's possible that list == NULL and that causes segfault when dereferencing it
You are declaring List* table[12] but it is never initialized. So it does contain garbage.
You have to do the following in order to initialize it: List* table[12] = {NULL};
As a general rule you should never have uninitialized variables in your code (unless for optimization purposes when you know exactly what you are doing).
Add default contructors to your structs and make use of initialization list. Also keep you variables as local as possible (move index inside the loop).
You don't need ascii() cause char is integer type. char+char and char*int get promoted to int.
Related
I would like to implement an array of linked lists to create a printing queue; with an array of five queues. Each queue is meant to represent a user printing a job sent to the printer.
This is the code I currently have:
#include "stdafx.h"
#include <iostream>
using namespace std;
struct node
{
float value;
struct node *next;
};
node *head = NULL;
node* A[5];
int insertNodes(node *head, int value)
{
node *aNode, *Ptr;
aNode = new node;
aNode->value = value;
aNode->next = NULL;
if (head == NULL)
head = aNode;
else
{
Ptr = head;
while (Ptr->next != NULL)
Ptr = Ptr->next;
Ptr->next = Ptr;
}
return head;
}
int _tmain(int argc, _TCHAR* argv[])
{
int num;
for (int i = 0; i < 5; i++)
{
cout << "Insert number";
cin >> num;
A[i] = insertNodes(i, num)
}
return 0;
}
This code does not work as intended, as I am unable to add "jobs" to the queues.
Where have I gone wrong?
There is a number of issues with your code:
You are programming in C++, not C, so instead of struct node *next you should simply write node *next.
Your insertNodes function returns a pointer to the head of the list, so you need to return node*, not int.
When you insert into a list with an existing head, you never insert the item. You have to do Ptr->next = aNode, not Ptr->next = Ptr.
In your main function, you are expected to pass a pointer to the head of the list to insertNodes, but you actually pass it an int. Instead, try A[i] = insertNodes(A[i], num).
You store float in your list nodes, but input int - is that actually desired?
However, since you are in C++, you can probably avoid most of these pitfalls entirely by relying on what the standard library already provides.
Simply #include <deque> and you can use everything that std::deque (a double-ended queue) provides, including push_back to add elements at the end, front to access the first element, and pop_front to remove it - a real queue, no need for custom linked lists:
#include "stdafx.h"
#include <deque>
#include <vector>
#include <iostream>
std::vector<std::deque<float>> A {5};
int _tmain(int argc, _TCHAR* argv[])
{
float input;
for (int i = 0; i < 5; i++)
{
std::cout << "Insert number: ";
std::cin >> input;
A[i].push_back(input);
}
return 0;
}
I have spent significant amount of time on this and I have finally made it work at all (as in it saves the values and prints them). I want to sort it counter alphabetically. If I add the values into my list they do not print out in the same order I have added them in but it seems kind of random... It seems that the strcpy doesn't work in the way I would imagine it to work...
#include <iostream>
#include <cstdlib>
#include <string.h>
#include <stdio.h>
using namespace std;
typedef struct list list_t;
struct list{
list *next;
char *nam;
int age;
};
static list_t *top = NULL;
void add_value(char * name1, int age){
list * neww = (list_t*)malloc(sizeof( list_t));
//tmp = top;
neww->age = age;
neww->nam = (char*)malloc(strlen(name1) + 1);
neww->next = NULL;
strcpy(neww->nam, name1);
list * tmp = (list_t*)malloc(sizeof(list_t));
tmp = top;
if (tmp==NULL){
top = neww;
//printf("%s\n", top->nam);
}else
while (1){
if (tmp->next == NULL){
tmp->next = neww;
break;
}
//printf("top - %s %d\n neww - %s %d\n tmp - %s %d", top->nam, top->age, neww->nam, neww->age, tmp->nam, tmp->age);
if (strcmp(neww->nam, tmp->nam)>=0){
neww->next = tmp->next;
tmp->next = neww;
break;
}
tmp = tmp->next;
}
}
void print(){
list * tmp = (struct list*)malloc(sizeof(struct list));
tmp = top;
while (tmp){
printf("%s %d\n", tmp->nam, tmp->age);
tmp = tmp->next;
}
}
int main(){
char namee[100];
int age;
for (int i = 0; i < 5; i++){
scanf("%s %d", &namee, &age);
add_value(namee, age);
}
print();
return 0;
}
I spotted two things which seem wrong.
a) This line
list * tmp = (struct list*)malloc(sizeof(struct list));
is wrong (used in two functions). You need a pointer - not a new element - so no need for malloc.
b) This code
if (tmp->next == NULL){
tmp->next = neww;
break;
}
seems to get active when you reach the last element. However, you must still check if the new element is to be inserted before or after the element already in the list. Your code always place the new element after. Consider the case when your list only have 1 element.
BTW - If you want to write c++ you should use std::string instead of c-style char arrays. Also, take a look at std::multimap instead of your own linked list.
Im reading strings from a file and inserting them into a LinkedList in alphabetical order (C++). I have made the node and list classes but something is wrong with them. I have done this in Java and it works 100% without any problems. This leads me to believe that I must have messed up with pointers somewhere. This is also only the second time I use the '->' symbol. So I may have used it erroneously somewhere. Some helpful tips are appreciated. Thanks in advance.
//NODE CLASS
#include <string>
#include <iostream>
using namespace std;
class Node {
string word;
int count;
Node* next;
public:
Node (string aWord) {
word = aWord;
count = 1;
}
Node (string aWord, Node* theNext) {
word = aWord;
next = theNext;
}
void increaseCount() {
count++;
}
string getWord() {
return word;
}
int getCount() {
return count;
}
Node* getNext() {
return next;
}
void setNext(Node* theNext) {
next = theNext;
}
};
//LIST CLASS
#include<iostream>
using namespace std;
class LinkedList {
Node* head;
public:
LinkedList() {
head = new Node(" ");
}
void insert(string word) {
Node* temp = head;
Node* previous = head;
while (temp != NULL && temp->getWord() < word) {
previous = temp;
temp = temp->getNext();
}
if (temp == NULL) {
Node* node= new Node(word);
previous-> setNext(node);
} else {
if (temp-> getWord() == word) {
temp->increaseCount();
} else if (temp->getWord() > word) {
Node* node = new Node(word, temp);
previous->setNext(node);
}
}
}
void print() {
Node* temp = head->getNext();
while (temp != NULL) {
cout<< temp;
temp=temp->getNext();
}
}
};
//MAIN
#include <iostream>
#include <iostream>
#include <fstream>
#include "Node.h"
#include "LinkedList.h"
using namespace std;
int main(int argc, const char * argv[]) {
ifstream inFile("WordsStatisticData1.txt");
if (!inFile.is_open())
cout<< "Could not open the file"<< endl;
else {
string readData;
LinkedList list = *new LinkedList(); //Probably a problem here
while (inFile >> readData) {
list.insert(readData);
inFile.close();
list.print();
}
}
}
I may be declaring things totally wrong within the main as well.
My output looks like an address '0x' with random characters.
You're printing out temp where temp is a Node*. A pointer is just the address of an object, hence why you're getting an address in your output.
Seems like you want to get the string that the Node contains. If so, you want:
cout << temp->getWord();
Another problem you have is that you close your file and print the list inside the loop, which means it'll happen right after the first word has been read. You probably mean to do this after the loop, so all of the words in the file can be read.
You also have problem with the line you marked as such. Using the new keyword will dynamically allocate an object. These objects need to be later deleted with delete. However, you dereference the dynamically allocated object (with *) and copy it, losing any reference to the dynamically allocated object - this is a classic memory leak. The dynamic allocation here is completely unnecessary. Just do:
LinkedList list;
Basically I want to print the data part of the Linked list which is basically an Integer pointer and I am assigning it an array at the time of creation, I want to print all the values of it how to do so ???
Thank you.
Here is my code
using namespace std;
struct Node{
Node *next;
int *data;
};
class DataLine{
private:
Node *first;
public:
DataLine(){
first=NULL;
}
void create_list(){
Node *temp=new Node;
int i=2;
int dat[5]={12,13,14,13,16};
temp->data=dat;
temp->next=NULL;
if(first==NULL){
//cout<<"hello 1"<<endl;
first=temp;
}
else{
Node *curr=first; //We are now doing trevercing so we are assigning the first to the node because we donot want to move the first bacuse link break if we move the first
while(curr->next!=NULL) //searching end of list
{
curr=curr->next; //Moving to the next node
}
curr->next=temp; //insert node
temp=NULL; //Making the temp enpty to use it for the new purpose
//delete temp;
}
}
void print_list()
{
Node *prnt=first; //We are now again want trevercing so we agin run the node by the new node
while(prnt!=NULL) //Checking the loop will run till it get the null in the node means its address part and data part both are nUll
{
for(int i=0;i<5;i++)
cout<<" ***** The "<<" node is "<<*(prnt->data+i)<<endl; //Printing the data
prnt=prnt->next; //Moving to the next node
}
}
};
int main(){
DataLine dl;
dl.create_list();
dl.print_list();
_getch();
return 0;
}
The idea of your void print_list(void) is correct but you can make it much cleaner, note however I changed your output to print a single node per line (change that back if you want). The structure of a for loop seems, to me, perfect for linked lists and keeps the linked list code our of the body of the loop.
void print_list(void) const
{
for (Node* p = first; p != NULL; p = p->next)
{
for (int i = 0; i < Node::unLength; ++i) std::cout << p->data[i] << ", ";
std::cout << std::endl;
}
}
However, as pointed out in some of the comments, there are other problems in your create list code. The way I would suggest to fix these (for this program) would be to redefine your structure to always hold a fixed number of integers.
struct Node
{
enum { unLength = 5 };
Node* next;
int data[unLength];
};
I have also added here a constant for the length of the array, since its bad practice to have magic numbers floating around your code, what happens if you mistype one of them?
Now in your void create_list() you can go:
void create_list()
{
Node* temp = new Node;
// Set the next node of temp
temp->next = NULL;
// Add some data to temp (we can't just assign the data pointer in C/C++)
int data[Node::unLength] = {0, 1, 2, 3, 4};
for (int i = 0; i < Node::unLength; ++i) temp->data[i] = data[i];
Node *p = first;
while (p != NULL) p = p->next;
p->next = temp;
}
There is no point setting temp to NULL since temp is deleted straight after the function returns. In your previous code you set the pointer in Node to data (temp->data=dat;, this doesn't work either since dat was deleted as soon as the function returned, you need to instead allocate memory and copy the values from dat which is what the for loop in the above code does.
For you class constructor (and destructor) I would suggest:
class DataLine
{
private:
Node* first;
public:
DataLine(void) : first(NULL) {}
~DataLine(void)
{
while (first != NULL)
{
Node *temp = first->next;
delete first;
first = temp;
}
}
You had the right idea, but there are a few subtle things about C/C++ that aren't obvious in higher level languages, such as copying arrays and the scope of variables.
If you are using C++ however, I would really suggest not worrying about linked lists, just create a std::vector, in C++ 11 something like the following might work (untested):
#include <vector>
#include <array>
int main(int argc, char** argv)
{
std::vector< std::array<int, 5> > myData;
myData.push_back({0, 1, 2, 3, 4});
myData.push_back({0, 1, 2, 3, 4});
myData.push_back({0, 1, 2, 3, 4});
for (const auto& i : myData)
{
for (int j : i) std::cout << j << ", ";
std::cout << std::endl;
}
return 0;
}
I'm trying to make linked list similar too the one here:
linked list in C
That is to have the "head", I called it first, inside another struct. However I found doing that change. Makes it hard to add values to the list_item struct. I have tried some few things to see if it works. It compiles, however when I run the code it will crash. Any help would be helpful here. I know the cause of the crash is when I want to point the new_node to the linked_list.
#include <iostream>
using namespace std;
struct list_item
{
int key;
int value;
list_item *next;
};
struct list
{
struct list_item *first;
};
int main()
{
list *head;
list *new_node;
head = NULL;
head->first = NULL;
for(int i = 0; i < 10; i++)
{
//allocate memory for new_node
new_node = (list*)malloc(sizeof(list));
new_node->first = (list_item*)malloc(sizeof(list_item));
//adding the values
new_node->first->key = i;
new_node->first->value = 10 + i;
//point new_node to first;
new_node->first->next = head->first;
//point first to new_node;
head->first = new_node->first;
}
//print
list *travel;
travel->first = head->first;
int i = 0;
while(travel != NULL)
{
cout << travel->first->value << endl;
travel->first = travel->first->next;
}
return 0;
}
You are creating 10 lists, I think you might try to do something like this:
#include <iostream>
using namespace std;
struct list_item
{
int key;
int value;
list_item *next;
};
struct list
{
struct list_item *first;
};
int main()
{
//Just one head is needed, you can also create this
// on the stack just write:
//list head;
//head.first = NULL;
list *head = (list*)malloc(sizeof(list));
list_item *new_node = NULL;
head->first = NULL;
for(int i = 0; i < 10; i++)
{
//allocate memory for new_node
new_node = (list_item*)malloc(sizeof(list_item));
//adding the values
new_node->key = i;
new_node->value = 10 + i;
//if the list is empty, the element you are inserting
//doesn't have a next element
new_node->next = head->first;
//point first to new_node. This will result in a LIFO
//(Last in First out) behaviour. You can see that when you
//compile
head->first = new_node;
}
//print the list
list_item *travel;
travel = head->first;
while(travel != NULL)
{
cout << travel->value << endl;
travel = travel->next;
}
//here it doesn't matter, but in general you should also make
//sure to free the elements
return 0;
}
This is what is going on. At first you only have one head and no elements.
head
|
|
V
NULL
Then you add your first element. Make sure that the "new_node->next==NULL":
head
|
|
V
node: ------------------> NULL
key = 0
value = 10
Then you add another node in front but append your first node to its next node. you move the pointer from the head to the new node
head:
first
|
|
V
node: ---------> node: -------------> NULL
key: 1 key: 0
value: 11 value: 10
etc.
Since you are using c++, you might consider using "new" and "delete". Just replace
new_node = (list_item*)malloc(sizeof(list_item));
with
list *head = new list
The next line only allocates memory for your list struct. The list contains only a pointer, you must also allocate memory for new_node->first before assigning to any of its members.
//allocate memory for new_node
new_node = (list*)malloc(sizeof(list));
I think you want something more like this:
#include <iostream>
#include <cstdlib>
using namespace std;
typedef struct tag_list_item
{
int key;
int value;
struct tag_list_item *next;
} list_item;
typedef struct
{
list_item *head;
} list;
int main()
{
list my_list;
list_item *new_node;
list_item *previous_node = NULL;
my_list.head = NULL;
for(int i = 0; i < 10; i++)
{
//allocate memory for new_node
new_node = (list_item*)malloc(sizeof(list_item));
//adding the values
new_node->key = i;
new_node->value = 10 + i;
if(previous_node == NULL)
{
my_list.head = new_node;
}
else
{
previous_node->next = new_node;
}
previous_node = new_node;
}
//print
list_item *iter = my_list.head;
while(iter != NULL)
{
cout << iter->value << endl;
iter = iter->next;
}
return 0;
}
Changes of note:
For malloc, I added:
#include <cstdlib>
I changed your list structures to typedefs, had to declare "next" using the tag since the typedef isn't complete at that point
typedef struct tag_list_item
{
int key;
int value;
struct tag_list_item *next;
} list_item;
I changed your list name to "my_list" and declared it directly (without the pointer). In this case you can just have the compiler allocate it automatically on the stack.
list my_list;
I keep a pointer for "previous_node" so that you can assign the "next" pointer much more easily. Notice that the first node allocated is pointed to by the "head" pointer in the list structure. I believe that is the traditional name for the pointer to the first element in a list.
if(previous_node == NULL)
{
my_list.head = new_node;
}
else
{
previous_node->next = new_node;
}
previous_node = new_node;
head = NULL;
head->first = NULL;
There's the issue. You can't follow a pointer and set it to NULL if you've set the pointer itself to NULL.
That should be
head = malloc(sizeof(list));
head->first = NULL;
That should fix your code.
Hope that helps,
Billy3
EDIT: There's also an issue with your FOR loop. When you allocate the list, you should only allocate the list itself once. When you insert an item, you only allocate a list_item. You're assigning a list pointer to a member which accepts only a list_item pointer ;)
See Gabe's post for a demonstration of correct behavior :)
Look at your struct declaration
struct list_item
{
int key;
int value;
list_item *next;
};
That should be
struct list_item
{
int key;
int value;
struct list_item *next;
};
Hope this helps,
Best regards,
Tom