CSCI-1200 Data Structures Test 3 Practice Problem Solutions

Similar documents
CSCI-1200 Data Structures Fall 2018 Lecture 19 Trees, Part III

CSCI-1200 Data Structures Spring 2015 Lecture 20 Trees, Part III

CSCI-1200 Data Structures Fall 2014 Lecture 18 Trees, Part III

CSCI-1200 Data Structures Spring 2018 Lecture 18 Trees, Part III

CSCI-1200 Data Structures Fall 2018 Lecture 21 Hash Tables, part 1

CSCI-1200 Data Structures Fall 2017 Lecture 18 Trees, Part II

CSCI-1200 Data Structures Spring 2015 Lecture 18 Trees, Part I

CSCI-1200 Data Structures Fall 2017 Lecture 17 Trees, Part I

CSCI-1200 Data Structures Spring 2018 Lecture 16 Trees, Part I

CSCI-1200 Data Structures Test 3 Practice Problems

CSCI-1200 Data Structures Fall 2017 Test 3 Solutions

Final Exam. Name: Student ID: Section: Signature:

CSCI-1200 Data Structures Fall 2015 Lecture 24 Hash Tables

Final Exam Solutions PIC 10B, Spring 2016

CSCI-1200 Data Structures Spring 2014 Lecture 19 Hash Tables

CSCI-1200 Data Structures Fall 2018 Lecture 22 Hash Tables, part 2 & Priority Queues, part 1

Lecture 2. Binary Trees & Implementations. Yusuf Pisan

Chapter 20: Binary Trees

CSCI-1200 Data Structures Fall 2017 Test 1 Solutions

CSCI-1200 Data Structures Spring 2018 Lecture 7 Order Notation & Basic Recursion

CSCI-1200 Data Structures Test 3 Practice Problems

CSCI-1200 Data Structures Fall 2017 Lecture 5 Pointers, Arrays, & Pointer Arithmetic

CSCI-1200 Data Structures Fall 2018 Lecture 5 Pointers, Arrays, & Pointer Arithmetic

Computer Science II Lecture 2 Strings, Vectors and Recursion

Figure 1. A breadth-first traversal.

CSCI-1200 Data Structures Spring 2016 Lecture 22 Priority Queues, part II (& Functors)

Trees. Chapter 6. strings. 3 Both position and Enumerator are similar in concept to C++ iterators, although the details are quite different.

CSCI-1200 Data Structures Spring 2018 Lecture 14 Associative Containers (Maps), Part 1 (and Problem Solving Too)

LECTURE 11 TREE TRAVERSALS

CS102 Binary Search Trees

CSCI-1200 Data Structures Spring 2016 Lecture 7 Iterators, STL Lists & Order Notation

Uses for Trees About Trees Binary Trees. Trees. Seth Long. January 31, 2010

CSE 250 Final Exam. Fall 2013 Time: 3 hours. Dec 11, No electronic devices of any kind. You can open your textbook and notes

Solution to CSE 250 Final Exam

Data Structures CSci 1200 Test 1 Questions

CSCI-1200 Data Structures Spring 2017 Lecture 5 Pointers, Arrays, Pointer Arithmetic

CSCI-1200 Data Structures Fall 2017 Lecture 9 Iterators & STL Lists

! Tree: set of nodes and directed edges. ! Parent: source node of directed edge. ! Child: terminal node of directed edge

- 1 - Handout #22S May 24, 2013 Practice Second Midterm Exam Solutions. CS106B Spring 2013

CSE100. Advanced Data Structures. Lecture 4. (Based on Paul Kube course materials)

COSC 2007 Data Structures II Final Exam. Part 1: multiple choice (1 mark each, total 30 marks, circle the correct answer)

CS 104 (Spring 2014) Final Exam 05/09/2014

CSCI-1200 Data Structures Fall 2018 Lecture 23 Priority Queues II

CSCI-1200 Data Structures Fall 2017 Lecture 7 Order Notation & Basic Recursion

SETS AND MAPS. Chapter 9

Data Structures CSci 1200 Test 2 Questions

CSCI Trees. Mark Redekopp David Kempe

SELF-BALANCING SEARCH TREES. Chapter 11

Module 4: Index Structures Lecture 13: Index structure. The Lecture Contains: Index structure. Binary search tree (BST) B-tree. B+-tree.

CSCI-1200 Data Structures Fall 2014 Lecture 8 Iterators

Binary Search Trees. Contents. Steven J. Zeil. July 11, Definition: Binary Search Trees The Binary Search Tree ADT...

