C++ code. Uses a Binary Search Tree structure instead of a doubly linked list
#include <iostream> #include <string> #include <fstream> using namespace std; struct Address { int streetNumber; string street; string streetType; string city; string state; int zipcode; }; struct Contact { string firstName; string lastName; Address address; string phoneNumber; string emailAddress; string twitterHandle; Contact* next; Contact* prev; }; enum sortBy{ FIRST = 1, LAST, STREET, CITY, STATE, PHONE, EMAIL, TWITTER }; Contact* loadList(string fileName); Contact* remove_(Contact* contact); Contact* insert_(Contact* contact); void saveList(Contact* head, string fileName); Contact* navigateRolodex(Contact* start, Contact* end); void displayContact(Contact* contact); Contact* search(Contact* head); void addContact(Contact* & head); void removeContact(Contact* & head); void sort(Contact* & head); int main() { string fileName = "contacts.txt"; Contact* rolodex = loadList(fileName); if (rolodex != nullptr) { int command = 0; while (command != 6) { cout << "Welcome to Mr. Orme's Rolodex!" << endl; cout << "What would you like to do? " << endl; cout << "\t1. Naviagate through Rolodex" << endl; cout << "\t2. Search for a Contact" << endl; cout << "\t3. Sort Contacts" << endl; cout << "\t4. Add a Contact" << endl; cout << "\t5. Remove a Contact" << endl; cout << "\t6. Quit" << endl; cin >> command; switch (command) { case 1: navigateRolodex(rolodex, nullptr); break; case 2: search(rolodex); break; case 3: sort(rolodex); break; case 4: addContact(rolodex); break; case 5: removeContact(rolodex); break; case 6: break; default: cout << "Please enter a valid command!" << endl; break; } system("PAUSE"); system("CLS"); } } saveList(rolodex, fileName); } Contact * loadList(string fileName) { ifstream fin; fin.open(fileName); if (!fin.is_open() && !fin.eof()) { cout << "ERROR! No rolodex file! Exiting program" << endl; return nullptr; } Contact* head = nullptr; Contact * currNode = head; Contact * temp = nullptr; while (!fin.eof()) { temp = new Contact; temp->next = nullptr; temp->prev = nullptr; fin >> temp->firstName; fin >> temp->lastName; fin >> temp->address.streetNumber; fin >> temp->address.street; fin >> temp->address.streetType; fin >> temp->address.city; fin >> temp->address.state; fin >> temp->address.zipcode; fin >> temp->phoneNumber; fin >> temp->emailAddress; fin >> temp->twitterHandle; temp = remove_(temp); if (currNode == nullptr) { head = temp; currNode = head; } else { currNode->next = temp; temp->prev = currNode; currNode = currNode->next; } } fin.close(); return head; } //removes underscores from street name and city name Contact * remove_(Contact * contact) { for (int i = 0; i < contact->address.street.size(); i++) { if (contact->address.street[i] == '_') contact->address.street[i] = ' '; } for (int i = 0; i < contact->address.city.size(); i++) { if (contact->address.city[i] == '_') contact->address.city[i] = ' '; } return contact; } //replace spaces with underscores. Contact * insert_(Contact * contact) { for (int i = 0; i < contact->address.street.size(); i++) { if (contact->address.street[i] == ' ') contact->address.street[i] = '_'; } for (int i = 0; i < contact->address.city.size(); i++) { if (contact->address.city[i] == ' ') contact->address.city[i] = '_'; } return contact; } void saveList(Contact * head, string fileName) { ofstream fout; fout.open(fileName); Contact * currNode = head; while (currNode != nullptr) { currNode = insert_(currNode); fout << currNode->firstName << " "; fout << currNode->lastName << endl; fout << currNode->address.streetNumber << " "; fout << currNode->address.street << " "; fout << currNode->address.streetType << " "; fout << currNode->address.city << " "; fout << currNode->address.state << " "; fout << currNode->address.zipcode << endl; fout << currNode->phoneNumber << " "; fout << currNode->emailAddress << " "; fout << currNode->twitterHandle; if (currNode->next != nullptr) cout << endl; currNode = currNode->next; } fout.close(); } Contact* navigateRolodex(Contact * start, Contact * end) { //can't start navigating from nowhere. if (start == nullptr) return nullptr; //when end is nullptr, we want to go to the end of the list //so we need to change end to the last item of the list. if (end == nullptr) { end = start; while (end->next != nullptr) { end = end->next; } } Contact* currContact = start; char command = ' '; while (command != 'q') { system("CLS"); displayContact(currContact); cout << "<<(p)revious, (q)uit, (n)ext>>"; cin >> command; switch (command) { case 'p': if (currContact != start) { currContact = currContact->prev; } break; case 'n': if (currContact != end) { currContact = currContact->next; } break; case 'q': break; default: cout << "Invalid Command!" << endl; system("PAUSE"); break; } } return currContact; } void displayContact(Contact * contact) { cout << contact->firstName << " " << contact->lastName << endl << contact->address.streetNumber << " " << contact->address.street << " " << contact->address.streetType << endl << contact->address.city << ", " << contact->address.state << " " << contact->address.zipcode << endl << "Phone: " << contact->phoneNumber << " Email: " << contact->emailAddress << " Twitter: " << contact->twitterHandle << endl; } void displayMenu() { cout << "\t1. First Name" << endl << "\t2. Last Name" << endl << "\t3. Street" << endl << "\t4. City" << endl << "\t5. State" << endl << "\t6. Phone Number" << endl << "\t7. Email" << endl << "\t8. Twitter Handle" << endl << "\t9. CANCEL" << endl; } void addContact(Contact *& head) { //create new contact and make new head. Contact* temp = new Contact; temp->next = head; temp->prev = nullptr; head->prev = temp; head = temp; //get information cout << "Please enter the contact's information: " << endl; cout << "First and Last name: "; cin >> temp->firstName >> temp->lastName; cout << "Street (i.e. 123 W_Main St): "; cin >> temp->address.streetNumber >> temp->address.street >> temp->address.streetType; cout << "City (put an underscore _ between words): "; cin >> temp->address.city; do { cout << "State (2 letter abbreviation): "; cin >> temp->address.state; } while (temp->address.state.size() != 2); cout << "Zipcode: "; cin >> temp->address.zipcode; cout << "Phone (xxx-xxx-xxxx): "; cin >> temp->phoneNumber; cout << "Email Address: "; cin >> temp->emailAddress; cout << "Twitter Handle: "; cin >> temp->twitterHandle; remove_(temp); cout << "Contact Added!!!" << endl; system("PAUSE"); } void removeContact(Contact *& head) { cout << "How do you want to search for the contact: " << endl; Contact* toDelete = search(head); if (toDelete != nullptr) { system("CLS"); cout << "Are you sure you want to delete this contact (y/n):" << endl; displayContact(toDelete); char command = ' '; cin >> command; if (command == 'y' || command == 'Y') { if (toDelete == head) head = toDelete->next; if (toDelete->next != nullptr) toDelete->next->prev = toDelete->prev; if (toDelete->prev != nullptr) toDelete->prev->next = toDelete->next; delete toDelete; cout << "Contacted Deleted!!!" << endl; } else { cout << "Nothing deleted. Returning to main menu" << endl; } } system("PAUSE"); } void swap(Contact* & head, Contact* & contact1, Contact* contact2) { //deal with head. if (contact1 == head) { head = contact2; } else if (contact2 == head) { head = contact1; } //take care of other things pointing at swappers, but only if they are not adjacent. . . if (contact1->next != nullptr && contact1->next != contact2) contact1->next->prev = contact2; if (contact2->next != nullptr && contact2->next != contact1) contact2->next->prev = contact1; if (contact1->prev != nullptr && contact1->prev != contact2) contact1->prev->next = contact2; if (contact2->prev != nullptr && contact2->prev != contact1) contact2->prev->next = contact1; //take care of swappers previous and next if (contact1->next == contact2) //adjacent, option 1 { contact1->next = contact2->next; contact2->next = contact1; contact2->prev = contact1->prev; contact1->prev = contact2; } else if (contact2->next == contact1) //adjacent, option 2 { contact2->next = contact1->next; contact1->next = contact2; contact1->prev = contact2->prev; contact2->prev = contact1; } else // not adjacent { Contact * temp = contact1->next; contact1->next = contact2->next; contact2->next = temp; temp = contact1->prev; contact1->prev = contact2->prev; contact2->prev = temp; } contact1 = contact2; } void sort(Contact *& head, sortBy sortKey) { Contact* sorted = head; Contact* currContact = nullptr; Contact* smallest = nullptr; while (sorted != nullptr) { currContact = sorted; smallest = sorted; //find smallest while (currContact != nullptr) { bool smallestContact = false; switch (sortKey) { case FIRST: if (currContact->firstName < smallest->firstName) smallestContact = true; break; case LAST: if (currContact->lastName < smallest->lastName) smallestContact = true; break; case STREET: { string fullAddress = to_string(currContact->address.streetNumber) + " " + currContact->address.street + " " + currContact->address.streetType; string smallestFullAddress = to_string(smallest->address.streetNumber) + " " + smallest->address.street + " " + smallest->address.streetType; if (fullAddress < smallestFullAddress) smallestContact = true; break; } case CITY: if (currContact->address.city < smallest->address.city) smallestContact = true; break; case STATE: if (currContact->address.state < smallest->address.state) smallestContact = true; break; case PHONE: if (currContact->phoneNumber < smallest->phoneNumber) smallestContact = true; break; case EMAIL: if (currContact->emailAddress < smallest->emailAddress) smallestContact = true; break; case TWITTER: if (currContact->twitterHandle < smallest->twitterHandle) smallestContact = true; break; } if (smallestContact) { smallest = currContact; } currContact = currContact->next; } //swap swap(head, sorted, smallest); sorted = sorted->next; } } void sort(Contact* & head) { system("CLS"); cout << "Sort by: " << endl; displayMenu(); int command; cin >> command; if (command != 9) sort(head, (sortBy)command); } Contact* search(Contact * head) { system("CLS"); //options are same as sortBy enum!!! cout << "Search by: " << endl; displayMenu(); int command = 0; cin >> command; if (command != 9) { //sort the list sort(head, (sortBy)command); cout << "Search text: "; string searchString; cin >> searchString; //search the list Contact* start = nullptr, *end = nullptr, *currContact = head; bool found; do { found = false; switch (command) { case 1: if (currContact->firstName == searchString) found = true; break; case 2: if (currContact->lastName == searchString) found = true; break; case 3: { string fullAddress = to_string(currContact->address.streetNumber) + " " + currContact->address.street + " " + currContact->address.streetType; if (fullAddress == searchString) found = true; break; } case 4: if (currContact->address.city == searchString) found = true; break; case 5: if (currContact->address.state == searchString) found = true; break; case 6: if (currContact->phoneNumber == searchString) found = true; break; case 7: if (currContact->emailAddress == searchString) found = true; break; case 8: if (currContact->twitterHandle == searchString) found = true; break; } if (found) { if (start == nullptr) { start = currContact; end = currContact; //in case there is only one. . . } else { end = currContact; } } currContact = currContact->next; } while ((end == nullptr || found == true) && currContact != nullptr); if (start == nullptr && end == nullptr) { cout << searchString << " not found!!" << endl; return nullptr; } else { return(navigateRolodex(start, end)); } } }