Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // NOTE FOR PASTEBIN USERS: I went and attached both the main cpp file and the header file to this paste.
- // To get this program to work you need to cut out the circularlydoublylinkedlist.h
- // class towards the end of this file, and paste it into another file and then you
- // need to build a project including both the main file and the header file.
- // Oh yeah, also, you need a text file in the directory of the project/.exe. It
- // has to be named "input.txt". It can contain anything.
- // tl;dr: cut and paste the class file into a new file, and include it in a project.
- // And don't forget to make an input.txt
- /// Lab 3: A Text Editing Program Using a Circularly & Doubly Linked List
- /// 2014-2-3
- ///
- /// This program uses the class LinkedList, which makes a circularly doubly linked
- /// list. This means each node points forwards AND backwards. Additionally, the last
- /// node in the list points to the beginning of the list. Or rather, the dummy node in
- /// the list. That's right - not only is this program using a souped-up linked list,
- /// it's using a sentinel and dummy node too!
- ///
- ///
- ///
- // This program demonstrates the displayList member function.
- #include <iostream>
- #include <string>
- #include <fstream> // To read from an input file
- #include <sstream> // for string stream, used to transfer data from a string filled with getline()
- #include <cstring> // for c_str() and other functions
- #include "CircularlyDoublyLinkedList.h" // The name describes it pretty well.
- using namespace std;
- const int NUMCOMMANDS = 10;
- const string COMMANDS = "TFBILDSHAQ"; // commands stores all ten command codes.
- bool fillList(LinkedList<string> *list);
- void help();
- void menu (LinkedList<string> *list);
- bool getCommand(string &, LinkedList<string> *list);
- void deleteLines(LinkedList<string> *list, int, int);
- void listLines(LinkedList<string> *list, int a, int b);
- int main()
- {
- LinkedList<string> *list = new LinkedList<string>; //def a pointer to a linked list object, and then allocate the pointer.
- // call fillList to read from an input file into the linked list. if no file found, returns false and program ends.
- if(!fillList(list))
- return 1;
- menu(list);
- return 0;
- }
- // getCommand gets input, validates it and processes it. When the user enters q or Q, the function will return
- // false and the program will end.
- bool getCommand(string & command, LinkedList<string> *list)
- {
- command.clear(); // clear the string "command" so as not to get improper results
- bool flag = false; // flag will be used to see if the user enters a valid command
- int length; // for size of the input string
- string temp;
- stringstream stream; // used to transfer data from the string "command" to other containers, like int variables
- while(!flag)
- {
- cout << "Enter a command: ";
- getline(cin, command);
- length = command.length();
- stream << command; // store the input in a string stream for later extraction
- for (int i = 0; i < NUMCOMMANDS; i++)
- if (COMMANDS[i] == toupper(command[0])) // Compare each command code to the user string.
- flag = true;
- if (length == 1) // If the length of the string is 1, then skip all other checks and see if flag is true or false.
- continue;
- if (command[1] != 32 ) // See if the user seperated the command with a space. No space means improper input, skip to beginning of loop.
- {
- flag = false;
- continue;
- }
- // If the first character in the input is S or s, the program may save the file.
- if (command[0] == 'S' || command[0] == 's')
- {
- int pos = command.find(".txt");
- if (pos == length - 4)
- {
- flag = true;
- temp = (command.substr(2, string::npos));
- list->saveText(temp);
- }
- else
- cout << "Improper filename.\n";
- continue;
- }
- // If the first character in the input is L or l, the program may list line(s)
- if (toupper(command[0]) == 'L' || toupper(command[0]) == 'l')
- {
- int num1, num2;
- char temp;
- if (stream >> temp >> num1 >> num2)
- {
- flag = true;
- // Call list Lines and pass the line numbers.
- listLines(list, num1, num2);
- }
- continue;
- }
- // If the first character in the input is I or i, the program may inseert a line.
- if (toupper(command[0]) == 'I' || toupper(command[0]) == 'i')
- {
- int num1;
- char temp;
- if (stream >> temp >> num1 && getline(stream,command))
- {
- command.append(1,'\n');
- command = command.substr(1, string::npos); // Deletes the space trailing after the number
- // Call the insertNode function to insert the line
- list->insertNode(command, num1);
- flag = true;
- }
- continue;
- }
- // If the first character in the input is D or d, the program may delete line(s)
- if (toupper(command[0]) == 'D' || toupper(command[0]) == 'd')
- {
- int num1, num2;
- char temp;
- if (stream >> temp && stream >> num1 && stream >> num2)
- {
- flag = true;
- deleteLines(list, num1, num2);
- }
- continue;
- }
- cout << "Improper input.\n"; // If the loop gets this far, the input is wrong
- }
- if (toupper(command[0]) == 'Q') // Check to see if the user wants to quit
- return false;
- if (toupper(command[0]) == 'T') // List # lines in text
- cout << "There are " << list->getCount() << " lines.\n";
- if (toupper(command[0]) == 'F') // Print all lines
- list->displayList();
- if (toupper(command[0]) == 'B') // Print all lines backwards
- list->displayListReversed();
- if (toupper(command[0]) == 'H') // Display the help dialogue
- cout << "\n\n\n", help();
- if (toupper(command[0]) == 'A') // Display information about the super awesome, mega smert, #1 homework doer
- {
- cout << "Developer: Joseph Burger\n"
- << " cis22C: Data Structures\n"
- << " Winter 2014\n"
- << " De Anza College\n";
- }
- return true;
- }
- // ListLines lists lines a through b. If a > b, then the lines will be listed in reverse order.
- void listLines(LinkedList<string> *list, int a, int b)
- {
- int numlines;
- if(a < 1 || a > list->getCount() || b < 1 || b > list->getCount())
- {
- cout << "Invalid line numbers.\n";
- return;
- }
- if (a > b)
- numlines = a - b + 1;
- else
- numlines = b - a + 1;
- for (int i = 0; i < numlines; i++)
- {
- if (a > b)
- list->displayLine(a), a--; // I chose to use the comma operator to save 6 lines of space combined for this if/else block
- else
- list->displayLine(a), a++;
- }
- return;
- }
- // deleteLines calls the deleteLine function in the LinkedList class.
- // It calls it repeatedly, until it deletes lines a through b inclusive.
- void deleteLines(LinkedList<string> *list, int a, int b)
- {
- int numlines;
- if(a < 1 || a > list->getCount() || b < 1 || b > list->getCount())
- {
- cout << "Invalid line numbers.\n";
- return;
- }
- if (a > b)
- numlines = a - b + 1;
- else
- numlines = b - a + 1;
- for (int i = 0; i < numlines; i++)
- {
- if (a > b)
- list->deleteNode(b);
- else
- list->deleteNode(a);
- }
- return;
- }
- // menu displays the help menu, then the program goes into
- // a while loop that ends when the user enters q or Q, making
- // getCommand return false and ending the program.
- void menu (LinkedList<string> *list)
- {
- // Display the Help menu
- help();
- // Enter a loop that starts with an input validation function
- string command;
- while (getCommand(command, list)){};
- return;
- }
- // A help menu that is displayed once, and again whenever
- // the user enters h or H
- void help()
- {
- cout << "Instructions for listed commands:\n"
- << "T: Display the total number of lines.\n"
- << "F: Print all lines.\n"
- << "B: Print all lines in reverse order.\n"
- << "I <line number> <text>: Insert a new line with text\n"
- << " \"<text>\" at line number \"<line number>\".\n"
- << "L <line number 1> <line number 2>: List lines \n"
- << " \"<line number 1>\" through lines \"<line number 2>.\"\n"
- << "D <line number 1> <line number 2>: Delete lines \n"
- << " \"<line number 1>\" through lines \"<line number 2>.\"\n"
- << "S <output file name>: Save the current file under a new name.\n"
- << "H: Display this help menu.\n"
- << "A: Display information about the developer.\n"
- << "Q: Quit editing the file (without saving it).\n";
- return;
- }
- // fillList searches for a file called "input.txt" and then
- // reads from it, inserting lines one at a time into nodes
- // in the linked list.
- bool fillList(LinkedList<string> *list)
- {
- string line; //this string will take input from the file
- ifstream fIn; //create an ifstream object
- fIn.open("input.txt"); //open it
- if(!fIn.is_open()) //check to see if the file is open, if not, exiting
- {
- cout << "File not found. Ending program.\n";
- return 0;
- }
- while(!fIn.eof())
- {
- getline(fIn, line);
- line.append(1, '\n');
- list->insertNode(line);
- line.clear();
- }
- fIn.close();
- return true;
- }
- /// THIS IS THE CLASS FILE YOU NEED TO CUT AND PASTE THIS FROM HERE TO THE END, INTO A NEW FILE.
- /// AND YOU NEED TO MAKE A PROJECT AND INCLUDE THIS FILE. IF YOU DON'T KNOW HOW TO BUILD A PROJECT
- /// USING YOUR IDE, GOOD F*CKING LUCK
- // A class template for holding a linked list.
- // The node type is also a class template.
- #ifndef CIRCULARLYDOUBLYLINKEDLIST_H
- #define CIRCULARLYDOUBLYLINKEDLIST_H
- #include <iomanip>
- #include <fstream>
- //*********************************************
- // The ListNode class creates a type used to *
- // store a node of the linked list. *
- //*********************************************
- template <class T>
- class ListNode
- {
- public:
- T value; // Node value
- ListNode<T> *next; // Pointer to the next node
- ListNode<T> *prev; // Pointer to the previous node
- // Constructor
- ListNode (T nodeValue){ value = nodeValue; next = NULL; prev = NULL; }
- };
- //*********************************************
- // The SentinelNode class creates a type used to
- // point to the dummy node in the
- // linked list, and the number of elements.
- //*********************************************
- template <class T>
- class SentinelNode
- {
- public:
- ListNode<T> *head; // List head pointer
- ListNode<T> *prev; // Pointer to the end of the list
- int count; // Number of ListNodes in the Linked List
- SentinelNode() { head = prev = new ListNode<T>("Dummy Node"); count = 0; } // Constructor
- };
- //*********************************************
- // LinkedList class *
- //*********************************************
- template <class T>
- class LinkedList
- {
- private:
- SentinelNode<T> *sentPtr; // Pointer to the sentinel node
- public:
- // Constructor
- LinkedList(){ sentPtr = new SentinelNode<T>; sentPtr->head->next = sentPtr->head->prev = sentPtr->head; }
- // Destructor
- ~LinkedList();
- // Linked list operations
- int getCount() {return sentPtr->count;}
- void insertNode(T, int lineNumber = 0); // LineNumber is an optional parameter
- void deleteNode(int);
- void saveText(std::string);
- // search
- // other linked list operations ...
- // ...
- void displayLine(int lineNo) const;
- void displayList() const;
- void displayListReversed() const;
- };
- // savetext is similar to the display function, but instead of sending output
- // to the console, it sends the linked list to a file.
- template <class T>
- void LinkedList<T>::saveText(std::string name)
- {
- std::ofstream out;
- out.open(name.c_str());
- ListNode<T> *nodePtr; // To move through the list
- // Position nodePtr at the head of the list.
- nodePtr = sentPtr->head->next;
- // While nodePtr points to a node, traverse
- // the list.
- int counter = 1; // Counter will be used to show the line numbers
- while (nodePtr != sentPtr->head)
- {
- out << nodePtr->value; // Display the value in this node.
- nodePtr = nodePtr->next; // Move to the next node.
- counter++;
- }
- out.close();
- return;
- }
- //*********************************************
- // deleteNode walks to a node and deletes it.
- // deleteNode works for both the previous and next
- // pointers.
- //*********************************************
- template <class T>
- void LinkedList<T>::deleteNode(int lineNumber)
- {
- ListNode<T> *nodePtr; // To traverse the list
- ListNode<T> *previousNode; // To point to the previous node
- // Initialize nodePtr to 1st non-dummy node in the list
- nodePtr = sentPtr->head->next;
- previousNode = sentPtr->head; // Point previousNode to the dummy node in the list
- // Walk to the line to be deleted
- for (int i = 1; i < lineNumber; i++)
- {
- previousNode = nodePtr;
- nodePtr = nodePtr->next;
- }
- // If node-to-delete not found OR no nodes; I don't want to delete the head node!!!
- if (nodePtr == sentPtr->head)
- return;
- // Determine if the first node is the one. Will always be true when lineNumber == 1
- if (previousNode == sentPtr->head)
- {
- nodePtr = nodePtr->next;
- delete sentPtr->head->next;
- sentPtr->head->next = nodePtr; // make the dummy node point to the 2nd node in the list. Similar to sentPtr->head->next->next, only the program crashes if I put that instead.
- sentPtr->head->next->prev = previousNode; // Make the new 1st node in the list point backwards to the dummy node.
- }
- else
- {
- // otherwise (node-to-delete found & not first node)
- previousNode->next = nodePtr->next;
- nodePtr->next->prev = previousNode;
- delete nodePtr;
- }
- sentPtr->count--;
- return;
- }
- //**************************************************
- // The insertNode function inserts a node with *
- // newValue copied to its value member. *
- //**************************************************
- template <class T>
- void LinkedList<T>::insertNode(T newValue, int lineNumber)
- {
- ListNode<T> *newNode; // A new node
- ListNode<T> *nodePtr; // To traverse the list
- ListNode<T> *previousNode = sentPtr->head; // The previous node
- newNode = new ListNode<T>(newValue); // Allocate a new node and store newValue there.
- newNode->next = newNode->prev = sentPtr->head; // Point the newNode's head and prev to the dummy node
- nodePtr = sentPtr->head->next; // Position nodePtr at the head of list.
- // Skip all nodes whose value is less than newValue.
- if(!lineNumber)
- while (nodePtr != sentPtr->head)//sentPtr->head)
- {
- previousNode = nodePtr;
- nodePtr = nodePtr->next;
- }
- else
- for (int i = 1; i < lineNumber; i++)
- {
- previousNode = nodePtr;
- nodePtr = nodePtr->next;
- }
- // If the new node is to be the 1st in the list,
- // insert it before all other nodes.
- if (previousNode == sentPtr->head)//sentPtr->head)
- {
- sentPtr->head->next = newNode;
- newNode->prev = sentPtr->head; // Make the first non-dummy node in the list point backwards to the dummy node.
- }
- else // Otherwise insert after the previous node.
- {
- previousNode->next = newNode;
- newNode->prev = previousNode; // Make the new node point backwards to the previous node.
- }
- if (newNode->next == sentPtr->head) // If the node points forward to the dummy node, then the dummy node should point backwards to this new node.
- sentPtr->head->prev = newNode;
- newNode->next = nodePtr;
- sentPtr->count++;
- }
- //**************************************************
- // displayList shows the value stored in each node *
- // of the linked list pointed to by head. *
- //**************************************************
- template <class T>
- void LinkedList<T>::displayList() const
- {
- ListNode<T> *nodePtr; // To move through the list
- // Position nodePtr at the head of the list.
- nodePtr = sentPtr->head->next;
- // While nodePtr points to a node, traverse
- // the list.
- int counter = 1; // Counter will be used to show the line numbers
- while (nodePtr != sentPtr->head)
- {
- std::cout << std::setw(2) << std::left << counter << std::right << " " << nodePtr->value; // Display the value in this node.
- nodePtr = nodePtr->next; // Move to the next node.
- counter++;
- }
- return;
- }
- //**************************************************
- // displayList shows the value stored in each node *
- // of the linked list pointed to by head... IN REVERSE!!!!
- //**************************************************
- template <class T>
- void LinkedList<T>::displayListReversed() const
- {
- ListNode<T> *nodePtr; // To move through the list
- // Position nodePtr at the rear of the list.
- nodePtr = sentPtr->head->prev;
- // While nodePtr points to a node, traverse
- // the list.
- int counter = 1; // Counter will be used to show the line numbers
- while (nodePtr != sentPtr->head)
- {
- std::cout << std::setw(2) << std::left << counter << std::right << " " << nodePtr->value; // Display the value in this node.
- nodePtr = nodePtr->prev; // Move to the next node. IN REVERSE!!!
- counter++;
- }
- return;
- }
- // displayLine takes an int and walks through the linked list to
- // the corresponding node number, then displays that node's value.
- template <class T>
- void LinkedList<T>::displayLine(int lineNo) const
- {
- ListNode<T> *nodePtr = sentPtr->head->next; // Initialize nodePtr to point to the first non-dummy node.
- int counter; // I declared counter outside of the for-loop so that the cout statement could access counter.
- for (counter = 1; counter < lineNo; counter++) // Counter will be used to walk through the linked list
- nodePtr = nodePtr->next;
- std::cout << std::setw(2) << std::left << counter << std::right << " " << nodePtr->value; // Display the value in this node.
- return;
- }
- //**************************************************
- // Destructor *
- // This function deletes every node in the list. *
- //**************************************************
- template <class T>
- LinkedList<T>::~LinkedList()
- {
- ListNode<T> *nodePtr; // To traverse the list
- ListNode<T> *nextNode; // To point to the next node
- // Position nodePtr at the head of the list.
- nodePtr = sentPtr->head->next;
- // While nodePtr is not at the end of the list...
- while (nodePtr != sentPtr->head)
- {
- // Save a pointer to the next node.
- nextNode = nodePtr->next;
- // Delete the current node.
- delete nodePtr;
- // Position nodePtr at the next node.
- nodePtr = nextNode;
- }
- delete sentPtr->head;
- delete sentPtr;
- }
- #endif
Advertisement
Add Comment
Please, Sign In to add comment