Trees. CptS 223 Advanced Data Structures. Larry Holder School of Electrical Engineering and Computer Science Washington State University

CS301 - Data Structures Glossary By

Computer Science II CSci 1200 Test 1 Overview and Practice

PIC10B/1 Winter 2014 Final Exam Study Guide

CSE 332 Autumn 2013: Midterm Exam (closed book, closed notes, no calculators)

CSCI-401 Examlet #5. Name: Class: Date: True/False Indicate whether the sentence or statement is true or false.

CSCI-1200 Data Structures Fall 2010 Lecture 8 Iterators

Basic program The following is a basic program in C++; Basic C++ Source Code Compiler Object Code Linker (with libraries) Executable

CSCI-1200 Data Structures Fall 2009 Lecture 20 Hash Tables, Part II

Trees. A tree is a directed graph with the property

Binary Trees. Examples:

TREES Lecture 10 CS2110 Spring2014

Trees, Part 1: Unbalanced Trees

Tree: non-recursive definition. Trees, Binary Search Trees, and Heaps. Tree: recursive definition. Tree: example.

COMP : Trees. COMP20012 Trees 219

CSCI-1200 Data Structures Fall 2013 Lecture 9 Iterators & Lists

CMSC 341 Lecture 10 Binary Search Trees

Computer Science Foundation Exam

Why Do We Need Trees?

Trees. (Trees) Data Structures and Programming Spring / 28

3137 Data Structures and Algorithms in C++

void insert( Type const & ) void push_front( Type const & )

Outline. Preliminaries. Binary Trees Binary Search Trees. What is Tree? Implementation of Trees using C++ Tree traversals and applications

FINALTERM EXAMINATION Fall 2009 CS301- Data Structures Question No: 1 ( Marks: 1 ) - Please choose one The data of the problem is of 2GB and the hard

CSCI-1200 Data Structures Fall 2017 Lecture 23 Functors & Hash Tables, part II

Binary Trees. Height 1

MARKING KEY The University of British Columbia MARKING KEY Computer Science 260 Midterm #2 Examination 12:30 noon, Thursday, March 15, 2012

CSCI-1200 Computer Science II Fall 2006 Lecture 23 C++ Inheritance and Polymorphism

CSE100 Practice Final Exam Section C Fall 2015: Dec 10 th, Problem Topic Points Possible Points Earned Grader

C++ Basics. Data Processing Course, I. Hrivnacova, IPN Orsay

Review of the Lectures 21-26, 30-32

MID TERM MEGA FILE SOLVED BY VU HELPER Which one of the following statement is NOT correct.

Part I: Short Answer (12 questions, 65 points total)

CS 231 Data Structures and Algorithms Fall Recursion and Binary Trees Lecture 21 October 24, Prof. Zadia Codabux

CS302 Data Structures using C++

Hash Tables. CS 311 Data Structures and Algorithms Lecture Slides. Wednesday, April 22, Glenn G. Chappell

Tutorial AVL TREES. arra[5] = {1,2,3,4,5} arrb[8] = {20,30,80,40,10,60,50,70} FIGURE 1 Equivalent Binary Search and AVL Trees. arra = {1, 2, 3, 4, 5}

8. Write an example for expression tree. [A/M 10] (A+B)*((C-D)/(E^F))

CSE 143. Complexity Analysis. Program Efficiency. Constant Time Statements. Big Oh notation. Analyzing Loops. Constant Time Statements (2) CSE 143 1

4. Trees. 4.1 Preliminaries. 4.2 Binary trees. 4.3 Binary search trees. 4.4 AVL trees. 4.5 Splay trees. 4.6 B-trees. 4. Trees

Trees : Part 1. Section 4.1. Theory and Terminology. A Tree? A Tree? Theory and Terminology. Theory and Terminology

CSE 332 Winter 2015: Midterm Exam (closed book, closed notes, no calculators)

CSCI-1200 Data Structures Spring 2018 Lecture 10 Vector Iterators & Linked Lists

Chapter 12: Indexing and Hashing. Basic Concepts

CSCE 2014 Final Exam Spring Version A

Student number: Datenstrukturen & Algorithmen page 1

CS106X Handout 35 Winter 2018 March 12 th, 2018 CS106X Midterm Examination

BBM 201 Data structures

CSCI 104 Binary Trees / Priority Queues / Heaps. Mark Redekopp Michael Crowley

Transcription:

