├── README.md ├── Deque.cpp ├── BinarySearchTree.cpp ├── Dictionary.cpp ├── DoublyLinkedList.cpp └── Graph.cpp /README.md: -------------------------------------------------------------------------------- 1 | # Data Structures 2 | 3 | A collection of data structure/ADT implementations in C++. Includes binary trees, dictionaries, deque, doubly-linked lists, graphs (using an adjacency list), hash tables. Some implementations make use of the stack or queue ADT. 4 | -------------------------------------------------------------------------------- /Deque.cpp: -------------------------------------------------------------------------------- 1 | //Purpose: Implementing a deque (double-ended queue) using a doubly linked list 2 | #include 3 | using namespace std; 4 | 5 | class Node{ 6 | public: 7 | int key; 8 | Node *prev; 9 | Node *next; 10 | Node(int); 11 | }; 12 | 13 | Node::Node(int key){ 14 | this->key = key; 15 | this->prev = NULL; 16 | this->next = NULL; 17 | } 18 | 19 | class Deque{ 20 | public: 21 | Node *front; 22 | Node *back; 23 | void push_front(int); 24 | void push_back(int); 25 | int pop_front(); 26 | int pop_back(); 27 | int peek_front(); 28 | int peek_back(); 29 | void print(); 30 | Deque(); 31 | ~Deque(); 32 | }; 33 | 34 | Deque::Deque(){ 35 | this->front = NULL; 36 | this->back = NULL; 37 | } 38 | 39 | Deque::~Deque(){ 40 | cout << "Calling destructor" << endl; 41 | Node *curr = this->front; 42 | while(curr != NULL){ 43 | Node *temp = curr; 44 | curr = curr->next; 45 | delete temp; 46 | } 47 | } 48 | 49 | void Deque::push_front(int key){ 50 | Node *new_node = new Node(key); 51 | if(this->front == NULL){ 52 | this->front = new_node; 53 | this->back = new_node; 54 | } 55 | else{ 56 | this->front->prev = new_node; 57 | new_node->next = this->front; 58 | this->front = new_node; 59 | } 60 | } 61 | 62 | void Deque::push_back(int key){ 63 | Node *new_node = new Node(key); 64 | if(this->front == NULL){ 65 | this->front = new_node; 66 | this->back = new_node; 67 | } 68 | else{ 69 | this->back->next = new_node; 70 | new_node->prev = this->back; 71 | this->back = new_node; 72 | } 73 | } 74 | 75 | int Deque::pop_front(){ 76 | int key = -99999; 77 | if(this->front != NULL){ 78 | //if there is only one element in the deque 79 | if(this->front == this->back){ 80 | key = this->front->key; 81 | delete this->front; 82 | this->front = NULL; 83 | this->back = NULL; 84 | } 85 | else{ 86 | key = this->front->key; 87 | this->front = this->front->next; 88 | delete this->front->prev; 89 | this->front->prev = NULL; 90 | } 91 | } 92 | return key; 93 | } 94 | 95 | int Deque::pop_back(){ 96 | int key = -99999; 97 | if(this->front != NULL){ 98 | if(this->front == this->back){ 99 | key = this->front->key; 100 | delete this->front; 101 | this->front = NULL; 102 | this->back = NULL; 103 | } 104 | else{ 105 | key = this->back->key; 106 | this->back = this->back->prev; 107 | delete this->back->next; 108 | this->back->next = NULL; 109 | } 110 | } 111 | return key; 112 | } 113 | 114 | int Deque::peek_front(){ 115 | int key = -99999; 116 | if(this->front != NULL){ 117 | key = this->front->key; 118 | } 119 | return key; 120 | } 121 | 122 | int Deque::peek_back(){ 123 | int key = -99999; 124 | if(this->back != NULL){ 125 | key = this->back->key; 126 | } 127 | return key; 128 | } 129 | 130 | void Deque::print(){ 131 | Node *curr = this->front; 132 | while(curr != NULL){ 133 | cout << curr->key << " "; 134 | curr = curr->next; 135 | } 136 | cout << endl; 137 | } 138 | 139 | int main(){ 140 | Deque *d = new Deque(); 141 | d->push_front(1); 142 | d->push_back(2); 143 | d->push_back(3); 144 | d->push_front(0); 145 | d->pop_front(); 146 | d->pop_back(); 147 | d->print(); 148 | delete d; 149 | return 0; 150 | } 151 | -------------------------------------------------------------------------------- /BinarySearchTree.cpp: -------------------------------------------------------------------------------- 1 | //Purpose: Reviewing BST implementation in C++ 2 | #include 3 | using namespace std; 4 | 5 | class TreeNode{ 6 | public: 7 | TreeNode(int); 8 | int key; 9 | TreeNode *left; 10 | TreeNode *right; 11 | }; 12 | 13 | TreeNode::TreeNode(int key){ 14 | this->key = key; 15 | this->left = NULL; 16 | this->right = NULL; 17 | } 18 | 19 | class Node{ 20 | public: 21 | TreeNode *tnode; 22 | Node *next; 23 | Node(TreeNode *); 24 | }; 25 | 26 | Node::Node(TreeNode *tnode){ 27 | this->tnode = tnode; 28 | this->next = NULL; 29 | } 30 | 31 | class Queue{ 32 | Node *head; 33 | public: 34 | Queue(); 35 | Queue(TreeNode *); 36 | ~Queue(); 37 | void enqueue(TreeNode *); 38 | TreeNode *dequeue(); 39 | bool empty(); 40 | void print(); 41 | }; 42 | 43 | Queue::Queue(){ 44 | this->head = NULL; 45 | } 46 | 47 | Queue::Queue(TreeNode *tnode){ 48 | Node *node = new Node(tnode); 49 | this->head = node; 50 | } 51 | 52 | Queue::~Queue(){ 53 | Node *curr = this->head; 54 | while(curr != NULL){ 55 | Node *temp = curr; 56 | curr = curr->next; 57 | delete temp; 58 | temp = NULL; 59 | } 60 | } 61 | 62 | void Queue::enqueue(TreeNode *tnode){ 63 | Node *node = new Node(tnode); 64 | if(this->head == NULL){ 65 | this->head = node; 66 | } 67 | else{ 68 | Node *curr = this->head; 69 | while(curr->next != NULL){ 70 | curr = curr->next; 71 | } 72 | curr->next = node; 73 | } 74 | } 75 | 76 | TreeNode *Queue::dequeue(){ 77 | TreeNode *tnode = NULL; 78 | if(this->head != NULL){ 79 | tnode = this->head->tnode; 80 | Node *temp = this->head; 81 | this->head = this->head->next; 82 | delete temp; 83 | } 84 | return tnode; 85 | } 86 | 87 | bool Queue::empty(){ 88 | bool result = false; 89 | if(this->head == NULL){ 90 | result = true; 91 | } 92 | return result; 93 | } 94 | 95 | class BinaryTree{ 96 | TreeNode *root; 97 | bool search_tree(TreeNode *, int); 98 | void insert_tree(TreeNode *, int); 99 | void in_order(TreeNode *); 100 | void level_order(TreeNode *); 101 | void clean_up(TreeNode *); 102 | public: 103 | BinaryTree(); 104 | BinaryTree(int); 105 | ~BinaryTree(); 106 | //helper functions 107 | bool search(int); 108 | void insert(int); 109 | void traverse_in_order(); 110 | void traverse_level_order(); 111 | }; 112 | 113 | BinaryTree::BinaryTree(){ 114 | this->root = NULL; 115 | } 116 | 117 | BinaryTree::BinaryTree(int key){ 118 | this->root = new TreeNode(key); 119 | } 120 | 121 | void BinaryTree::clean_up(TreeNode *node){ 122 | //need to traverse post-order for cleaning up (deallocate child nodes first) 123 | if(node != NULL){ 124 | clean_up(node->left); 125 | clean_up(node->right); 126 | delete node; 127 | } 128 | } 129 | 130 | BinaryTree::~BinaryTree(){ 131 | //de-allocate all nodes 132 | clean_up(this->root); 133 | } 134 | 135 | bool BinaryTree::search(int key){ 136 | return this->search_tree(this->root, key); 137 | } 138 | 139 | //assumes bst ordering 140 | bool BinaryTree::search_tree(TreeNode *node, int key){ 141 | if(node == NULL){ 142 | return false; 143 | } 144 | else if(key < node->key){ 145 | return this->search_tree(node->left, key); 146 | } 147 | else if(key > node->key){ 148 | return this->search_tree(node->right, key); 149 | } 150 | else{ //key == node->key 151 | return true; 152 | } 153 | } 154 | 155 | void BinaryTree::insert(int key){ 156 | this->insert_tree(this->root, key); 157 | } 158 | 159 | void BinaryTree::insert_tree(TreeNode *node, int key){ 160 | if(node == NULL){ 161 | //node = new TreeNode(key); //assigning to node doesn't work 162 | this->root = new TreeNode(key); 163 | } 164 | else if(key < node->key && node->left == NULL){ 165 | //allocate new node 166 | node->left = new TreeNode(key); 167 | } 168 | else if(key >= node->key && node->right == NULL){ 169 | node->right = new TreeNode(key); 170 | } 171 | else{ 172 | if(key < node->key){ 173 | this->insert_tree(node->left, key); 174 | } 175 | else{ 176 | this->insert_tree(node->right, key); 177 | } 178 | } 179 | } 180 | 181 | void BinaryTree::traverse_in_order(){ 182 | this->in_order(this->root); 183 | } 184 | 185 | void BinaryTree::in_order(TreeNode *node){ 186 | if(node != NULL){ 187 | in_order(node->left); 188 | cout << node->key << endl; 189 | in_order(node->right); 190 | } 191 | } 192 | 193 | void BinaryTree::traverse_level_order(){ 194 | this->level_order(this->root); 195 | } 196 | 197 | void BinaryTree::level_order(TreeNode *root){ 198 | 199 | Queue *queue = new Queue(); 200 | TreeNode *current_v; 201 | queue->enqueue(root); 202 | 203 | while(!queue->empty()){ 204 | current_v = queue->dequeue(); 205 | cout << current_v->key << endl; 206 | if(current_v->left != NULL){ 207 | queue->enqueue(current_v->left); 208 | } 209 | if(current_v->right != NULL){ 210 | queue->enqueue(current_v->right); 211 | } 212 | } 213 | delete queue; 214 | } 215 | 216 | int main(){ 217 | BinaryTree *bst = new BinaryTree(); 218 | bst->insert(10); 219 | bst->insert(6); 220 | bst->insert(1); 221 | bst->insert(8); 222 | bst->insert(7); 223 | bst->insert(9); 224 | bst->insert(15); 225 | bst->insert(13); 226 | bst->insert(11); 227 | bst->insert(99); 228 | bst->traverse_level_order(); 229 | delete bst; 230 | return 0; 231 | } 232 | -------------------------------------------------------------------------------- /Dictionary.cpp: -------------------------------------------------------------------------------- 1 | //Purpose: Reviewing Dictionary ADT implementation using a hash table as the underlying data structure 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | //set number of buckets to a prime number 7 | #define NUM_BUCKETS 13 8 | #define ALPHABET_SIZE 128 //ascii characters only 9 | 10 | class Node{ 11 | public: 12 | string key; 13 | string value; 14 | Node *next; 15 | Node(string, string); 16 | }; 17 | 18 | Node::Node(string key, string value){ 19 | this->key = key; 20 | this->value = value; 21 | this->next = NULL; 22 | } 23 | 24 | class LinkedList{ 25 | Node *head; 26 | public: 27 | LinkedList(); 28 | LinkedList(string, string); 29 | ~LinkedList(); 30 | string get_value(string); 31 | void set_value(string, string); 32 | void insert(string, string); 33 | void remove(string); 34 | void print(); 35 | }; 36 | 37 | LinkedList::LinkedList(){ 38 | this->head = NULL; 39 | } 40 | 41 | LinkedList::LinkedList(string key, string value){ 42 | Node *node = new Node(key, value); 43 | this->head = node; 44 | } 45 | 46 | LinkedList::~LinkedList(){ 47 | Node *curr = this->head; 48 | while(curr != NULL){ 49 | Node *next = curr->next; 50 | delete curr; 51 | curr = next; 52 | } 53 | } 54 | 55 | string LinkedList::get_value(string key){ 56 | string value = ""; 57 | bool not_found = true; 58 | Node *curr = this->head; 59 | while(curr != NULL && not_found){ 60 | if(curr->key == key){ 61 | value = curr->value; 62 | not_found = false; 63 | } 64 | curr = curr->next; 65 | } 66 | return value; 67 | } 68 | 69 | void LinkedList::set_value(string key, string value){ 70 | Node *curr = this->head; 71 | bool not_set = true; 72 | while(curr != NULL && not_set){ 73 | if(curr->key == key){ 74 | curr->value = value; 75 | not_set = false; 76 | } 77 | curr = curr->next; 78 | } 79 | } 80 | 81 | void LinkedList::insert(string key, string value){ 82 | Node *node = new Node(key, value); 83 | node->next = this->head; 84 | this->head = node; 85 | } 86 | 87 | void LinkedList::remove(string key){ 88 | //to do 89 | } 90 | 91 | void LinkedList::print(){ 92 | Node *curr = this->head; 93 | while(curr != NULL){ 94 | cout << "(" << curr->key << ", " << curr->value << ")" << endl; 95 | curr = curr->next; 96 | } 97 | } 98 | 99 | class Dictionary{ 100 | //an array of LinkedList pointers 101 | LinkedList *list[NUM_BUCKETS]; 102 | int get_bucket_index(string); 103 | unsigned long get_hashed_value(string); 104 | void insert_bucket(int, string, string); 105 | void replace(int, string, string); 106 | public: 107 | string key; 108 | string value; 109 | Dictionary(); 110 | ~Dictionary(); 111 | string get(string); 112 | void insert(string, string); 113 | void print(); 114 | }; 115 | 116 | Dictionary::Dictionary(){ 117 | for(int i = 0; i < NUM_BUCKETS; i ++){ 118 | this->list[i] = new LinkedList(); 119 | } 120 | } 121 | 122 | Dictionary::~Dictionary(){ 123 | for(int i = 0; i < NUM_BUCKETS; i ++){ 124 | LinkedList *list = this->list[i]; 125 | delete list; 126 | this->list[i] = NULL; 127 | } 128 | } 129 | 130 | //use Horner's Rule to evaluate a polynomial in linear time, O(n) 131 | //this hash function is taken from the Algorithm Design Manual 132 | //unsigned long at 32 bits can store a max value of around 4.2 billion 133 | unsigned long Dictionary::get_hashed_value(string key){ 134 | unsigned long sum = 0; 135 | for(unsigned int i = 0; i < key.length(); i ++){ 136 | int val = key[i] - 'a'; 137 | sum = (sum * ALPHABET_SIZE) + val; 138 | } 139 | return sum; 140 | } 141 | 142 | int Dictionary::get_bucket_index(string key){ 143 | unsigned long hashed_value = get_hashed_value(key); 144 | int bucket_index = hashed_value % NUM_BUCKETS; 145 | return bucket_index; 146 | } 147 | 148 | string Dictionary::get(string key){ 149 | string value = ""; 150 | int bucket = get_bucket_index(key); 151 | if(bucket >= 0 && bucket < NUM_BUCKETS){ 152 | LinkedList *list = this->list[bucket]; 153 | value = list->get_value(key); 154 | } 155 | return value; 156 | } 157 | 158 | void Dictionary::insert_bucket(int bucket, string key, string value){ 159 | if(bucket >= 0 && bucket < NUM_BUCKETS){ 160 | LinkedList *list = this->list[bucket]; 161 | list->insert(key, value); 162 | } 163 | } 164 | 165 | void Dictionary::replace(int bucket, string key, string value){ 166 | if(bucket >= 0 && bucket < NUM_BUCKETS){ 167 | LinkedList *list = this->list[bucket]; 168 | list->set_value(key, value); 169 | } 170 | } 171 | 172 | void Dictionary::insert(string key, string value){ 173 | string existing_value = get(key); 174 | int index = get_bucket_index(key); 175 | if(existing_value.empty()){ 176 | insert_bucket(index, key, value); 177 | } 178 | else{ 179 | //if the key is already contained in the hash table, then just replace it's value 180 | replace(index, key, value); 181 | } 182 | } 183 | 184 | void Dictionary::print(){ 185 | for(int i = 0; i < NUM_BUCKETS; i ++){ 186 | LinkedList *list = this->list[i]; 187 | cout << "Bucket " << i << endl; 188 | list->print(); 189 | } 190 | } 191 | 192 | int main(){ 193 | Dictionary *dict = new Dictionary(); 194 | dict->insert("hello", "world"); 195 | dict->insert("goodbye", "planet"); 196 | dict->insert("noodle", "oodle"); 197 | dict->insert("goodbye", "jupiter"); 198 | cout << "Dictionary Contents:" << endl; 199 | dict->print(); 200 | cout << "Values:" << endl; 201 | cout << dict->get("noodle") << endl; 202 | cout << dict->get("goodbye") << endl; 203 | cout << dict->get("hello") << endl; 204 | delete dict; 205 | return 0; 206 | } 207 | -------------------------------------------------------------------------------- /DoublyLinkedList.cpp: -------------------------------------------------------------------------------- 1 | //Purpose: Implementing a Doubly Linked List 2 | #include 3 | using namespace std; 4 | 5 | class Node{ 6 | public: 7 | int key; 8 | Node *prev; 9 | Node *next; 10 | Node(int); 11 | }; 12 | 13 | Node::Node(int key){ 14 | this->key = key; 15 | this->prev = NULL; 16 | this->next = NULL; 17 | } 18 | 19 | class DoublyLinkedList{ 20 | public: 21 | Node *head; 22 | Node *tail; 23 | DoublyLinkedList(); 24 | ~DoublyLinkedList(); 25 | void insert(int); 26 | void insert_ordered(int); 27 | void remove(int); 28 | void traverse_forward(); 29 | void traverse_backward(); 30 | }; 31 | 32 | DoublyLinkedList::DoublyLinkedList(){ 33 | this->head = NULL; 34 | this->tail = NULL; 35 | } 36 | 37 | DoublyLinkedList::~DoublyLinkedList(){ 38 | Node *curr = this->head; 39 | while(curr != NULL){ 40 | Node *temp = curr; 41 | curr = curr->next; 42 | delete temp; 43 | } 44 | } 45 | 46 | void DoublyLinkedList::insert(int key){ 47 | Node *new_node = new Node(key); 48 | if(this->head == NULL){ 49 | this->head = new_node; 50 | this->tail = new_node; 51 | } 52 | else{ 53 | new_node->next = this->head; 54 | this->head->prev = new_node; 55 | this->head = new_node; 56 | } 57 | } 58 | 59 | void DoublyLinkedList::insert_ordered(int key){ 60 | Node *new_node = new Node(key); 61 | if(this->head == NULL){ //if list is empty 62 | this->head = new_node; 63 | this->tail = new_node; 64 | } 65 | //implement all cases, then cut down any duplicate code 66 | //coding all cases gives extra assurance that we have 67 | //not missed any cases, then we can optimize further 68 | /* 69 | else if(this->head == this->tail){ 70 | Node *first = this->head; 71 | if(first->key >= key){ 72 | new_node->next = first; 73 | first->prev = new_node; 74 | this->head = new_node; 75 | } 76 | else{ 77 | new_node->prev = first; 78 | first->next = new_node; 79 | this->tail = new_node; 80 | } 81 | } 82 | */ 83 | else{ 84 | bool found_greater = false; 85 | Node *curr = this->head; 86 | Node *target = NULL; 87 | while(curr != NULL && !found_greater){ 88 | if(curr->key >= key){ 89 | found_greater = true; 90 | target = curr; 91 | } 92 | curr = curr->next; 93 | } 94 | if(found_greater){ 95 | if(this->head == target){ //insert at beginning of the list 96 | new_node->next = target; 97 | target->prev = new_node; 98 | this->head = new_node; 99 | } 100 | /* 101 | else if(this->tail == target){ 102 | new_node->next = target; 103 | new_node->prev = target->prev; 104 | target->prev->next = new_node; 105 | target->prev = new_node; 106 | } 107 | */ 108 | else{ //insert in middle of the list 109 | new_node->next = target; 110 | new_node->prev = target->prev; 111 | target->prev->next = new_node; 112 | target->prev = new_node; 113 | } 114 | } 115 | else{ //insert at end of the list 116 | new_node->prev = this->tail; 117 | this->tail->next = new_node; 118 | this->tail = new_node; 119 | } 120 | } 121 | } 122 | 123 | void DoublyLinkedList::remove(int key){ 124 | if(this->head != NULL){ //verify that list is not empty 125 | if(this->head == this->tail){ //if list has a single node 126 | Node *temp = this->head; 127 | this->head = NULL; 128 | this->tail = NULL; 129 | delete temp; 130 | } 131 | else if(this->head->key == key){ //if the node to delete is the head node 132 | Node *temp = this->head; 133 | this->head = this->head->next; 134 | this->head->prev = NULL; 135 | delete temp; 136 | } 137 | else if(this->tail->key == key){ //if the node to delete is a tail node 138 | Node *temp = this->tail; 139 | this->tail->prev->next = NULL; 140 | this->tail = this->tail->prev; 141 | delete temp; 142 | } 143 | else{ //if the node to delete is in the middle of the list 144 | bool found = false; 145 | Node *curr = this->head; 146 | Node *target = NULL; 147 | while(curr != NULL && !found){ 148 | if(curr->key == key){ 149 | found = true; 150 | target = curr; 151 | } 152 | curr = curr->next; 153 | } 154 | if(found){ 155 | target->prev->next = target->next; 156 | target->next->prev = target->prev; 157 | delete target; 158 | } 159 | } 160 | } 161 | } 162 | 163 | void DoublyLinkedList::traverse_forward(){ 164 | Node *curr = this->head; 165 | while(curr != NULL){ 166 | cout << curr->key << " "; 167 | curr = curr->next; 168 | } 169 | cout << endl; 170 | } 171 | 172 | void DoublyLinkedList::traverse_backward(){ 173 | Node *curr = this->tail; 174 | while(curr != NULL){ 175 | cout << curr->key << " "; 176 | curr = curr->prev; 177 | } 178 | cout << endl; 179 | } 180 | 181 | int main(){ 182 | DoublyLinkedList *list = new DoublyLinkedList(); 183 | list->insert_ordered(10); 184 | list->insert_ordered(1); 185 | list->insert_ordered(99); 186 | list->insert_ordered(5); 187 | list->insert_ordered(2); 188 | list->insert_ordered(98); 189 | list->insert_ordered(95); 190 | list->insert_ordered(-95); 191 | list->traverse_forward(); 192 | delete list; 193 | return 0; 194 | } 195 | -------------------------------------------------------------------------------- /Graph.cpp: -------------------------------------------------------------------------------- 1 | //Purpose: Reviewing graph implementation using an adjacency list (good for sparse and most graph problems) 2 | //the other alternative is an adjacency matrix which is good for dense graphs 3 | #include 4 | using namespace std; 5 | 6 | #define MAXV 1000 //maximum number of vertices 7 | 8 | class Node{ 9 | public: 10 | int key; 11 | Node *next; 12 | Node(int); 13 | }; 14 | 15 | Node::Node(int key){ 16 | this->key = key; 17 | this->next = NULL; 18 | } 19 | 20 | class Queue{ 21 | Node *head; 22 | public: 23 | Queue(); 24 | Queue(int); 25 | ~Queue(); 26 | void enqueue(int); 27 | int dequeue(); 28 | bool empty(); 29 | void print(); 30 | }; 31 | 32 | Queue::Queue(){ 33 | this->head = NULL; 34 | } 35 | 36 | Queue::Queue(int key){ 37 | Node *node = new Node(key); 38 | this->head = node; 39 | } 40 | 41 | Queue::~Queue(){ 42 | Node *curr = this->head; 43 | while(curr != NULL){ 44 | Node *temp = curr; 45 | curr = curr->next; 46 | delete temp; 47 | temp = NULL; 48 | } 49 | } 50 | 51 | void Queue::enqueue(int key){ 52 | Node *node = new Node(key); 53 | if(this->head == NULL){ 54 | this->head = node; 55 | } 56 | else{ 57 | Node *curr = this->head; 58 | while(curr->next != NULL){ 59 | curr = curr->next; 60 | } 61 | curr->next = node; 62 | } 63 | } 64 | 65 | int Queue::dequeue(){ 66 | int value = -1; 67 | if(this->head != NULL){ 68 | value = this->head->key; 69 | Node *temp = this->head; 70 | this->head = this->head->next; 71 | delete temp; 72 | } 73 | return value; 74 | } 75 | 76 | bool Queue::empty(){ 77 | bool result = false; 78 | if(this->head == NULL){ 79 | result = true; 80 | } 81 | return result; 82 | } 83 | 84 | void Queue::print(){ 85 | Node *curr = this->head; 86 | while(curr != NULL){ 87 | cout << curr->key << endl; 88 | curr = curr->next; 89 | } 90 | } 91 | 92 | class EdgeNode{ 93 | public: 94 | int key; 95 | int weight; 96 | EdgeNode *next; 97 | EdgeNode(int); 98 | EdgeNode(int, int); 99 | }; 100 | 101 | EdgeNode::EdgeNode(int key){ 102 | this->key = key; 103 | this->weight = 0; 104 | this->next = NULL; 105 | } 106 | 107 | EdgeNode::EdgeNode(int key, int weight){ 108 | this->key = key; 109 | this->weight = weight; 110 | this->next = NULL; 111 | } 112 | 113 | class Graph{ 114 | 115 | EdgeNode *edges[MAXV + 1]; 116 | int degree[MAXV + 1]; 117 | int nedges; 118 | bool directed; 119 | 120 | //data members for graph traversal 121 | bool processed[MAXV + 1]; //which vertices have been processed 122 | bool discovered[MAXV + 1]; //which vertices have been found 123 | int parent[MAXV + 1]; //discovery relation 124 | 125 | //function members for graph traversal 126 | void initialize_search(); 127 | void process_vertex_early(int); 128 | void process_vertex_late(int); 129 | void process_edge(int, int); 130 | 131 | public: 132 | Graph(bool); 133 | ~Graph(); 134 | void insert_edge(int, int, bool); 135 | void print_graph(); 136 | void breadth_first_search(int); 137 | void depth_first_search(int); 138 | void find_path(int, int); 139 | }; 140 | 141 | Graph::Graph(bool directed){ 142 | 143 | this->nedges = 0; 144 | this->directed = directed; 145 | 146 | for(int i = 0; i <= MAXV; i ++){ 147 | this->edges[i] = NULL; 148 | this->degree[i] = 0; 149 | } 150 | } 151 | 152 | Graph::~Graph(){ 153 | for(int i = 0; i <= MAXV; i ++){ 154 | EdgeNode *e = this->edges[i]; 155 | while(e != NULL){ 156 | EdgeNode *temp = e; 157 | e = e->next; 158 | delete temp; 159 | temp = NULL; 160 | } 161 | } 162 | } 163 | 164 | void Graph::insert_edge(int x, int y, bool directed){ 165 | 166 | //create new edge 167 | EdgeNode *edge = new EdgeNode(y); 168 | //insert new edge as the head of the list 169 | edge->next = this->edges[x]; 170 | this->edges[x] = edge; 171 | this->degree[x] ++; 172 | 173 | if(!directed){ 174 | insert_edge(y, x, true); 175 | } 176 | else{ 177 | this->nedges ++; 178 | } 179 | } 180 | 181 | void Graph::print_graph(){ 182 | //interate through vertices 183 | for(int v; v <= MAXV; v ++){ 184 | if(this->degree[v] > 0){ 185 | //interate through edges of the vertex 186 | cout << "Vertex " << v << endl; 187 | EdgeNode *e = this->edges[v]; 188 | while(e != NULL){ 189 | cout << e->key << endl; 190 | e = e->next; 191 | } 192 | } 193 | } 194 | } 195 | 196 | void Graph::process_vertex_early(int v){ 197 | cout << "Processed vertex " << v << endl; 198 | } 199 | 200 | void Graph::process_vertex_late(int v){ 201 | } 202 | 203 | void Graph::process_edge(int x, int y){ 204 | cout << "Processed edge (" << x << "," << y << ")" << endl; 205 | } 206 | 207 | void Graph::initialize_search(){ 208 | for(int i = 0; i <= MAXV; i ++){ 209 | this->processed[i] = false; 210 | this->discovered[i] = false; 211 | this->parent[i] = -1; 212 | } 213 | } 214 | 215 | void Graph::breadth_first_search(int start_vertex){ 216 | 217 | initialize_search(); 218 | Queue *queue = new Queue(); //queue of vertices still left to visit 219 | int current_v; //current vertex 220 | EdgeNode *p; //temporary pointer 221 | 222 | queue->enqueue(start_vertex); 223 | this->discovered[start_vertex] = true; 224 | 225 | while(!queue->empty()){ 226 | current_v = queue->dequeue(); 227 | process_vertex_early(current_v); 228 | p = this->edges[current_v]; 229 | while(p != NULL){ 230 | int neighbor_v = p->key; 231 | if(!this->discovered[neighbor_v]){ 232 | //add to Q and set to discovered 233 | queue->enqueue(neighbor_v); 234 | this->discovered[neighbor_v] = true; 235 | this->parent[neighbor_v] = current_v; 236 | } 237 | if(!this->processed[neighbor_v] || this->directed){ 238 | process_edge(current_v, neighbor_v); 239 | } 240 | p = p->next; 241 | } 242 | this->processed[current_v] = true; 243 | } 244 | delete queue; 245 | initialize_search(); 246 | } 247 | 248 | //DFS is similar to BFS with the difference being the order in which vertices are explored 249 | //main difference is that DFS uses a stack instead of a queue 250 | //DFS is done recursively to make use of the implicit stack from recursion 251 | //as opposed to an iterative DFS with an explicit stack 252 | void Graph::depth_first_search(int start_vertex){ 253 | 254 | int current_v = start_vertex; 255 | this->discovered[current_v] = true; 256 | EdgeNode *p = this->edges[current_v]; 257 | process_vertex_early(current_v); 258 | 259 | while(p != NULL){ 260 | int neighbor_v = p->key; 261 | if(!this->discovered[neighbor_v]){ 262 | //this->discovered[neighbor_v] = true; 263 | this->parent[neighbor_v] = current_v; 264 | process_edge(current_v, neighbor_v); 265 | depth_first_search(neighbor_v); 266 | } 267 | //2nd case is needed because 1st case isn't enough to visit all edges (because 1st case sets all neighbors 268 | //to discovered which excludes some visits to edges later) 269 | else if(((!this->processed[neighbor_v]) && (this->parent[current_v] != neighbor_v)) || (this->directed)){ 270 | process_edge(current_v, neighbor_v); 271 | } 272 | p = p->next; 273 | } 274 | this->processed[current_v] = true; 275 | } 276 | 277 | /* 278 | void Graph::find_path(int start, int end){ 279 | cout << end << endl; 280 | if(start != end){ 281 | find_path(start, this->parent[end]); 282 | } 283 | } 284 | */ 285 | 286 | int main(){ 287 | Graph *g = new Graph(false); 288 | g->insert_edge(1, 2, false); 289 | g->insert_edge(1, 5, false); 290 | g->insert_edge(1, 6, false); 291 | g->insert_edge(2, 5, false); 292 | g->insert_edge(2, 3, false); 293 | g->insert_edge(5, 4, false); 294 | g->insert_edge(3, 4, false); 295 | g->print_graph(); 296 | //g->breadth_first_search(1); 297 | g->depth_first_search(1); 298 | delete g; 299 | return 0; 300 | } 301 | --------------------------------------------------------------------------------