Data Structures: Test 1
Write a simple function template declaration where a function takes in a value of the template type, and uses the ostream operator to print to the screen. Then, write a main function that prints an integer, a double, and a character array to the screen calling the templated function
#include<iostream> template<class T> void printFunc(T t_var){ std::cout << t_var << std::endl; } int main(){ int i = 1842; double j = 3.14; char *k = "Go Irish!"; printFunc(i); printFunc(j); printFunc(k); }
5 key benefits of data structures
*These all basically <=> they are simpler* 1) (generally) More sophisticated data structure => simpler algorithm 2) Simple algorithms are less expensive to develop 3) There is less code to read and comprehend 4) The logic is simpler and it is easier to modify without introducing errors 5) Easier to repair defects, make modifications, or add enhancements
Describe why std::cout << "The " << 5 << "th value of IntVec x is " << (*x)[5] << std::endl is fine, and std::cout << "The " << 5 << "th value of IntVec x is " << *x[5] << std::endl; fails
*x[5] => the 5th element of an array of pointers
Disadvantages of Linked List vs. Array
1) Linked Lists do not allow direct access to the individual elements. If you want to access a particular item then you have to start at the head and follow the references until you get to that item. 2) A linked list uses more memory compare with an array, because a register must be allocated for each pointer.
Advantages to Linked List over array
1) The number of nodes in a list is not fixed and can grow and shrink on demand. Any application which has to deal with an unknown number of objects should need to use a linked list. 2) Easier to implement within mathematical model for data types than arrays.
Evaluate the postfix expression 2 3 - 43 +
42
Evaluate the postfix notation 15 9 6 * + 12 - 15 +
72 (maybe)
Path
A path from node V1 to node Vk is a sequence of nodes such that Vi is the parent of Vi+1 for 1 <= i <= k.
Tree
A tree is a linked data structure where each node consists of a data element and one or more child (leaf) nodes. • A tree may be empty, meaning no data and the child nodes are null. • If not, then there is a distinguished node r, called root and zero or more non-empty subtrees T1, T2, ... Tk, each of whose roots are connected by a directed edge from r. • A parent is node that refers to a child node
Level
All nodes of the same depth are at the same level.
ADT (abstract data type)
An ADT is a class of objects whose logical behavior is defined by a set of values and a set of operations, where low-level details are omitted or hidden with a higher-level idea.
Why must function declarations and definitions be in the same header file for a templated class?
Because function and class templates are re-compiled every time a different type is used, the function declarations and definitions must be in the same header file
Design and draw the following data structure and its relationships for a singly-linked list: Assignment Operator
Drawing on 1st set of slides, page 20: LinkedList<T>& operator=(const LinkedList<T>& copy) { Node<t>* temp = copy.head; while(temp != nullptr) { this->insert(temp->data); temp = temp->next } }
Design and draw the following data structure and its relationships for a singly-linked list: Empty Constructor
Drawing on 1st set of slides, page 20: LinkedList<T>() { head = new Node<T>(); }
Design and draw the following data structure and its relationships for a singly-linked list: Delete
Drawing on 1st set of slides, page 20: Note that the provided code doesn't actually delete anything, it just goes around it. void deleteNode(T key) { if(head == nullptr) throw std::out_of_range("invalid LinkedList Node"); else if(head->data == key) { head = head->next; return; } Node<T>* current = head; Node<T>* prev = nullptr; while(current != nullptr && current->data != key) { prev = current; current = current->next; } if(current == nullptr) std::cerr << "Element " << key << " is not in the Linked List" << std:: endl; //delete node prev->next = current->next; }
Design and draw the following data structure and its relationships for a singly-linked list: Insert
Drawing on 1st set of slides, page 20: case 1 corresponds to an empty list. void insert(T value) { if (head->next == NULL) { tail = head; head->next = tail; head->data = value; { else { tail->next = new Node<T>(); tail = tail->next; tail->next = nullptr; } length++; }
Design and draw the following data structure and its relationships for a singly-linked list: Node Template
Drawing on 1st set of slides, page 20: template<class T> struct Node { T data; Node *next; };
Design and draw the following data structure and its relationships for a singly-linked list: Destructor
Drawing on 1st set of slides, page 20: ~LinkedList<T>() { Node<T>* current = head; while (current != nullptr) { Node<T>* next = current->next; delete current; current = next; } head = nullptr; tail = nullptr; }
Design and draw the following data structure and its relationships for a doubly-linked list: Assignment Operator
Drawing on 1st set of slides, page 23: DLlist<T>& operator=(const DList<T> & copy) { Node<T>& temp = copy.head; while(temp != nullptr) { this->insert(temp->data); temp = temp->next; } }
Design and draw the following data structure and its relationships for a doubly-linked list: Node
Drawing on 1st set of slides, page 23: template<class T> struct Node{ T data Node *next; Node *prev; };
Design and draw the following data structure and its relationships for a doubly-linked list: Insert
Drawing on 1st set of slides, page 23: void insert(T value) { if(head->next == nullptr) { tail = head; head->next = tail; dead->data = value; } else { tail->next = new Node<T>(); tail->next->prev = tail; tail = tail->next; tail->data = value; tail->next = nullptr; } length++; }
Design and draw the following data structures and their relationships for a Splay Tree: Zig (Left child) y | | z x | | | | a b c d
Drawings on 2nd set of slides, page 11. y | | z x | | | | a b c d => root = z z->right = y y->left = b => z | | a y | | b x | | c d
Design and draw the following data structures and their relationships for a Splay Tree: Zig-zag (right child then left child) y | | z x | | | | a b c d
Drawings on 2nd set of slides, page 11. y | | z x | | | | a b c d => y->right = c c->right = x => y | | z c | | | a b x | d => root = c c->left = y => c | | y x | | z d | | a b
Binary tree
Each tree has precisely two children.
Write a function that returns the second element of a stack.
If it is a linked list, you can just move to the next node then pull the data.
What is the main difference between a class and struct?
In C++, structs have default public members and bases and classes have default private members and bases.
why is this link implementation wrong? node* link( ) const { return link_field; }
It will allow the returned link list element to be edited. This would be better. const node* link( ) const { return link_field; }
Two algorithms, C2,C1, sort imported characters by letter. C2 has a 94.87% improvement in efficiency for 78 machine instructions, which comprises 40% of the machine code. Calculate the Improvement, C1 Total instructions, C2 total instructions and Improvement when 538, 128080, and 4303232 characters are sorted.
Let ImpEff = Improvement in efficiency of C2 = 0.9487 Improvement factor = ImpFac = 1/(1-ImpEff) = 19.5 *Note that there are a variety of improvement metrics* Unaffected code = 78/0.4 - 78 = 117 Total Instructions = (old code instructions)/(ImpFac) + (Unaffected code) = 121 *This literally simplifies to (New Improved code) + (Unaffected Code)* Improvement by song: ((old code) * characters + (Unaffected code independent of characters))/((New code) * characters + (Unaffected code independent of characters) = 18.54 = 19.4957 = 19.4998
How to refer to a pointer?
Pointers are referred to in C++ code using two characters: • & - The address of the variable • * - The contents of the address of de-reference or "value pointed to by"
Design and draw the following data structures and their relationships for a Binary Tree: findMin
See 2nd lecture slides, page 6 for drawings. BSTNode<T>* findMin(BSTNode<T> * t) const { if( t == nullptr ) return nullptr; if( t->left == nullptr) return t; return findMin( t->left ); } (findMax is virtually the same)
Design and draw the following data structures and their relationships for a Binary Tree: remove
See 2nd lecture slides, page 6 for drawings. void remove( const T & x, BSTNode<T> * t ) { if( t == nullptr) return; // Item not found // now you basically do a search else if( x < t->element ) remove( x, t->left ); else if( x > t->element) remove( x, t->right ); // Next when we find it, different behavior based on children else if( t->left && t-right) { // 2 children t->element = findMin(t->right)->element; // Make a duplicate then remove original remove( t->element, t->right); } else { // if only 1 or fewer child we rearrange BSTNode<T>* oldNode = t; // left one will still be less than right one so check if single child left t = (t->left) ? t->left : t->right; delete oldNode; } }
When are splay trees typically used?
Splay trees are typically used in the implementation of • Caches • memory allocators • garbage collectors • data compression
FILO and FIFO
Stacks are FILO - First in, last-out Queues are FIFO - First in, first out
The Rule of Three
The Rule of Three states that there are three member functions must all be defined if one of them is: the destructor, the copy constructor, and the assignment operator. *If he says use the rule of three, he means implement all three things to the code*
Depth of a node
The depth of any node in a tree is the length of the path from root to the node.
Depth of a tree
The depth of the tree's deepest leaf.
What is Speedup?
The factor by which Execution time is decreased. Speedup = (Old execution time)/(New execution time)
Height of a tree
The height of a tree is the height of its root.
Spatial locality
The locality principle stating that if a data location is referenced, data locations with nearby addresses will tend to be referenced soon.
Why wouldn't you insert nodes from smallest to largest in a BST
They would just be in a normal list from right to left.
Traversal
Traversal is an algorithm where each node is processed, and the same operation is applied to each node.
Data Structure
a collection of data values, the relationships among them, and the functions or operations that can be applied to the data
algorithm
a process or set of rules to be followed in calculations or other problem-solving operations
21 | | 15 27 | | | | 10 18 24 30 a) Which element is the root of the tree b) State all elements on the path to the node containing the value 18 c) State the depth of 21, 27, and 10 d) State all nodes on the level of 24 e) State the height of 21, 27, and 10 f) State the ancestor and descendants of 15
a) 21 b) 21->15->18 c) 0, 1, 2 d) 10, 18, 24, 30 e) 2, 1, 0 f) ancestor: 21, descendants: 10, 18
Express each formula in big-O notation. a) n^2 + 5n b) 3n^2 + 5n c) (n+7)(n-2) d) 100n + 5 e) 5n + 3n^2 f) the number of digits in 2n g) The number of times that n can be divided by 10 before dropping below 1.0
a) O(n^2) b) O(n^2) c) O(n^2) d) O(n) e) O(n^2) f) O(log(n)) g) O(log10(n))
Why does a postfix evaluation algorithm only need one stack?
all numbers and operations go in the same stack
What is a typical implementation of a STL stack?
dynamic array
When would a stack have no need for a preset capacity?
dynamic array (or linked list)
Two uses for nullptr
final link field of a linked list, placeholder when no nodes made yet
Zig-zig
is a scenario of splaying when one of the two conditions is met given a node x 1) The given node x is a left child of a left child 2) The given node x is a right child of a right child
Zig-Zag
is a scenario of splaying when one of the two conditions is met given a node x 1) The given node x is a right child of a left child 2) The given node x is a left child of a right child
Write the following expression in prefix and postfix notation (7+3)*2
postfix: 7 3 + 2 * prefix: * + 7 3 2
Static memory allocation
the mechanism by which memory is allocated at compile time.
Dynamic memory allocation
the mechanism by which memory is allocated during run time.
NULL
the null pointer is a special value that can be used for the pointer that does not point anywhere.
Advantages of data abstraction
Class internals are protected from inadvertent user-level errors, which might corrupt the state of the object. The class implementation may evolve over time in response to changing requirements or bug reports without requiring change in user-level code.
What are classes an example of?
Classes define ADTs
ADT vs. Data Structure
Data structures are concrete representations of data, and are the point of view of an implementer, not a user. An ADT is a mathematical model for data types, where a data type is defined by its behavior from the point of view of a user of the data
Given an array of n integers, a number r, and a direction d (e.g L or R), select a Data Structure that can perform r rotations on the n integers in the d direction, and design and draw the new function calls and their relationship to the data structure. Draw, as examples the example outputs show below In: 5 4 L 1 2 3 4 5 Out: 5 1 2 3 4
Doubly-Linked List something like this might work int main(argc, argv) { r = atoi(argv[2]); n = atoi(argv[1]); D = argv[3]; List = new DList<int>(n); int r = arg while(cin >> k) { List->insert(k) } // make it a loop List->head->prev = tail; List->tail->next = head; // rotate while(r > 0) { List->head = head->next; List->tail = tail->prev; } //Break the loop List->head->prev = nullptr; List->tail->next = nullptr; // c it out Node<T>* current = List->head; while(current != nullptr) { cout << current->data << " "; current = current->next } }
Design and draw the following data structure and its relationships for a doubly-linked list: Empty constructor
Drawing on 1st set of slides, page 23: DList<T>() { this->head = new Node<T>(); }
Design and draw the following data structure and its relationships for a doubly-linked list: Delete
Drawing on 1st set of slides, page 23: Note prev would need to be switched as I use it for two different things in this example. void deleteNode(T key) { if(head == nullptr) throw std::out_of_range("Invalid LinkedList Node"); else if(head->data == key) { head = head->next; head->prev = nullptr; length--; return; } Node<T>* current = head; Node<T>* prev = nullptr; while(current != nullptr && current->data != key) { prev = current; current = current->next } if(current == nullptr) { std::cerr << // key not an element } prev->next = current->next; if(current != nullptr) { prev->next->prev = prev; } if(current == tail) { tail = tail->prev; tail->next = nullptr; } delete current; length--; }
Design and draw the following data structure and its relationships for a doubly-linked list: Destructor
Drawing on 1st set of slides, page 23: ~DList<T>() { Node<T>* current = head; while(current != nullptr) { Node<T>* next = current->next; delete current; current = next; } head = nullptr; tail = nullptr; }
Linked List
A linked list is a set of objects which are arranged in a linear order. Unlike an array, however, the order in a linked list is determined by a pointer in each object.
Node
A node is a fundamental element of the data structure which consists of two fundamental elements 1) Data - The information to be stored in the node 2) Links - Pointers to the additional elements in the ADT.
The principle of locality
A program tends to access data that forms a physical cluster in memory - multiple accesses may be made within the same block
Queue
A queue is a list of elements where a new element is enqueued on one end of the list, and is dequeued on the other end. Elements are first-in, first out.
Register
A register is a small memory element that may hold an instruction, a storage address, or any kind of data as dictated by the program.
Splay tree
A splay tree is a self-adjusting binary search tree with the additional property that recently accessed elements are quick to access again
Stack
A stack is a single-ended ADT where the elements where pushed and popped into the structure such that the elements are returned last-in, first-out.
Key idea of ADT
A type is characterized by the operations you can perform on it. (numbers can be added and multiplied) data structures have an impact on the behavior and performance of the abstract data type. (might not match abstract model, limit capabilities of data type, affect how data type is utilized).
Pointer
A variable whose value is the address of another variable In base addressing, the pointer is the numeric value stored in the register. The offset is the sign extended immediate value.
What would happen if omit parentheses in (*head_ptr).data()
Accessing a data member has higher priority than dereferencing so it will cause an error
Design and draw the following relationships for a Binary Tree node struct: a) Construct a fundamental node b) A constructor with a const c) Move constructor
Drawing on 2nd slides, page 5. template<class T> struct BSTNode { T element; BSTNode *left; BSTNode *right; BSTNode( const T & theElemetn, BSTNode *lt, BSTNode *rt ) : element( theElement ), left( lt ), right( rt ) { } // Create a new node given left and right nodes BSTNode( T && theElement, BSTNode *lt, BSTNode *rt ) : element( std::move( theElement ) ), left( lt ), right( rt ) {} }
Design and draw a queue - and its relationships - that is implemented using two stacks and O(1) additional storage. The implementation should be efficient: the time to do a sequence of n combined operations should be O(n)
Drawings in 1st slides, page 34. We have elements a0, ..., an. If we have two stacks, first verify they are empty. If not, pop out all initial objects. Next, place a0, ..., an on a stack in numerical order, then pop then push these values from this stack into the next stack. This will return them to the original order from the "front" to the "back" of the stack. To get the front() element, use top on the second stack. To get the back() element, use the top on the first stack. Empty must check if both stacks are empty. proving space/time complexity is trivial.
Design and draw the following data structures and their relationships for a Splay Tree: Zig (right child) y | | z x | | | | a b c d
Drawings on 2nd set of slides, page 11. y | | z x | | | | a b c d => root = x x->left = y y->right = c => x | | y d | | z c | | a b
Design and draw the following data structures and their relationships for a Splay Tree: Zig-zig (right-right) y | | z x | | | | a b c d
Drawings on 2nd set of slides, page 11. y | | z x | | | | a b c d => y->right = d d->left = x x->left = c => y | | z d | | | a b x | c => root = d d->left = y y->right = x => d | y | | z x | | | a b c
Function templates
Function templates are special functions that can operate with generic types. This allows us to create a function template whose functionality can be adapted to more than one type or class without repeating the entire code for each type. The formats for declaring function templates with type parameters are: template <class identifier> function_declaration; template <typename identifier> function_declaration;
Given the following code segment, determine and state the runtime in Big-O notation. Assume m and array_length are integers. for(int i = 0; i < m; ++i){ for(int j = 0; j < array_length; ++j) k += array[i][j]; } while(m > 0) m /= 2;
Getting an array value and addition are inner-loop has 2 steps per loop. The inner loop has n occurrences and the outer-loop repeats this n times, so there will be 2n^2 operations. The while loop occurs as many times as 2 divides into m, thus it is log2(n). Thus our total function has 2n^2 + log2(n) steps, and we see that for c = 3, 0 <= 2n^2 + log(n) <= 3n^2 <=> -n^2 <= log(n) <= n^2 choosing n0 = 1, we get -1 <= 0 <= 1 thus 0 <= 2n^2 + log(n) <= 3n^2 for all n => 1 <=> Our function is O(n^2).
Design and draw the following data structures and their relationships for a Binary Tree: traverse
He provided no code for this one, but I believe this would work void traverse( BSTNode<T>* t ) const { if(~t) // error about putting in nullptr else { if(t->left) traverse(t->left) else // display or whatever if(t->right) traverse(t->right) else // display or whatever } }
Amdahl's Law
Helps find the maximum expected improvement to the overall system performance when only part of the system is improved. New Execution Time = Affected/Improvement + Unaffected = Affected(n2/n1) + Unaffected One example is setting setting unaffected and affected to the initial number of instructions changed and unchanged
leaf
I am pretty sure these are nodes with no children
Temporal locality
If an item is referenced, it'll tend to be referenced again soon
Ancestor/descendant
If there is a path from V1 to V2 then V1 is an ancestor of V2 and V2 is a descendent of V1.
What is a double free or corruption error?
If you define a destructor then make a shallow copy of an object your compiler will try to delete the same memory twice.
What elements do queues have?
Queues will have the following elements: push(value) - Insert an element at back pop() - Delete the element at the front front() - Access element at the front back() - Access element at the back empty() - Returns a bool if the queue has any elements
What is a problem with storing noncomplete binary trees as an array?
It would be hard to distinguish which nodes are which
Big-O notation
Let g(n) be a function. Then O(g(n)) := {f(n) : exists positive constants c,n0 such that 0 <= f(n) ,= c*g(n), all n >= n0}
What is improvement in memory allocation?
Let n1 = the memory of the initial program n2 = .... new program Improvement = 1 - n2/n1
Given the following integers, perform insertion for a Binary Search Tree, and then delete the specified integers in order, showing the tree after each insertion.
Page 8 for pictures, but easy. What is trick is in deleting, remember the findMin approach.
Design and draw a stack - and its relationships - which supports max and min operations, which returns the maximum or minimum value stored in the stack when called at any time. Draw a small proof-of-concept to demonstrate the effectiveness of your stack ADT. Prove that the max and min operation runs in O(1) time, and use O(n) space complexity.
Pictures in 1st lecture notes page 30. Make three stacks, one for all of the data, min_stack, and max_stack. As data elements are added to the main stack, compare them with max_stack/min_stack. If it is >=/<= push it appropriately, if not, advance. Use the >=/<= operator as you want redundancy. If you pop the last x elements, you will retain the max/min info for the remainder of the stack. the desired proofs of space/time complexity are left to the reader
Design and draw the following data structures and their relationships for a Binary Tree: contains
See 2nd lecture slides, page 6 for drawings. bool contains( const T & x, BSTNode<T>* t ) const { if( t == nullptr) return false; else if( x < t->element) contains( x, t->left); else if( x > t->element) contains(x, t->right); else return true;
Design and draw the following data structures and their relationships for a Binary Tree: Insert
See 2nd lecture slides, page 6 for drawings. void insert( const T & x, BSTNode<T> * & t ) { if( t == nullptr ) t = new BSTNode<T>( x, nullptr, nullptr); else if( x < t->element ) insert( x, t->left ); else if(t->element < x) insert( x, t->right ); else ; // Duplicate; do nothing }
What are the elements of a stack?
Stacks will have the following elements: • push(value) - Insert an element at the top • pop() - Delete the element at the top • top() - Access element at the top • empty() - Determine whether or not there are any elements
Height of a node
The height of any node in a tree is the length of the longest path from the node to a leaf.
Length of a path
The length of this path is the number of edges encountered. The length of the path is one less than the number of nodes on the path ( k - 1 in this example)
Fundamental idea of splay tree
When a node is accessed, it is immediately pushed to the root. • It is not a simple swap operation between the node and the root. • If the node is deep, there are many nodes on the path which are also deep and by restructuring we can make future accesses simpler on these nodes. • Restructuring, in fact, has side effect of balancing (to some extent)
Zig
Zig is a scenario of splaying where the given node x is the left or right child of the root node
Binary search tree
a binary tree where the left node has a data value less than the parent, and a right value greater than the parent.
An engineer wishes to store a set of integers that can be accessed efficiently as possible. Additionally, the engineer knows that certain elements that are searched for will be searched for again very soon. Propose a data structure that takes advantage of the principle of locality. Show the following operations for insertions and access, and state the best, worst, and average case for insertion. Insertions: 10, 15, 6, 9, 11 Access: 10
too much to type out, see second slide set page 13. It is a splay tree. Best case: O(1) if access the root Worst case: O(n) if splaying causes tree to be all right node. Average case: The search space will be cut in half after each decision => If there are n nodes in the tree, then each decision will divide the possibilities by half => Given c choices, there are 2^cc = n nodes that have been evaluated => log2(n) = c. Also, the splay requires zigs or zags for each level that was traversed => c choices to search and c splays to get the node to the top =? Requires 2c => 2*log2(n) => For c = 2 and n0 = 0 0 < log2(n) < 2*log2(n) Insert runs on average in O(log2(n)) using the proposed Splay Tree
What are malloc and calloc?
malloc and calloc are are library functions that allocate memory dynamically. It means that memory is allocated during runtime (execution of the program), and they return a pointer to the first byte of the allocated memory block if the allocation succeeds. The difference is what the functions do to the memory that has been allocated. malloc allocates memory faster, but the information that was previously in the memory is still there. With calloc, the memory allocation is slower, but this is because all the memory that is allocated is replaced with 0's, getting rid of the previous information