Programming Fundamentals

Information

  • This page contains extra challenge exercises for week 08.
  • These exercises are not compulsory, nor do they provide any marks in the course.
  • These exercises are intended for students that want more challenge in the course.
  • You cannot submit any of these exercises, however autotests are available for them (Command included at bottom of each exercise).

Exercise
(●●◌)
:

List Array Sum

Download list_array_sum.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity list_array_sum

Your task is to add code to these functions in list_array_sum.c:

//
// Print a linked list given the `head` of that list.
//
// Print occurs in the following format, depending on what nodes exist and
// the values in each array:
//
// #Elements: 3, Elements: [1, 2, 3]
// |
// v
// #Elements: 2, Elements: [1, 2]
// |
// v
// #Elements: 4, Elements: [1, 2, 3, 4]
// |
// v
// X
//
void print_list(struct node *head) {
    // TODO: Implement this function (replace the line below)
    printf("You need to implement the `print_list` function!");
}
//
// Sum up all the array values in all nodes of a linked list provided by `head`.
//
// For example, if there are 3 nodes with arrays [1, 2, 3], [1, 2], [-3, 1]
// then this function should return 1 + 2 + 3 + 1 + 2 - 3 + 1 = 7
//
int total_list_sum(struct node *head) {
    // TODO: Implement this function (replace the line below)
    return 42;
}

In this exercise, you are provided a linked list with more complex data attached to each node:

#define MAX_ELEMENTS 100

struct node {
    struct node *next;
    int          n_elements;
    int          data[MAX_ELEMENTS];
};

What this means is that every node in the linked list will contain a certain number of integers, stored in an array data. The number of actual integers stored in the array is identified by n_elements.

In this exercise, we have already provided you with the code to generate and populate the linked list.

Your job is to fill in the functions defined above. The print_list() will print out the linked list in a nice format and the total_list_sum() will find the total sum of the linked list by adding up each element in every array of every node.

Examples

dcc list_array_sum.c -o list_array_sum
./list_array_sum
How many array elements for this node? 2
Enter elements: 5 9

How many array elements for this node? 4
Enter elements: 1 4 7 10

How many array elements for this node? 1
Enter elements: 3

How many array elements for this node?
Linked List:
#Elements: 2, Elements: [5, 9]
|
v
#Elements: 4, Elements: [1, 4, 7, 10]
|
v
#Elements: 1, Elements: [3]
|
v
X
Sum: 39
./list_array_sum
How many array elements for this node? 5
Enter elements: -4 3 10 -4 0

How many array elements for this node? 2
Enter elements: 1 -1

How many array elements for this node? 10
Enter elements: -5 -4 -3 -2 -1 0 1 1 1 1

How many array elements for this node? 1
Enter elements: -3

How many array elements for this node?
Linked list:
#Elements: 5, Elements: [-4, 3, 10, -4, 0]
|
v
#Elements: 2, Elements: [1, -1]
|
v
#Elements: 10, Elements: [-5, -4, -3, -2, -1, 0, 1, 1, 1, 1]
|
v
#Elements: 1, Elements: [-3]
|
v
X
Sum: -9
./list_array_sum
How many array elements for this node? 3
Enter elements: 0 0 0

How many array elements for this node? 2
Enter elements: 0 0

How many array elements for this node? 5
Enter elements: 0 0 0 0 0

How many array elements for this node?
Linked list:
#Elements: 3, Elements: [0, 0, 0]
|
v
#Elements: 2, Elements: [0, 0]
|
v
#Elements: 5, Elements: [0, 0, 0, 0, 0]
|
v
X
Sum: 0
./list_array_sum
How many array elements for this node? 0
Enter elements: 
How many array elements for this node? 3
Enter elements: 1 2 3

How many array elements for this node? 0
Enter elements: 
How many array elements for this node? 0
Enter elements: 
How many array elements for this node? 5
Enter elements: -1 4 -5 10 0

How many array elements for this node? 
Linked list:
#Elements: 0, Elements: []
|
v
#Elements: 3, Elements: [1, 2, 3]
|
v
#Elements: 0, Elements: []
|
v
#Elements: 0, Elements: []
|
v
#Elements: 5, Elements: [-1, 4, -5, 10, 0]
|
v
X
Sum: 14

Assumptions/Restrictions/Clarifications

  • Only change the functions specified in the question
  • You can assume that the length provided for all arrays are non-negative
  • You can assume that the length provided for all the array will never exceed 100
  • Think about how you can find the sum of an array in a single node, then try to do this for every node

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest list_array_sum
Sample solution for list_array_sum.c
//
// Program to print out a linked list where each node contains an array of
// values then print out the total sum of these values.
//
// Written by Rory Golledge (z5308772) on 03-04-2022
//

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define MAX_ELEMENTS 100

