I try to implement a program written in C language where I've got two linked list and I need to create a third one in which there are all the values of the first list eventually renamed with the values of the second one based on them order. Any of the value in updated third list should not repeat ,it should return error.
Look at the example given below to understand how this program works:
Ex.1
A = [a, b, c, d]
B = [e, f]
The third one will be:
C = [e, f, c, d]
Ex.2
A = [a, b, c, d]
B = [a, e]
The third one will be:
C = [a, e, c, d]
Ex.3
A = [a, b, c, d]
B = [c, d]
This should return an error because C will be
C = [c, d c, d]
but it can't have duplicate values.
Ex.4
A = [a, b, c, d]
B = [b, a]
This shouldn't return any error because C will be
C = [b, a, c, d]
(there are not duplicate values and the first two elements of the list A will be renamed with the first two elements of the list B).
Below you can find how my idea looks like but I'm interested about different solutions of this problem
T //Temp
C //Result
for (int i = 0; i < |A|; i++)
{
if(i > length of B && T is not empty)
{
//One or more elements were not been renamed
return ERROR
}
if(A[i] == B[i])
{
C[i] = B[i];
}
else
{
C[i] = B[i];
if(T contains A[i])
{
pop A[i] from T
}
else
{
push A[i] in T
}
}
}
EDIT
Background: this algorithm supports the creation of an alias table (C) from a concrete table (A) given a list of filed names (B).
each list/table cannot contain duplicate values.
length of B is less or equal than length of A (I can't rename more values of those I've got)
This could be easily done in Python. Something like this:
def merge_lists(list1, list2):
if len(list2) > len(list1):
raise ValueError("list2 cannot be of greater length than list1")
list3 = list(list1) # make copy of list1
list_after_overlap = list1[len(list2):] # get slice of list1 starting from end of list2
index = 0
for item in list2:
if item not in list_after_overlap:
list3[index] = item
else:
raise ValueError("merged list would have repeated values")
index += 1
return list3
This isn't just Python showing off, although it is arguably a better tool for this job. This also reads nicely like pseudo-code, and having prototyped and tested our algorithm, we can implement the same logic in C, we just need some helper functions.
As it's been indicated, a simple array would do, and since you haven't specified the data type in your question, we'll use a plain old int:
merged_list_t merge_lists(const list_t list1, const list_t list2)
{
merged_list_t result;
result.merged_list.list_length = 0;
result.merged_list.values = NULL;
if (list2.list_length > list1.list_length)
{
result.error = ERROR_LENGTH_EXCEEDED;
}
else
{
result.merged_list.values = (int*)malloc(sizeof(int)*(list1.list_length));
result.error = (result.merged_list.values == NULL) ? ERROR_MEMORY : ERROR_NONE;
}
if (result.error == ERROR_NONE)
{
replicate_list(&result.merged_list, list1, list2.list_length);
list_t list_after_overlap = get_list_slice(list1, list2.list_length);
for (size_t index = 0; index < list2.list_length && result.error == ERROR_NONE; index++)
{
if (!item_in_list(list2.values[index], list_after_overlap))
{
result.merged_list.values[index] = list2.values[index];
}
else
{
result.error = ERROR_REPEATED_VALUES;
free(result.merged_list.values); /* we won't be needing this anymore */
result.merged_list.values = NULL;
result.merged_list.list_length = 0;
}
}
}
return result;
}
As you can see, the algorithm is essentially the same, with an improvement. In the python code we were copying the entire list1, only to then overwrite the overlapped values, which is a waste that could be meaningful on large lists. Now we only get the part after the overlap, which starts after list2, and use it for testing for duplicates. Here is the complete code, with a hack on main for some basic testing:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
typedef enum {
ERROR_NONE, /* success */
ERROR_REPEATED_VALUES, /* merged list would have repeated values */
ERROR_LENGTH_EXCEEDED, /* second list length exceeds that of first list */
ERROR_MEMORY /* could not allocate memory for the merged list */
} error_t;
typedef struct {
int *values; /* pointer to int array that contains the list values */
size_t list_length; /* the number of elements in the list (array) */
}list_t;
typedef struct {
list_t merged_list; /* has pointer (values) to merged list (array), which MUST be freed */
error_t error; /* indicates success or the error code of the merge operation */
}merged_list_t;
typedef enum {FALSE=0, TRUE=1} bool_t; /* use stdbool.h preferably, if available */
/* === Test Utility functions */
static void print_list(const list_t list)
{
putchar('[');
for (size_t index = 0; index < list.list_length; index++)
{
printf("%d", list.values[index]);
if (index < list.list_length - 1)
{
printf(", ");
}
}
printf("]\n");
}
static void print_merged_list(const merged_list_t list)
{
if (list.merged_list.values != NULL && list.error == ERROR_NONE)
{
print_list(list.merged_list);
}
else
{
switch (list.error)
{
case ERROR_NONE: printf("Merged list is null (empty)\n"); break;
case ERROR_LENGTH_EXCEEDED: printf("Error: Length of list2 is greater than length of list1\n"); break;
case ERROR_MEMORY: printf("Error: Unable to allocate memory for result\n"); break;
case ERROR_REPEATED_VALUES: printf("Error: Merged list would have duplicate entries\n"); break;
default: printf("Unexpected or unhandled error\n"); break;
}
}
}
/* utility functions */
static void replicate_list(list_t *new_list, const list_t list, size_t start)
{
for (size_t index = start; index < list.list_length; index++)
{
new_list->values[index] = list.values[index];
}
new_list->list_length = list.list_length;
}
static list_t get_list_slice(const list_t list, size_t start_index)
{
list_t sliced_list;
if (list.values != NULL && start_index < list.list_length)
{
sliced_list.values = list.values + start_index;
sliced_list.list_length = list.list_length - start_index;
}
return sliced_list;
}
static bool_t item_in_list(int item, const list_t list)
{
bool_t in_list = FALSE;
for (size_t i=0; i < list.list_length && !in_list; i++)
{
in_list = (item == list.values[i]) ? TRUE : FALSE;
}
return in_list;
}
/*
Produces a merged list which consists of list1 replaced by the overlapping elements of list2,
as long as the resulting list does not cause elements of the merged list to be repeated.
Input:
list1[]: int array of arbitrary length consisting of unique elements
list2[]: int array of length smaller than of list1 consisting of unique elements
Returns:
A merged_list_t structure containing the merged list structure (which MUST be freed) and its length
or an error code if the lists are of invalid length or the merge operation produces duplicate values
*/
merged_list_t merge_lists(const list_t list1, const list_t list2)
{
merged_list_t result;
result.merged_list.list_length = 0;
result.merged_list.values = NULL;
if (list2.list_length > list1.list_length)
{
result.error = ERROR_LENGTH_EXCEEDED;
}
else
{
result.merged_list.values = (int*)malloc(sizeof(int)*(list1.list_length));
result.error = (result.merged_list.values == NULL) ? ERROR_MEMORY : ERROR_NONE;
}
if (result.error == ERROR_NONE)
{
replicate_list(&result.merged_list, list1, list2.list_length);
list_t list_after_overlap = get_list_slice(list1, list2.list_length);
for (size_t index = 0; index < list2.list_length && result.error == ERROR_NONE; index++)
{
if (!item_in_list(list2.values[index], list_after_overlap))
{
result.merged_list.values[index] = list2.values[index];
}
else
{
result.error = ERROR_REPEATED_VALUES;
free(result.merged_list.values); /* we won't be needing this anymore */
result.merged_list.values = NULL;
result.merged_list.list_length = 0;
}
}
}
return result;
}
void main(void)
{
printf("Testing basic scenario\n");
int a1[] = { 1, 2, 3, 4, 5 };
int a2[] = { 6, 7 };
list_t l1;
l1.list_length = sizeof(a1) / sizeof(a1[0]); /* get number of elements */
l1.values = a1;
list_t l2;
l2.list_length = sizeof(a2) / sizeof(a2[0]);
l2.values = a2;
merged_list_t ml = merge_lists(l1, l2);
print_list(l1);
print_list(l2);
print_merged_list(ml);
free(ml.merged_list.values);
printf("Testing merge with duplicate values\n");
int a3[] = { 1, 2, 3, 4, 5 };
int a4[] = { 4, 6, 8 };
list_t l3;
l3.list_length = sizeof(a3) / sizeof(a3[0]); /* get number of elements */
l3.values = a3;
list_t l4;
l4.list_length = sizeof(a4) / sizeof(a4[0]);
l4.values = a4;
merged_list_t ml2 = merge_lists(l3, l4);
print_list(l3);
print_list(l4);
print_merged_list(ml2);
free(ml2.merged_list.values);
printf("Testing list2 with value from list1\n");
int a5[] = { 1, 2, 3, 4, 5 };
int a6[] = { 3, 6, 9 };
list_t l5;
l5.list_length = sizeof(a5) / sizeof(a5[0]); /* get number of elements */
l5.values = a5;
list_t l6;
l6.list_length = sizeof(a6) / sizeof(a6[0]);
l6.values = a6;
merged_list_t ml3 = merge_lists(l5, l6);
print_list(l5);
print_list(l6);
print_merged_list(ml3);
free(ml3.merged_list.values);
_getch();
}
But you specifically asked for linked lists, so to finally answer your question, here is one way to do it:
merged_list_t merge_lists(const list_t list1, const list_t list2)
{
merged_list_t result;
list_t list_after_overlap;
initialize_list(&result.merged_list);
if (list2.list_length > list1.list_length)
{
result.error = ERROR_LENGTH_EXCEEDED;
}
else
{
bool_t success = replicate_list(&list_after_overlap, list1, list2.list_length);
result.error = (success) ? ERROR_NONE: ERROR_MEMORY;
}
if (result.error == ERROR_NONE)
{
for (list_item_t *item = list2.head; item != NULL && result.error == ERROR_NONE; item = item->next)
{
if (!item_in_list(*item->value, list_after_overlap))
{
/* duplicate each item and append to merged_list */
bool_t success = append_list_item(&result.merged_list, new_list_item(*item->value));
result.error = success ? ERROR_NONE : ERROR_MEMORY;
}
else
{
result.error = ERROR_REPEATED_VALUES;
destroy_list(&list_after_overlap);
destroy_list(&result.merged_list);
}
}
}
if (result.error == ERROR_NONE)
{
/* join overlap with difference */
result.merged_list.tail->next = list_after_overlap.head;
list_after_overlap.head = result.merged_list.head;
result.merged_list.tail = list_after_overlap.tail;
}
return result;
}
Again, same logic, the merge function and friends were just refactored to deal with linked lists. Here is the full code:
/* Enable debug heap functions (Visual Studio) */
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include <stdio.h>
#include <conio.h>
typedef enum {
ERROR_NONE, /* success */
ERROR_REPEATED_VALUES, /* merged list would have repeated values */
ERROR_LENGTH_EXCEEDED, /* second list length exceeds that of first list */
ERROR_MEMORY /* could not allocate memory for the merged list */
} error_t;
typedef struct list_item_ {
int *value; /* pointer to single value */
list_item_ *next;
list_item_ *previous;
}list_item_t;
typedef struct {
list_item_t *head;
list_item_t *tail;
size_t list_length;
}list_t;
typedef struct {
list_t merged_list; /* linked list with result, MUST be freed */
error_t error; /* indicates success or the error code of the merge operation */
}merged_list_t;
typedef enum {FALSE=0, TRUE=1} bool_t;
/* === Test Utility functions === */
static void print_list(const list_t list)
{
putchar('[');
for (list_item_t *item = list.head; item != NULL; item = item->next)
{
printf("%d", *item->value);
if (item->next != NULL)
{
printf(", "); /* add comma if it's not the last item (tail) */
}
}
printf("]\n");
}
static void print_merged_list(const merged_list_t list)
{
if (list.merged_list.head != NULL && list.error == ERROR_NONE)
{
print_list(list.merged_list);
}
else
{
switch (list.error)
{
case ERROR_NONE: printf("Merged list head is null (empty list)\n"); break;
case ERROR_LENGTH_EXCEEDED: printf("Error: Length of list2 is greater than length of list1\n"); break;
case ERROR_MEMORY: printf("Error: Unable to allocate memory for result\n"); break;
case ERROR_REPEATED_VALUES: printf("Error: Merged list would have duplicate entries\n"); break;
default: printf("Unexpected or unhandled error\n"); break;
}
}
}
/* helper functions */
static void initialize_list(list_t *list)
{
list->head = NULL;
list->tail = NULL;
list->list_length = 0;
}
static list_item_t* new_list_item(int value)
{
list_item_t *item = (list_item_t*)malloc(sizeof(list_item_t));
if (item != NULL)
{
item->value = (int*)malloc(sizeof(int));
if (item->value != NULL)
{
*item->value = value;
item->next = NULL;
item->previous = NULL;
}
else
{
free(item);
item = NULL;
}
}
return item;
}
static bool_t append_list_item(list_t *list, list_item_t *item)
{
bool_t success = TRUE;
if (item == NULL)
{
success = FALSE;
}
else
{
if (list->head == NULL)
{
/* first item, set as head and tail */
list->head = item;
list->head->next = NULL;
list->head->previous = NULL;
list->tail = item;
}
else
{
/* item (new tail) will be preceded by the current tail */
item->previous = list->tail;
/* link current tail to new item */
list->tail->next = item;
/* make item the new tail */
list->tail = item;
list->tail->next = NULL;
}
list->list_length++;
}
return success;
}
static bool_t set_list_values(list_t *list, const int *values, size_t values_length)
{
bool_t success = TRUE;
initialize_list(list);
for (size_t index = 0; index < values_length && success; index++)
{
list_item_t *item = new_list_item(values[index]);
success = append_list_item(list, item);
}
if (success)
{
list->list_length = values_length;
}
return success;
}
static void destroy_list(list_t *list)
{
list_item_t *next_item = NULL;
for (list_item_t *item = list->head; item != NULL; item = next_item)
{
next_item = item->next;
free(item->value);
item->value = NULL;
free(item);
item = NULL;
}
list->list_length = 0;
list->head = NULL;
list->tail = NULL;
}
static bool_t replicate_list(list_t *new_list, const list_t list, const size_t start)
{
size_t count = 0;
list_item_t *item;
bool_t success = TRUE;
initialize_list(new_list);
for (item = list.head; item != NULL && success; item = item->next, count++)
{
/* skip items before start */
if (count >= start)
{
/* create new list with remaining items */
success = append_list_item(new_list, new_list_item(*item->value));
}
}
if (!success)
{
destroy_list(new_list);
}
return success;
}
static bool_t item_in_list(int item, const list_t list)
{
bool_t in_list = FALSE;
for (list_item_t *l_item = list.head; (l_item != NULL) && !in_list; l_item = l_item->next)
{
in_list = (item == *l_item->value) ? TRUE : FALSE;
}
return in_list;
}
/*
Produces a merged list which consists of list1 replaced by the overlapping elements of list2,
as long as the resulting list does not cause elements of the merged list to be repeated.
Input:
list1[]: a linked list of arbitrary length consisting of unique elements
list2[]: a linked list of length less than or equal to the length of list 1, also with unique elements
Returns:
A merged_list_t structure containing the merged linked list (which MUST be freed) and its length
or an error code if the lists are of invalid length or the merge operation produces duplicate values
*/
merged_list_t merge_lists(const list_t list1, const list_t list2)
{
merged_list_t result;
list_t list_after_overlap;
initialize_list(&result.merged_list);
if (list2.list_length > list1.list_length)
{
result.error = ERROR_LENGTH_EXCEEDED;
}
else
{
bool_t success = replicate_list(&list_after_overlap, list1, list2.list_length);
result.error = (success) ? ERROR_NONE: ERROR_MEMORY;
}
if (result.error == ERROR_NONE)
{
for (list_item_t *item = list2.head; item != NULL && result.error == ERROR_NONE; item = item->next)
{
if (!item_in_list(*item->value, list_after_overlap))
{
/* duplicate each item and append to merged_list */
bool_t success = append_list_item(&result.merged_list, new_list_item(*item->value));
result.error = success ? ERROR_NONE : ERROR_MEMORY;
}
else
{
result.error = ERROR_REPEATED_VALUES;
destroy_list(&list_after_overlap);
destroy_list(&result.merged_list);
}
}
}
if (result.error == ERROR_NONE)
{
/* join overlap with difference */
result.merged_list.tail->next = list_after_overlap.head;
list_after_overlap.head = result.merged_list.head;
result.merged_list.tail = list_after_overlap.tail;
}
return result;
}
void main(void)
{
printf("Testing basic scenario\n");
int a1[] = { 1, 2, 3, 4, 5 };
int a2[] = { 6, 7 };
list_t l1;
set_list_values(&l1, a1, sizeof(a1) / sizeof(a1[0]));
list_t l2;
set_list_values(&l2, a2, sizeof(a2) / sizeof(a2[0]));
print_list(l1);
print_list(l2);
merged_list_t ml = merge_lists(l1, l2);
print_merged_list(ml);
destroy_list(&l1);
destroy_list(&l2);
destroy_list(&ml.merged_list);
printf("Testing merge with duplicate values\n");
int a3[] = { 1, 2, 3, 4, 5 };
int a4[] = { 4, 6, 8 };
list_t l3;
set_list_values(&l3, a3, sizeof(a3) / sizeof(a3[0]));
list_t l4;
set_list_values(&l4, a4, sizeof(a4) / sizeof(a4[0]));
print_list(l3);
print_list(l4);
ml = merge_lists(l3, l4);
print_merged_list(ml);
destroy_list(&l3);
destroy_list(&l4);
destroy_list(&ml.merged_list);
printf("Testing list2 with value from list1\n");
int a5[] = { 1, 2, 3, 4, 5 };
int a6[] = { 3, 6, 9 };
list_t l5;
set_list_values(&l5, a5, sizeof(a5) / sizeof(a5[0]));
list_t l6;
set_list_values(&l6, a6, sizeof(a6) / sizeof(a6[0]));
print_list(l5);
print_list(l6);
ml = merge_lists(l5, l6);
print_merged_list(ml);
destroy_list(&l5);
destroy_list(&l6);
destroy_list(&ml.merged_list);
printf("Try printing empty list...\n");
print_merged_list(ml);
/* print memory leak report (Visual Studio)*/
_CrtDumpMemoryLeaks();
_getch();
}
Notice the _CrtDumpMemoryLeaks() macro if you are using Visual Studio, very handy for detecting memory leaks. Of course, if you are lucky to be running Linux just get rid of that and use Valgrind instead. On my system, it was clean.
Here is a sample of the output produced by main:
Testing basic scenario
[1, 2, 3, 4, 5]
[6, 7]
[6, 7, 3, 4, 5]
Testing merge with duplicate values
[1, 2, 3, 4, 5]
[4, 6, 8]
Error: Merged list would have duplicate entries
Testing list2 with value from list1
[1, 2, 3, 4, 5]
[3, 6, 9]
[3, 6, 9, 4, 5]
Try printing empty list...
Merged list head is null (empty list)
Related
[ WOW - Someone gave me and negative point for my question ]
[ You could at least put a comment why you did not like my question ]
I am stuck.
I remember doing something similar in C++ but for some reason, I can't get it to work in plain C.
I'm trying to swap 2 nodes in a singly linked list.
The starting list is populated as [9,8,7,5,3,2] and I'm trying to bubble sort it, 2 nodes at a time to final list of [2,3,5,7,8,9]
The first iteration(swap) works find with the head. The list returns perfect with [8,9,7,5,3,2]
...but in the second iteration, I loose the 7 and get [8,9,5,3,2] which is WTF and I tried changing the code a bit but I have lost hope.
Can someone actually find what I did wrong. Please no double pointers... if it's only possible with double pointers... Why and How? since I have no idea what are double pointers?
Here is my program so far:
/*
___ENTER TITLE HERE___
Author : Patrick Miron
Date : Oct 20, 2021
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct listNode
{
int data;
struct listNode *next;
} listNode;
typedef struct list
{
struct listNode *head;
struct listNode *tail;
} list;
int isEmpty( const list *l)
{
return (l == NULL);
}
void printList(list *ptrToList, char *title)
{
int counter = 0; //Counter to count the listItem printed so we can add a carriage return at each 5th element.
printf("%s\n", title);
listNode *ptrToCurrentItem = ptrToList->head;
while (ptrToCurrentItem != NULL)
{
counter++;
printf("%d", ptrToCurrentItem->data);
if (counter % 5 != 0)
{
printf(" : ");
}
else
{
printf("\n");
}
ptrToCurrentItem = ptrToCurrentItem->next;
}
}
list *createListWithHeadData(int data)
{
list *ptrList = malloc((sizeof(ptrList)));
listNode *ptrNewNode = malloc(sizeof(listNode));
ptrNewNode->data = data;
ptrList->head = ptrNewNode;
ptrList->tail = ptrNewNode;
return ptrList;
}
void addToFrontList(list *ptrList, listNode *ptrListNode)
{
listNode *tempPtr = ptrList->head;
ptrList->head = ptrListNode;
ptrListNode->next = tempPtr;
}
list *arrayToList(int data[], int size)
{
list *ptrToNewList = createListWithHeadData(data[0]);
for (int i = 1; i < size; i++)
{
listNode *ptrToNewListNode = malloc(sizeof(listNode));
ptrToNewListNode->data = data[i];
addToFrontList(ptrToNewList, ptrToNewListNode);
}
return ptrToNewList;
}
int count(listNode *ptrToHead)
{
if (ptrToHead == NULL)
{
return 0;
}
else
{
return (1 + count(ptrToHead->next));
}
}
void concat(listNode *head1, listNode *head2)
{
assert(head1 != NULL);
if (head1->next == NULL)
{
head1->next = head2;
}
else
{
concat(head1->next, head2);
}
}
void insert(
listNode *p1, // first element
listNode *p2, // second element
listNode *q) // new element to insert between first and second element
{
assert(p1->next == p2);
p1->next = q;
q->next = p2;
}
void delete(listNode *listNode)
{
assert(listNode != NULL);
listNode = NULL;
}
void deleteList(list *list)
{
if (list->head != NULL)
{
list->head = list->head->next;
deleteList(list);
}
}
void swapListNodeWithNext(listNode *ptrToListNode1)
{
//Swap items
listNode *ptrTempNode1 = ptrToListNode1->next;
listNode *ptrTempNode2 = ptrToListNode1->next->next;
//Set the next node from temp1 (ptrToListNode->next->next) to itself
//Could be written as ptrToListNode->next->next = ptrToListNode
ptrTempNode1->next = ptrToListNode1;
ptrToListNode1->next = ptrTempNode2;
ptrToListNode1 = ptrTempNode1;
ptrTempNode1 = NULL;
ptrTempNode2 = NULL;
}
void sortList(list *ptrToListToSort)
{
if (ptrToListToSort->head == NULL)
{
return;
}
listNode *ptrToCurrentItem = ptrToListToSort->head;
listNode *ptrToLastUnsortedItem = ptrToListToSort->tail;
while (ptrToLastUnsortedItem != ptrToListToSort->head)
{
ptrToCurrentItem = ptrToListToSort->head;
while(ptrToCurrentItem->next != NULL)
{
if (ptrToCurrentItem->data > ptrToCurrentItem->next->data)
{
listNode *ptrToHead = ptrToListToSort->head;
if (ptrToCurrentItem == ptrToListToSort->head)
{
ptrToHead = ptrToCurrentItem->next;
}
//Swap items
swapListNodeWithNext(ptrToCurrentItem);
ptrToListToSort->head = ptrToHead;
}
else
{
ptrToCurrentItem = ptrToCurrentItem->next;
}
}
ptrToLastUnsortedItem = ptrToCurrentItem;
}
}
int main(void)
{
printf("\n");
list listOfInt;
int data[6] = { 2, 3, 5, 7, 8, 9 };
list *ptrToNewList = arrayToList(data, 6);
printList(ptrToNewList, "Array to Element List");
sortList(ptrToNewList);
printList(ptrToNewList, "Sorted List");
printf("\n");
printf("...End of line...\n");
printf("\n");
return 0;
}
I found a couple issues but the major one was that I did not change my previous ptr's next ( ptrPreviousItem->next) to point to the correct item after the swap. I was only changing the pointer to current item which was just a copy of the head advancing thru my iterations and the previous->next was still pointing to the original item.
Why in the world did it work for my first iteration? Probably because I would not update the last item since it was in correct order it would not get updated after that.
I have included a correct version of my singly linked list bubble sort with pointers. It works and I hope it can help the next person. Believe me alot of the tutorial on the subject barely make the code more readable then identifiers like "a" and "b"...
Oh, and #chqrlie, I don't understand some of the corrections you made in my previous question, some of them are quite unnecessary the others were formated like that when I put the code in brackets and the * in pointers can be put where you want. int* likeThis; int * likeThis; or int *likeThis. But I do usually format it like you with the asterix right against the identifier. I use a space between them when I mean the dereferenced value. Cheers!
/*
Singly Linked List Bubble Sort with Pointers
Author : Patrick Miron
Date : Nov 17, 2021
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct listNode
{
int data;
struct listNode * next;
} listNode;
typedef struct list
{
struct listNode *head;
struct listNode *tail;
} list;
int isEmpty( const list *l)
{
return (l == NULL);
}
void printList(list *ptrToList, char *title)
{
int counter = 0; //Counter to count the listItem printed so we can add a carriage return at each 5th element.
printf("%s\n", title);
listNode *ptrToCurrentItem = ptrToList->head;
while (ptrToCurrentItem != NULL)
{
counter++;
printf("%d", ptrToCurrentItem->data);
if ((counter % 5) != 0 && (ptrToCurrentItem->next != NULL))
{
printf(" : ");
}
else
{
printf("\n");
}
ptrToCurrentItem = ptrToCurrentItem -> next;
}
}
list *createListWithHeadData(int data)
{
list *ptrList = malloc((sizeof(list)));
listNode *ptrNewNode = malloc(sizeof(listNode));
ptrNewNode->data = data;
ptrNewNode->next = NULL;
ptrList->head = ptrNewNode;
ptrList->tail = ptrNewNode;
return ptrList;
}
void addToFrontList(list *ptrList, listNode *ptrListNode)
{
listNode *tempPtr = ptrList->head;
ptrList->head = ptrListNode;
ptrListNode->next = tempPtr;
}
list *arrayToList(int data[], int size)
{
list *ptrToNewList = createListWithHeadData(data[0]);
for (int i =1; i<size; i++)
{
listNode *ptrToNewListNode = malloc(sizeof(listNode));
ptrToNewListNode->data = data[i];
addToFrontList(ptrToNewList, ptrToNewListNode);
}
return ptrToNewList;
}
int count(listNode *ptrToHead)
{
if (ptrToHead == NULL)
{
return 0;
}
else
{
return (1 + count(ptrToHead->next));
}
}
void concat(listNode *head1, listNode *head2)
{
assert(head1 != NULL);
if (head1->next == NULL)
{
head1->next = head2;
}
else
{
concat(head1->next, head2);
}
}
void insert(
listNode *p1, // first element
listNode *p2, // second element
listNode *q) // new element to insert between first and second element
{
assert(p1->next == p2);
p1->next = q;
q->next = p2;
}
void delete(listNode *listNode)
{
assert(listNode != NULL);
listNode = NULL;
}
void deleteList(list *list)
{
if (list->head != NULL)
{
list->head = list->head->next;
deleteList(list);
}
}
void swapListNodeWithNext(listNode *ptrToCurrentNode, listNode *ptrToPreviousNode)
{
//Swap items
listNode *ptrTempNode1 = ptrToCurrentNode->next;
listNode *ptrTempNode2 = ptrToCurrentNode->next->next;
//Set the next node from temp1 (ptrToListNode->next->next) to itself
//Could be written as ptrToListNode->next->next = ptrToListNode
ptrTempNode1->next = ptrToCurrentNode;
ptrToCurrentNode->next = ptrTempNode2;
ptrToCurrentNode = ptrTempNode1;
if (ptrToPreviousNode != NULL)
{
ptrToPreviousNode->next = ptrToCurrentNode;
}
ptrTempNode1 = NULL;
ptrTempNode2 = NULL;
}
void sortList(list *ptrToListToSort)
{
if (ptrToListToSort->head == NULL)
{
return;
}
listNode *ptrToCurrentItem = ptrToListToSort->head;
listNode *ptrToPreviousItem = NULL;
int sizeOfList = count(ptrToListToSort->head);
int innerLoopCounter = 0;
int unsortedElementLeft = sizeOfList;
listNode *ptrToHead = ptrToListToSort->head;
int swappedAtLeastOneItem = 0;
for (int indexOuterLoop = 0; indexOuterLoop < sizeOfList; indexOuterLoop++)
{
ptrToCurrentItem = ptrToListToSort->head;
while((ptrToCurrentItem->next != NULL) && (innerLoopCounter < unsortedElementLeft))
{
// If the data in the next item greater then the current item, swap nodes.
if (ptrToCurrentItem->data > ptrToCurrentItem->next->data)
{
swappedAtLeastOneItem = 1;
// If the current item is the head of the list, and since it will be swap, point to the next item.
if (ptrToCurrentItem == ptrToListToSort->head)
{
ptrToHead = ptrToCurrentItem->next;
}
//Swap items
swapListNodeWithNext(ptrToCurrentItem, ptrToPreviousItem);
//if the ptrToHead has changed, then update the changes.
if (ptrToListToSort->head != ptrToHead)
{
ptrToListToSort->head = ptrToHead;
}
}
// if the nodes do not need to swap, make sure to update the current item and previous items.
else
{
if (ptrToCurrentItem->next != NULL)
{
ptrToCurrentItem = ptrToCurrentItem->next;
}
}
if (ptrToPreviousItem != NULL)
{
ptrToPreviousItem = ptrToPreviousItem->next;
}
else
{
ptrToPreviousItem = ptrToHead;
}
innerLoopCounter++;
}
// If during the first loop no items were swap then exit early all items are already in order.
if (!swappedAtLeastOneItem)
{
printf("**List is already sorted!**\n");
return;
}
unsortedElementLeft--;
innerLoopCounter=0;
ptrToPreviousItem = NULL;
if (ptrToCurrentItem->next == NULL)
{
ptrToListToSort->tail = ptrToCurrentItem;
}
}
}
int main(void)
{
printf("\n");
int data1[6] = {2,3,5,7,8,9};
list *ptrToNewList = arrayToList(data1,6);
printList(ptrToNewList, "Array to Element List");
sortList(ptrToNewList);
printList(ptrToNewList, "Sorted List");
printf("\n");
printf("----------------------------\n");
printf("\n");
int data2[8] = {10,11,2,3,5,7,8,9};
ptrToNewList = arrayToList(data2,8);
printList(ptrToNewList, "Array to Element List");
sortList(ptrToNewList);
printList(ptrToNewList, "Sorted List");
printf("\n");
printf("\n");
printf("----------------------------\n");
printf("\n");
int data3[10] = {10,11,2,3,5,7,8,1,9,1};
ptrToNewList = arrayToList(data3,10);
printList(ptrToNewList, "Array to Element List");
sortList(ptrToNewList);
printList(ptrToNewList, "Sorted List");
printf("\n");
printf("\n");
printf("----------------------------\n");
printf("\n");
int data4[10] = {1,1,1,1,1,1,1,1,1,1};
ptrToNewList = arrayToList(data4,10);
printList(ptrToNewList, "Array to Element List");
sortList(ptrToNewList);
printList(ptrToNewList, "Sorted List");
printf("\n");
printf("\n");
printf("----------------------------\n");
printf("\n");
int data5[10] = {21,19,16,13,10,9,6,2,1,1};
ptrToNewList = arrayToList(data5,10);
printList(ptrToNewList, "Array to Element List");
sortList(ptrToNewList);
printList(ptrToNewList, "Sorted List");
printf("\n");
printf("\n");
printf("----------------------------\n");
printf("\n");
printf("...End of line...\n");
printf("\n");
return 0;
}
Please note, I did not finish my commenting so don't judge me, I always complete it last.
Hope this helps for anyone having similar issues to me.
I am trying to solve a question in C language. The problem statement is(reading whole problem is not important for my doubt):
Given an arbitrary unweighted rooted tree which consists of N nodes.
The goal of the problem is to find largest distance between two nodes in a tree.
Distance between two nodes is a number of edges on a path between the nodes (there will be a unique path between any pair of nodes since it is a tree).
The nodes will be numbered 0 through N - 1.
The tree is given as an array A, there is an edge between nodes A[i] and i (0 <= i < N). Exactly one of the i's will have A[i] equal to -1, it will be root node.
I made TreeNode and I am storing all next connections TreeNode pointers in array(like adjacency list in graph)
My solution is:
/**
* #input A : Integer array
* #input n1 : Integer array's ( A ) length
*
* #Output Integer
*/
struct TreeNode2 {
int value;
struct TreeNode2 *next;
};
struct TreeNode2* createNode(int n)
{
struct TreeNode2 *node = (struct TreeNode2 *)calloc(1, sizeof(struct TreeNode2));
node->value = n;
node->next = NULL;
return node;
}
int maximum(int a,int b)
{
if(a>b)
return a;
return b;
}
int dfs(struct TreeNode2 **tree, int node)
{
if( tree[node] == NULL )
return 0;
int len1 = 0;
int len2 = 0;
struct TreeNode2 *ptr = tree[node];
while(ptr!=NULL)
{
int curr = dfs(tree, (ptr->value));
if( curr > len1 )
{
len1 = curr;
}
else if(curr > len2)
{
len2 = curr;
}
ptr = ptr->next;
}
return maximum( len1 + len2 , maximum( len1 , len2 ) + 1 );
}
int solve(int* A, int n1)
{
struct TreeNode2 *tree[n1];
int i=0;
for(i=0;i<n1;i++)
{
tree[i] = NULL;
}
for(i=0;i<n1;i++)
{
if(A[i] != -1)
{
struct TreeNode2 *temp = tree[i];
struct TreeNode2 *newNode = createNode(A[i]);
tree[i] = newNode;
newNode->next = temp;
// printf("A[i] = %d \n",A[i]);
struct TreeNode2 *temp2 = tree[ A[i] ];
struct TreeNode2 *newNode2 = createNode(i);
tree[ A[i] ] = newNode2;
newNode2->next = temp2;
}
}
int ans = dfs(tree, 0);
return ans;
}
I'm getting the segmentation fault the moment I am adding
tree[ A[i] ] = newNode2;
in solve function in forloop for input -1, 0. I tried tree[A[i]] = NULL (it worked). The problem is when A[i] = 0, tree[0] = NULL is working but tree[0] = newNode2 is not working why.?
Finally I caught the problem, actually in this problem tree connection is undirected so the code is stuck in loop inside dfs. I used visited array to solve this issue.
From the link, the example explanation shows that node 0 has three [direct] children (nodes, 1, 2, 3).
I could be wrong about this, but I think an algorithm that works is as follows:
As we build the tree, we remember the node with the maximum depth.
After the tree is built, we can traverse it to find the maximum depth of any [leaf] node that is not max node we found when building.
The solution is the sum of the depth of those two nodes
Here's some code I wrote to do that. I submitted it for test input and it passed.
Edit: I've revised the test and now it passes all tests but exceeds the time limit in the "Efficiency" test.
I expected as much because of the [seeming] O(n^2) but I wanted to try a non-standard approach that doesn't use "visited".
I added some code to dump a text file that can be fed to graphviz with -DGRAPH. It produces an output file: grf. To process this, do:
dot -Tsvg < grf > grf.svg
Then, you can point your browser to the grf.svg file to display the graph.
Anyway, here's the working but slow code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define sysfault(_fmt...) \
do { \
printf(_fmt); \
exit(1); \
} while (0)
#ifndef ROOTLEAF
#define ROOTLEAF 0
#endif
#if ROOTLEAF
#define PTROK(_ptr) (_ptr != NULL)
#else
#define PTROK(_ptr) 1
#endif
#ifdef DEBUG
#define dbgprt(_fmt...) \
do { \
printf(_fmt); \
} while (0)
#define nodeshow(_node,_tag) \
do { \
_nodeshow(_node,_tag); \
} while (0)
#ifndef GRAPH
#define GRAPH
#endif
#else
#define dbgprt(_fmt...) \
do { \
} while (0)
#define nodeshow(_node,_tag) \
do { \
} while (0)
#endif
#define MAXNODE 40000
#define COUNTOF(_arr) \
(sizeof(_arr) / sizeof(_arr[0]))
typedef struct node node_t;
struct node {
int paridx;
int depth;
node_t *parent;
node_t *next;
node_t *cldhead;
node_t *cldtail;
node_t *leaf;
};
static node_t *root = NULL;
static node_t *lhsbest = NULL;
static node_t *rhsbest = NULL;
static int Acnt = -1;
static node_t nodelist[MAXNODE + 1] = { 0 };
static int soldepth;
static FILE *xfgrf;
static char *
tlsbuf(void)
{
static int bufidx = 0;
static char buf[16][1000];
char *bp;
bp = buf[bufidx];
++bufidx;
bufidx %= 16;
*bp = 0;
return bp;
}
static int
nodenum(node_t *node)
{
if (node != NULL)
return node - nodelist;
else
return -1;
}
static char *
nodexid(node_t *lhs,node_t *rhs)
{
int lhsnum = nodenum(lhs);
int rhsnum = nodenum(rhs);
int tmp;
char *buf;
if (lhsnum > rhsnum) {
tmp = lhsnum;
lhsnum = rhsnum;
rhsnum = tmp;
}
buf = tlsbuf();
sprintf(buf,"%d,%d",lhsnum,rhsnum);
return buf;
}
static void
_nodeshow(node_t *node,const char *tag)
{
#ifdef DEBUG
if (node != NULL) {
dbgprt("nodeshow: %s node=%d paridx=%d depth=%d\n",
tag,nodenum(node),node->paridx,node->depth);
}
else
dbgprt("nodeshow: %s null\n",tag);
#endif
}
// newnode -- create new node;
static node_t *
newnode(int idx,node_t *par)
{
node_t *node;
node = &nodelist[idx];
if (par != NULL) {
node->paridx = nodenum(par);
node->depth = par->depth + 1;
}
else
node->paridx = -1;
node->parent = par;
return node;
}
// fastfind -- find node based on i from A[i]
static node_t *
fastfind(int value)
{
node_t *node;
node = &nodelist[value];
nodeshow(node,"fastfind");
return node;
}
// addchild -- attach child node to parent
static void
addchild(node_t *par,node_t *cld)
{
cld->next = par->cldhead;
par->cldhead = cld;
}
int
pathok(node_t *cur)
{
int okay;
if (ROOTLEAF)
okay = (cur != NULL);
else
okay = (cur != NULL) && (cur != root);
return okay;
}
int
pathcost(node_t *lhs,node_t *rhs)
{
int lhsok;
int rhsok;
int cost;
dbgprt("pathcost: ENTER lhs=%d rhs=%d xid=%s\n",
nodenum(lhs),nodenum(rhs),nodexid(lhs,rhs));
cost = 0;
if (lhs == root) {
dbgprt("pathcost: QWKROOT\n");
cost = rhs->depth;
lhs = NULL;
rhs = NULL;
}
while (1) {
if ((lhs == NULL) && (rhs == NULL))
break;
// join at lower level than root
if (lhs == rhs)
break;
#ifdef DEBUG
nodeshow(lhs,"LHS");
nodeshow(rhs,"RHS");
#endif
lhsok = pathok(lhs);
rhsok = pathok(rhs);
if (PTROK(lhs) && PTROK(rhs) && (lhs->depth > rhs->depth)) {
//nodeshow(lhs,"LHSDEEP");
if (lhsok) {
cost += 1;
dbgprt("pathcost: LCOST/D cost=%d\n",cost);
lhs = lhs->parent;
}
continue;
}
if (PTROK(lhs) && PTROK(rhs) && (rhs->depth > lhs->depth)) {
//nodeshow(lhs,"RHSDEEP");
if (rhsok) {
cost += 1;
dbgprt("pathcost: RCOST/D cost=%d\n",cost);
rhs = rhs->parent;
}
continue;
}
if (PTROK(lhs) && lhsok) {
cost += 1;
dbgprt("pathcost: LCOST/S cost=%d\n",cost);
lhs = lhs->parent;
}
if (PTROK(rhs) && rhsok) {
cost += 1;
dbgprt("pathcost: RCOST/S cost=%d\n",cost);
rhs = rhs->parent;
}
}
dbgprt("pathcost: EXIT cost=%d\n",cost);
return cost;
}
void
search1(void)
{
int curcost;
node_t *end = &nodelist[Acnt];
node_t *leafbase = NULL;
node_t *lhs = NULL;
node_t *rhs = NULL;
int bestcost = 0;
int leafcnt = 0;
// link all leaf nodes together
for (rhs = nodelist; rhs < end; ++rhs) {
if (ROOTLEAF) {
if (rhs != nodelist) {
if (rhs->cldhead != NULL)
continue;
}
}
else {
if (rhs->cldhead != NULL)
continue;
}
nodeshow(rhs,"ISLEAF");
if (leafbase == NULL)
leafbase = rhs;
if (lhs != NULL)
lhs->leaf = rhs;
lhs = rhs;
++leafcnt;
}
lhsbest = NULL;
rhsbest = NULL;
do {
if (leafcnt == 1) {
bestcost = leafbase->depth;
lhsbest = leafbase;
break;
}
for (lhs = leafbase; lhs != NULL; lhs = lhs->leaf) {
nodeshow(lhs,"LEAFLHS");
for (rhs = lhs->leaf; rhs != NULL; rhs = rhs->leaf) {
curcost = pathcost(lhs,rhs);
if (curcost > bestcost) {
lhsbest = lhs;
nodeshow(lhsbest,"LHSGUD");
rhsbest = rhs;
nodeshow(rhsbest,"RHSGUD");
bestcost = curcost;
}
}
}
} while (0);
nodeshow(lhsbest,"LHSBEST");
nodeshow(rhsbest,"RHSBEST");
soldepth = bestcost;
}
int
pathcost2(node_t *lhs,node_t *rhs)
{
int lhsok;
int rhsok;
int cost;
dbgprt("pathcost2: ENTER lhs=%d rhs=%d xid=%s\n",
nodenum(lhs),nodenum(rhs),nodexid(lhs,rhs));
cost = 0;
if (lhs == root) {
dbgprt("pathcost: QWKROOT\n");
cost = rhs->depth;
lhs = NULL;
rhs = NULL;
}
while (1) {
if ((lhs == NULL) && (rhs == NULL))
break;
// join at lower level than root
if (lhs == rhs)
break;
#ifdef DEBUG
nodeshow(lhs,"LHS");
nodeshow(rhs,"RHS");
#endif
lhsok = pathok(lhs);
rhsok = pathok(rhs);
if (PTROK(lhs) && PTROK(rhs) && (lhs->depth > rhs->depth)) {
//nodeshow(lhs,"LHSDEEP");
if (lhsok) {
cost += 1;
dbgprt("pathcost: LCOST/D cost=%d\n",cost);
lhs = lhs->parent;
}
continue;
}
if (PTROK(lhs) && PTROK(rhs) && (rhs->depth > lhs->depth)) {
//nodeshow(lhs,"RHSDEEP");
if (rhsok) {
cost += 1;
dbgprt("pathcost: RCOST/D cost=%d\n",cost);
rhs = rhs->parent;
}
continue;
}
if (PTROK(lhs) && lhsok) {
cost += 1;
dbgprt("pathcost: LCOST/S cost=%d\n",cost);
lhs = lhs->parent;
}
if (PTROK(rhs) && rhsok) {
cost += 1;
dbgprt("pathcost: RCOST/S cost=%d\n",cost);
rhs = rhs->parent;
}
}
dbgprt("pathcost2: EXIT cost=%d\n",cost);
return cost;
}
void
search2(void)
{
int curcost;
node_t *end = &nodelist[Acnt];
node_t *leafbase = NULL;
node_t *lhs = NULL;
node_t *rhs = NULL;
int bestcost = 0;
int leafcnt = 0;
int maxdepth = 0;
lhsbest = NULL;
rhsbest = NULL;
// link all leaf nodes together
for (rhs = nodelist; rhs < end; ++rhs) {
if (rhs->cldhead != NULL)
continue;
nodeshow(rhs,"ISLEAF");
if (rhs->depth > maxdepth) {
maxdepth = rhs->depth;
rhsbest = rhs;
}
if (leafbase == NULL)
leafbase = rhs;
if (lhs != NULL)
lhs->leaf = rhs;
lhs = rhs;
++leafcnt;
}
do {
bestcost = maxdepth;
lhsbest = leafbase;
if (leafcnt == 1) {
bestcost = leafbase->depth;
lhsbest = leafbase;
break;
}
for (lhs = leafbase; lhs != NULL; lhs = lhs->leaf) {
nodeshow(lhs,"LEAFLHS");
for (rhs = lhs->leaf; rhs != NULL; rhs = rhs->leaf) {
curcost = pathcost(lhs,rhs);
if (curcost > bestcost) {
lhsbest = lhs;
nodeshow(lhsbest,"LHSGUD");
rhsbest = rhs;
nodeshow(rhsbest,"RHSGUD");
bestcost = curcost;
}
}
}
} while (0);
nodeshow(lhsbest,"LHSBEST");
nodeshow(rhsbest,"RHSBEST");
soldepth = bestcost;
}
void
dograph(void)
{
#ifdef GRAPH
int idx;
node_t *cur;
node_t *par;
char *bp;
char buf[100];
xfgrf = fopen("grf","w");
fprintf(xfgrf,"digraph {\n");
for (idx = 0; idx < Acnt; ++idx) {
cur = &nodelist[idx];
bp = buf;
bp += sprintf(bp,"label=\"N%d D%d\"",nodenum(cur),cur->depth);
if (cur == rhsbest)
bp += sprintf(bp," color=Green");
if (cur == lhsbest)
bp += sprintf(bp," color=Red");
fprintf(xfgrf,"\tN%d [%s]\n",nodenum(cur),buf);
par = cur->parent;
if (par != NULL)
fprintf(xfgrf,"\tN%d -> N%d\n",nodenum(par),nodenum(cur));
}
fprintf(xfgrf,"}\n");
fclose(xfgrf);
#endif
}
int
solve(int *A,int argcnt)
{
int idx;
int parval;
node_t *par;
if (root != NULL) {
memset(nodelist,0,sizeof(nodelist));
root = NULL;
}
// find the root node
// FIXME/CAE -- probably always the first
Acnt = argcnt;
for (idx = 0; idx < Acnt; ++idx) {
int parval = A[idx];
if (parval == -1) {
dbgprt("solve: ROOT idx=%d\n",idx);
root = newnode(idx,NULL);
break;
}
}
// build all child nodes:
for (idx = 0; idx < Acnt; ++idx) {
parval = A[idx];
if (parval == -1)
continue;
dbgprt("solve: NODE idx=%d parval=%d\n",idx,parval);
// find parent
par = fastfind(parval);
// create node
node_t *cur = newnode(idx,par);
// attach child to parent
addchild(par,cur);
}
// traverse all nodes in the tree to find max distance ...
search2();
dograph();
return soldepth;
}
I'm working on a project where I need to solve a maze, and prints the solution on the standart output:
From this:
To this:
To do so, I used the A* (astar) algorithm, without the cost problem, cause I don't care about finding the shortest path since the maze is solved. So I just have two linked list, which contains nodes which are the positions on the map.
Anyway, it is now working, but I want to improve my times on bigger mazes, cause it takes more than 10 seconds on 500x500 mazes, and more than a whole minute on 1000x1000 mazes, I already did few things, such as optimizing my add_node function, or the call of in_list function which search if a node is already on closed list, but, even if It had doubled or trippled the speed, this is clearly not enough A* algorithm should be way faster.
Here is my implementation of the program in C:
//my header's structures:
typedef struct node_s
{
int x;
int y;
} node_t;
typedef struct maze_s
{
char **map;
int dim[2];
node_t start;
node_t objective;
node_t *current;
bool states[4];
} maze_t;
typedef struct linked_list_s
{
node_t node;
node_t *parent;
struct linked_list_s *next;
} linked_list_t;```
//And here The Most Important Utils Functions:
void in_closed(linked_list_t *closed_list, maze_t *maze)
{
linked_list_t *tmp = closed_list;
node_t *crt = maze->current;
if (!tmp)
return;
while (tmp) {
if (tmp->node.x == crt->x + 1 && tmp->node.y == crt->y) {
maze->states[0] = true;
}
if (tmp->node.x == crt->x && tmp->node.y == crt->y + 1) {
maze->states[1] = true;
}
if (tmp->node.x == crt->x && tmp->node.y == crt->y - 1) {
maze->states[2] = true;
}
if (tmp->node.x == crt->x - 1 && tmp->node.y == crt->y) {
maze->states[3] = true;
}
tmp = tmp->next;
}
}
linked_list_t *add_node(linked_list_t *list, node_t node, node_t *parent)
{
linked_list_t *new = malloc(sizeof(linked_list_t));
new->node = node;
new->parent = parent;
new->next = list;
return (new);
}
linked_list_t *remove_node(linked_list_t *list, node_t *node)
{
linked_list_t *head = list;
if (list->node.x == node->x && list->node.y == node->y) {
list = list->next;
return (list);
}
while (list->next) {
if (list->next->node.x == node->x && list->next->node.y == node->y) {
list->next = list->next->next;
return (head);
} else {
list = list->next;
}
}
return (NULL);
}
//And then the main algorithm (all the functions that I didn't show were not important for my problem) :
linked_list_t *check_neighbour(int neighbour, maze_t *maze,
linked_list_t *list, linked_list_t *closed_list)
{
node_t *crt = maze->current;
if (neighbour == 1 && crt->x + 1 < maze->dim[0] && !maze->states[0]
&& maze->map[crt->x + 1][crt->y] == '*') {
list = add_node(list, (node_t){crt->x + 1, crt->y}, crt);
}
if (neighbour == 2 && crt->y + 1 < maze->dim[1] && !maze->states[1]
&& maze->map[crt->x][crt->y + 1] == '*') {
list = add_node(list, (node_t){crt->x, crt->y + 1}, crt);
}
if (neighbour == 0 && crt->y > 0 && !maze->states[2]
&& maze->map[crt->x][crt->y - 1] == '*') {
list = add_node(list, (node_t){crt->x, crt->y - 1}, crt);
}
if (neighbour == 3 && crt->x > 0 && !maze->states[3]
&& maze->map[crt->x - 1][crt->y] == '*') {
list = add_node(list, (node_t){crt->x - 1, crt->y}, crt);
}
return (list);
}
void end(maze_t *maze, linked_list_t *closed_list)
{
linked_list_t *tmp = closed_list;
bool cond = true;
for (int x = maze->objective.x, y = maze->objective.y; tmp->next;) {
if (tmp->node.x == x && tmp->node.y == y) {
maze->map[x][y] = 'o';
x = tmp->parent->x;
y = tmp->parent->y;
closed_list = remove_node(closed_list, &tmp->node);
tmp = closed_list;
cond = false;
}
if (cond) {
tmp = tmp->next;
} else {
cond = true;
}
}
maze->map[0][0] = 'o';
}
linked_list_t *solve_maze(maze_t *maze, linked_list_t *list,
linked_list_t *closed_list)
{
while (list) {
if (list->node.x == maze->objective.x
&& list->node.y == maze->objective.y)
return (closed_list);
maze->current = &list->node;
closed_list = add_node(closed_list, list->node, list->parent);
in_closed(closed_list, maze);
for (int i = 0; i < 4; i++)
list = check_neighbour(i, maze, list, closed_list);
for (int i = 0; i < 4; i++)
maze->states[i] = false;
list = remove_node(list, maze->current);
}
return(NULL);
}
int solver(char **av)
{
int *dim = get_dimensions(av[1]);
maze_t maze = {.dim = {dim[0], dim[1]}, .map = get_map(av[1], dim),
.start = {0, 0}, .objective = {dim[0] - 1, dim[1] - 1}, .states =
{false, false, false, false}};
linked_list_t *list = get_open_list(&maze);
linked_list_t *closed_list = NULL;
if (maze.map[0][0] == 'X' || maze.map[dim[0] - 1][dim[1] - 1] == 'X')
return (printf("no solution found\n"));
closed_list = solve_maze(&maze, list, closed_list);
if (!closed_list)
return (printf("no solution found\n"));
closed_list = add_node(closed_list, maze.objective, &closed_list->node);
printf("algorithm done\n");
end(&maze, closed_list);
printf("end finished\n");
print_map_color(&maze);
return (0);
}
If your entire goal here is just to solve the maze once, then A* is completely overkill. The main virtue of A* is that a lot of the time you don't need to look at a bunch of the spaces on the maze. In this case, you are reading the entire maze into memory anyway (plus your maze is only ~10^6 squares in size, which is fairly small). If you have to read the entire grid into memory anyway, your solution is going to be O(n) bestcase where n is the number of spaces in the grid. From the looks of it, you have made some extremely complicated code that is probably O(n^2) or O(pathLength * n) worst case.
You should be able to use just BFS. The code below is in Java and runs in O(n).
Here's the output of my solution on a 10 by 10 case:
Possible
oX********
ooo*X***X*
**oX****X*
XXoX**X**X
X*ooX*****
*X*ooooooX
****X***oX
*****X**oo
*X***X***o
*****X***o
1
Here's the code in Java:
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
public class BFS {
public static void main(String[] args) {
int w=1000, h=1000;
long time=System.currentTimeMillis();
Random r=new Random();
char[][] board=new char[w][h];
for (int x=0; x<w; x++)
for (int y=0; y<h; y++)
board[x][y]=r.nextInt(5)<1?'X':'*';
int[] dx= {1, 0, -1, 0};
int[] dy= {0, -1, 0, 1};
int[][] cameFrom=new int[w][h];
boolean[][] visited=new boolean[w][h];
Queue<Integer> xs=new LinkedList<>(), ys=new LinkedList<>();
xs.add(0);
ys.add(0);
cameFrom[0][0]=-1;
visited[0][0]=true;
while (!xs.isEmpty()) {
int fromX=xs.remove(), fromY=ys.remove();
for (int d=0; d<4; d++) {
int nx=fromX+dx[d], ny=fromY+dy[d];
if (nx<0||ny<0||nx>=w||ny>=h||visited[nx][ny]||board[nx][ny]=='X') continue;
visited[nx][ny]=true;
cameFrom[nx][ny]=d;
xs.add(nx);
ys.add(ny);
}
}
PrintWriter out=new PrintWriter(System.out);
if (!visited[w-1][h-1]) {
out.println("Impossible...");
}
else {
out.println("Possible");
int x=w-1, y=h-1;
while (cameFrom[x][y]!=-1) {
board[x][y]='o';
int d=cameFrom[x][y];
x-=dx[d];
y-=dy[d];
}
for (y=0; y<h; y++) {
for (x=0; x<w; x++) out.print(board[x][y]);
out.println();
}
}
out.println(System.currentTimeMillis()-time);
out.close();
}
}
This runs in under 0.6 seconds for a 1000 by 1000 grid, and most of that time is spent printing the output grid. It also always finds the shortest path since the graph is unweighted.
I've got the following code:
#include <stdio.h>
#include <stdlib.h>
#define MAXN 100
typedef int key;
typedef int data;
struct list * createElement(key k, data info);
struct list{
key k;
data info;
struct list *next;
};
struct list *L;
void init(key k, data info)
{
L = createElement(k, info);
}
struct list * createElement(key k, data info)
{
struct list *temp;
temp = (struct list *) malloc(sizeof(*temp));
temp->k = k;
temp->info = info;
return temp;
}
void insert(struct list * element)
{
element->next = L;
L = element;
}
void insertBefore(struct list * element, key k)
{
struct list * currentElement = L;
while(currentElement != NULL)
{
if(currentElement->k == k)
{
struct list *temp = currentElement;
currentElement = element;
currentElement->next = temp;
return;
}
currentElement = currentElement->next;
}
}
void insertAfter(struct list * element, key k)
{
struct list * currentElement = L;
while(currentElement != NULL)
{
if(currentElement->k == k)
{
struct list *temp = currentElement->next;
currentElement->next = element;
element->next = temp;
return;
}
currentElement = currentElement->next;
}
}
void deleteElement(struct list * element)
{
struct list * currentElement = L;
while(currentElement != NULL)
{
if(currentElement == element)
{
struct list * temp = currentElement;
currentElement = currentElement->next;
free(temp);
return;
}
currentElement = currentElement->next;
}
}
struct list * getElementByKey(key k) {
printf("\n1");
struct list *currentElement = L;
printf("2");
while(currentElement != NULL)
{
printf("3");
if(currentElement->k == k)
{
printf("4");
return currentElement;
}
printf("5");
currentElement = currentElement->next;
printf("6");
}
printf("There is no such element in the list");
}
struct list * pop()
{
struct list *element = L;
L = L->next;
return element;
}
int main()
{
init(0, 13);
struct list * element = createElement(5, 155);
insert(element);
struct list * k = createElement(7, 243);
insert(k);
//insertBefore(createElement(3, 100), 5);
printf("The first element value is: %d", pop()->info);
printf("The second element value is: %d", pop()->info);
printf("The element value is: %d", getElementByKey(5)->info);
return 0;
}
So when i execute it the debugger gives me segmantation fault on line 84 which is if(currentElement->k == k) on method getElementByKey. I know that i'm trying to access an unexisting element(because i use the pop method and it removes the first element in the list) but it should print me a warning message. it seems that there is a problem in the previous element's key or something that i failed to notice.
In your createElement function, you forgot to initialize the next pointer to NULL.
struct list * createElement(key k, data info)
{
struct list *temp;
temp = (struct list *) malloc(sizeof(*temp));
temp->k = k;
temp->info = info;
temp->next = NULL;
return temp;
}
So when you're browsing your list, it never finds the last element of the list because next pointer never equals NULL, and goes at some random position in the memory, trying to access to parts it is not allowed to do so.
When deleting an element (using deleteElement()) you miss to re-initialise L.
The segmenataion violation in if(currentElement->k == k)most likey dues to currentElement referring to an invalid memory address. As you test if against NULL some lines before line 84, it can only be the case that currentElement had either been assigned an invalid address explicitly or the address it points had been freed already.
From the code shown in deleteElement() I assume the latter.
two problem
1)at createElement()
need
temp->next = NULL;
2)at insertBefore()
not change pointer of list
currentElement = element;
e.g)
void insertBefore(struct list * element, key k)
{
struct list * currentElement = L; //add case of L->k
while(currentElement != NULL)
{
if(currentElement->next && currentElement->next->k == k)
{
element->next = currentElement->next;
currentElement->next = element;
return;
}
currentElement = currentElement->next;
}
}
stack. I've got a binary tree of type TYPE (TYPE is a typedef of data*) that can add and remove elements. However for some reason certain values added will overwrite previous elements. Here's my code with examples of it inserting without overwriting elements and it not overwriting elements.
the data I'm storing:
struct data {
int number;
char *name;
};
typedef struct data data;
# ifndef TYPE
# define TYPE data*
# define TYPE_SIZE sizeof(data*)
# endif
The tree struct:
struct Node {
TYPE val;
struct Node *left;
struct Node *rght;
};
struct BSTree {
struct Node *root;
int cnt;
};
The comparator for the data.
int compare(TYPE left, TYPE right) {
int left_len; int right_len; int shortest_string;
/* find longest string */
left_len = strlen(left->name);
right_len = strlen(right->name);
if(right_len < left_len) { shortest_string = right_len; } else { shortest_string = left_len; }
/* compare strings */
if(strncmp(left->name, right->name, shortest_string) > 1) {
return 1;
}
else if(strncmp(left->name, right->name, shortest_string) < 1) {
return -1;
}
else {
/* strings are equal */
if(left->number > right->number) {
return 1;
}
else if(left->number < right->number) {
return -1;
}
else {
return 0;
}
}
}
And the add method
struct Node* _addNode(struct Node* cur, TYPE val) {
if(cur == NULL) {
/* no root has been made */
cur = _createNode(val);
return cur;
}
else {
int cmp;
cmp = compare(cur->val, val);
if(cmp == -1) {
/* go left */
if(cur->left == NULL) {
printf("adding on left node val %d\n", cur->val->number);
cur->left = _createNode(val);
}
else {
return _addNode(cur->left, val);
}
}
else if(cmp >= 0) {
/* go right */
if(cur->rght == NULL) {
printf("adding on right node val %d\n", cur->val->number);
cur->rght = _createNode(val);
}
else {
return _addNode(cur->rght, val);
}
}
return cur;
}
}
void addBSTree(struct BSTree *tree, TYPE val)
{
tree->root = _addNode(tree->root, val);
tree->cnt++;
}
The method to create a new node:
struct Node* _createNode(TYPE val) {
struct Node* new_node;
new_node = (struct Node*)malloc(sizeof(struct Node*));
new_node->val = val;
new_node->left = NULL;
new_node->rght = NULL;
return new_node;
}
The function to print the tree:
void printTree(struct Node *cur) {
if (cur == 0) {
printf("\n");
}
else {
printf("(");
printTree(cur->left);
printf(" %s, %d ", cur->val->name, cur->val->number);
printTree(cur->rght);
printf(")\n");
}
}
Here's an example of some data that will overwrite previous elements:
struct BSTree myTree;
struct data myData1, myData2, myData3;
myData1.number = 5;
myData1.name = "rooty";
myData2.number = 1;
myData2.name = "lefty";
myData3.number = 10;
myData3.name = "righty";
initBSTree(&myTree);
addBSTree(&myTree, &myData1);
addBSTree(&myTree, &myData2);
addBSTree(&myTree, &myData3);
printTree(myTree.root);
Which will print:
((
righty, 10
)
lefty, 1
)
Finally here's some test data that will go in the exact same spot as the previous data, but this time no data is overwritten:
struct BSTree myTree;
struct data myData1, myData2, myData3;
myData1.number = 5;
myData1.name = "i";
myData2.number = 5;
myData2.name = "h";
myData3.number = 5;
myData3.name = "j";
initBSTree(&myTree);
addBSTree(&myTree, &myData1);
addBSTree(&myTree, &myData2);
addBSTree(&myTree, &myData3);
printTree(myTree.root);
Which prints:
((
j, 5
)
i, 5 (
h, 5
)
)
Does anyone know what might be going wrong? Sorry if this post was kind of long.
it looks like there is an error in your _addNode procedure. It looks like you arent properly storing the new node references in the tree.
struct Node* _addNode(struct Node* cur, TYPE val) {
if(cur == NULL) {
/* no root has been made */
cur = _createNode(val);
return cur;
}
else {
int cmp;
cmp = compare(cur->val, val);
if(cmp == -1) {
/* go left */
cur->left = _addNode(cur->left, val);
}
else if(cmp >= 0) {
/* go right */
cur->left = _addNode(cur->right, val);
}
return cur;
}
the _addnode function was kind of confusing because you were using the return value inconsistently. i believe this version should avoid loosing any nodes.
I don't see an obvious flaw. I would suggest reworking the tree to hold int's or something simpler than your current data. If the tree works fine then at least you know where to look and not worry about the generic tree code.
I suspect _createNode(), can you add that code?