1 Short Answer [ /21] CSCI-1200 Data Structures Test 3 Practice Problem Solutions 1.1 TreeNode Parent Pointers [ /5] In our initial version of the ds set class, the TreeNode object had 3 member variables: the value, and pointers to the left and right sub-trees. Why did we later add a parent pointer to each TreeNode object? Write 2-3 concise and well-written sentences. We added the parent pointers to the TreeNode class so that we could implement the iterator increment and decrement operators. Finding the next or previous node in a binary search tree can require climbing up or down in the tree hierarchy, and parent pointers are a nice way to do this. (Although they do require extra maintenance work in insert & erase.) 1.2 Hash Function for Phone Numbers [ /5] In Lecture 19 we discussed a simple application for hash tables: Caller ID reverse telephone lookup to find the person s name matching the query 10-digit phone number. Why is the following function a poor choice for the hash function to map these numbers to locations in a hash table with 1000 bins? Write 2-3 concise and well written sentences. Note: The type u int64 t is a 64-bit unsigned integer. int hash_function(u_int64_t phone_number) { return phone_number / 10000000; This function extracts the area code from the 10 digit number and stores all phone numbers with the same area code in the same bin. For a collection of phone numbers for people living in one area of the country, the data will not be uniformly distributed throughout the hash table and due to the cost of resolving these collisions we will not achieve optimal expected hash table performance. 1.3 Red-Black Trees [ /6] Fill in the following tree with the integers 1-7 to make a binary search tree. Also, color each node red or black so that the tree also fulfills the requirements of a Red-Black tree. 3 black 1 black 6 red 2 red 5 black 7 black 4 red 1

1.4 Improving the Performance of Inverse Word Search [ /5] In Homework 6 you tackled the problem of Inverse Word Search, creating a grid of letters that contained all required words on the input list. How might the ordering of the words on the list affect the running time of the solver? Describe a simple method to re-order the input words to achieve faster performance. Explain why your new order is better than a random order. Write 3-4 concise and well written sentences. In general it makes sense to place the longest words first, since they will fit in the fewest places and heavily constrain the layout of the other words. Once a long word is placed the smaller words can be placed around it. If a word does not fit in the current intermediate board we can abandon further search of that partial solution. Thus, the list should be sorted by word length, with the longest words first. A random order may have the longest word last, and the program could waste a lot of time investigating intermediate solutions that are impossible if the biggest word does not fit. 2 Sorting with a Set [ /15] 2.1 Implementation [ /12] Write a fragment of C++ code to read in n integers from cin and then output those numbers to cout in sorted order (smallest first). Your code should use the STL set container class. You may not use arrays, vectors, lists, or maps. You may assume there are no duplicates in the input data. std::set<int> data; int num; // read in the data, store in a set for (int i = 0; i < n; i++) { std::cin >> num; data.insert(num); // output directly from the set (will be sorted!) for (std::set<int>::iterator itr = data.begin(); itr!= data.end(); itr++) { std::cout << *itr << " "; std::cout << std::endl; 2.2 Order Notation [ /3] What is the order notation of your solution? O(n log n) 3 Width of Binary Tree [ /36] In this problem you will write 2 versions of a function to calculate the width of a binary tree; that is, the maximum number of elements that appear on any level of the tree, where a level is all elements that are the same distance from the root node. In the example below the widest level is level 3 which has 6 elements, so both versions of the function should return the value 6 for this example. 2

a level 0: 1 element b c level 1: 2 elements d e f level2: 3 elements g h i j k l level 3: 6 elements m n o p level 4: 4 elements q r s t u level 5: 5 elements The first version of the function should be implemented using iteration, and following a breadth-first traversal; that is, visiting all elements of a particular level of the tree before progressing to visit elements on the next level of the tree. The second version of the function should be implemented using recursion, and a depth-first traversal. Both versions need to visit every element of the tree, and will thus require O(n) time to execute (where n is the number of elements in the tree). The implementation of your functions should be efficient and not require more than O(n) time. 3.1 Order Notation for Memory Usage [ /6] For both versions of the function consider the order notation of the memory usage of the implementation. Assume the input tree has n elements, the height of the tree is h, the width of the tree (what these functions are calculating) is w, and the number of leaf elements is m. What is the maximum memory usage at any point during execution of the program? (After you complete the implementation on the next pages, revise your answers below as necessary.) The breadth-first (iterative) solution requires O(w) because the current vector will need to store the Node* s for each level, and the maximum vector length throughout execution is equal to the width. The depth-first (recursive) solution requires O(h) both to store the stack (at maximum recursion depth we will have h stack frames) and also to store the vector of counters for the number of elements found at each level. Now on to the implementation. Each version is passed a single argument, a pointer to the root node of the tree. Note: This problem does not involve STL maps, STL sets, or the ds_set class. class Node { public: Node(char c) { value=c; left=null; right=null; char value; Node* left; Node* right; ; 3.2 Implement tree width breadth first using Iteration [ /15] int tree_width_breadth_first(node *t) { int max_width = 0; // a place to store the elements on the current and next levels std::vector<node*> current, next; if (t!= NULL) current.push_back(t); while (current.size() > 0) { 3

if (current.size() > max_width) max_width = current.size(); // loop through the current level and construct the list of elements on the next level for (int i = 0; i < current.size(); i++) { if (current[i]->left!= NULL) next.push_back(current[i]->left); if (current[i]->right!= NULL) next.push_back(current[i]->right); // advance to next level current = next; next.clear(); return max_width; 3.3 Implement tree width depth first using Recursion [ /15] // the recursive function void tree_width_depth_first_helper(node *t, std::vector<int> &level_widths, int level) { if (t == NULL) return; // make sure the vector contains a slot for this level while (level_widths.size() <= level) level_widths.push_back(0); // increment the count for this level level_widths[level]++; // recurse on the right and left branches tree_width_depth_first_helper(t->left,level_widths,level+1); tree_width_depth_first_helper(t->right,level_widths,level+1); // the "driver function" int tree_width_depth_first(node *t) { // a vector to store the number of elements discovered at each level std::vector<int> level_widths; // calculate the level widths using recursive helper function tree_width_depth_first_helper(t,level_widths,0); // loop through and return the maximum width int max = 0; for (int i = 0; i < level_widths.size(); i++) { if (level_widths[i] > max) max = level_widths[i]; return max; 4 Mutual Best Friends [ /25] In this problem we will store and access data for best friend relationships between people. Each person (represented by an STL string) is allowed to have one best friend. You will be asked to scan through this data and output all pairs of people for whom this best friend relationship is mutual; that is, Person A s best friend is Person B, and Person B s best friend is Person A. We use a typedef to specify the type of the data structure that stores this information. Here is an example of how the data structure is constructed and initialized: typedef ***PART_1*** best_friends_type; best_friends_type best_friends; best_friends["alice"] = "henry"; best_friends["bob"] = "ed"; 4

best_friends["dan"] = "alice"; best_friends["ginny"] = "carol"; best_friends["ed"] = "bob"; best_friends["carol"] = "ginny"; best_friends["frank"] = "carol"; 4.1 The best friends Data Type [ /3] What is the type for the best friends data structure? Fill in the blank marked ***PART 1***. typedef std::map<std::string,std::string> best friends type 4.2 Visualizing the Data Structure [ /6] Draw a picture to represent the best friends data structure that has been constructed by the commands above. As much as possible use the conventions from lecture and lab for drawing these pictures. Please be neat when drawing the picture so we can give you full credit. alice bob carol dan ed frank ginny henry ed ginny alice bob carol carol 4.3 Output Mutual Best Friends [ /13] Now write the fragment of code to output the mutual best friends in the best friends data structure. Here is the expected output for the example presented above: mutual best friends: bob & ed carol & ginny // iterate through all people in the data structure for (best_friends_type::iterator itr = best_friends.begin(); itr!= best_friends.end(); itr++) { const std::string &f1 = itr->first; const std::string &f2 = itr->second; // to avoid duplicate output, only consider friendships where A < B alphabetically if (f1 > f2) continue; // see if the friendship is mutual best_friends_type::iterator itr2 = best_friends.find(f2); if (itr2!= best_friends.end() && itr2->second == f1) { cout << " " << f1 << " & " << f2 << endl; 4.4 Order Notation [ /3] Assuming the best friends data structure stores data for n people, what is the order notation of your code for the previous part? O(n log n) 5

5 Short Answer [ /18] 5.1 Red-Black Trees [ /4] Which of the following statements about Red-Black trees are true? Write the letters for all true statements in the box below. A) The number of red nodes in each level of the tree is fixed in a Red-Black tree. B) Red-Black trees ensure that the least frequently accessed elements are near the bottom of the tree. C) Red-Black trees can be used to ensure that the O(log n) expected running time of tree operations is achieved. D) Red-Black trees are theoretically powerful, but rarely used in practice. E) Red-Black trees are non-trivial to implement because a series of rotations and re-colorings are often necessary to maintain the tree properties. Statements C & E are true. 5.2 Operator Overloading [ /4] There are 3 different ways we can overload an operator in C++: as a non-member function, as a member function, and as a friend function. Which way cannot be used for the input & output stream operators (>> and <<)? Why not? Write 2-3 concise and well-written sentences. The stream operators cannot be written as member functions of a custom class. These binary operators require that a stream object be on the left argument, thus when re-written as a function call, the stream object will be the first argument. When written as a member function, the left argument is the object whose member function is called. 5.3 TreeNode Parent Pointers [ /5] In our initial version of the cs2set class, the TreeNode object had 3 member variables: the value, and pointers to the left and right sub-trees. Why did we later add a parent pointer to each TreeNode object? Write 2-3 concise and well-written sentences. We added the parent pointers to the TreeNode class so that we could implement the iterator increment and decrement operators. Finding the next or previous node in a binary search tree can require climbing up or down in the tree hierarchy, and parent pointers are a nice way to do this. (Although they do require extra maintenance work in insert & erase.) 5.4 STL Vectors vs. Sets [ /5] Both vectors and sets can be used to efficiently sort a collection of numbers (or strings, etc.) What is the expected running time to use these data structures for sorting? Describe a specific application where one data structure may be more advantageous than the other. Write 2-3 concise and well written sentences explaining these differences. 6

