CSE240: Linked List Labyrinth

Your Complete Guide to HW5

LEVEL 1: FORGING YOUR CHARACTER (Structs & Enums)

Before we can venture into the labyrinth, we need to define our character's attributes. In C, we use a struct to group different data types into a single "record". For this quest, our character is a studentRecord.

The `studentRecord` Blueprint

Our struct holds all the essential stats for one student. Notice how it contains character arrays for strings, an integer for the ID, and a special enum type for the school year.

struct studentRecord {
    char studentName[MAX_NAME_LENGTH];
    char major[MAX_NAME_LENGTH];
    schoolYearType schoolYear; // This is our special Enum type!
    unsigned int IDNumber;
    struct studentRecord* next; // The magic pointer that links to the next character!
};

The `enum` Scroll

An enum (enumeration) is a way to create a set of named integer constants. It makes our code more readable than using magic numbers like 0, 1, 2, 3. Here, `freshman` is secretly `0`, `sophomore` is `1`, and so on.

typedef enum { freshman = 0, sophomore, junior, senior } schoolYearType;

LEVEL 2: MASTERING THE POINTER WAND (Memory Management)

Pointers are the magic wands of C. They don't hold data themselves; they hold the memory address *where* data lives. To create new student records on the fly, we must master memory allocation.

Casting `malloc()`

The malloc() spell (memory allocation) reserves a chunk of memory from the "heap". We tell it how much space we need (the size of one `studentRecord`), and it gives us back a generic pointer to that space. We then "cast" it to the correct pointer type.

// Reserve memory for one new student and get a pointer to it.
struct studentRecord* newNode = (struct studentRecord*)malloc(sizeof(struct studentRecord));

The `free()` Spell of Banishment

Memory you allocate with `malloc()` is not automatically cleaned up! If you lose the pointer to it, that memory becomes a "memory leak," draining your system's power. The free() spell is essential. You must cast it on every piece of memory you're done with to return it to the system.

// When we delete a node, we must free its memory to prevent leaks.
free(nodeToDelete);

LEVEL 3: NAVIGATING THE LABYRINTH (Linked Lists)

A linked list is a chain of `structs` (we call them "nodes"). Each node holds its own data and, crucially, a pointer to the `next` node in the chain. The last node's `next` pointer is `NULL`, signaling the end of the path.

Traversal: The Basic Move