struct node {
    struct node *next;
    int          n_elements;
    int          data[MAX_ELEMENTS];
};

int total_list_sum(struct node *head);
struct node *new_node(int n_elements);
void print_list(struct node *head);

// DO NOT CHANGE THIS MAIN FUNCTION

int main(void) {
    struct node *head = NULL;
    struct node *tail = NULL;

    int n_array_elements;
    printf("How many array elements for this node? ");
    while (scanf("%d", &n_array_elements) == 1) {
        printf("Enter elements: ");

        struct node *node = new_node(n_array_elements);

        // If node is the first, we point the head at it. Otherwise, we add
        // the node after the tail.
        if (head == NULL) {
            head = node;
            tail = node;
        } else {
            tail->next = node;
            tail = node;
        }

        printf("\nHow many array elements for this node? ");
    }
    printf("\n");

    print_list(head);
    printf("Sum: %d\n", total_list_sum(head));

    return 0;
}


//
// Print a linked list given the `head` of that list.
//
// Print occurs in the following format, depending on what nodes exist and
// the values in each array:
//
// #Elements: 3, Elements: [1, 2, 3]
// |
// v
// #Elements: 2, Elements: [1, 2]
// |
// v
// #Elements: 4, Elements: [1, 2, 3, 4]
// |
// v
// X
//
void print_list(struct node *head) {
    printf("Linked list:\n");
    struct node *current_node = head;
    while (current_node != NULL) {
        printf(
            "#Elements: %d, Elements: [",
            current_node->n_elements
        );
        int i = 0;
        while (i < current_node->n_elements) {
            printf("%d", current_node->data[i]);
            if (i < current_node->n_elements - 1) {
                printf(", ");
            }
            i++;
        }
        printf("]\n|\nv\n");
        current_node = current_node->next;
    }
    printf("X\n");
}

//
// Sum up all the array values in all nodes of a linked list provided by `head`.
//
// For example, if there are 3 nodes with arrays [1, 2, 3], [1, 2], [-3, 1]
// then this function should return 1 + 2 + 3 + 1 + 2 - 3 + 1 = 7
//
int total_list_sum(struct node *head) {
    int sum = 0;
    struct node *current_node = head;
    while (current_node != NULL) {
        int i = 0;
        while (i < current_node->n_elements) {
            sum += current_node->data[i];
            i++;
        }
        current_node = current_node->next;
    }

    return sum;
}


// DO NOT CHANGE THIS FUNCTION
// create a new node and fills array elements equal to the `n_elements` provided
struct node *new_node(int n_elements) {
    struct node *node = malloc(sizeof(struct node));

    node->n_elements = n_elements;
    node->next = NULL;

    int element_index = 0;
    // Loop and add all elements to array of new node.
    while (
        element_index < n_elements &&
        scanf("%d", &node->data[element_index]) == 1
    ) {
        element_index++;
    }

    // If this assertion fails, then the required number of elements were not
    // scanned in.
    assert(element_index == n_elements);

    return node;
}

Exercise
(●●●)
:

List Join Detection

Download list_join_detection.c here

Or, copy these file(s) to your CSE account using the following command:

1511 fetch-activity list_join_detection

Your task is to add code to these functions in list_join_detection.c:

//
// Gets the index relative to `second_list` where `first_list` and
// `second_list` join together.
//
// Returns this index if found, otherwise return -1
//
int join_detection_point(struct node *first_list, struct node *second_list) {
    // TODO: Implement this function (And delete the line below)
    return -1;
}

In this exercise you will scan in values for two different lists and will be asked where to join the second list to the first list.

Here is an example:

dcc list_join_detection.c -o list_join_detection
./list_join_detection
Enter first list: 1 2 3 4 5
Enter second list: 6 7 8 9
Which node of list 1 will the end of list 2 point at? 2
These lists join at node 4 of the second list!

In this example we have two lists first_list and second_list. However, the end of second_list is pointing into first_list. This is what we're interested in and is what we specify in the third line of input. When 2 was input, the end of the second list will point at node 2 of the first list (we are counting the first node as node 0).

The last line of output is what your function will be implementing. That is, the first node in the second_list that also exists in the first_list.

Please note that looking at the input should make it very obvious when this occurs as you know what the second list looks like. However, inside the function you will not have this luxury, as all the pointers have been setup for both lists.

As a result, you are given the final versions of both lists and need to determine where they join.

Examples

