/*---- implementation file for my collection of linked list functions that use my Node class by: Sharon Tuttle last modified: 2022-11-01 - adding search_for, insert_after, delete_node 2022-10-27 - started with insert_at_front, print_list, and delete_list ----*/ #include <cstdlib> #include <iostream> #include <string> #include <cmath> #include "Node.h" #include "linked-list-functs.h" using namespace std; /*---- signature: insert_at_front: Node*& NodeDataType -> void purpose: expects a head pointer to a linked list that is PASSED BY REFERENCE, and a piece of data we want to "add" to the front of this list, has the side-effects of: * creating a new Node with this data * adding this new node to the FRONT of this list, CHANGING the address in the head pointer ARGUMENT ...and returns nothing tests: for: Node *start_here = NULL; insert_at_front(start_here, 47); afterwards: * start_here should point to a Node containing 47 and that Node should have a next data field of NULL if I THEN: insert_at_front(start_here, 36); afterwards: * start_here should point to a Node containing 36 and that Node should point to the Node containing 36 and the Node containing 36 should have a next data field of NULL ----*/ void insert_at_front(Node*& head_ptr, NodeDataType new_data) { // need a new Node to hold the new element Node *new_node_ptr; new_node_ptr = new Node(new_data); // to add this new node to the front of the list, // I have 2 cases: is the list currently // empty, or not? // I'm handling the empty case first if (head_ptr == NULL) { head_ptr = new_node_ptr; } // and if the list was not empty, handle that here else { // make the next data field of the new node // point to the CURRENT first node new_node_ptr->set_next(head_ptr); // NOW it is OK to change the head_ptr to // to the new node head_ptr = new_node_ptr; } } /*--- signature: print_list: Node* -> void purpose: expects a pointer to the beginning of a linked list, has the side effect of printing the data in each node to the screen on its own line, and returns nothing tests: for: Node *my_first; my_first = NULL; print_list(my_first); ...prints to the screen: List contents: ============== ============== if I then: insert_at_front(my_first, 12); insert_at_front(my_first, 700); insert_at_front(my_first, 15); print_list(my_first); ...prints to the screen: List contents: ============== 15 700 12 ============== ---*/ void print_list(Node* head_ptr) { cout << "List contents:" << endl; cout << "==============" << endl; // set up a pointer to help me "walk through" the list Node *curr_node_ptr; // start it where the current head_ptr is curr_node_ptr = head_ptr; while (curr_node_ptr != NULL) { cout << curr_node_ptr->get_data() << endl; curr_node_ptr = curr_node_ptr->get_next(); } cout << "==============" << endl; } /*--- signature: delete_list: Node*& -> int purpose: expects a pointer to a dynamic linked list PASSED BY REFERENCE, has the side-effect of freeing those list nodes and setting the argument pointer to NULL, and returns the number of list nodes freed. tests: if I have: Node *start_test = NULL; delete_list(start_test) == 0 if I have: insert_at_front(start_test, 400); insert_at_front(start_test, 300); insert_at_front(start_test, 200); insert_at_front(start_test, 100); delete_list(start_test) == 4 ---*/ int delete_list(Node*& head_ptr) { Node *curr_ptr; int num_freed = 0; curr_ptr = head_ptr; while (curr_ptr != NULL) { head_ptr = head_ptr->get_next(); delete curr_ptr; curr_ptr = head_ptr; num_freed++; } return num_freed; } /*---- signature: search_for: Node* NodeDataType -> Node* purpose: (this is one of MANY possible kinds of search functions for searching for something in a linked list!!) expects a pointer to the beginning of a linked list and a desired element value to search for in that list, and returns a pointer to the FIRST node in that list that contains this element (so -- if the element value is NOT in the list, it will return NULL) tests: for: Node *stuff = NULL; insert_at_front(stuff, 300); insert_at_front(stuff, 400); insert_at_front(stuff, 250); insert_at_front(stuff, 400); insert_at_front(stuff, 25); search_for(stuff, 10) == NULL search_for(stuff, 25) == stuff search_for(stuff, 400) == stuff->get_next() ---*/ Node* search_for(Node *start_ptr, NodeDataType desired_element) { bool found = false; Node* curr; curr = start_ptr; while ((curr != NULL) && (found == false)) { //cout << "IN SEARCH LOOP - curr->get_data(): " // << curr->get_data() << endl; if (curr->get_data() == desired_element) { found = true; // and notice that curr is pointing to // this node that has the desired data } else { curr = curr->get_next(); } } if (found == true) { return curr; } else { return NULL; } } /*--- one of MANY possible insert-in-middle function possibilities! signature: insert_after: Node* NodeDataType -> void purpose: expects a pointer to a node in a linked list and a desired element to add to the list AFTER the given node, has the side-effect of adding a new node with that desired element AFTER the given node (without losing elements after the given node), and returns nothing. tests: Node *stuff = NULL; insert_at_front(stuff, 300); insert_at_front(stuff, 400); insert_at_front(stuff, 250); insert_at_front(stuff, 400); insert_at_front(stuff, 25); Node *node_before = search_for(stuff, 250); insert_after(node_before, 8); if I call print_list(stuff); ....should see the elements 25, 400, 250, 8, 400, 300 node_before = search_for(stuff, 300); insert_after(node_before, 16); if I call print_list(stuff); ....should see the elements 25, 400, 250, 8, 400, 300, 16 ---*/ void insert_after(Node *existing_node, NodeDataType new_element) { Node *new_val_node; new_val_node = new Node(new_element, existing_node->get_next()); /* or if you prefer: Node *new_val_node = new Node; new_val_node->set_data(new_element); new_val_node->set_next( existing_node->get_next() ); */ existing_node->set_next(new_val_node); } /*--- signature: delete_node: Node*& Node*& -> void purpose: expects a pointer to the beginning of a linked list and a pointer to a node IN that list to be removed, BOTH PASS BY REF, has the side-effects of removing that mode from the list (changing the starting pointer to point to the 2nd element if it was the first node), and freeing that removed node's memory, and returns nothing. ---*/ void delete_node(Node*& head, Node*& node_to_remove) { // what if the node to remove is the first node? if (head == node_to_remove) { // change head to point to SECOND mode in list head = head->get_next(); delete node_to_remove; node_to_remove = NULL; } // what if node to remove is NOT the first node? else { Node *before; before = head; while (before->get_next() != node_to_remove) { before->set_next( before->get_next() ); } if (node_to_remove->get_next() == NULL) { before->set_next(NULL); } else { before->set_next( node_to_remove->get_next() ); } delete node_to_remove; node_to_remove = NULL; } }