diff --git a/spring-2025/sec-203/SEC-203: Concept to real-world security incident - Thanawin Pattanaphol.odt b/spring-2025/sec-203/SEC-203: Concept to real-world security incident - Thanawin Pattanaphol.odt new file mode 100644 index 0000000..ae57b66 Binary files /dev/null and b/spring-2025/sec-203/SEC-203: Concept to real-world security incident - Thanawin Pattanaphol.odt differ diff --git a/spring-2025/sec-203/SEC-203: Concept to real-world security incident - Thanawin Pattanaphol.pdf b/spring-2025/sec-203/SEC-203: Concept to real-world security incident - Thanawin Pattanaphol.pdf new file mode 100644 index 0000000..a5159d6 Binary files /dev/null and b/spring-2025/sec-203/SEC-203: Concept to real-world security incident - Thanawin Pattanaphol.pdf differ diff --git a/spring-2025/sen-107/00020/a.out b/spring-2025/sen-107/00020/a.out new file mode 100755 index 0000000..7cd8800 Binary files /dev/null and b/spring-2025/sen-107/00020/a.out differ diff --git a/spring-2025/sen-107/00020/lab.c b/spring-2025/sen-107/00020/lab.c new file mode 100644 index 0000000..e1a234b --- /dev/null +++ b/spring-2025/sen-107/00020/lab.c @@ -0,0 +1,243 @@ +/* matrilineal +* +* Build a simple, non-sorted tree of mother-daughter relationships +* +* Created by Nunthatinn Veerapaiboon, 30 Jan 2025 +*/ +#include +#include +#include +/* Adds person with a given name at the root. +*/ +#define MAX_CHILDREN 10 +#define MAX_NAME_LENGTH 25 + +typedef struct NODE_T +{ + char name[MAX_NAME_LENGTH]; + int numChildren; + struct NODE_T * parent; + struct NODE_T *children[MAX_CHILDREN]; + +} NODE_T; + +NODE_T* root = NULL; + +NODE_T* createNode(char* name) { + NODE_T* newNode = (NODE_T*)malloc(sizeof(NODE_T)); + if (newNode == NULL) { + printf("Memory allocation failed.\n"); + exit(1); + } + strncpy(newNode->name, name, MAX_NAME_LENGTH - 1); + newNode->name[MAX_NAME_LENGTH - 1] = '\0'; + newNode->numChildren = 0; + newNode->parent = NULL; + for (int i = 0; i < MAX_CHILDREN; i++) { + newNode->children[i] = NULL; + } + printf("Added\n"); + return newNode; +} + +// create Root +NODE_T* addRoot(char* name) +{ + if (root != NULL) + { + printf("Root already exists.\n"); + return root; + } + root = createNode(name); + return root; +} + +// Helper function to find a node by name (DFS) +NODE_T* findNode(NODE_T* currentNode, char* name) +{ + if (currentNode == NULL) + { + return NULL; + } + // Found at current node + if (strcmp(currentNode->name, name) == 0) + { + return currentNode; + } + + for (int i = 0; i < currentNode->numChildren; i++) + { + // recursively find in Children node + NODE_T* found = findNode(currentNode->children[i], name); + // Return node if it was found + if (found != NULL) + { + return found; + } + } + return NULL; +} + +/* Adds person with a given name and mother's name to the tree. +*/ +NODE_T* addNonRoot(char* name, char* motherName) +{ + if (root == NULL) + { + printf("Error: Root does not exist. Please add a root first.\n"); + return NULL; + } + + // Find mother node + NODE_T* motherNode = findNode(root, motherName); + if (motherNode == NULL) + { + printf("Not Found\n"); + return NULL; + } + if (motherNode->numChildren == MAX_CHILDREN) + { + printf("Unsuccessful\n"); + return NULL; + } + + // Create new node + NODE_T* newNode = createNode(name); + newNode->parent = motherNode; + motherNode->children[motherNode->numChildren] = newNode; + motherNode->numChildren++; + + return newNode; +} + +/* Prints the person's mother. +*/ +void queryMother(char* name) +{ + if (root == NULL) + { + printf("The tree is empty.\n"); + return; + } + + NODE_T* node = findNode(root, name); + if (node == NULL) + { + printf("Not Found\n"); + } + else if (node->parent == NULL) + { + printf("Not Found\n"); + } + else + { + printf("%s", node->parent->name); + } +} + +/* Prints the person's daughters. +*/ +void queryDaughters(char* name) +{ + if (root == NULL) + { + printf("The tree is empty.\n"); + return; + } + + NODE_T* node = findNode(root, name); + if (node == NULL) + { + printf("Not Found\n"); + } + else if (node->numChildren == 0) + { + printf("Not Found\n"); + } + else + { + for (int i = 0; i < node->numChildren; i++) + { + printf("%s ", node->children[i]->name); + } + printf("\n"); + } +} + +/* Prints the person's sisters. +*/ +void querySisters(char* name) +{ + if (root == NULL) + { + printf("The tree is empty.\n"); + return; + } + + NODE_T* node = findNode(root, name); + if (node == NULL) + { + printf("Not Found\n"); + } + else if (node->parent == NULL) + { + printf("Not Found\n"); + } + else + { + NODE_T* motherNode = node->parent; + if (motherNode->numChildren <= 1) + { + printf("Not Found\n"); + } + else + { + for (int i = 0; i < motherNode->numChildren; i++) + { + // Don't print self name + if (strcmp(motherNode->children[i]->name, name) != 0) + { + printf("%s ", motherNode->children[i]->name); + } + printf("\n"); + } + } + } +} + +int main() + { + char input[64]; // Input operation name + char name[MAX_NAME_LENGTH]; // The name of the woman + char motherName[MAX_NAME_LENGTH]; // The number of woman's mother + int numOperations; // The number of operations. + + scanf("%d", &numOperations); + scanf("\n%s", name); + NODE_T* root = addRoot(name); + + for (int i = 1 ; i < numOperations ; i ++) + { + scanf("\n%s ", input); + if (strcmp(input, "Add") == 0) + { + scanf("%s %s", name, motherName); + addNonRoot(name, motherName); + } + else if (strcmp(input, "Mother") == 0) + { + scanf("%s", name); + queryMother(name); + } + else if (strcmp(input, "Daughters") == 0) + { + scanf("%s", name); + queryDaughters(name); + } + else + { + scanf("%s", name); + querySisters(name); + } + } +} diff --git a/spring-2025/sen-107/00020/matrilinealDescendant.c b/spring-2025/sen-107/00020/matrilinealDescendant.c new file mode 100644 index 0000000..acba8b2 --- /dev/null +++ b/spring-2025/sen-107/00020/matrilinealDescendant.c @@ -0,0 +1,226 @@ +/* matrilineal.c +* +* A non-sorted tree of mother-daughter relationships +* +* Created by Pasin Manurangsi, 2025-01-08 +* Modified by Thanawin Pattanaphol, 2025-05-02 +* +*/ + +#include +#include +#include + +/* Adds person with a given name at the root +*/ +#define MAX_CHILDREN 10 +#define MAX_NAME_LENGTH 25 +#define MAX_PATH_LENGTH 100 + +typedef struct NODE_T +{ + char name[MAX_NAME_LENGTH]; + int numChildren; + struct NODE_T* parent; + struct NODE_T* children[MAX_CHILDREN]; +} NODE_T; + +NODE_T* root = NULL; + +NODE_T* createNode(char* name) +{ + NODE_T* newNode = (NODE_T*)malloc(sizeof(NODE_T)); + + if (newNode == NULL) + { + printf("Memory allocation failed.\n"); + exit(1); + } + + strncpy(newNode->name, name, MAX_NAME_LENGTH - 1); + newNode->name[MAX_NAME_LENGTH - 1] = '\0'; + newNode->numChildren = 0; + newNode->parent = NULL; + + for (int i = 0; i < MAX_CHILDREN; i++) + { + newNode->children[i] = NULL; + } + + printf("Added\n"); + return newNode; +} + +// Create the root +NODE_T* addRoot(char* name) +{ + if (root != NULL) + { + printf("Root already exists.\n"); + return root; + } + + root = createNode(name); + return root; +} + +// Function that helps finding a node by name +NODE_T* findNode(NODE_T* currentNode, char* name) +{ + if (currentNode == NULL) return NULL; + if (strcmp(currentNode->name, name) == 0) return currentNode; + + for (int i = 0; i < currentNode->numChildren; i++) + { + NODE_T* found = findNode(currentNode->children[i], name); + if (found != NULL) return found; + } + + return NULL; +} + +/* Adds person with a given name and mother's name to the tree. +*/ +NODE_T* addNonRoot(char* name, char* motherName) +{ + if (root == NULL) + { + printf("Error: Root does not exist. Please add a root first.\n"); + return NULL; + } + + NODE_T* motherNode = findNode(root, motherName); + if (motherNode == NULL) + { + printf("Unsuccessful\n"); + return NULL; + } + + if (motherNode->numChildren == MAX_CHILDREN) + { + printf("Unsuccessful\n"); + return NULL; + } + + NODE_T* newNode = createNode(name); + newNode->parent = motherNode; + motherNode->children[motherNode->numChildren++] = newNode; + return newNode; +} + +/* DFS function +*/ +void dfsPrintDescendants(NODE_T* node) +{ + for (int i = 0; i < node->numChildren; i++) + { + printf("%s ", node->children[i]->name); + dfsPrintDescendants(node->children[i]); + } +} + +/* Prints the descendants of a given node. +*/ +void printDescendants(char* name) +{ + NODE_T* node = findNode(root, name); + if (node == NULL || node->numChildren == 0) + { + printf("Not Found\n"); + return; + } + dfsPrintDescendants(node); + printf("\n"); +} + +/* DFS function to find the maximum chain +*/ +void dfsFindMaxChain( + NODE_T* node, + NODE_T* path[], + int depth, + NODE_T* maxPath[], + int* maxDepth +) +{ + path[depth] = node; + + if (node->numChildren == 0) + { + if (depth + 1 > *maxDepth) + { + *maxDepth = depth + 1; + for (int i = 0; i <= depth; i++) + { + maxPath[i] = path[i]; + } + } + } + else + { + for (int i = 0; i < node->numChildren; i++) + { + dfsFindMaxChain( + node->children[i], + path, + depth + 1, + maxPath, + maxDepth + ); + } + } +} + +// Function to print the longest chain +void printLongestChain() +{ + if (root == NULL) + { + printf("Tree is empty\n"); + return; + } + NODE_T* path[MAX_PATH_LENGTH]; + NODE_T* maxPath[MAX_PATH_LENGTH]; + int maxDepth = 0; + + dfsFindMaxChain(root, path, 0, maxPath, &maxDepth); + + for (int i = 0; i < maxDepth; i++) + { + printf("%s ", maxPath[i]->name); + } + printf("\n"); +} + + +int main() +{ + char input[64]; + char name[MAX_NAME_LENGTH]; + char motherName[MAX_NAME_LENGTH]; + int numOperations; + + scanf("%d", &numOperations); + scanf("%s", name); + addRoot(name); + + for (int i = 1; i < numOperations; i++) + { + scanf("%s", input); + if (strcmp(input, "Add") == 0) + { + scanf("%s %s", name, motherName); + addNonRoot(name, motherName); + } + else if (strcmp(input, "Descendant") == 0) + { + scanf("%s", name); + printDescendants(name); + } + else if (strcmp(input, "Max") == 0) + { + printLongestChain(); + } + } + return 0; +} diff --git a/spring-2025/sen-107/00030/a.out b/spring-2025/sen-107/00030/a.out new file mode 100755 index 0000000..420fd0a Binary files /dev/null and b/spring-2025/sen-107/00030/a.out differ diff --git a/spring-2025/sen-107/00030/lab.c b/spring-2025/sen-107/00030/lab.c new file mode 100644 index 0000000..978b7c3 --- /dev/null +++ b/spring-2025/sen-107/00030/lab.c @@ -0,0 +1,177 @@ +/* AICE Tree +* +* Build a sorted binary tree for competency information +* +* Template for Fundamental Data Structures Lab 3 +* Created by Nunthatinn Veerapaiboon, 2025-02-15 +*/ +#include +#include +#include + +#define MAX_COMPETENCY_CODE 8 +#define MAX_COMPETENCY_TITLE 64 + +// Define the structs here +// Node Binary tree structure +typedef struct NODE_BT { + char competency_code[8]; + char competency_title[64]; + int credit; + int year; + int semester; + struct NODE_BT *leftChildren; + struct NODE_BT *rightChildren; +} NODE_BT; + +// Declare a global variable for the root of the binary tree +NODE_BT* root = NULL; + +/* Creates the node containing compentency's information +**** You may change the type of the function to make it matches the function +output **** +*/ +NODE_BT * create_node(char competency_code[MAX_COMPETENCY_CODE], char competency_title[MAX_COMPETENCY_TITLE], int credit, int year, int semester) +{ + NODE_BT* newNode = (NODE_BT*)malloc(sizeof(NODE_BT)); + if (newNode == NULL) { + printf("Memory allocation failed.\n"); + exit(1); + } + strncpy(newNode->competency_code, competency_code, MAX_COMPETENCY_CODE - 1); + newNode->competency_code[MAX_COMPETENCY_CODE - 1] = '\0'; + strncpy(newNode->competency_title, competency_title, MAX_COMPETENCY_TITLE - 1); + newNode->competency_title[MAX_COMPETENCY_TITLE - 1] = '\0'; + newNode->credit = credit; + newNode->year = year; + newNode->semester = semester; + newNode->leftChildren = NULL; + newNode->rightChildren = NULL; + return newNode; +} + +/* Inserts the node into the sorted binary tree +**** You may add the function's parameter **** +*/ +void insert(NODE_BT* newNode, NODE_BT* currentNode) +{ + if (root == NULL) { + root = newNode; + return; + } + + // compare year + if (currentNode->year < newNode->year) { + if (currentNode->rightChildren == NULL) + currentNode->rightChildren = newNode; + else + insert(newNode, currentNode->rightChildren); + return; + } + + if (currentNode->year > newNode->year) { + if (currentNode->leftChildren == NULL) + currentNode->leftChildren = newNode; + else + insert(newNode, currentNode->leftChildren); + return; + } + + // If years are equal, compare semester + if (currentNode->semester < newNode->semester) { + if (currentNode->rightChildren == NULL) + currentNode->rightChildren = newNode; + else + insert(newNode, currentNode->rightChildren); + return; + } + + if (currentNode->semester > newNode->semester) { + if (currentNode->leftChildren == NULL) + currentNode->leftChildren = newNode; + else + insert(newNode, currentNode->leftChildren); + return; + } + + // If both year and semester are equal, compare competency codes + for (int i = 0; i < MAX_COMPETENCY_CODE; i++) { + if (currentNode->competency_code[i] < newNode->competency_code[i]) { + if (currentNode->rightChildren == NULL) + currentNode->rightChildren = newNode; + else + insert(newNode, currentNode->rightChildren); + return; + } + + if (currentNode->competency_code[i] > newNode->competency_code[i]) { + if (currentNode->leftChildren == NULL) + currentNode->leftChildren = newNode; + else + insert(newNode, currentNode->leftChildren); + return; + } + } +} + + + +/* Prints competencies in-order +*/ +void print_subtree(NODE_BT* currentNode) +{ + if(currentNode->leftChildren != NULL) + { + print_subtree(currentNode->leftChildren); + } + printf("%d %d %s %s\n", currentNode->year, currentNode->semester, currentNode->competency_code, currentNode->competency_title); + if(currentNode->rightChildren != NULL) + { + print_subtree(currentNode->rightChildren); + } +} + +void print_competencies() +{ + print_subtree(root); +} + +/* Free the contents +*/ +void freeBT(NODE_BT* node) { + if (node == NULL) return; // Base case: empty node + + freeBT(node->leftChildren); // Free left subtree + freeBT(node->rightChildren); // Free right subtree + + free(node); // Free the current node +} + +// Wrapper function to free the entire tree +void free_all() { + freeBT(root); // Free all nodes starting from the root + root = NULL; // Set root to NULL to prevent dangling reference +} + + +int main() +{ + char competency_code[8]; + char competency_title[64]; + int credit; + int year; + int semester; // Spring = 0, Fall = 1 + int num_operations; // The number of operations. + + scanf("%d", &num_operations); + + for (int i = 0; i < num_operations; i++) + { + scanf("%7s %63s %d %d %d", competency_code, competency_title, &credit, + &year, &semester); + NODE_BT * new_node = create_node(competency_code, competency_title, credit, year, semester); // You may change the datatype + insert(new_node, root); // You may add the function's argument + } + print_competencies(); + free_all(); +} \ No newline at end of file diff --git a/spring-2025/sen-107/00030/orgchart.c b/spring-2025/sen-107/00030/orgchart.c new file mode 100644 index 0000000..3cd8d99 --- /dev/null +++ b/spring-2025/sen-107/00030/orgchart.c @@ -0,0 +1,337 @@ +/* orgChart + * + * Build a corporate hierarchy structure and sorted binary tree + * + * Created by Chavakorn Arunkunarax and Phasit Thanitkul, 2025-01-12 + * Modified by Thanawin Pattanaphol, 2025-05-02 + */ +#include +#include +#include +#include + +// Structure for an employee in the organization chart (general tree node) +typedef struct EmployeeNode +{ + char name[32]; + char employeeId[8]; + char jobTitle[32]; + struct EmployeeNode *supervisor; + struct EmployeeNode *firstChild; + struct EmployeeNode *nextSibling; +} EmployeeNode; + +// Structure for a node in the sorted binary tree (index) +typedef struct IndexNode +{ + char key[40]; // Concatenation of Name and EmployeeId + EmployeeNode *employeePtr; + struct IndexNode *left; + struct IndexNode *right; +} IndexNode; + +EmployeeNode *root = NULL; // Root of the organization chart +IndexNode *indexRoot = NULL; // Root of the sorted binary tree + +// Function to create a new employee node +EmployeeNode *createEmployeeNode(char *name, char *employeeId, char *jobTitle) +{ + EmployeeNode *newNode = (EmployeeNode *)malloc(sizeof(EmployeeNode)); + + if (newNode == NULL) + { + perror("Failed to allocate memory for employee node"); + exit(EXIT_FAILURE); + } + + strcpy(newNode->name, name); + strcpy(newNode->employeeId, employeeId); + strcpy(newNode->jobTitle, jobTitle); + newNode->supervisor = NULL; + newNode->firstChild = NULL; + newNode->nextSibling = NULL; + return newNode; +} + +// Function to create a new index node +IndexNode *createIndexNode(char *key, EmployeeNode *employeePtr) +{ + IndexNode *newNode = (IndexNode *)malloc(sizeof(IndexNode)); + + if (newNode == NULL) + { + perror("Failed to allocate memory for index node"); + exit(EXIT_FAILURE); + } + + strcpy(newNode->key, key); + newNode->employeePtr = employeePtr; + newNode->left = NULL; + newNode->right = NULL; + return newNode; +} + +// Function to insert into the sorted binary tree +IndexNode *insertIndexNode(IndexNode *root, char *key, EmployeeNode *employeePtr) +{ + if (root == NULL) + { + return createIndexNode(key, employeePtr); + } + + int cmp = strcmp(key, root->key); + if (cmp < 0) + { + root->left = insertIndexNode(root->left, key, employeePtr); + } + else if (cmp > 0) + { + root->right = insertIndexNode(root->right, key, employeePtr); + } + return root; +} + +/* Adds employee to the corporate hierarchy structure and sorted binary tree +*/ +void addEmployee(char *name, char *employeeId, char *jobTitle, char *supervisorName, char *supervisorId) +{ + EmployeeNode *newEmployee = createEmployeeNode(name, employeeId, jobTitle); + char indexKey[40]; + sprintf(indexKey, "%s%s", name, employeeId); + indexRoot = insertIndexNode(indexRoot, indexKey, newEmployee); + + if (strcmp(supervisorName, "--") == 0) + { + if (root == NULL) + { + root = newEmployee; + } + else + { + fprintf(stderr, "Error: Multiple root employees found.\n"); + // Handle this error as needed, maybe free the newEmployee + } + return; + } + + EmployeeNode *supervisorNode = NULL; + // Search for the supervisor in the existing organization chart + // A simple linear search here. For larger organizations, a hash map would be more efficient. + // However, for this exercise, we'll keep it straightforward. + EmployeeNode *queue[100]; // Assuming a reasonable maximum number of employees for the queue + int head = 0, tail = 0; + + if (root != NULL) + { + queue[tail++] = root; + } + + while (head < tail) + { + EmployeeNode *current = queue[head++]; + + if (strcmp(current->name, supervisorName) == 0 && strcmp(current->employeeId, supervisorId) == 0) + { + supervisorNode = current; + break; + } + + EmployeeNode *child = current->firstChild; + while (child != NULL) + { + queue[tail++] = child; + child = child->nextSibling; + } + } + + if (supervisorNode != NULL) + { + newEmployee->supervisor = supervisorNode; + if (supervisorNode->firstChild == NULL) + { + supervisorNode->firstChild = newEmployee; + } + else + { + EmployeeNode *sibling = supervisorNode->firstChild; + while (sibling->nextSibling != NULL) + { + sibling = sibling->nextSibling; + } + sibling->nextSibling = newEmployee; + } + } + else + { + fprintf(stderr, "cannot_add %s %s\n", name, employeeId); + // Free the allocated memory for the employee node since it couldn't be added + free(newEmployee); + } +} + +/* Prints the corporate hierarchy structure, pre-order +*/ +void printCorporateHierarchyHelper(EmployeeNode *node, int level) +{ + if (node == NULL) + { + return; + } + + for (int i = 0; i < level; i++) + { + printf("..."); + } + + printf("%s %s %s\n", node->name, node->employeeId, node->jobTitle); + EmployeeNode *child = node->firstChild; + while (child != NULL) + { + printCorporateHierarchyHelper(child, level + 1); + child = child->nextSibling; + } +} + +void printCorporateHierarchy() +{ + printCorporateHierarchyHelper(root, 0); +} + +// Helper function for in-order traversal of the index tree to print sorted list +void printSortedListHelper(IndexNode *root) +{ + if (root == NULL) + { + return; + } + + printSortedListHelper(root->left); + printf("%s %s %s\n", root->employeePtr->name, root->employeePtr->employeeId, root->employeePtr->jobTitle); + printSortedListHelper(root->right); +} + +/* Prints the sorted list of employees +*/ +void printSortedList() +{ + printSortedListHelper(indexRoot); +} + +/* Searches for an employee in the corporate hierarchy structure using the index tree +*/ +void searchEmployee(char *name, char *employeeId) +{ + char searchKey[40]; + sprintf(searchKey, "%s%s", name, employeeId); + + IndexNode *current = indexRoot; + while (current != NULL) + { + int cmp = strcmp(searchKey, current->key); + if (cmp < 0) + { + current = current->left; + } + else if (cmp > 0) + { + current = current->right; + } + else + { + EmployeeNode *employee = current->employeePtr; + printf("%s %s %s\n", employee->jobTitle, employee->supervisor ? employee->supervisor->name : "Top", employee->employeeId); + return; + } + } + printf("not_found\n"); +} + +// Helper function to free the organization chart tree +void freeOrganizationChart(EmployeeNode *node) +{ + if (node == NULL) + { + return; + } + + EmployeeNode *child = node->firstChild; + + while (child != NULL) + { + EmployeeNode *next = child->nextSibling; + freeOrganizationChart(child); + child = next; + } + free(node); +} + +// Helper function to free the index tree +void freeIndexTree(IndexNode *node) +{ + if (node == NULL) + { + return; + } + + freeIndexTree(node->left); + freeIndexTree(node->right); + free(node); +} + +/* Free the contents of the datastructures used */ +void freeAll() +{ + freeOrganizationChart(root); + freeIndexTree(indexRoot); + root = NULL; + indexRoot = NULL; +} + +int main() +{ + char input[128]; + char name[32]; + char employeeId[8]; + char jobTitle[32]; + char supervisorName[32]; + char supervisorId[8]; + int numEmployees; + int numQuestions; + + if (scanf("%d", &numEmployees) != 1) + { + fprintf(stderr, "Error reading number of employees.\n"); + return 1; + } + + if (scanf("%d", &numQuestions) != 1) + { + fprintf(stderr, "Error reading number of queries.\n"); + return 1; + } + + for (int i = 0; i < numEmployees; i++) { + if (scanf("%s %s %s %s %s", name, employeeId, jobTitle, supervisorName, supervisorId) != 5) + { + fprintf(stderr, "Error reading employee data.\n"); + return 1; + } + addEmployee(name, employeeId, jobTitle, supervisorName, supervisorId); + } + + printCorporateHierarchy(); + + for (int i = 0; i < numQuestions; i++) + { + if (scanf("%s %s", name, employeeId) != 2) + { + fprintf(stderr, "Error reading query.\n"); + return 1; + } + searchEmployee(name, employeeId); + } + + printSortedList(); + freeAll(); + return 0; +} \ No newline at end of file diff --git a/spring-2025/sen-107/00050/a.out b/spring-2025/sen-107/00050/a.out new file mode 100755 index 0000000..1470dbf Binary files /dev/null and b/spring-2025/sen-107/00050/a.out differ diff --git a/spring-2025/sen-107/00050/cmkl_book.c b/spring-2025/sen-107/00050/cmkl_book.c new file mode 100644 index 0000000..5e399c6 --- /dev/null +++ b/spring-2025/sen-107/00050/cmkl_book.c @@ -0,0 +1,446 @@ +/* cmkl_book + * + * Build a social network with basic functionalities + * + * Template for Fundamental Data Structures Lab 2 + * Modified by Thanawin Pattanaphol, 2025-05-02 + */ +#include +#include +#include +#include + +#define MAX_ACCOUNTS 1000 // Arbitrary limit for simplicity +#define MAX_FRIENDS 100 // Arbitrary limit for simplicity + +// Structure for an account +typedef struct Account +{ + char emailAddress[55]; + char firstName[25]; + char lastName[25]; + bool isActive; + int numFriends; + struct Account *friends[MAX_FRIENDS]; +} Account; + +// Hash table structure +#define HASH_TABLE_SIZE 101 // A prime number for better distribution + +typedef struct HashNode +{ + char emailAddress[55]; + Account *account; + struct HashNode *next; +} HashNode; + +HashNode *accountHashTable[HASH_TABLE_SIZE]; +int numAccounts = 0; +Account accounts[MAX_ACCOUNTS]; + +// Hash function +unsigned long hash(const char *str) +{ + unsigned long hash = 5381; + int c; + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + return hash % HASH_TABLE_SIZE; +} + +// Find an account by email in the hash table +Account *findAccount(const char *emailAddress) +{ + unsigned long index = hash(emailAddress); + HashNode *current = accountHashTable[index]; + while (current != NULL) + { + if (strcmp(current->emailAddress, emailAddress) == 0 && current->account->isActive) + { + return current->account; + } + current = current->next; + } + return NULL; +} + +// Insert an account into the hash table +void insertAccount(Account *account) +{ + unsigned long index = hash(account->emailAddress); + HashNode *newNode = (HashNode *)malloc(sizeof(HashNode)); + + if (newNode == NULL) + { + perror("Failed to allocate memory for hash node"); + exit(EXIT_FAILURE); + } + + strcpy(newNode->emailAddress, account->emailAddress); + newNode->account = account; + newNode->next = accountHashTable[index]; + accountHashTable[index] = newNode; +} + +// Delete an account from the hash table (mark as inactive) +Account *deleteAccountFromTable(const char *emailAddress) +{ + unsigned long index = hash(emailAddress); + HashNode *current = accountHashTable[index]; + HashNode *prev = NULL; + while (current != NULL) + { + if (strcmp(current->emailAddress, emailAddress) == 0 && current->account->isActive) + { + current->account->isActive = false; + return current->account; + } + prev = current; + current = current->next; + } + return NULL; +} + +// Add a new account +void newAccount(char *emailAddress, char *firstName, char *lastName) +{ + if (numAccounts >= MAX_ACCOUNTS) + { + fprintf(stderr, "Error: Maximum number of accounts reached.\n"); + return; + } + + if (findAccount(emailAddress) != NULL) { + printf("Error: Duplicate\n"); + return; + } + + Account *newAccountPtr = &accounts[numAccounts++]; + + strcpy(newAccountPtr->emailAddress, emailAddress); + strcpy(newAccountPtr->firstName, firstName); + strcpy(newAccountPtr->lastName, lastName); + + newAccountPtr->isActive = true; + newAccountPtr->numFriends = 0; + + insertAccount(newAccountPtr); + printf("Success\n"); +} + +// Delete an account +void deleteAccount(char *emailAddress) +{ + Account *accountToDelete = deleteAccountFromTable(emailAddress); + if (accountToDelete == NULL) + { + printf("Error: Not Found\n"); + return; + } + + // Remove this account from the friend lists of others + for (int i = 0; i < numAccounts; i++) + { + if (accounts[i].isActive) + { + Account *friendAccount = &accounts[i]; + for (int j = 0; j < friendAccount->numFriends; j++) + { + if (friendAccount->friends[j] == accountToDelete) + { + // Shift remaining friends to the left + for (int k = j; k < friendAccount->numFriends - 1; k++) + { + friendAccount->friends[k] = friendAccount->friends[k + 1]; + } + + friendAccount->numFriends--; + break; // Only one instance of the deleted friend + } + } + } + } + + printf("Success %s %s\n", accountToDelete->firstName, accountToDelete->lastName); +} + +// Make two accounts friends +void addFriend(char *firstEmailAddress, char *secondEmailAddress) +{ + Account *account1 = findAccount(firstEmailAddress); + Account *account2 = findAccount(secondEmailAddress); + + if (account1 == NULL || account2 == NULL) + { + printf("Error: Account Not Found\n"); + return; + } + if (strcmp(firstEmailAddress, secondEmailAddress) == 0) + { + printf("Error: Can’t add friend to self\n"); + return; + } + + bool areFriends = false; + for (int i = 0; i < account1->numFriends; i++) + { + if (account1->friends[i] == account2) + { + areFriends = true; + break; + } + } + + if (areFriends) + { + printf("Error: Accounts are already friends\n"); + return; + } + + if (account1->numFriends < MAX_FRIENDS && account2->numFriends < MAX_FRIENDS) + { + account1->friends[account1->numFriends++] = account2; + account2->friends[account2->numFriends++] = account1; + printf("Success\n"); + } + else + { + fprintf(stderr, "Error: Maximum number of friends reached for one of the accounts.\n"); + } +} + +// Unfriend two accounts +void unfriend(char *firstEmailAddress, char *secondEmailAddress) +{ + Account *account1 = findAccount(firstEmailAddress); + Account *account2 = findAccount(secondEmailAddress); + + if (account1 == NULL || account2 == NULL) + { + printf("Error: Account Not Found\n"); + return; + } + if (strcmp(firstEmailAddress, secondEmailAddress) == 0) + { + printf("Error: Can’t unfriend self\n"); + return; + } + + int index1 = -1, index2 = -1; + for (int i = 0; i < account1->numFriends; i++) + { + if (account1->friends[i] == account2) + { + index1 = i; + break; + } + } + for (int i = 0; i < account2->numFriends; i++) + { + if (account2->friends[i] == account1) + { + index2 = i; + break; + } + } + + if (index1 == -1 || index2 == -1) + { + printf("Error: Can’t unfriend accounts that are not friends\n"); + return; + } + + // Remove from account1's friend list + for (int i = index1; i < account1->numFriends - 1; i++) + { + account1->friends[i] = account1->friends[i + 1]; + } + account1->numFriends--; + + // Remove from account2's friend list + for (int i = index2; i < account2->numFriends - 1; i++) + { + account2->friends[i] = account2->friends[i + 1]; + } + account2->numFriends--; + + printf("Success\n"); +} + +// List all friends of an account +void listFriends(char *emailAddress) +{ + Account *account = findAccount(emailAddress); + if (account == NULL) + { + printf("Error: Account Not Found\n"); + return; + } + + if (account->numFriends == 0) + { + printf("No Friend\n"); + return; + } + + for (int i = 0; i < account->numFriends; i++) + { + printf("%s %s", account->friends[i]->firstName, account->friends[i]->lastName); + + if (i < account->numFriends - 1) + { + printf(", "); + } + } + + printf("\n"); +} + +// List friend suggestions for an account +void listSuggestions(char *emailAddress) +{ + Account *account = findAccount(emailAddress); + if (account == NULL) + { + printf("Error: Account Not Found\n"); + return; + } + + if (account->numFriends == 0) + { + printf("No Friend Suggestion\n"); + return; + } + + Account *suggestions[MAX_ACCOUNTS]; + int numSuggestions = 0; + bool isSuggested; + + for (int i = 0; i < account->numFriends; i++) + { + Account *friend = account->friends[i]; + + for (int j = 0; j < friend->numFriends; j++) + { + Account *potentialFriend = friend->friends[j]; + + // Don't suggest self or existing friends + if (potentialFriend == account) continue; + bool isAlreadyFriend = false; + for (int k = 0; k < account->numFriends; k++) + { + if (account->friends[k] == potentialFriend) + { + isAlreadyFriend = true; + break; + } + } + + if (isAlreadyFriend) continue; + + // Check if already suggested + isSuggested = false; + for (int k = 0; k < numSuggestions; k++) + { + if (suggestions[k] == potentialFriend) + { + isSuggested = true; + break; + } + } + + if (!isSuggested && potentialFriend->isActive) + { + suggestions[numSuggestions++] = potentialFriend; + } + } + } + + if (numSuggestions == 0) + { + printf("No Friend Suggestion\n"); + return; + } + + for (int i = 0; i < numSuggestions; i++) + { + printf("%s %s", suggestions[i]->firstName, suggestions[i]->lastName); + if (i < numSuggestions - 1) + { + printf(", "); + } + } + printf("\n"); +} + +// Free the contents of the datastructures used +void freeAll() +{ + // Accounts array is statically allocated, no need to free individually + // Free hash table nodes + for (int i = 0; i < HASH_TABLE_SIZE; i++) + { + HashNode *current = accountHashTable[i]; + while (current != NULL) + { + HashNode *temp = current; + current = current->next; + free(temp); + } + accountHashTable[i] = NULL; + } + numAccounts = 0; +} + +int main() { + char input[64]; // Input operation name + char emailAddress[55]; // Email address of a person + char secondEmailAddress[55]; // Email address of another person + char firstName[25]; // First name of the person + char lastName[25]; // First name of the person + int numOperations; // The number of operations. + + // Initialize hash table + for (int i = 0; i < HASH_TABLE_SIZE; i++) + { + accountHashTable[i] = NULL; + } + + scanf("%d", &numOperations); + for (int i = 0; i < numOperations; i++) + { + scanf("\n%s", input); + if (strcmp(input, "New") == 0) + { + scanf(" %s %s %s", emailAddress, firstName, lastName); + newAccount(emailAddress, firstName, lastName); + } + else if (strcmp(input, "Delete") == 0) + { + scanf(" %s", emailAddress); + deleteAccount(emailAddress); + } + else if (strcmp(input, "Add") == 0) + { + scanf(" %s %s", emailAddress, secondEmailAddress); + addFriend(emailAddress, secondEmailAddress); + } + else if (strcmp(input, "Unfriend") == 0) + { + scanf(" %s %s", emailAddress, secondEmailAddress); + unfriend(emailAddress, secondEmailAddress); + } + else if (strcmp(input, "Friend") == 0) + { + scanf(" %s", emailAddress); + listFriends(emailAddress); + } + else if (strcmp(input, "Suggestion") == 0) + { + scanf(" %s", emailAddress); + listSuggestions(emailAddress); + } + } + freeAll(); + return 0; +} \ No newline at end of file