Algorithm 1: T(n) = n + 5n2 + 80 Algorithm 2: T(n) = 10000log n + 10000
You should choose algorithm 1 because for such small values of n, the constants in Algorithm 2 outweigh the better Big-O running time of Algorithm 2. For example, for n = 50, T(50) for Algorithm 1 is 12630 while T(50) for Algorithm 2 is roughly 66438.
You should choose Algorithm 2 because for large n, the Big-O running time dominates and the constants become insignificant. Since the Big-O running time of Algorithm 2 is less than the Big-O running time of Algorithm 1, you would prefer Algorithm 2.
a. vector b. list c. deque d. map e. set f. multimap g. multiset h. hash table
string a, b; string *x, *y;Also suppose that the above variables are assigned the following memory addresses:
a: 0x1000 b: 0x1100 x: 0x1200 y: 0x1204After each of the following code sequence executes, what are the values of a, b, x, and y? Assume that code segments 1 and 2 execute independently (i.e., code segment 2 does not execute after code segment 1.
Code Segment 1 x = &b; *x = "Smiley"; y = x; *y = "Brad"; b = *x; Code Segment 2 x = new string("Michelle"); // address of new string = 0x2000 a = *x; y = new string("Charles"); // address of new string = 0x2100 x = y; b = *x; Code Segment 1 Code Segment 2 a: "" a: Michelle b: "Brad" b: Charles x: 0x1100 x: 0x2100 y: 0x1100 y: 0x2100 *x: Charles *y: Charles
class Picture { public: ifstream *sourceFile; int rows; int cols; }; Picture *p; string *name1, *name2; name1 = new string("Hank Aaron"); name2 = name1; delete name1; p = new Picture(); p->sourceFile = new ifstream(); p->rows = 30; p->cols = 40; *name2 = "Hammerin Hank Aaron"; p->sourceFile->open("mountain.jpg");
Answer the following questions about the above code:
The most likely result is a seg fault because there is a good chance that name2 points to the same memory as p and hence the string "Hammerin Hank Aaron" has overwritten the memory pointed to by p. In particular, the memory address in p->sourceFile has been overwritten with random characters and therefore is likely to no longer represent a valid memory address. When you try to access an invalid memory address, you get a seg fault.
The other less likely result is that when p->sourceFile was overwritten with random characters, the memory address was a valid one but instead of this memory address being the ifstream that was allocated, it is a random memory address. Since p->SourceFile no longer points to the ifstream object, it is hard to predict what will happen but at the very least, the open function will not get called. There is also a good chance that a seg fault will happen because it is unlikely that the memory address to which p->SourceFile points is a valid function address.
Data Structure | Insert | Find |
---|---|---|
Map | O(n log n) | O(n log n) |
Hash Table | O(n) | O(n) |
List | O(n) | O(n2) |
Vector | O(n2) | O(n2) |
Here is the rationale for each of the answers:
Brad VanderZanden Smiley VanderZanden Minnie Mouse Mickey Mouse Ebby VanderZandenthen the set {Brad, Ebby, Smiley} will be associated with "VanderZanden" and the set {Mickey, Minnie} will be associated with "Mouse".
typedef set <string> fnset; map <string, fnset> lnames; string fn, ln; fnset firstnames; while (cin >> fn >> ln) { firstnames = lnames[ln]; firstnames.insert(fn); lnames[ln] = firstnames; }
The line firstnames = lnames[ln] makes a copy of the set associated with ln. The next line inserts into this copy and the final line copies this copy back into the original set. Making copies is expensive and should be avoided if possible.
You can fix the inefficiency by avoiding the copy and modifying
the original set instead. This
can be done in two ways.
lnames[ln].insert(fn);
This statement modifies the return value of lnames[ln] and
C++ does not make a copy of the return value. It modifies
the original value which in this case is the first name set
associated with ln.
fnset &firstnames = lnames[ln];
firstnames.insert(fn);
lnames[ln] = firstnames;
The reference variable points to the original set and
no copy gets made.
class ListNode { public: string name; ListNode *next; ListNode *prev; ListNode(string n) : name(n) {} };Further suppose that a series of inserts have created the following list:
The code below is supposed to move the node containing "Ben" so that it is between "Nancy" and "Sarah". However, the code eventually seg faults and there are some other issues with the code as well.
1) ListNode *nextNode = currentNode->next; 2) currentNode->prev = currentNode->prev->prev; 3) currentNode->next = currentNode->prev; 4) nextNode->prev = currentNode->prev; 5) currentNode->prev->prev = currentNode; 6) currentNode->next->next = nextNode;
Statement 2 messes everything up because it prematurely sets
Nancy's node (which is the node to which currentNode points) to
NULL. That means that statement 3 sets currentNode->next
(i.e., Nancy's next field) to NULL and statement 4 sets
nextNode->prev (i.e., Sarah's prev field) to NULL.
---------------- ----------------- -----------------
| name: "Ben" | | name: "Nancy" | | name: "Sarah" |
| next: -------|------>| next: NULL | | next: NULL |
| prev: NULL | | prev: NULL | | prev: NULL |
---------------- ----------------- -----------------
^ ^
| |
currentNode nextNode
It appears to be trying to make Ben's prev field point to Nancy's node. This is consistent with Ben being moved after Nancy in the list.
ListNode *nextNode = currentNode->next;
ListNode *prevNode = currentNode->prev;
currentNode->next = prevNode;
currentNode->prev = prevNode->prev;
prevNode->next = nextNode;
prevNode->prev = currentNode;
nextNode->prev = prevNode;
class Person { public: string name; Person *bestFriend; Person(string n) { name = n; } }; string names[] = { "mickey", "bugs", "daffy", "winnie" }; list<Person *> friends; Person *newPerson; Person *lastPerson; int i; lastPerson = NULL; for (i = 0; i < 4; i++) { newPerson = new Person(names[i]); newPerson->bestFriend = lastPerson; friends.push_back(newPerson); lastPerson = newPerson; }Draw a diagram that shows the list, the Person objects that get created, and the objects to which each pointer points when the code has finished execution. Make sure that:
void deleteCodes(list<string> &usedCodes, list<string> &codes) { list<string>::iterator usedIter, codesIter; codesIter = codes.begin(); usedIter = usedCodes.begin(); // The used codes list will be exhausted before the outstanding codes // list so we stop when we have exhausted the used codes list while (usedIter != usedCodes.end()) { if (*codesIter == *usedIter) { codesIter = codes.erase(codesIter); usedIter++; } else { codesIter++; } } }
void HashTable::Insert(string clubName, Person *student) { unsigned int bucketIndex = Hash(clubName)%table.size(); int i; Club *c; for (i = 0; i < table[bucketIndex].size(); i++) { if (table[bucketIndex][i]->name == clubName) { table[bucketIndex][i]->members.push_back(student); return; } } // if we get here then the club did not exist, so create a new club // and then add the student to it c = new Club(clubName); c->members.push_back(student); table[bucketIndex].push_back(c); }
void AddStudentsAndClubs(HashTable *clubs, map<int, Person*> &students) { string command; while (cin >> command) { if (command == "AddStudent") { string studentName; int studentId; cin >> studentId >> studentName; students[studentId] = new Person(studentId, studentName); } else if (command == "JoinClub") { string clubName; int studentId; Person *student; cin >> studentId >> clubName; student = students[studentId]; if (student == NULL) { continue; // student does not exist } else { clubs->Insert(clubName, student); } } } }