dcc list_join_detection.c -o list_join_detection
./list_join_detection
Enter first list: 1 6 -10 4 3 50 20 6
Enter second list: 0 0 5 4 1 -10 3 4 6 9 10 3 6 20
Which node of list 1 will the end of list 2 point at? 5
These lists join at node 14 of the second list!
./list_join_detection
Enter first list: 0 5 2 10
Enter second list: 1 3
Which node of list 1 will the end of list 2 point at? 7
These lists do not join at all.

Assumptions/Restrictions/Clarifications

  • You will always be provided valid input
  • Providing any index for first_list that does not exist means that second_list will never point into it
  • You should return -1 if the two lists do not join
  • You cannot use the values of nodes to determine if they are in both lists. This because two nodes can have the same value. How could you check if both lists point at the same node at a certain point?

When you think your program is working, you can use autotest to run some simple automated tests:

1511 autotest list_join_detection
Sample solution for list_join_detection.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define MAX_INPUT_STRING_LENGTH 1024

struct node {
    struct node *next;
    int          data;
};

int join_detection_point(struct node *first_list, struct node *second_list);
struct node *scan_in_list();
struct node *string_to_list(char *string);

// DO NOT CHANGE THIS MAIN FUNCTION

int main(void) {
    printf("Enter first list: ");
    struct node *first_list = scan_in_list();
    printf("Enter second list: ");
    struct node *second_list = scan_in_list();
    if (second_list == NULL) {
        printf("The second list will always have at least 1 element.\n");
        return 1;
    }

    printf("Which node of list 1 will the end of list 2 point at? ");
    int node_index;
    scanf("%d", &node_index);

    // Find the node we need the end of the second list to point at.
    struct node *current_node = first_list;
    int counter = 0;
    while (current_node != NULL && counter != node_index) {
        current_node = current_node->next;
        counter++;
    }

    // Find the last node of the second list to join them together
    struct node *last_node = second_list;
    while (last_node->next != NULL) {
        last_node = last_node->next;
    }

    last_node->next = current_node;

    int res = join_detection_point(first_list, second_list);
    if (res == -1) {
        printf("These lists do not join at all.\n");
    } else {
        printf("These lists join at node %d of the second list!\n", res);
    }

    return 0;
}

//
// Gets the index relative to `second_list` where `first_list` and
// `second_list` share a node.
//
// Returns this index if found, otherwise return -1
//
int join_detection_point(struct node *first_list, struct node *second_list) {
    int point = -1;

    struct node *second_list_curr = second_list;
    int second_list_index = 0;
    while (second_list_curr != NULL && point == -1) {
        struct node *first_list_curr = first_list;
        while (first_list_curr != NULL && point == -1) {
            // Compare the addresses of every pair of nodes in list 1 and 2.
            // The first time they are equal is the point where the lists
            // joined.
            if (first_list_curr == second_list_curr) {
                point = second_list_index;
            }
            first_list_curr = first_list_curr->next;
        }

        second_list_curr = second_list_curr->next;
        second_list_index++;
    }

    return point;
}

// DO NOT CHANGE THIS FUNCTION
// Handles input/output to scan in a list
struct node *scan_in_list() {
    char inputs[MAX_INPUT_STRING_LENGTH];
    char *input_res = fgets(inputs, MAX_INPUT_STRING_LENGTH, stdin);

    // create linked list input line
    struct node *head = NULL;
    if (input_res != NULL) {
        // Remove newline off string
        if (inputs[strlen(inputs) - 1] == '\n') {
            inputs[strlen(inputs) - 1] = '\0';
        }
        
        // Make sure all elements are valid
        int i = 0;
        // Flag for whether string is valid. An empty string is not valid and
        // initial value is based off that.
        int valid_string = strlen(inputs) > 0;
        while (valid_string && inputs[i] != '\0') {
            // Strings can only contain numbers/spaces
            if ((inputs[i] < '0' || inputs[i] > '9') && inputs[i] != ' ' && inputs[i] != '-') {
                printf("%c\n", inputs[i]);
                valid_string = 0;
            }
            i++;
        }
        
        if (valid_string) {
            head = string_to_list(inputs);
        }
    }

    return head;
}

// DO NOT CHANGE THIS FUNCTION
// create linked list from string of ints
struct node *string_to_list(char *string) {
    struct node *head = NULL;
    struct node *tail = NULL;

    char *token = strtok(string, " ");

    while (token != NULL) {
        struct node *n = malloc(sizeof (struct node));
        assert(n != NULL);
        n->next = NULL;
        n->data = atoi(token);
        if (head == NULL) {
            head = n;
            tail = n;
        } else {
            tail->next = n;
            tail = n;
        }

        token = strtok(NULL, " ");
    }   

    return head;
}