Related
I am having trouble figuring out how to do this correctly. I have a linked list of nodes then those nodes have pointers put into an array contained in that node. These nodes make up a sort of one-way graph between the nodes. I must then traverse the nodes randomly until the node "Home" is reached.
The main issue I'm having is assigning the graph nodes into the list nodes. I want the function to take in the head of the list, the names of the nodes and the weight (cost to travel between nodes). I'm not sure how to do this correctly and I don't know what I did but I think there's an infinite loop somehow. Any help is greatly appreciated.
The input file is structured as such:
Applebees
GroundRound
BlueMoose
DrunkenNoodle
Home
STOP
Applebees BlueMoose 10
Applebees DrunkenNoodle 13
GroundRound Applebees 2
GroundRound DrunkenNoodle 7
GroundRound Home 52
STOP STOP 0
GroundRound
Ignore the print statements in graphInsert() those are me trying to debug the loops.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
struct graphNode {
char name[100]; // Establishment name
int arcCnt; // Number of outgoing arc from this node
int weights[10]; // Weights of each outgoing arc from this node
struct graphNode* arcs[10]; // Holds other graph nodes that are connected to this node (this node is source)
};
struct listNode {
char name[100]; // Establishment name
struct listNode* next;
struct graphNode* graph; // Pointer into graph
};
void listInsert(struct listNode **head, char name[100]) {
// setup new nodes
struct graphNode* newGraph = (struct graphNode*)malloc(sizeof(struct graphNode));
for (int i = 0; i < 100; i++) {
newGraph->name[i] = name[i];
}
for (int i = 0; i < 10; i++) {
newGraph->arcs[i] = NULL;
}
newGraph->arcCnt = 0;
struct listNode* newNode = (struct listNode*)malloc(sizeof(struct listNode));
for (int i = 0; i < 100; i++) {
newNode->name[i] = name[i];
}
newNode->next = NULL;
newNode->graph = newGraph;
// check if head is NULL
if (*head == NULL) {
*head = newNode;
return;
}
// if the list is populated then add the node to the end
struct listNode* current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
void graphInsert(struct listNode** head, char src[100], char dst[100], int weight) {
struct listNode* srcNode = *head;
printf("CALL:");
while (srcNode->next != NULL) { // loop through list to find src
printf("%s %s", srcNode->name, src);
if (strcmp(srcNode->name, src) == 0) { // when it finds the name, find the dst update the graph node data
printf("FOUND");
struct listNode* dstNode = *head;
while (dstNode->next != NULL) { // this loop is to find the pointer to the dst node
printf(" %s %s", dstNode->name, dst);
if (strcmp(dstNode->name, src) == 0) { // when it finds name finally update all the info
printf("FOUND");
// assign the new arc to the right spot based on arcCnt (how many arcs there are), then return to exit the loops
srcNode->graph->arcs[srcNode->graph->arcCnt] = dstNode->graph;
srcNode->graph->weights[srcNode->graph->arcCnt] = weight;
srcNode->graph->arcCnt++;
return;
}
dstNode = dstNode->next;
}
}
srcNode = srcNode->next;
}
}
int main(){
srand(2021);
// setup variables
struct listNode* head = NULL;
struct graphNode* sourceNode = NULL;
FILE* data = fopen("./hw10.data", "r");
int i = 0;
int section = 1; // flag to read the file correctly
// this loop reads the file
while (1) {
char name[100];
char name2[100];
int weight = 0;
if (section == 1) { // reads the first section
fscanf(data, "%100s", name);
if (strcmp(name, "STOP") == 0) { // if end of section then increment section counter
section++;
} else { // if its not the end of the section then add the name to the linked list
listInsert(&head, name);
}
} else if (section == 2) { // reads the first section and builds the graph
fscanf(data, "%100s %100s %d", name, name2, &weight);
if (strcmp(name, "STOP") == 0) { // if end of section then increment section counter
section++;
} else {
//graphInsert(&head, name, name2, weight);
}
} else if (section == 3) { // this section only reads one line and gets the
char tmp[100];
fscanf(data, "%100s", tmp);
struct listNode* current = head;
while (current->next != NULL) { // loop through to find the right node for the name
if (strcmp(current->name, tmp) == 0) { // if names are equal update the node
sourceNode = current->graph;
break;
}
current = current->next;
}
}
if (feof(data)) break;
i++;
}
// debug print data
printf("\n");
struct listNode* current = head;
while (current != NULL) {
printf("%s\n", current->name);
current = current->next;
}
printf("\n");
// starting node
printf("%s ", sourceNode->name);
// now walk through the graph from sourceNode until we reach the node "Home"
int totalWeight = 0;
i = 0;
while (i < 100) {
char* tmp = sourceNode->name;
if (strcmp(tmp, "Home") == 0) { // if were home then exit program
// ending node and cost
printf("%s %d", sourceNode->name, totalWeight);
return 0;
} else { // if were not home then keep looping
int index = (rand() % sourceNode->arcCnt); // Generates random number between 0 and sourceNode->arcCnt
sourceNode = sourceNode->arcs[index];
//printf("Going to: %s, Index: %d", sourceNode->name, totalWeight);
}
i++;
}
return 0;
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 11 months ago.
Improve this question
I am trying to modify this code to add new numbers to the list with symbol "+" and delete with symbol "-". If the number entered is even, it should insert the number at the start of the list, if its odd, it should insert it at the end. The program will end after 0 (+0 or -0) is entered. Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int data;
struct node *ptr;
} node;
node * insert(node *head, int num)
{
node *temp = malloc(sizeof(node));
temp->data = num;
if (head == NULL || head->data > num)
{
temp->ptr = head;
head = temp;
}
else
{
node *current = head;
while ((current->ptr != NULL) && !(num < current->ptr->data))
{
current = current->ptr;
}
temp->ptr = current->ptr;
current->ptr = temp;
}
return head;
}
node * delete_if_less( node *head, int data )
{
while ( head != NULL && head->data < data )
{
node *temp = head;
head = head->ptr;
free( temp );
}
if ( head != NULL )
{
for ( node *current = head; current->ptr != NULL; )
{
if ( current->ptr->data < data )
{
node *temp = current->ptr;
current->ptr = current->ptr->ptr;
free( temp );
}
else
{
current = current->ptr;
}
}
}
return head;
}
void free_list(node *head) {
node *prev = head;
node *cur = head;
while(cur) {
prev = cur;
cur = prev->ptr;
free(prev);
}
}
int main(){
int num, min;
node *head, *p;
head = NULL;
do {
printf("Enter a number: ");
scanf("%d",&num);
if(num) {
head = insert(head, num);
for ( p = head; p != NULL; p = p->ptr )
{
printf("%d ", p->data);
}
printf("\n");
}
} while(num);
p = head;
printf("\nThe entered numbers are:\n");
while(p) {
printf("%d ", p->data);
p = p->ptr;
}
free_list(head);
head = delete_if_less( head, num );
if ( num != 0 ) {
printf( "There are deleted %zu nodes.\n", num );
}
printf("\nEnter minimum: ");
scanf("%d", & min);
return 0;
}
I want it then to calculate 1) the sum of all added integers 2) the sum of all deleted integers 3) the total sum of the remaining numbers of the list 4) the number of integers left and 5) the arithmetic average of the remaining numbers. The input should look like something like this:
Enter +/- to add/del a number: +1
1
Enter +/- to add/del a number: +2
2 1
Enter +/- to add/del a number: +3
2 1 3
Enter +/- to add/del a number: +1
2 1 3 1
Enter +/- to add/del a number: +5
2 1 3 1 5
Enter +/- to add/del a number: -4
Numbers not in list.
2 1 3 1 5
Enter +/- to add/del a number: -3
2 1 1 5
Enter +/- to add/del a number: -1
2 1 5
Enter +/- to add/del a number: +0
2 1 5
add sum: 13
del sum: 5
total sum: 8
elements: 3
average: 2.67
Can anyone help me with this? I would appreciate it alot. :)
Here is my approach to your code!
I used linked lists with a sentinel to optimize a bit. Also since in your example you wanted to keep the information about the deleted values, there are actually two linked lists in the program, one for present values, and another for bin values.
It works exactly as you have described in the input section,though I have added several more functionalities.
Here are the possible inputs:
in each of them n is an integer from 0 to 9
+on -> adds n to a linked list
-on -> deletes n from a linked list if it exists, if n not present prints an error message
-an -> deletes all occurrences of n from a linked list, if n not present prints an error message
+m -> deletes the maximum of a linked list
-m -> deletes the minimum of a linked list
0 -> terminates the function
Of course you could parse it differently to include larger int values but I guess I will leave that part to you!
At each operation the two linked lists will be printed out on the terminal so you can see the result of your operation and the current state of the two lists. If your message did not match the parsing, an error will be raised and will be printed on the terminal. Same goes for deleting a value that does not exist in the linked list.
After entering 0 the program will calculate different properties of the list based on what you have asked in your example.
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <err.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
typedef struct node
{
int value;
struct node *next;
} node;
// Prints a string of characters.
static inline void print(const char* f, ...)
{
va_list args;
va_start(args, f);
vprintf(f, args);
va_end(args);
}
// Prints a string of characters followed by a new line.
static inline void println(const char* f, ...)
{
va_list args;
va_start(args, f);
vprintf(f, args);
va_end(args);
printf("\n");
}
static inline void* mem_alloc(size_t size)
{
void* p = malloc(size);
if (p == NULL)
{
err(EXIT_FAILURE, "Problem with malloc().");
}
return p;
}
// Verify if node is empty
int node_is_empty(node * head)
{
return head == NULL;
}
// Verify if node is not empty
int node_is_not_empty(node * head)
{
return head != NULL;
}
//Builds the sentinell of the node structure
node* node_build_sentinel()
{
// Creates the sentinel.
node* head = mem_alloc(sizeof(node));
head->value = 0;
head->next = NULL;
// Returns the head of the node which is the sentinell.
return head;
}
//Prints the contents of a node
void node_print(node* head)
{
print("{");
while(head->next)
{
head = head->next;
print(" %d", head->value);
}
println(" }");
}
//Frees the allocated node
void node_free(node* head)
{
node* previous;
while (head)
{
previous = head;
head = head->next;
free(previous);
}
}
// Inserts a value right after the head
/*
HEAD -> 1 -> 2 -> ..... -> 8
node_insert_beg(node* HEAD, int 42);
HEAD -> 42 -> 1 -> 2 -> ..... -> 8
*/
void node_insert_beg(node* head, int value)
{
node* tmp = mem_alloc(sizeof(node));
tmp->value = value;
tmp->next = head->next;
head->next = tmp;
}
// Inserts a value right after the head
/*
HEAD -> 1 -> 2 -> ..... -> 8
node_insert_end(node* HEAD, int 42);
HEAD -> 1 -> 2 -> ..... -> 8 -> 42
*/
void node_insert_end(node* head, int value)
{
node* tmp = mem_alloc(sizeof(node));
for (; node_is_not_empty(head->next); head = head->next)
{
//This loop runs to the last node and quits with head being that last node
continue;
}
tmp->value = value;
tmp->next = head->next;
head->next = tmp;
}
//Inserts odd values to the end and even values to the beginning
void node_insert_num(node* head, int value)
{
//odd
if(value % 2)
{
node_insert_end(head, value);
}
//even
else
{
node_insert_beg(head, value);
}
}
//Extracts the minimum value of the node (in other words deletes it from the node)
void node_extract_min(node* list,node *sup)
{
node *before_min = list;
while (list->next != NULL)
{
if (list->next->value < before_min->next->value)
{
before_min = list;
}
list = list->next;
}
node *output = before_min->next;
before_min->next = before_min->next->next;
output->next = NULL;
while (sup->next!=NULL)
{
sup = sup->next;
}
sup->next = output;
}
//Extracts the maximum value of the node (in other words deletes it from the node)
void node_extract_max(node* list, node* sup)
{
node *before_max = list;
while (list->next != NULL)
{
if (list->next->value > before_max->next->value)
{
before_max = list;
}
list = list->next;
}
node *output = before_max->next;
before_max->next = before_max->next->next;
output->next = NULL;
while (sup->next!=NULL)
{
sup = sup->next;
}
sup->next = output;
}
//Deletes the first occurence of value in node
int node_delete_first_occurence(node* head, node* sup, int value)
{
int seen = 0;
node *tmp = head;
while (head->next != NULL)
{
if (head->next->value == value)
{
tmp = head;
seen+=1;
break;
}
head = head->next;
}
if(seen == 0)
{
return seen;
}
node *output = head->next;
tmp->next = tmp->next->next;
output->next = NULL;
while (sup->next!=NULL)
{
sup = sup->next;
}
sup->next = output;
return seen;
}
//Deletes all occurences of value in node
int node_delete_all_occurences(node* head, node* sup, int value)
{
int seen = 0;
node *tmp = head;
while (head->next != NULL)
{
if (head->next->value == value)
{
seen+=1;
tmp = head;
node *output = head->next;
tmp->next = tmp->next->next;
output->next = NULL;
while (sup->next!=NULL)
{
sup = sup->next;
}
sup->next = output;
continue;
}
head = head->next;
}
return seen;
}
//Get a node at index if index invalid return NULL
//DOES NOT DELETE THE NODE
node * node_get_at(node* node, unsigned long index)
{
while (node != NULL && index > 0)
{
node = node->next;
index--;
}
if (node != NULL)
{
node = node->next;
}
return node;
}
int* node_sum(node * head)
{
int * sum_elem = malloc(sizeof(int)*2);
int sum = 0;
int elements = 0;
while (head->next != NULL)
{
elements+=1;
sum += head->next->value;
head = head->next;
}
sum_elem[0] = sum;
sum_elem[1] = elements;
return sum_elem;
}
int main()
{
node * present_node = node_build_sentinel();
node * deleted_nodes = node_build_sentinel();
char message[4];
while (1)
{
printf("Enter +/- followed by type (o = one/a = all/m = min or max) followed by the number to add/del a number or 0 to quit the app:");
scanf("%3s",message);
if(message[0] == '+')
{
if(message[1] == 'o')
{
node_insert_num(present_node,message[2] - '0');
node_print(present_node);
node_print(deleted_nodes);
continue;
}
if(message[1] == 'm')
{
node_extract_max(present_node,deleted_nodes);
node_print(present_node);
node_print(deleted_nodes);
continue;
}
if(message[1] == 'a')
{
printf("Invalid syntax on opperand 2 after + (no a is possible) please try again!\n");
}
else
{
printf("Invalid syntax on opperand 2 after + please try again!\n");
}
continue;
}
if(message[0] == '-')
{
if(message[1] == 'o')
{
int err = node_delete_first_occurence(present_node,deleted_nodes,message[2] - '0');
if(err == 0)
{
printf("The number to delete was not present in the node!\n");
}
node_print(present_node);
node_print(deleted_nodes);
continue;
}
if(message[1] == 'a')
{
int err = node_delete_all_occurences(present_node,deleted_nodes,message[2] - '0');
if(err == 0)
{
printf("The number to delete was not present in the node!\n");
}
node_print(present_node);
node_print(deleted_nodes);
continue;
}
if(message[1] == 'm')
{
node_extract_min(present_node,deleted_nodes);
node_print(present_node);
node_print(deleted_nodes);
continue;
}
else
{
printf("Invalid syntax on opperand 2 after - please try again!\n");
}
continue;
}
if(message[0] == '0')
{
break;
}
else
{
printf("Invalid syntax on opperand 1 please try again!\n");
}
}
int * present_sum_elem = node_sum(present_node);
printf("The sum of present node: %d \n",present_sum_elem[0]);
printf("The number of elements in present node: %d\n",present_sum_elem[1]);
if(present_sum_elem[1]!=0)
{
printf("The average of the present node %4f \n", (float)present_sum_elem[0]/(float)present_sum_elem[1]);
}
int * deleted_sum_elem = node_sum(deleted_nodes);
printf("The sum of deleted node: %d \n",deleted_sum_elem[0]);
printf("The number of elements in deleted node: %d\n",deleted_sum_elem[1]);
if(deleted_sum_elem[1] != 0)
{
printf("The average of the deleted node %4f \n", (float)deleted_sum_elem[0]/(float)deleted_sum_elem[1]);
}
free(present_sum_elem);
free(deleted_sum_elem);
node_free(present_node);
node_free(deleted_nodes);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <limits.h>
#define Malloc(n, type) (type *)malloc((unsigned)((n) * sizeof(type)))
#define Realloc(ptr, n, type) (type *)realloc(ptr, (n) * sizeof(type))
typedef struct Node
{
int key;
struct Node *next;
struct Node *down;
} Node;
typedef struct
{
int level;
struct Node *header;
} skiplist;
int level()
{
/*
This function takes the coin flip and decides the level of the node with each
level having a probability of 0.25.
arg: void
return: a number from the set {1,2,3, 4}
*/
int level = 1;
for (int i = 0; i < 3; i++)
{
unsigned int coin = (unsigned int)rand();
coin = coin % 2;
if (coin)
{
level++;
}
else
break;
}
return level;
}
skiplist skip_list_init();
Node *Traverse_Express(Node *, int);
Node *skip_list_search(skiplist, int);
Node *insert_level(Node *, int, int, int);
void skip_list_insert(skiplist *, int);
void skip_print(skiplist);
int main()
{
srand(time(0));
int arr[10000];
for (int i = 0; i < 10; i++)
{
arr[i] = (int)rand();
}
printf("The array is initialised\n");
skiplist list;
list = skip_list_init();
printf("The Skip list is initialised\n");
if (list.header == NULL)
{
printf("List is null\n");
}
for (int i = 0; i < 10; i++)
{
skip_list_insert(&list, arr[i]);
printf("The %d element is initialised with key: %d\n", i, arr[i]);
}
printf("The skip list is:\n");
skip_print(list);
return 0;
}
void skip_print(skiplist list)
{
/*
The function prints the skip list level-wise.
arg: list
return: none
*/
Node *temp = list.header;
int count = 0;
for (int i = list.level; i > 0; i--)
{
printf("The Keys at level %d:\n", i);
while (NULL != temp->next)
{
printf("%d ->", temp->key);
temp = temp->next;
}
printf("%d\n", temp->key);
int dummy = count;
temp = list.header;
while (dummy)
{
temp = temp->down;
dummy--;
}
count++;
}
}
skiplist skip_list_init()
{
/*
This function creates the first node in the skip list with key value
to be negative infinity and level of the list =1.
arg: None
return: Skiplist initialised with a Node having key as INT_MIN.
*/
skiplist list;
Node *head;
if (NULL == (head = Malloc(1, Node)))
{
exit(1);
}
list.header = head;
list.level = 1;
head->key = INT_MIN;
head->next = NULL;
head->down = NULL;
return list;
}
Node *skip_list_search(skiplist list, int key)
{
/*
The function returns a pointer to the either the key itself if present
or the key immediatedly smaller than the searched key.
arg:
list:The skiplist to be searched. Type: skiplist
key: A key to be searched. Type: int.
return: Type: Node pointer
A pointer to the searched key or immediately smaller it.
*/
if (list.header == NULL)
exit(1);
else
skip_print(list);
int level = list.level; // Number of levels already present in the list
Node *curr = list.header;
printf("Inside Skip search\n");
printf("The value of level %d\n", level);
for (; level > 0; level--)
{
curr = Traverse_Express(curr, key);
if ((curr->key == key) && (INT_MIN != curr->key))
{
return curr;
}
if (NULL != curr->down)
curr = curr->down;
}
printf("The value at current node %d\n", curr->key);
printf("Leaving Skip_search\n");
return curr;
}
Node *Traverse_Express(Node *temp, int key)
{
printf("On the express way\n");
printf("We are searching the key: %d\n", key);
while (key > temp->key && NULL != temp->next)
{
printf("Loop of expressway\n");
printf("The current key : %d\n", temp->key);
if (key >= temp->next->key)
temp = temp->next;
else
break;
}
printf("Left the express way\n");
return temp;
}
Node *insert_level(Node *nod, int key, int lev, int list_lev)
{
/*
Inserting the key till the required level
arg:
nod: a pointer to the exsiting skip list
key: key to be inserted
lev: the level of the key
list_lev: the number of levels in the given skiplist
return: A Node pointer to the head of the skiplist with the key
inserted to the existing list.
*/
Node *temp1 = nod, *temp3 = NULL;
printf("\nStarting of insert at level procedure\n");
// Procedure to cut-off the extra levels in the list if any
if (lev < list_lev)
{
for (int i = list_lev - lev; i > 0; i--)
{
printf("Searching on the level: %d\n", i + lev);
temp1 = Traverse_Express(temp1, key);
temp1 = temp1->down;
}
}
printf("The value of first node: %d\n", temp1->key);
// Procedure to insert from the required level till level 1
for (int i = 0; i < lev; i++)
{
Node *temp2 = Malloc(1, Node);
temp2->key = key;
temp2->next = NULL;
temp2->down = NULL;
temp1 = Traverse_Express(temp1, key);
printf("Temp1 current key:%d\n", temp1->key);
if (NULL == temp1->next)
{
temp1->next = temp2;
printf("Node inserted at level: %d\n", lev - i);
}
else
{
printf("Entered the else procedure\n");
temp2->next = temp1->next;
temp1->next = temp2;
printf("%d\n", temp1->next->key);
}
if (i > 0)
{
temp3->down = temp2;
}
temp1 = temp1->down;
temp3 = temp2;
/*
free(temp2);
if(temp3==NULL)
{
printf("did a fuck up\n");
exit(1);
}*/
}
skiplist list;
// list = skip_list_init(list);
list.header = nod;
list.level = list_lev;
printf("Printing skip list from insert level\n");
skip_print(list);
printf("End insert level procedure\n\n\n");
temp1 = temp3 = NULL;
return nod;
free(temp1);
free(temp3);
}
void skip_list_insert(skiplist *list, int key)
{
/*
This function finds the key value and if already present, then returns back
else it inserts the key at its right place.
arg: a skilplist by reference and a key
return: None
*/
printf("Inside skip_list_insert\n");
Node *req = skip_list_search(*list, key);
printf("The value returned by skip search %d\n", req->key);
if (key == req->key)
{
printf("Key %d is already present in skip list\n", key);
}
Node *temp1 = list->header;
int list_lev = list->level;
printf("The list level = %d\n", list_lev);
int lev = level();
printf("The prob level %d\n", lev);
Node *hold_prev = NULL;
// creating a skip list if level returned is greater than existing one.
if (lev > list_lev)
{
for (int i = lev - list_lev; i > 0; i--)
{
skiplist l = skip_list_init();
Node *inser = Malloc(1, Node);
printf("The value of i in loop %d\n", i);
inser->key = key;
inser->down = NULL;
inser->next = NULL;
l.header->next = inser;
Node *trans = l.header;
// Zipping the previous levels with new level
while (NULL != hold_prev)
{
trans->down = hold_prev;
trans = trans->next;
hold_prev = hold_prev->next;
}
hold_prev = l.header;
l.header = NULL;
if (hold_prev == NULL)
{
printf("Big Mistake");
exit(1);
}
else
{
printf("You are doing it correct way\n");
}
}
list->header = hold_prev;
list->level = lev - list_lev;
skip_print(*list);
// Returning a pointer to the zeroth element of last level in this list.
while (NULL != hold_prev->down)
{
hold_prev = hold_prev->down;
}
}
// Inserting the node till the min(list_lev, level())
if (list_lev > lev)
{
temp1 = insert_level(temp1, key, lev, list_lev);
}
else
{
temp1 = insert_level(temp1, key, list_lev, list_lev);
}
skiplist l1 = skip_list_init();
l1.header = temp1;
l1.level = list_lev;
skip_print(l1);
printf("\n Now the Zipping procedure with level()>list_lev starts\n");
// Zipping Procedure only if level()>list_lev
if (lev > list_lev)
{
hold_prev->down = temp1;
skiplist l1 = skip_list_init();
l1.header = list->header;
l1.level = lev;
skip_print(l1);
printf("the key at the first node:%d\n", temp1->key);
hold_prev = hold_prev->next;
while (temp1->key != key)
{
temp1 = temp1->next;
printf("Zipping over keys:\n");
printf("Current key: %d\n", temp1->key);
}
hold_prev->down = temp1;
list->level = lev;
}
if (list_lev > lev)
{
list->level = list_lev;
}
printf("\n\n\n");
}
The above is my implementation. I have tried with all my might to debug the code but I am falling to implement a skip list for past 1 month. I genuinely request with pleading hands 🙏🙏🙏 to look into the implementation and please do let me know the fixes, I can do.
It would be a great help. Thank you.
I have tried with all my might to debug the code but I am falling to implement a skip list for past 1 month.
You will have much easier time debugging if you fill the list with some non-random values (you can switch back to random values once the program is working for all hand-coded combinations).
Also fix your comments so they match the code. E.g. here the comments are clearly wrong:
skiplist skip_list_init()
{
/*
This function creates the first node in the skip list with key value
to be negative infinity and level of the list =1.
arg: It takes a list by reference
return: None
*/
There is no arg and the return is not None.
You should avoid making a copy of the list when calling skip_list_search (pass a pointer to the list).
You should avoid this construct:
if (hold_prev == NULL)
{
printf("Big Mistake");
exit(1);
}
else
{
printf("You are doing it correct way\n");
}
It make your code way too long. Instead, do this:
assert(hold_prev != NULL);
Giving your variables meaningful names will also go a long way helping you and others understand the code.
With the value inputs by Gene and Employed Russian, the skip list implementation has a mistake in the function skip_print which unfortunately didn't transverse all the levels of the skip-list.
See here:
int count=0;
and
int dummy = count;
temp = list.header;
while (dummy)
{
temp = temp->down;
dummy--;
}
count++;
When count=0 implies dummy=0. This doesn't let your pointer temp transverse to the bottom level till the next iteration when count=1. Thus, effectively only transversing and printing till list.level-1.
Hence, the implementation doesn't work correctly.
Please incorporate the following code for skip_print:
void skip_print(skiplist list)
{
/*
The function prints the skip list level-wise.
arg: list
return: none
*/
Node *temp = list.header;
int count = 1;
while (temp)
{
Node *n1 = temp;
printf("Printing the keys at level: %d\n", count);
while (NULL != n1->next)
{
printf("%d ->", n1->key);
n1 = n1->next;
}
printf("%d\n", n1->key);
temp = temp->down;
count++;
}
}
The rest of the code seems to be working fine for me.
I've read half a dozen answers with regards to this here and am relatively loathe to ask such a question, but I'm attempting to create a linked list using a struct in C, and was having some issues in passing pointers to the linked list. I think it's mostly sorted, but honestly am having acute issues trying to get the linked list working.
#include <stdio.h>
#include <stdlib.h>
typedef struct cell
{
int value;
struct cell *next;
} cell;
int inputplace = 0;
cell * createlist()
{
cell curElement = (cell *) malloc(sizeof(cell));
cell *head = &curElement;
cell *curEl = &curElement;
curEl->value = 900;
FILE *fp;
char *mode = "r";
fp = fopen("input",mode);
if(fp==NULL)
{
fprintf(stderr, "Unable to open input file 'input'");
exit(1);
}
int val;
int tempplace = 0;
while(tempplace < inputplace)
{
if(fscanf(fp, "%d", &val) != EOF)
{
tempplace++;
printf("%d", &val);
}
else
break;
}
while(fscanf(fp, "%d", &val)!=EOF)
{
inputplace++;
printf("%d\n", curEl);
if(val < 0)
{
curEl->value = -1;
curEl->next = -1;
break;
}
printf("%d\n", val);
curEl->value = val;
curEl->next = malloc(sizeof(struct cell));
curEl= curEl->next;
}
return head;
}
cell* reverse(cell* p)
{
cell * prev = -1;
cell * current = p;
cell * next;
while(current->value != -1)
{
next = current->next;
current->next = prev;
prev = current;
current = next;
}
return prev;
}
cell* append(cell* p, cell* q)
{
cell * current = p;
cell * r = p;
while(1)
{
if(current->value == -1)
{
current->value = q->value;
current->next = q->next;
}
}
return r;
}
int last(cell *p)
{
cell q = *p;
int last = -1;
while(1)
{
if(q.value == -1)
{
return last;
}
else
{
last = q.value;
q = *q.next;
}
}
}
cell * delete(int n, cell *p)
{
cell * head = p;
cell * prev = -1;
cell * current = p;
if(current-> value == n)
{
return current->next;
}
else
{
while(current->value != -1)
{
if(current->value==n)
{
prev->next = current->next;
break;
}
prev = current;
current = current->next;
}
}
return head;
}
int member(int n, cell *p)
{
cell q = *p;
while(1)
{
if(q.value == n)
{
return 1;
}
if(q.value == -1)
{
return 0;
}
q = *q.next;
}
}
int display(cell *p)
{
printf(" %c", '[');
cell q = *p;
while(1)
{
if(q.value == -1)
{
printf("%c ",']');
return 1;
}
if(q.next != p->next)
printf("%c ",',');
printf("%d", q.value);
q = *q.next;
}
printf("\n\n");
}
int main()
{
cell *head = createlist();
cell *headk = createlist();
cell *head3 = delete(5, head);
printf("%d, %d\n", head->value, head->next->value);
printf("Last head: %d\n", last(head));
display(headk);
display(head);
display(head3);
cell *head4 = delete(6, head);
display(head4);
cell *head5 = delete(7, head);
display(head5);
printf("Member2 6, head: %d\n", member(6,head));
printf("Member2 3, head: %d\n", member(3, head));
cell *head2 = reverse(head);
//print(head2);
printf("%d, %d\n", head2->value, head2->next->value);
}
So the input file contains numerical data with a negative one terminating the list:
Example input I'm using:
5
6
7
-1
1
2
3
-1
The issue I'm having is the second list is apparently overriding the first or some such, and my pointer-fu is weak, what do I need to do to successfully allocate the new structs?
Charles B.
You return a pointer to a local variable, and local variables goes out of scope once the function returns and that leaves you with a stray pointer. Using that stray pointer will lead to undefined behavior.
The problem starts with the declaration of curElement, and the compiler should really have screamed at you for that:
cell curElement = (cell *) malloc(sizeof(cell));
Here you declare curElement to be an actual structure, and not a pointer to the structure.
There's also the problem that you don't really have an end to the list. You allocate the next pointer of the last node you add, regardless if there's going to be a next node or not, and you don't initialize that node so the memory you allocate will be uninitialized, and trying to access it will lead to yet another undefined behavior.
I suggest something like the following abbreviated code:
cell *head = NULL;
cell *tail = NULL;
...
while (fscanf(fp, "%d", &val) == 1)
{
...
cell *current = malloc(sizeof(*current));
current->val = val;
current->next = NULL; // Very important!
// Check if this is the first node in the list
if (head == NULL)
head = tail = current;
else
{
// List is not empty, append node to end of list
tail->next = current;
tail = current;
}
}
Beside the change in how the list is handled and added to, there are also two other changes: The first is that the return value from the fscanf function is compared against 1, because fscanf (and family) will return the number of successfully parsed items, and this allows you to find format errors in the input file.
The second change is to not cast the return of malloc. In C you should never cast from or to void *, cast like that can hide subtle bugs.
I've got a programming class assignment due tonight at 8 PM CDT that I'm having trouble with. We are to take a list of the following numbers via reading a file:
9
30
20
40
35
22
48
36
37
38
place them in an array (easy enough), and then read these into a binary search tree using C. The first number in the list is the number of elements in the tree. The rest are placed into the following struct:
typedef struct node_struct {
int data;
struct node_struct* left;
struct node_struct* right;
} Node;
I think I've got the first part down pat. Take the stuff in using fscanf (I didn't choose to use this method, I like fgets better), call an insertion function on each member of the array, then call a "createNode" function inside the insertion function.
Problem is, I'm only getting one member into the BST. Furthermore, the BST must satisfy the condition node->left->data <= node->data < node->right->data... in other words, the nodes must be in order in the tree.
Here's what I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// def BST node struct
typedef struct node_struct {
int data;
struct node_struct* left;
struct node_struct* right;
} Node;
// prototypes
Node* createNode(int data);
Node* bstInsert(Node* root, int data);
// helper function prototypes
void padding(char ch, int n);
void displayTree(Node* root, int depth);
int main(int argc, char **argv)
{
FILE *in = NULL;
int num_read, count=0, array_size = 0;
if(argc != 2){
printf("hw3 <input-file>\n");
return 1;
}
in = fopen(argv[1], "r");
if(in == NULL){
printf("File can not be opened.\n");
return 2;
}
// read in the first line to get the array size
fscanf(in, "%d", &array_size);
// declare the array
int array[array_size];
// read from the second line to get each element of the array
while(!feof(in)){
fscanf(in, "%d", &num_read);
array[count] = num_read;
count++;
}
fclose(in);
if (array_size != count) {
printf("data error. Make sure the first line specifies the correct number of elements.");
return 3;
}
Node *root1 = NULL, *root2 = NULL, *root3 = NULL;
int i;
// task1: construct a bst from the unsorted array
printf("=== task1: construct a bst from the unsorted array ===\n");
for (i = 0; i < array_size; i++) {
root1 = bstInsert(root1, array[i]);
}
displayTree(root1, 0);
return 0;
}
Node* bstInsert(Node* root, int data) {
if(root == NULL){
root = createNode(data);
if(root != NULL){
root= createNode(data);
}
else{
printf("%d not inserted, no memory available.\n", data);
}
}
Node* current, previous, right;
current = root;
previous = root->left;
next = root->right;
else{
if(previous->data <= current->data){
}
}
return root;
}
Node* createNode(int data) {
// TODO
Node* aRoot;
if(!data)
return NULL;
aRoot = malloc(sizeof(Node));
if(!aRoot){
printf("Unable to allocate memory for node.\n");
return NULL;
}
aRoot->data = data;
aRoot->left = NULL;
aRoot->right = NULL;
return aRoot;
}
/* helper functions to print a bst; You just need to call displayTree when visualizing a bst */
void padding(char ch, int n)
{
int i;
for (i = 0; i < n; i++)
printf("%c%c%c%c", ch, ch ,ch, ch);
}
void displayTree(Node* root, int depth){
if (root == NULL) {
padding (' ', depth);
printf("-\n");
}
else {
displayTree(root->right, depth+1);
padding(' ', depth);
printf ( "%d\n", root->data);
displayTree(root->left, depth+1);
}
}
main, createNode, displayTree, and padding are okay, I believe. It's bstInsert where I'm having trouble. I'm just not sure how to order things to create a valid tree.
EDIT:
I've edited bstInsert and injected some more logic. It should be printing out more leaves on the tree, but alas, it's only printing out the number "30". Here's the new function.
Node* bstInsert(Node* root, int data) {
if(root == NULL){
root = createNode(data);
if(root != NULL){
root= createNode(data);
}
else{
printf("%d not inserted, no memory available.\n", data);
}
}
else{
if(data < root->data){
bstInsert(root->left, data);
}
else if(data > root->data || data == root->data){
bstInsert(root->right, data);
}
}
return root;
}
You have to assign the newly created node pointer to the correct part of the tree. This code does that. The key change is using the return value from bstInsert() correctly. The other changes are cosmetic. Note that I checked the input array by printing it out; also, it is sensible to print out the BST as you build it.
Don't use feof() as a loop control condition. It is almost invariably wrong when used as a loop control, but at least you have to also check the input operation that follows. I've written a lot of programs in my time; I've hardly ever used feof() (I found two places in my own code with it; in both, it was correctly used to distinguish between EOF and an error after an input had failed.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// def BST node struct
typedef struct node_struct
{
int data;
struct node_struct* left;
struct node_struct* right;
} Node;
// prototypes
Node *createNode(int data);
Node *bstInsert(Node *root, int data);
// helper function prototypes
void padding(char ch, int n);
void displayTree(Node *root, int depth);
int main(int argc, char **argv)
{
FILE *in = NULL;
int num_read, count=0, array_size = 0;
if (argc != 2)
{
printf("hw3 <input-file>\n");
return 1;
}
in = fopen(argv[1], "r");
if (in == NULL)
{
printf("File can not be opened.\n");
return 2;
}
// read in the first line to get the array size
fscanf(in, "%d", &array_size);
// declare the array
int array[array_size];
// read from the second line to get each element of the array
while (count < array_size && fscanf(in, "%d", &num_read) == 1)
array[count++] = num_read;
fclose(in);
if (array_size != count)
{
printf("data error. Make sure the first line specifies the correct number of elements.");
return 3;
}
for (int i = 0; i < array_size; i++)
printf("%d: %d\n", i, array[i]);
Node *root1 = NULL;
// task1: construct a bst from the unsorted array
printf("=== task1: construct a bst from the unsorted array ===\n");
for (int i = 0; i < array_size; i++)
{
root1 = bstInsert(root1, array[i]);
displayTree(root1, 0);
}
displayTree(root1, 0);
return 0;
}
Node *bstInsert(Node *root, int data)
{
if (root == NULL)
{
root = createNode(data);
if (root == NULL)
printf("%d not inserted, no memory available.\n", data);
}
else if (data < root->data)
root->left = bstInsert(root->left, data);
else
root->right = bstInsert(root->right, data);
return root;
}
Node *createNode(int data)
{
Node *aRoot;
aRoot = malloc(sizeof(Node));
if (!aRoot)
{
printf("Unable to allocate memory for node.\n");
return NULL;
}
aRoot->data = data;
aRoot->left = NULL;
aRoot->right = NULL;
return aRoot;
}
/* helper functions to print a bst; You just need to call displayTree when visualizing a bst */
void padding(char ch, int n)
{
for (int i = 0; i < n; i++)
printf("%c%c%c%c", ch, ch, ch, ch);
}
void displayTree(Node *root, int depth)
{
if (root == NULL) {
padding (' ', depth);
printf("-\n");
}
else {
displayTree(root->right, depth+1);
padding(' ', depth);
printf ( "%d\n", root->data);
displayTree(root->left, depth+1);
}
}
Ok, think about what you want to do in the different tree configurations:
when the tree is empty -> create a root node
when the tree isn't empty -> how do the value to be inserted and the value of the root compare?
above -> insert in the right subtree
below -> insert in the left subtree
equal -> do nothing (this actually depends on how your assignment tells you to treat duplicates)
From this basic algorithm, you should be able to figure out all the corner cases.
A simplified solution (naive insertion with recursion, data input noise removed):
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
static int nums[] = { 6, 8, 4, 1, 3, 7, 14, 10, 13 }; // instead of the user input
typedef struct _node {
int value;
struct _node *left;
struct _node *right;
} node;
node *node_new(int v)
{
node *n = malloc(sizeof(*n));
assert(n);
n->value = v;
n->left = NULL;
n->right = NULL;
return n;
}
void insert(node **tree, node *leaf)
{
if (*tree == NULL) {
*tree = leaf;
} else if (leaf->value > (*tree)->value) {
insert(&((*tree)->right), leaf);
} else {
insert(&((*tree)->left), leaf);
}
}
void dump(node *tree, int level)
{
static const char *pad = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
if (tree != NULL) {
printf("%sSelf: %d\n", pad + 16 - level, tree->value);
if (tree->left) {
printf("%sLeft node:\n", pad + 16 - level);
dump(tree->left, level + 1);
}
if (tree->right) {
printf("%sRight node:\n", pad + 16 - level);
dump(tree->right, level + 1);
}
} else {
printf("%sEmpty\n", pad + 16 - level);
}
}
int main()
{
size_t n = sizeof(nums) / sizeof(*nums);
int i;
node *tree = NULL;
for (i = 0; i < n; i++) {
insert(&tree, node_new(nums[i]));
}
dump(tree, 0);
// give some work to the kernel
return 0;
}
You should consider doing this recursively. Remember that each node is a tree in itself:
#include <stdio.h>
#include <stdlib.h>
typedef struct tree_struct {
int value;
struct tree_struct* left;
struct tree_struct* right;
} Tree;
Tree* addToTree(int value, Tree* tree)
{
if (tree == NULL) {
tree = malloc(sizeof(Tree));
tree->value = value;
tree->left = NULL;
tree->right = NULL;
} else {
if (value < tree->value) {
tree->left = addToTree(value, tree->left);
} else {
tree->right = addToTree(value, tree->right);
}
}
return tree;
}
int main(int argc, char** argv)
{
Tree* tree = NULL;
int in;
while (scanf("%d", &in) != EOF) {
tree = addToTree(in, tree);
}
return 0;
}