CS 112 Final Exam SLOs
define the functionality of a deque and how to best implement it
Can add or remove items from both ends of a deque Sort of like a linked list but more fancy
Reason about the difference between a dynamic array's size and capacity
Capacity: number of locations in the array Size: Number of locations in the array that have been filled Capacity is doubled every time capacity=size so a new array is not made every time append is called
Describe the process of completion of a program
preprocessing: .h files are added to .cpp compile: file is checked for errors /.o file is created/ link: .o file is combined with external libraries /exe is created/
open, read from, write to, and close files
OPEN: ifstream stream_name; //or ofstream READ: while(stream_name >> string){ get line(stream_name, string); } WRITE: stream_name << var; CLOSE: stream_name.close();
properly use try, catch, and throw in C++ code
try: code to do catch: if try code throws error, catch and print throw: if something is wrong with try code, throw error (throw exception_name("error message");
Implement test-driven development for a class
under section, create an instance of the class, fill it with info using set, then test whatever method you are going to code and REQUIRE that it equals the value it should
perform basic I/O using cout and cin, with << and >>
<< is the injection operator SAMPLE CODE: #include <iostream> using namespace std; int main(){ cout << "hi!"; int x; cin >> x; }
Reason about the time complexity for operations on a dynamic array (append, insert, remove, copy constructor)
APPEND Amortized constant time -- sometimes fast, sometimes slow INSERT Linear time -- Takes longer to insert at the beginning of the array than at the end, and in a linear fashion (for looping items in indexes down) REMOVE Linear time-- Takes longer to remove at the beginning of the array than at the end, and in a linear fashion (for looping items in indexes up) COPY CONSTRUCTOR Linear time -- the more items in an array, the longer it takes to copy over (for loop)
define the structure of a recursive solution -- base case and recursive case.
Base case: establishes what to do in a case that isn't like the rest (a function that checks if a value is in an array can immediately return false if size == 0) Recursive case: after the base case has run, the recursive case runs repeatedly (a function that checks if a value is in an array will need to walk through an array, comparing the given value to the values in the array)
Define and implement constructors and destructors and general methods
DEFAULT CONSTRUCTOR - takes in no parameters - initializes an empty constructor EXPLICIT VALUE CONSTRUTOR - takes in parameters - initializes a constructor with values DESTRUCTOR - destroys an object using delete[] GETTER - constant - takes in one parameter (location) - returns Item SETTER - takes in two parameters (object, location) - returns void ...
define an abstract data type
Describe how a data type works without using code From the user's point of view Discuss features, potential functions, values that can be held, etc
Describe when appending to a dynamic array is "inexpensive" and when it is "expensive"
EXPENSIVE When capacity=mySize Array must be copied over to memory space from the heap using new, extending the length of the array, and then can add the next value INEXPENSIVE When capacity>mySize Index is found (quick) and value is placed in that memory location
describe the concept of Big-Oh notation for analyzing algorithmic complexity
Look at the general formulaic structure for an operation to determine as an array or list gets bigger, how much more time it will take
describe the crucial ideas behind Insertion Sort and Selection Sort.
Insertion sort: Start at beginning of the array; Compare to values below, then place it in the correct spot Selection sort: find smallest element in unsorted part; swap with first element in the unsorted part
identify the crucial differences between Insertion and Selection Sort.
Insertion sort: keeps values in same order, requires minimal extra space, can add new values in easily
identify the time complexity of Insertion and Selection sort in best and worst cases.
Insertion: best is O(n), worst is O(lg(n)) Selection: always O(lg(n))
Understand the time complexity terms linear time, constant time, and amortized constant time
LINEAR TIME The operation will take more time (in a linear growth fashion) to complete when the object gets larger ex. any method with a for loop CONSTANT TIME The operation will take the same amount of time, regardless the size of the object Ex. indexing AMORTIZED CONSTANT TIME Some operations are constant, some are linear, and overall they equal out to be about 2x (think about the animation in class) ex. array appending
Explain what a class template is simply
Like a cookie recipe -- can easily swap out chocolate chips for m+ms. Class template provides all the basis and functionality that is wanted, but allows the user to set what specific data type is desired for the particular application
Describe the organization of linked list (how nodes are chained together)
Linked list contains myFirst, myLast, and myNext Each node contains myItem and myNext
use the new operator to dynamically allocate memory and the delete and delete[] operators to free up the memory
NEW pulls memory space out of the heap need to specify data type and number of them needed known as dynamic allocation DELETE and DELETE[] - needs to be used for deep copies in which the original copy is no longer going to be used - gives memory space back to operating system to prevent a memory leak
identify the time complexity of each operation on a hash table
O(1), if a good hash function is used and there is 2n buckets
understand the time complexity of the Towers of Hanoi problem.
O(2^n)
Reason about the time complexity of prepend, append, remove, transverse, searching, indexing
Prepend: Array n Vector n Linked List 1 Append: Array n Vector 1* Linked List 1 Remove: Array n Vector n Linked List 1 Transverse: n (?) Searching: n Indexing: Array 1 Vector 1 Linked List n
Reason about the access modifiers public and private
Public can be accessed outside of a class (ex, a test file) Includes useful, useable methods, like setters and getters Private cannot be accessed outside of a class, unless .h file is #include(d) Used for "behind the scenes" variables and calculations that are intermediate to the useable methods
explain the reasons for creating class templates instead of classes
Reduces the amount of duplicate code if classes with different datatypes are desired Can simply #include (or get from library) the class template into whatever project it is needed in
Reason about the difference between a shallow and deep copy of a data structure
SHALLOW A new object points to the address of an old object When either object is modified, it modifies both DEEP Everything in an old object is copied over and stored in memory space taken from the heap When either object is modified, the other is not changed
enumerate the typical API for a Stack and Queue
Stack Push() Pop() Peek() Last in, first out (LIFO) Queue Push() Pop() Peek() First in, first out
reason about how to best implement stacks and queues so that all operations are O(1) using either fixed sized arrays or linked lists
Stack fixed size array push/pop on end linked list push/pop on front Queue fixed size array need to know myFirst and myLast linked lists
Defend the argument that Big-Oh notation is a description of the carbon footprint of an algorithm, and thus, using better algorithms is a way for Christians to care for the earth
Using an algorithm with a lower Oh allows for shorter computational time, less energy, and reduced carbon release
instantiate objects statically
Static objects exist for the length of the program, until it ends and the destructor is called (~object();)
define and call functions correctly
datatype function(datatype parameter){ ... }
reason about the time-space tradeoff manifested in a hash table
The larger the hash table, the better it performs time-wise. Ideally, there will be 2n buckets, but this is a lot of space to store minimal items.
Describe recursion simply
When a function calls itself. Often, it is infinite, but if called wisely, it can end.
Identify the 3 situations in which a copy constructor is called
When copy constructor is directly called When pass by value is used When return is called
Explain when it is important to implement the destructor explicitly for a class
When new is used, and the original copy is no longer going to be used
reason about how a Big-Oh notations is an approximation of the exact time complexity of an algorithm, expressed as a*f(n)+b
a and b are relatively small compared to f(n) when the array is large, therefore they are often ignored
describe the role the runtime stack plays in the execution of a recursive function.
a new stack is created every time the function is recursively called. As the function unwinds, stacks are deleted
write the basic data structure for storing items in a hash table
a vector of lists of items
explain the behavior of an iterator
acts like a pointer but is not. can get value of iterator using *iterator can get the value after using iterator++ can perform iterator arithmetic Can only compare iterators using == or !=
reason about the complexity of operations on a BST -- for best and worst cases.
best: lg(n), when tree is fat and short worst: n, when tree looks more like a linked list
create correct while loops and for loops, including using break and continue statements
break: exits main loop continue: exits subloop
describe the effect of putting #pragma omp parallel for above a for loop in code.
breaks threads into smaller sections
implement operator overloading for a class
defines what to do to objects to the left and right of an operator 3+4 = 3.+(4)
write values in decimal, hexadecimal, and binary, and convert between them
d = 4; h = 4; b = 100 d = 16; h = 10; b = 10000 d = 45; h = 2d; b = 101101
declare array variables and initialize them
datatype array[size] = {0}; datatype array[size] = {x,y,z};
compare/contrast the strengths and weaknesses of a linked list vs a dynamic array
dynamic array -time efficient to index -fairly space efficient -time costly to add items at the beginning or middle -time costly to remove items linked list -time efficient to add/remove items - time costly to index or find items - requires more memory per item
reason about the unique behavior of indexing in a map object
element.first accesses key (must be unique) element.second accesses value (can be duplicate)
describe the time complexity of set container operations, like find, insert, remove.
find: O(lg(n)) insert: O(lg((n)) remove: O(lg(n))
write code using iterators to traverse all items in a map.
for(map <datatype, datatype>::iterator it = set.begin(); it != set.end(); it++)
write code using iterators to traverse all items in a set.
for(set <datatype>::iterator it = set.begin(); it != set.end(); it++)
describe the effect of putting #pragma omp parallel in front of a block of statements.
fork-join
use function overloading, define default arguments, and define constant parameters
function overloading: functions with the same names can run different code (need to have a different number of parameters) default arguments: declared in default constructor of .cpp file, indicates what values will be if an empty function is made constant parameters: datatype const parameter means the parameter cannot be changed
describe why computer manufacturers could not increase processor speed indefinitely.
heat could not be adequately managed
articulate the differences between in, out, and in/out parameters
in: takes a value in out: returns a value in/out: takes in a value and returns it
articulate the operations one can do on a Binary Search Tree.
insert() find() -- lg(n) remove() getHeight()
understand the implementation of a BST and the algorithms for insert, contains(), remove(), getHeight(), the destructor, and the various traversals.
insert(): check if the newValue is less than or greater than the current node, keep traveling the tree until a nullptr is reached contains(): similar to insert, but is a bool function remove(): find value and delete. Relocate pointer to one less than or one greater than root getHeight(): travel down the tree until nullptr is reached. Return height to parent node; if a parent node has two children, it takes the height of the tallest one, adds one to it, then returns value to its parent destructor: children are deleted before parents postorder traversal: go left, go right, get item preorder traversal: get item, go left, go right in order traversal: go left, get item, go right (returns smallest to greatest) Traversal examples: (a+b)*(c-d)/e Postorder: (((ab+)(cd-)*)e/) Preorder: (/(*(+ab)(-cd))e) Inorder: a+b*c-d/e
identify the size of different data types
int 4 unsigned 4 long 8 long long 16 short 2 bool 1 char 1 string variable
define two-dimensional arrays, iterate over them, and manipulate them
int array[5][4]; for (int r = 0; r < 5; r++) for(int c = 0; c < 4; c++) int array[r][c] = 5;
create constant values using the const keyword
int const x = 5; x = 7; //would break code
create and use pointers
int y = 5; //address of 12345678 p* = &y; //pointer p is equal to the address of y p* = 5; //dereferencing p = 12345678;
simply explain how a circular array works
keep track of beginning and end; if at the last spot in the linear array, the next value is circled around to the front of the array
describe the time complexity of map container operations, like find, insert, remove, and indexing/subscripting
lg(n)
describe the algorithm for finding the maximum node in a left subtree and minimum node in a right subtree, for use during the remove() algorithm.
maximum node, left subtree: go left one, then go right until nullptr minimum node, right subtree: go right one, then go left until nullptr
describe the fork-join paradigm.
multiple threads are run on the same code, split (fork), then wait until they are all done (join)
implement a basic recursive implementation -- e.g., for the factorial function.
n! = n * (n-1)! base case: if n==0 or 1, return 1. recursive case: return n *factorial(n-1)
Recognize a copy constructor and/or implement it
parameter is the address of an object Do a deep copy (do not use a pointer)
pass arrays as parameters
pass by reference, either array[] or *array
correctly choose between pass-by-value, pass-by-reference, and pass-by-const-ref parameters
pass-by-value: calls copy constructor, value will not be changed pass-by-reference: passes in pointer to value; value may be changed pass-by-const-reference: passes in pointer to value; value will not be changed; useful for large values that need to be passed
Explain how the node destructor causes a chain reaction to delete all nodes in the list
recursion Deleting one node calls for myNext to be deleted -- once a nullptr is reached
argue why a recursive solution is generally less efficient than an equivalent iterative solution.
recursion results in a new stack being created every time the function is called
describe Moore's "law"
size of transistors will half every 12-18 months
describe the unique characteristics of the STL map container
stores key, value pairs, with unique keys stored in sorted order. Like a Python dictionary
describe the unique characteristics of the STL set container
stores unique values in sorted order (Red-black tree, stays balanced)
write if, if-else, if-else-if, and switch statements correctly
switch(test statement){ case integer/variable: //statement break; ... default: //statement }
Write code to walk through a linked list
use a for loop review: first value establishes the value to be manipulated and sets base value (ex int i = 0), second value indicates the conditions under which to loop, kind of a "failure/breaking" point (ex i<4), third value indicates what to do to variable to continue the for loop (ex i++) linked list application: for(Node *currPtr = myFirst, currPtr, currPtr = currPtr->myNext) creates a Node pointer (currPtr) set to point at the beginning of the linked list. The pointer will go through the list until it does not exist (becomes equal to nullptr). Each time the for loop is completed, the pointer will move to the next node by following myNext
articulate the importance of initializing variables
variables must be initialized in C++ so they may be given an appropriate amount of memory space
reason about important properties of a good hash algorithm
want to insert, remove, and search while still being O(1) Distributes items well (on the level of random insertion) Deterministic, same output for the same input (cannot actually be random insertion)
Explain when C++ calls the destructor on an object
when new is called (must be coded in to prevent memory leaks) when an object of the class goes out of scope (automatic)
correctly use the words "winding phase" and "unwinding phase".
winding phase: The act of recursion: the recursive function is called on the next value unwinding phase: the act of returning a value after recursion: the result from one value is returned to the previous value