// DOUBLE.CPP // PHONE NUMBER DATABASE // An example of using a doubly-linked list. // compiler directives #include #include #include #include // global structures and variables struct friend_node { char last_name[20]; char first_name[15]; char phone_num[15]; friend_node *next; friend_node *previous; }; friend_node *head_ptr; friend_node *current_ptr; // function prototypes void handle_choice(int choice); void add_record(); void insert_node(friend_node *new_rec_ptr); friend_node *position_insertion_point(char lastname[20]); void make_node_new_head(friend_node *new_rec_ptr); void add_node_to_end(friend_node *new_rec_ptr); void move_current_to_end(); void display_list(); void delete_record(); void delete_head_of_list(); void delete_end_of_list(friend_node *previous_ptr); void delete_from_middle_of_list(friend_node *previous_ptr); int verify_delete(); void delete_node(friend_node *previous_ptr); void delete_list(); void search_by_lastname(); void display_next_record(); void display_previous_record(); void load_list_from_file(); void write_list_to_file(); // main function int main() { int choice; head_ptr = NULL; load_list_from_file(); current_ptr = head_ptr; do { cout << "\nFRIEND DATABASE\n"; cout << "0 - Exit program\n"; cout << "1 - Add record\n"; cout << "2 - Display all records\n"; cout << "3 - Search for friend by last name\n"; cout << "4 - Delete record\n"; cout << "5 - Display next record\n"; cout << "6 - Display previous record\n"; cout << "Enter choice: "; cin >> choice; handle_choice(choice); } while(choice != 0); return 0; } // end of main function // function to direct program flow based on user's choice void handle_choice(int choice) { switch(choice) { case 0: write_list_to_file(); if(head_ptr != NULL) { delete_list(); } break; case 1: add_record(); // add a record to the linked list break; case 2: display_list(); // display all records in linked list break; case 3: search_by_lastname(); // search for record by last name break; case 4: delete_record(); // search for record by last name break; case 5: display_next_record(); break; case 6: display_previous_record(); break; default : cout << "\nInvalid choice\n"; break; } } // function to add record to the linked list void add_record() { friend_node *new_rec_ptr; // Declare temporary pointer for the new node. new_rec_ptr = new friend_node; // Allocate memory for a new node and // initialize pointer to point to it. cin.ignore(80,'\n'); cout << "\nEnter a new record.\n"; cout << "Last Name: "; cin.get(new_rec_ptr->last_name,20); cin.ignore(80,'\n'); cout << "First Name: "; cin.get(new_rec_ptr->first_name,15); cin.ignore(80,'\n'); cout << "Phone Number: "; cin.get(new_rec_ptr->phone_num,15); cin.ignore(80,'\n'); insert_node(new_rec_ptr); } // Function to insert new node into correct position in list. void insert_node(friend_node *new_rec_ptr) { friend_node *before_ptr; friend_node *after_ptr; if(head_ptr == NULL) { // If no nodes exist, make the node new_rec_ptr->next = NULL; // the head. new_rec_ptr->previous = NULL; head_ptr = new_rec_ptr; } else { if(strcmp(new_rec_ptr->last_name, head_ptr->last_name) < 0) { // If new record comes before head, make_node_new_head(new_rec_ptr); // make it the new head. } else // Else, determine where the new node { // should be inserted. current_ptr = position_insertion_point(new_rec_ptr->last_name); before_ptr = current_ptr; // Use pointers to keep track of nodes after_ptr = current_ptr->next; // on each side of the insertion point. if(after_ptr == NULL) // If after_ptr is NULL, the node needs to be { // added to the end of the list. add_node_to_end(new_rec_ptr); } else // Else add the node between the nodes pointed to { // by before_ptr and after_ptr. before_ptr->next = new_rec_ptr; new_rec_ptr->next = after_ptr; new_rec_ptr->previous = before_ptr; after_ptr->previous = new_rec_ptr; } } } } // Function that positions current_ptr at the node before the position // where the new node should be inserted. friend_node *position_insertion_point(char lastname[20]) { char temp_name[20]; friend_node *temp_ptr; int tempint; if(head_ptr->next != NULL) // If more than one node exists, search the { // list for the correct insertion point. current_ptr = head_ptr; temp_ptr = current_ptr->next; strcpy(temp_name, temp_ptr->last_name); // Loop until the population of the node following current_ptr has // less population than the current node. tempint = strcmp(lastname,temp_name); while((tempint > 0) && (current_ptr->next !=NULL)) { current_ptr = temp_ptr; temp_ptr = current_ptr->next; strcpy(temp_name, temp_ptr->last_name); tempint = strcmp(lastname,temp_name); } } else // If only one node exists in the list, current_ptr is the same { // as head_ptr. New node will be added to the end of the list. current_ptr = head_ptr; } return(current_ptr); } // Function that makes the node pointed to by new_rec_ptr the new // head of the linked list. It handles the special case of inserting at // the front of the list. void make_node_new_head(friend_node *new_rec_ptr) { friend_node *temp_ptr; temp_ptr = head_ptr; temp_ptr->previous = new_rec_ptr; new_rec_ptr->next = temp_ptr; new_rec_ptr->previous = NULL; head_ptr = new_rec_ptr; } // Function that adds a node to the end of the linked list. It handles // the special case of inserting at the end of the list. void add_node_to_end(friend_node *new_rec_ptr) { new_rec_ptr->next = NULL; // Set next node pointer of new node to NULL. move_current_to_end(); // Make sure current_ptr is at end of list. current_ptr->next = new_rec_ptr; // Place new node at the end of the list. new_rec_ptr->previous = current_ptr; } // Function that moves current_ptr to end of the linked list. void move_current_to_end() { current_ptr = head_ptr; // Move current_ptr to head of the list. while(current_ptr->next != NULL) { // Traverse list until NULL is reached. current_ptr = current_ptr->next; } } // Function that displays entire linked list. void display_list() { char fullname[36]; // used to combine names into one array current_ptr = head_ptr; // Move current_ptr to head of list. if(current_ptr != NULL) { cout << endl; cout << "Friend Phone Number\n"; cout << "----------------------------------- ------------\n"; do { strcpy(fullname,""); // clear fullname strcat(fullname, current_ptr->last_name); // put last name in fullname strcat(fullname, ", "); // put comma in fullname strcat(fullname, current_ptr->first_name); // put first name in fullname cout.setf(ios::left); cout << setw(36) << fullname; cout.setf(ios::right); cout << setw(12) << current_ptr->phone_num << endl; current_ptr = current_ptr->next; // set current_ptr to point to next node } while(current_ptr != NULL); // loop until end of list } else { cout << "\nNO RECORDS TO DISPLAY\n"; } current_ptr = head_ptr; } // Function that deletes individual nodes from the linked list. void delete_record() { char search_string[20]; friend_node *previous_ptr; previous_ptr = NULL; // initialize previous_ptr to NULL current_ptr = head_ptr; // Move current_ptr to head of list // to begin search. cin.ignore(80,'\n'); cout << "\nEnter the last name of the friend you want to delete: "; cin.get(search_string,20); cin.ignore(80,'\n'); while((strcmp(current_ptr->last_name, search_string) != 0) && (current_ptr != NULL)) { previous_ptr = current_ptr; current_ptr = current_ptr->next; } if(current_ptr != NULL) // If current_ptr is not NULL, then match was { // found. cout << "\nRECORD FOUND\n"; cout << current_ptr->first_name << ' ' << current_ptr->last_name << endl; cout << current_ptr->phone_num << endl; if(verify_delete()) { delete_node(previous_ptr); cout << "\nRECORD DELETED\n"; } else { cout << "\nRECORD NOT DELETED\n"; } } else { cout << "\nNO MATCH FOUND. NO RECORD DELETED.\n"; } } // Function to ask user to verify intention to delete the node. int verify_delete() { char YesNo; cout << "\nDo you wish to delete this record? (Y/N) "; cin >> YesNo; if((YesNo == 'Y') || (YesNo == 'y')) { return(1); } else { return(0); } } // Function that deletes node pointed to by current_ptr. void delete_node(friend_node *previous_ptr) { if(current_ptr == head_ptr) { delete_head_of_list(); } else { if(current_ptr->next == NULL) { delete_end_of_list(previous_ptr); } else { delete_from_middle_of_list(previous_ptr); } } } //Function that deletes the head of the list. void delete_head_of_list() { current_ptr = head_ptr; if(head_ptr->next != NULL) { head_ptr = current_ptr->next; head_ptr->previous = NULL; } else { head_ptr = NULL; } delete current_ptr; } // Function that deletes the last node of the linked list. void delete_end_of_list(friend_node *previous_ptr) { delete current_ptr; previous_ptr->next = NULL; current_ptr = head_ptr; // Set current_ptr to head to give it a value. } // Function that deletes a node from the middle of the list. void delete_from_middle_of_list(friend_node *previous_ptr) { previous_ptr->next = current_ptr->next; current_ptr->next->previous = previous_ptr; delete current_ptr; current_ptr = head_ptr; } // Function that frees the memory used by the linked list. void delete_list() { friend_node *temp_ptr; // pointer used for temporary storage current_ptr = head_ptr; // Move current_ptr to head of the list. do // Traverse list until the end is reached. { temp_ptr = current_ptr->next; // Set temporary pointer to point // to the remainder of the list. delete current_ptr; // Delete current node. current_ptr = temp_ptr; // Set current_ptr to next node after the } while(temp_ptr != NULL); // deleted one. } // Function that searches linked list for the first occurrence of a given // last name and displays the record to the screen. void search_by_lastname() { char search_string[20]; // Character array for last name to search for. current_ptr = head_ptr; // Move current_ptr to head of list // to begin search. cin.ignore(80,'\n'); cout << "\nEnter the last name for which you want to search: "; cin.get(search_string,20); cin.ignore(80,'\n'); while((strcmp(current_ptr->last_name, search_string) != 0) && (current_ptr != NULL)) { current_ptr = current_ptr->next; } if(current_ptr != NULL) // If current_ptr is not NULL, then match was { // found. cout << "\nRECORD FOUND\n"; cout << current_ptr->first_name << ' ' << current_ptr->last_name << endl; cout << current_ptr->phone_num << endl; } else { cout << "\nNO MATCH FOUND\n"; } } // Function that allows the user to browse through records by displaying // the next record in the linked list. void display_next_record() { if(current_ptr->next != NULL) // If current_ptr is not { // already at the end of the current_ptr = current_ptr->next; // list, move current_ptr cout << current_ptr->first_name << ' ' // forward in the list and << current_ptr->last_name << endl; // display the data in the next cout << current_ptr->phone_num << endl; // node. } else // Otherwise, display message { // to alert user that the last cout << "\nLAST RECORD\n"; // record has been reached and cout << current_ptr->first_name << ' ' // display the last record << current_ptr->last_name << endl; // again. cout << current_ptr->phone_num << endl; } } // Function that allows the user to browse through records by displaying // the previous record in the linked list. void display_previous_record() { if(current_ptr->previous != NULL) // If current_ptr is not { // already at the beginning of current_ptr = current_ptr->previous; // the list, move current_ptr cout << current_ptr->first_name << ' ' // backward in the list and << current_ptr->last_name << endl; // display the data in the cout << current_ptr->phone_num << endl; // previous node. } else // Otherwise, display message { // to alert user that the first cout << "\nFIRST RECORD\n"; // record has been reached and cout << current_ptr->first_name << ' ' // display the first record << current_ptr->last_name << endl; // again. cout << current_ptr->phone_num << endl; } } // Function to load the linked list from the data file. void load_list_from_file() { friend_node *new_rec_ptr; ifstream infile; infile.open("FRIENDS.DAT",ios::in); // open file for input if (infile) // If no error occurred while opening file { // input the data from the file. do { new_rec_ptr = new friend_node; infile.get(new_rec_ptr->last_name,20); infile.ignore(80,'\n'); infile.get(new_rec_ptr->first_name, 15); infile.ignore(80,'\n'); infile.get(new_rec_ptr->phone_num, 15); infile.ignore(80,'\n'); if(strcmp(new_rec_ptr->last_name, "END OF FILE") != 0) { insert_node(new_rec_ptr); } else { delete new_rec_ptr; new_rec_ptr=NULL; } } while(new_rec_ptr!=NULL && strcmp(new_rec_ptr->last_name,"END OF FILE") != 0); infile.close(); } else // If error occurred, display message. { cout << "No usable data file located. List is empty.\n"; } } // Function to write linked list data to the data file. void write_list_to_file() { ofstream outfile; outfile.open("FRIENDS.DAT",ios::out); // open file for output if (outfile) { current_ptr = head_ptr; if(head_ptr != NULL) { do // Traverse list until the end is reached. { outfile << current_ptr->last_name << endl; outfile << current_ptr->first_name << endl; outfile << current_ptr->phone_num << endl; current_ptr = current_ptr->next; } while(current_ptr != NULL); } outfile << "END OF FILE" << endl; outfile.close(); } else { cout << "Error opening file.\n"; } }