/* 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; }