To walk through the list, you create a temporary pointer (let's call it `current`) and start it at the head of the list. Then, you loop, moving the pointer forward with `current = current->next;` until you hit `NULL`.

struct studentRecord* current = list; // Start at the beginning.
while (current != NULL) {
    // Do something with the 'current' node...
    current = current->next; // Move to the next node.
}

BOSS BATTLES: IMPLEMENTING THE CORE FUNCTIONS

These are the key functions from your homework. Master them, and you've conquered the level.

Mini-Boss: `countNodes()`

A simple traversal to count every node in the list. This is your warm-up.

int countNodes()
{
    int count = 0; // Start counter at zero.
    struct studentRecord* current = list; // Temporary pointer to walk the list.

    while (current != NULL) {
        count++; // Add one for the current student.
        current = current->next; // Move to the next student.
    }
    return count; // Return the total.
}

Mini-Boss: `displayList()`

Traverse the list and print each student's stats. The key challenge is converting the `schoolYear` enum back to a human-readable string.

void displayList()
{
    struct studentRecord* current = list; // Temp pointer to walk the list.
    while (current != NULL) {
        printf("\nStudent name: %s", current->studentName);
        printf("\nStudent major: %s", current->major);
        printf("\nID number: %d", current->IDNumber);

        // Use a switch to translate the enum number to a string.
        switch (current->schoolYear) {
            case freshman: printf("\nSchoolYear: freshman\n"); break;
            case sophomore: printf("\nSchoolYear: sophomore\n"); break;
            case junior: printf("\nSchoolYear: junior\n"); break;
            case senior: printf("\nSchoolYear: senior\n"); break;
        }
        current = current->next; // Move to the next student.
    }
}

Helper Mob: `swapNodes()`

A crucial helper function for sorting. It swaps the *data* inside two nodes but leaves their `next` pointers untouched. This is much more efficient than re-wiring the list structure.

void swapNodes(struct studentRecord* node1, struct studentRecord* node2)
{
    // We need temporary variables to hold the data from node1 during the swap.
    char tempName[MAX_NAME_LENGTH];
    char tempMajor[MAX_NAME_LENGTH];
    schoolYearType tempSchoolYear;
    unsigned int tempID;

    // Use strcpy for strings and direct assignment for numbers/enums.
    strcpy(tempName, node1->studentName);
    strcpy(tempMajor, node1->major);
    tempSchoolYear = node1->schoolYear;
    tempID = node1->IDNumber;

    strcpy(node1->studentName, node2->studentName);
    strcpy(node1->major, node2->major);
    node1->schoolYear = node2->schoolYear;
    node1->IDNumber = node2->IDNumber;

    strcpy(node2->studentName, tempName);
    strcpy(node2->major, tempMajor);
    node2->schoolYear = tempSchoolYear;
    node2->IDNumber = tempID;
}

Final Boss: `deleteNode()`

This is where your pointer skills are truly tested. You must find the node, carefully re-wire the `next` pointers to bypass it, and then `free()` its memory. Handling the head of the list is a critical special case!

int deleteNode(char* studentName_input)
{
	struct studentRecord* current = list; // To find the node.
	struct studentRecord* previous = NULL; // To keep track of the node before.

	// Case 1: The list is empty.
	if (list == NULL) {
		return -1; // Nothing to delete.
	}

	// Case 2: The head node is the one to delete.
	if (strcmp(list->studentName, studentName_input) == 0) {
		current = list;       // Mark the head for deletion.
		list = list->next;    // The second node is now the new head.
		free(current);        // Banish the old head!
		return 1;             // Success!
	}

	// Case 3: Search the rest of the list.
	while (current != NULL && strcmp(current->studentName, studentName_input) != 0) {
		previous = current;      // Move 'previous' to where 'current' is.
		current = current->next; // Move 'current' one step forward.
	}

	// If we finished the loop and 'current' is NULL, the student wasn't found.
	if (current == NULL) {
		return 0; // Not found.
	}
	else { // We found the node at 'current'.
		// Stitch the list: make the previous node's 'next' skip over 'current'.
		previous->next = current->next;
		free(current); // Banish the found node.
		return 1; // Success!
	}
}

TREASURE ROOM: THE COMPLETE `addSort()` FUNCTION

This is the final challenge, combining all your skills: duplicate checking, memory allocation, appending to the list, and finally, sorting the list using a Bubble Sort and your `swapNodes` helper. This is the complete solution to Q1.

int addSort(char* studentName_input, char* major_input, char* schoolYear_input, unsigned int IDNumber_input)
{
    struct studentRecord* current = list;
    
    // 1. Check for Duplicates
    while(current != NULL){
        if(strcmp(current->studentName, studentName_input) == 0){
            return 0; // Found a duplicate, fail.
        }
        current = current->next;
    }

    // 2. Create New Node
    struct studentRecord* newNode = (struct studentRecord*)malloc(sizeof(struct studentRecord));
    strcpy(newNode->studentName, studentName_input);
    strcpy(newNode->major, major_input);
    newNode->IDNumber = IDNumber_input;
    newNode->next = NULL;
    
    if (strcmp(schoolYear_input, "freshman") == 0) newNode->schoolYear = freshman;
    else if (strcmp(schoolYear_input, "sophomore") == 0) newNode->schoolYear = sophomore;
    else if (strcmp(schoolYear_input, "junior") == 0) newNode->schoolYear = junior;
    else if (strcmp(schoolYear_input, "senior") == 0) newNode->schoolYear = senior;

    // 3. Append Node to List
    if (list == NULL) {
        list = newNode;
    } else {
        current = list;
        while (current->next != NULL) {
            current = current->next;
        }
        current->next = newNode;
    }

    // 4. Sort The List (Bubble Sort)
    int swapped;
    struct studentRecord* ptr1;
    if (list == NULL || list->next == NULL) {
        return 1; // Already sorted.
    }
    do {
        swapped = 0;
        ptr1 = list;
        while (ptr1->next != NULL) {
            if (strcmp(ptr1->studentName, ptr1->next->studentName) > 0) { 
                swapNodes(ptr1, ptr1->next);
                swapped = 1;
            }
            ptr1 = ptr1->next;
        }
    } while (swapped);

    return 1; // Success!
}