Both vectors and sets can be used to sort a collection of numbers in O(n log n) time. When using a vector, all the elements are inserted, then the STL sort algorithm is called. Because vectors are packed sequentially, there is little extra memory overhead to store the elements. On the other hand, the elements can be added one at a time into a set, and they will be incrementally sorted, which is useful for many applications. 6 Counting the NULL Left and Right Children [ /15] Write a recursive function named count_left_right_null that takes in a pointer to a TreeNode templated over type T and returns a pair of two integers that represent the total number of NULL left and right child pointers in the tree, in that order. For example, when called on the root of the tree shown on the right, the function returns the pair (5,4) because there are 5 NULL left pointers (the nodes with values a, f, k, m, and z) and 4 NULL right pointers (the nodes with values a, f, m, and z). a c g s z template <class T> class TreeNode { public: T value; TreeNode<T>* left; TreeNode<T>* right; ; f k m template <class T> pair<int,int> count_left_right_null(treenode<t> *p) { if (p == NULL) return make_pair(0,0); pair<int,int> left,right; if (p->left == NULL) left = make_pair(1,0); else left = count_left_right_null(p->left); if (p->right == NULL) right = make_pair(0,1); else right = count_left_right_null(p->right); return make_pair(left.first+right.first,left.second+right.second); 7 Binary Tree Traversal Order [ /28] In this problem we will investigate different traversal orders in which to visit and print the nodes in a tree. For each subproblem below a particular ordering is demonstrated for the tree on the right. You will first identify the common name for this traversal order (choose from the list below). Then you will write a function of the type specified (recursive or iterative) that takes in the root pointer to the tree, a TreeNode templated over type T, and visits and prints (to std::cout) the nodes of the tree in that order. The traversal orderings below are one of: 7

A) leaf order B) pre-order C) post-order D) breadth first E) in-order F) random order 7.1 c a s g z f k m [ /12] Common Name: D) breadth first a c s Iterative function: template <class T> void breadth_first(treenode<t> *p) { if (p == NULL) return; list<treenode<t>*> todo; todo.push_back(p); while (!todo.empty()) { TreeNode<T> *tmp = todo.front(); todo.pop_front(); if (tmp->left!= NULL) todo.push_back(tmp->left); if (tmp->right!= NULL) todo.push_back(tmp->right); cout << tmp->value << " "; f g k m z 7.2 a c f g k m s z [ /8] Common Name: E) in-order Recursive Function: template <class T> void in_order(treenode<t> *p) { if (p == NULL) return; in_order(p->left); cout << p->value << " "; in_order(p->right); 7.3 a f m k g z s c [ /8] Common Name: C) post-order Your choice: Iterative or Recursive Function: (using recursion) template <class T> void post_order(treenode<t> *p) { if (p == NULL) return; post_order(p->left); post_order(p->right); cout << p->value << " "; 8

8 Family Maps [ /35] In this problem we store information about families with children. In particular we will store the years in which the siblings were born and the family s last name. We want to efficiently access information about the family based on the birth years and the overall difference in these years. In fact, we want to store the families sorted by the number of years between the first born and last born child. We will use a map to define this data structure. Your first task is to deduce the specific type of the map that is used from the examples below. You will complete the following typedef: typedef ***PART_1*** map_type; And here is how we add data into the structure: map_type family_data; vector<int> smith_kids; smith_kids.push_back(1990); smith_kids.push_back(1993); smith_kids.push_back(1995); family_data.insert(make_pair(smith_kids,string("smith"))); vector<int> jones_kids; jones_kids.push_back(1989); jones_kids.push_back(1995); family_data.insert(make_pair(jones_kids,string("jones"))); vector<int> davis_kids; davis_kids.push_back(1992); family_data.insert(make_pair(davis_kids,string("davis"))); vector<int> williams_kids; williams_kids.push_back(1991); williams_kids.push_back(1992); family_data.insert(make_pair(williams_kids,string("williams"))); vector<int> miller_kids; miller_kids.push_back(1991); miller_kids.push_back(1996); family_data.insert(make_pair(miller_kids,string("miller"))); You may assume that the birth years for the children within a family will always be given in chronological order as shown above. As always, we need to make sure that the operator< ordering function for the key used in our map has been appropriately defined so that our data is sorted within the map as desired. We want the entries in our data structure to be ordered first by the difference between the birth year of the first and last born children. In the above example, the Smith family will appear after the Williams family because the Smith family spans 5 years and the Williams family spans 1 year. Families with a single child have a span of 0 years and will be listed first. When two families have the same year span, the tie is broken by looking at the birth years of the children, and the family with the earliest birth year will be listed first (looking at the second born children to break further ties, etc.). For example, the Smith family and Miller families both span 5 years, but the Smith family will be listed first because 1990 < 1991. You may assume no two families have the same number of children born in the same set of years. 9

8.1 The Map Type [ /4] What is the specific typedef for the map? Fill in the blank marked ***PART 1***. typedef map<vector<int>, string> map type; Note: When fully implemented with functors (see implementation of my vector sort in part 4.3), this will be: typedef map<vector<int>,string, my vector sort> map type; 8.2 Visualizing the Data Structure [ /10] Draw a picture to represent the family data data structure that has been constructed by the commands above. As much as possible use the conventions from lecture and lab for drawing these pictures. Please be neat when drawing the picture so we can give you full credit. Optional: You may also write a few concise sentences to explain your picture. A map (table) between vector<int>s and strings. The rows of the table are sorted as described earlier. The vectors have exactly as many spots as necessary to store the birth year for each child in the family. vector<int> string 1992 1991 1992 1990 1993 1995 1991 1996 1989 1995 davis williams smith miller jones 8.3 Ordering the Map Keys [ /10] Now implement the function that will be used to order the keys. You should implement this by overloading the operator< function for the key type. Note: Technically this code must be wrapped up in a C++ functor for this example, but we haven t covered functors yet, so just write it as operator<. bool operator< (const vector<int> &a, const vector<int> &b) { int a_diff = a.back() - a.front(); int b_diff = b.back() - b.front(); if (a_diff < b_diff) return true; if (a_diff > b_diff) return false; unsigned int i = 0; while (i < a.size() && i < b.size()) { if (a[i] < b[i]) return true; if (a[i] > b[i]) return false; i++; return a.size() < b.size(); 10

And here s what the code looks like wrapped in a C++ function object, a functor, where the function call operator is overloaded with the ordering functionality: class my_vector_sort { public: bool operator()(const vector<int> &a, const vector<int> &b) { int a_diff = a.back() - a.front(); int b_diff = b.back() - b.front(); if (a_diff < b_diff) return true; if (a_diff > b_diff) return false; unsigned int i = 0; while (i < a.size() && i < b.size()) { if (a[i] < b[i]) return true; if (a[i] > b[i]) return false; i++; return a.size() < b.size(); ; 8.4 Searching for a Particular Family [ /8] Now assume many more families have been added to the data structure. Write a fragment of code that will efficiently search the data structure for a family with three children that were born in 1992, 1993, and 1994. If such a family exists in the database, the code should output a short message to cout with the family s last name, otherwise it should output a message stating that no such family exists. vector<int> query; query.push_back(1992); query.push_back(1993); query.push_back(1994); map_type::iterator tmp = family_data.find(query); if (tmp!= family_data.end()) { cout << "The family name is " << tmp->second << endl; else { cout << "No such family" << endl; 8.5 Order Notation [ /3] If there are f families stored in the map, and each family has at most c children, what is the running time for your code above? The running time of is O( log f c ). 11