CS260 Final Study Guide
A program can keep track of the front node by using an IntNode reference variable such as...
...head, which is not an IntNode. It is a reference to an IntNode.
Adding a Node to non-balanced BST has runtime...
...in worst case O(n)
If this BST is the same as addend BST, it can cause...
...infinite recursive calls. public void addAll(IntTreeBag addend) { IntBTNode addroot; if (root == addend.root) { addroot = IntBTNode.treeCopy(addend.root); addTree(addroot); } else addTree(addend.root); }
An AVL double rotation is used when an...
...inner subtree is too tall.
If you want to have operations that occur at a cursor, you should use a(n)...
...linked list
If you want to insert/delete operations in middle of list, you should use a(n)...
...linked list
If you want to change capacity or the capacity is not known in advance, you should use a(n)...
...linked list to avoid resizing inefficiency of an array
An AVL single rotation is used when an...
...outside subtree is too tall.
Depth of Tree
--> Maximum leaf depth --> Empty tree has depth = -1
Advantage of Merge Sort
--> Works with linked lists without need for a temporary array. --> Can be used to sort data in a huge disk file. --> A file much too large to fit in memory. --> Subdivide the file into pieces small enough to fit in memory. --> Sort the pieces. --> Merge the pieces together.
Collection class
--> A class in which instances contain collections of elements. --> Can be implemented as a class, along with methods to add, remove, and examine items --> Arrays are often used to implement collection classes
Tree?
--> A data structure in which each Node has exactly one parent, with the exception of the Root node, which has no Parent. --> leaf: Node with no Children
Array Representation of Complete Binary Trees
--> A partially-filled array is perfect data representation for a complete binary tree. --> A new node is added to the tree at the next available position on the deepest level. This corresponds to array position given by "manyNodes." It is possible to "ensureCapacity" when needed. State -private char[ ] data; -private int manyNodes
Dynamic Queue
--> A priority queue is similar to a regular queue except a priority is attached to each item --> The item with the highest priority is removed next, regardless of where it occurs in the sequence --> Items with equal priority are removed FIFO
Insertion Sort
--> A simple sorting algorithm that builds the final sorted array (or list) one item at time. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort. --> Each insert operation places an additional element into a portion of the array that has already been sorted as follows: public static void insertionsort(int[ ] data, int first, int n) { //Consider data[0..0] already sorted for (i = 1; i < n; i++) { //Insert data[i] into the proper position of //data[0..i] } }
Binary trees may be represented using...
--> Arrays (This is only practical for complete binary trees) --> Pointers (Each node has two pointers)
IntTreeBag class
--> Assume nodes are represented by class IntBTNode, similar to generic node class BTNode<E>. --> Assume that the BST is always kept in balance. public class IntTreeBag implements Cloneable -private IntBTNode root public IntTreeBag { root = null; }
Heap removeNode()
--> Method to remove the node at the root and then to put the remaining nodes back into the form of a heap. --> Copy the data in the root to local variable answer. --> Copy data d in the last node to the root node. --> Remove the last node. --> Return the tree to the form of a heap. while ((node of d is not a leaf) && (d < data in either of d's children)) //swap d with the data in the largest child --> This step is known as "reheapification downward". --> Return answer. --> The big-O of remove is O(log(n)).
Heap
--> a complete binary tree such that, at each node n, the value is >= the values in its children. --> The parent node is bigger/smaller or equal to that of the child.
Constructing hash() methods
--> Assume that the key has already been converted to an int using hashCode() or some other method. --> The hash() method used to map the int to a valid array index should: --> Be efficient to compute with O(1). --> Distribute the keys evenly throughout the array. --> Use all key information. --> Break up natural clusters of keys. --> A very good hash method is known as division hash function hash(key) = Math.abs(key) % table.length --> This method satisfies the first 3 criteria for a good hash function. --> However, it does not break up natural clusters of keys. --> Nearby keys keep their relative positions except when one key wraps around and the other does not. --> Another hash method is multiplication. Let M = (5^(0.5) - 1)/2 = 0.6180339887... hash(key) = (int)(arrayCapacity* < fractional part of M*key >) --> Still another is called mid-square. hash(key) = < extract some middle digits or bits from (key)2 >
Quick Sort runtime
--> Best case = average case = O(nlog(n)). --> When pivot occurs near the center of each time --> Number of levels = O(log(n)). --> Number of probes within each level = O(n). --> Worst case = O(n2). --> When pivot occurs near an end most of the time, for example, when the array is already sorted. --> Number of levels is only limited by n.
Serial Search runtime
--> Best case: --> Success on the first access. --> O(1) - constant performance. --> Worst case: --> Failure. --> O(n) - linear performance. --> Average case: --> Assume success equally likely at each position (Average # of accesses) = [(total # of accesses over all positions)/(number of positions)] = (n(n+1)/2)/n = (n+1)/2 --> O(n) - linear performance.
Improvements for Merge Sort and Quick Sort
--> Both mergesort and quicksort encounter more and more overhead due to recursion when the subarrays get small, so both can be improved as follows: --> When a subarray represents less than some number M of elements, use the insertion sort method on the subarray instead of making a recursive call. --> A typical value for M might be around 100.
Full Binary Tree
--> Each leaf has the same depth --> Every non-leaf has 2 children --> A full binary tree of depth d has 2^(d+1)-1 nodes
Hash Code Method
--> Every Java class inherits method hashCode() --> This method maps any key object to an int. --> The resulting int must subsequently be mapped to the range 0...(table.length - 1) by a method hash() supplied by the programmer. table[hash(key.hashCode())] --> Objects that are equal (shallow copy) must return the same hash code. --> Different objects do not need to return different hash codes. --> a.hashCode() == b.hashCode() does not imply a.equals(b).
Selection Sort runtime
--> For (n - 1) element requires the time of finding the suitable index. --> May require n - 1 comparisons in max. --> Best case = worst case = average case = O(n2).
Insertion Sort runtime
--> For n elements it may require n times compare and shift operations. --> Worst case = average case = O(n2). --> Best case = O(n). --> The algorithm takes advantage of the situation when the array is already sorted.
Hashing Collision Example
--> Hash your birthday to the range 0..365, ignoring leap years. --> Question:In a classroom with 23 students, what is the probability of the students having at least one collision? --> Answer: Greater than 50%. --> So, with an array loading factor of less than 6%, there more than a 50-50 chance of a collision. --> Collisions are almost guaranteed to happen. --> They must be handled in an efficient manner.
Search by Hashing
--> Hashing is a search technique with average O(1) performance used to search a key-value table. --> A key-value table is also known as a Dictionary, Map, or Associative array. --> A hash function associates every possible key with a position in the array. --> The hash function must be easy to compute. --> To search for a key-value pair, the hash function is applied to the key and the resulting position in the array is accessed. --> Not only is the average hashing performance constant, it is also efficient to add and remove key-value pairs. --> The hash function has the form: private int hash(<key type> key) --> The integer returned by the hash function must be a valid array index. --> Hashing is fast for searching, insert, and delete.
Heap Sort
--> Heapsort is a superior O(n log(n)) method. --> Array size doesn't change, but heap size does. --> Take off bottom, reshuffle, repeat. --> Less efficient than max-heapify because it sorts from the top instead of the bottom. --> Assume the array to sort is int[] a = new int[n] --> First convert an unsorted array to a heap. --> Then, iteratively, remove the root element, rebuilding the heap each time. --> The root element is always the largest remaining element. --> The elements, as removed, are in descending order. --> Notation: Define a[i .. j] to consist of the elements a[i], a[i+1], a[i+2], ..., a[j].
Array Representation of Incomplete Binary Trees
--> If the binary tree is not complete, the array representation has poor space efficiency. --> If node J had a right child, the capacity would have to increase from 15 to 31. --> If the nodes contain object rather than primitive data, then null can be used for each missing child. --> No need for the Boolean array in this case.
Heap addNewNode()
--> Initially place the new node in the next available position in the complete binary tree. --> This is easy with the partially-filled array representation. --> This temporarily results in a non-heap. --> Return the tree to the form of a heap. while ((new data is not at the root) && (new data > parent's data)) //swap new data with parent's data --> The final step is known as "reheapification upward". --> The big-O of add is O(log(n)).
If key-value pairs in a binary tree are stored unordered using an array or a linked list, then...
--> Insertion has constant time performance, but the look-up and deletion operations have only linear performance.
Maintaining a priority queue using heap
--> Interpret the priority of each node as the "value" contained in the node. --> After insert and delete operation, the tree remains complete. --> Note that the highest priority node will be at the root. --> For this to be practical, it must be possible to remove the root node, and put the remaining nodes back into the form of a heap. --> Also, it must be possible to add new nodes to the heap.
Complete binary tree
--> Like a full binary tree except nodes may be missing from the right side of the deepest level --> require the nodes to fill in each level from left-to-right before starting the next level
Quick Sort
--> Non-stable, in-place sort. Works by making use of a divide and conquer method. The array is divided into 2 parts, and then the parts are sorted independently. An arbitrary value is chosen as the partition. Afterwards, all items which are larger than this value go to the right of it, and all items which are less than this value go to the left of it. --> Quicksort works in a manner opposite to Merge Sort. --> The partition operation iterates through all the elements before the recursive calls rather than after. --> The partition operation does rough sorting ahead of time. public static void quicksort(int[] data, int first, int n) { int pivotIndex; //Array index for the pivot element int n1; //Number of elements before the pivot element int n2; //Number of elements after the pivot element if (n > 1) { //"Partition" the array in two parts such that //(all elements in left part) < (all elements in the //right //part) and set the pivot index. pivotIndex = partition(data, first, n); //Compute the sizes of the two pieces. n1 = pivotIndex - first; n2 = n - n1 - 1; //Recursively call quicksort to each part to sort //the two pieces. quicksort(data, first, n1); quicksort(data, pivotIndex + 1, n2); } }
Applications of Stack
--> Organize from the most recently used/accessed data --> Evaluation of arithmetic expressions --> Expression conversion (Infix to Postfix and Prefix, etc.) --> Language processing (Check matching parenthesis) --> Processing undo operations --> Reverse a sequence of data --> Processing function calls (Recursion) --> Solving backtracking algorithms --> Some algorithms to increase the efficiency
Binary Search runtime
--> Recall the precondition: --> The array must be sorted before the binary search may be used --> Worst and Average case: O(log(n)).
Merge Sort
--> Recursive sorting algorithm that divides a list in half, then combines them (2 lists at a time). public static void mergesort(int[] data, int first, int n) { //Divide the array in half. int n1; //Size of the first half of the array int n2; //Size of the second half of the array //Recursively apply mergesort to each half. if (n > 1) { // Compute sizes of the two halves n1 = n / 2; n2 = n - n1; mergesort(data, first, n1); //Sort data[first] through data[first+n1-1] mergesort(data, first + n1, n2); //Sort data[first+n1] to the end //Merge the sorted halves into a sorted temporary array merge(data, first, n1, n2); } //Copy the temporary array back to the original //array } --> Recursive stopping case: when a subarray to be sorted consists of only one element. --> During the merge process, when one of the halves becomes empty, simply copy the remainder of the remaining half to the end of the temporary array.
Heap Sort runtime
--> Since the heap is complete binary tree, it is automatically balanced. --> The depth of tree is O(log2(n)). --> Worst case analysis of heapsort: Operation to build the initial heap + Operations to pull the elements out of the heap one at a time. --> Building the initial heap for (n - 1) requires number of operations for one reheapification upward = (n - 1) * (log2(n)). --> Operations to pull the elements out of the heap one at a time require the same amount of time: (n - 1) * (log2n). --> Total time = O(2nlog2(n)). --> Worst case analysis of heapsort is O(nlog(n)). --> The worse case performance is also the best case performance and the average case performance.
Balanced binary trees
--> The height of the left and right subtrees can differ by at most one. --> Otherwise, rotations are required. --> An unbalanced tree may be balanced by using the AVL (Adel'son, Vel'skii, and Landis) algorithm, which relies on 2 basic operations - Single rotation & Double rotation
What is a problem with hashing?
--> The ideal situation is to store the key-value pair in table[hash(key)] --> Problem: the possibility of a collision or a "hash clash." --> A collision is when: key1 != key2 but hash[key1] == hash[key2] --> It is not usually possible to obtain a perfect hash function. --> How we resolve this problem leads to various special hashing techniques: --> Open-address hashing. --> Double hashing. --> Chained hashing.
Depth of a Node
--> The number of ancestors, including the root --> Depth of root = 0
Open Address Hashing
--> The open-address hashing algorithm for searching is to use linear probing until the key is found, i.e. success, or until table[Lp].hasBeenUsed == false, i.e. failure. --> To reduce the number of collisions, the maximum number of items to be placed in the table needs to be known in advance. --> The capacity of the array must be set to a size somewhat larger.
Open-Address Hashing
--> The open-address hashing technique resolves collisions using linear probing. --> For linear probing, establish a sequence of predetermined alternate locations to use in the event of a collision. Let L0 = hash(key) If L0 is occupied, use a series of alternate locations L1, L2, L3, ... Alternate Lp is defined by Lp+1 = (Lp + 1) % table.length --> Note that this wraps around the array if necessary. --> Linear probing uses the first available open location. --> Alternate locations are tried in order. --> The sequence of alternates is needed in the event there are collisions at some of the alternate locations. --> To handle deletions, you need to mark each location as one of: --> hasBeenUsed or hasNotBeenUsed. -For this purpose, add a new boolean instance variable hasBeenUsed to the Pair class.
Merge Sort Runtime
--> The usual technique of determining the big-O of a recursive methods does not work here, since there are only half as many elements in the merge phase within each successive recursive call. --> Instead look at the merge activity across an entire level at a time and ignore the actual number of recursive calls. --> The big-O of merge across each level is O(n). --> There are O(log(n)) levels. --> Worst case = average case = best case = O(nlog(n)).
Finding the rightmost node of a binary tree
--> To find the rightmost node of a binary tree, start at the root and iteratively follow right pointers until a right pointer is null. --> The final node in this sequence is the rightmost node. public E getRightmostData() { if (right == null) return data; else return right.getRightmostData(); }
Method removeLeftmost()
--> Use of removeLeftmost() is not restricted to the leftmost node of the entire tree. public BTNode<E> removeLeftmost() { if (left == null) return right; else { left = left.removeLeftmost(); return this; } } root.setRight(root.getRight().removeLeftmost());
Disadvantages of Linked Lists
--> Wastes storage for the links --> added complexity --> no "random" access as with an array
Advantages of Linked Lists
--> do not have to be stored in consecutive memory locations, successor can be stored anywhere physically --> can insert and delete without shifting data --> can easily increase size of data structure (Linked Lists dynamically grow and shrink, more flexible than an array) --> Memory added only incrementally
Recursion
--> is the concept of a method calling itself --> is often an alternative to iteration --> a recursive algorithm must have at least one stopping case with a non-recursive solution
Tree Traversal
--> iterating over a tree. --> Each node must be visited exactly once in a systematic way. --> There are three common techniques, all O(n): 1. Preorder NLR 2. Inorder LNR 3. Postorder LRN --> Each traversal technique is best implemented with a recursive method.
Queue
--> one of the most useful of all data structures --> used when elements have to wait their turn, or buffering data --> has First-In-First-Out behavior
Stack
--> one of the most useful of all data structures. --> a sequence of elements in which elements can be added or removed only at one end called the top. --> has Last-In-First-Out behavior.
The class definition for an ADT should have...
--> private instance variables --> public instance methods and constructor(s)
Disadvantage of Merge Sort
--> when used with arrays, a second temporary array is needed. --> This effectively cuts the size of the largest array that can be sorted in half
Finding the leftmost node of a binary tree
-->To find the leftmost node of a binary tree, start at the root and iteratively follow left pointers until a left pointer is null. --> The final node in this sequence is the leftmost node. public E getLeftmostData() { if (left == null) return data; else return left.getLeftmostData(); }
Insertion Sort is a good method to use when...
...a few updates need to be added from time to time so that the array remains sorted.
If you want to have frequent random access operations, you should use a(n)...
...array
If you want to have operations that occur at a two-way cursor, you should use a(n)...
...doubly linked list
Adding a Node to a balanced BST and Heap has runtime...
...O(log(n))
Removing a Node from a balanced BST and Heap has runtime...
...O(log(n))
Searching a Node from a balanced BST has runtime...
...O(log(n))
What is Stack underflow?
An attempt to pop or peek an empty stack.
4 Types of Collection Classes
1. Bag - an UNORDERED collection of elements of the same type with duplicates PERMITTED. 2. Set - an UNORDERED collection of elements of the same type with duplicates PROHIBITED. 3. Sequence - an ORDERED collection of elements of the same type with duplicates PERMITTED. The data is not necessarily sorted. 4. Dictionary/Map - an UNORDERED collection of key/value pairs in which there are NO duplicates among the keys. Duplicates among the values are permitted.
What is a better way to choose the pivot value for Quick Sort?
1. Choose the median of the three values... •data[first] •data[first + n - 1] •data[first + n/2] -2. Swap the chosen value with data[first]. -3. Continue as before. •This method is called the median of 3. •Statistically, this gives a much better pivot value. --> Performance is much more likely to be O(nlog(n)). --> Even when the data is already sorted.
4. Steps to add an IntNode to the front of the Linked List
1. Create a new Node. 2. Place the data in the new Node's data field. 3. Connect the new Node to the front of the List. 4. Make the head refer to the new head of the Linked List.
8 steps for converting a non-generic class to a generic class
1. Update the name of the class by adding <E>. 2. Find all places where the type of the underlying element should be changed to E. 3. Change any static methods to generic static methods. 4. Don't create new E objects or arrays. 5. Replace any primitive equality test "==" or "!=" by calls to equals. 6. Decide if null is ever allowed as an element. If so, then equals( ) cannot be applied to null elements. 7. Set unused reference variables to null. 8. Update all documentation.
//Which of the 3 casts is a widening conversion, narrowing conversion, and compiler error? String s = new String( "Message" ); Object obj; obj = s; s = obj; s = (String) obj;
1. Widening conversion (automatic in Java) 2. Compiler error 3. Narrowing conversion
What is a tree used for?
A binary taxonomy tree can be used to represent certain kinds of knowledge
What is a clone?
A clone is an exact copy of an instance
Abstract Data Type
A data structure emphasizing properties, functionality, and use rather than implementation. (ADT) consists of private data together with methods that act on that data.
Binary Tree
A data structure that consists of nodes, with one root node at the base of the tree, and two nodes (left child and right child) extending from the root, and from each child node. Each node only has 2 children.
Linked List
A linear data structure, much like an array, that consists of nodes, where each node contains data as well as a link to the next node, but that does not use contiguous memory. Each Node is an object consisting of "info" and the "link". This "info" could be primitive data or a reference to another object.
What is a doubly-Linked List?
A linked list that has pointers to the next node and the previous node, which is effective for moving forward and backward through a list.
Traversal of the addend tree is best done with what kind of method?
A recursive (private) helper method private void addTree(IntBTNode addend) { if (addend != null) { add(addend.getData()); //Recursive call to add all of left subtree //Recursive call to add all of right subtree } }
Selection Sort
A sorting routine that uses a nested loop process to systematically select the best value among the unsorted elements of the array for the next position in the array, starting with position zero all the way to the end. public static void selectionsort(int[ ] data, int first, int n) { //Find the largest element. Swap it with the last. //Find the next largest. Swap it with the next to last. //Etc. } --> The sort range is data[first .. (first + n - 1)] --> A typical call is selectionsort(a, 0, n) --> Here a is an array of n cells.
Subtree
Any node together with all of its descendants
Serial Search (or linear or sequential search)
Goal: Look for a target value in a[ first .. (first + n - 1) ] --> A search method typically might return (first + i) for success or -1 to indicate failure. int i; for(i = 0; (i < n) && (a[first + i] != target); i++); //loop //ended. if ((i < n) && (a[first + i] == target)) { < success at (first + i) >; } else < failure >;
Inorder Tree Traversal
LNR = Left Node Right D B A E G C H F I 1. Process the nodes in the left subtree with a recursive call. 2. Process the root. 3. Process the nodes in the right subtree with a recursive call. public void inorderPrint() { if (left != null) left.inorderPrint(); System.out.println(data); if (right != null) right.inorderPrint(); }
Postorder Tree Traversal
LRN = Left Right Node D B G E H I F C A 1. Process the nodes in the left subtree with a recursive call. 2. Process the nodes in the right subtree with a recursive call. 3. Process the root. public void postorderPrint() { if (left != null) left.postorderPrint(); if (right != null) right.postorderPrint(); System.out.println(data); }
Binary Search
Looking for an item in an already sorted list by eliminating large portions of the data on each comparison. Often written as a recursive method. public static int binarySearch(int[] a, int first, int last, int target) { int mid = (first + last)/2; if(first > last) { return -1; } if(target < a[mid]) { return binarySearch(a, first, mid-1, target); } else if(target == a[mid]) { return mid; } else { return binarySearch(a, mid+1, last, target); } }
If a binary search tree is balanced, what is the Big O complexity of search?
O(log(n))
Preorder Tree Traversal
NLR = Node Left Right A B D C E G F H I 1. Process the root. 2. Process the nodes in the left subtree with a recursive call. 3. Process the nodes in the right subtree with a recursive call. public void preorder() { data.visit(); if (left != null) left.preorder(); if (right != null) right.preorder(); }
Can you create a new array of elements of the generic type?
No
Can you call a constructor for the generic type?
No.
does t2 = t1 create a clone?
No. This just gives an alias. A special clone( ) method must be implemented.
If a binary search tree is unbalanced, what is the Big O complexity of search?
O(n)
total order semantics
Operations <, >, <=, >=, ==, and !=
Array Representation of Complete Binary Trees
Suppose each node contains one character char[ ] a = new char[ n ]; //n is the number of nodes 1. Store root in a[0] 2. Store left child of a[i] in a[2 * i + 1] 3. Store right child of a[i] in a[2 * i + 2] 4. Parent of a[i] is in a[(i - 1)/2] //int division
Why should an inorder traversal should be avoided when using addAll() for a IntTreeBag?
The nodes would be visited in ascending order, creating a long, unbalanced tree. public void addAll(IntTreeBag addend)
What is Queue Underflow?
When remove is applied to an empty queue
Serial Search
a search for information in which several stores or slots of information are sequentially examined for match to the target
If a BST is traversed using an inorder traversal, then the nodes are visited in _________ order.
ascending
Array Representation of Incomplete Binary Trees
char[ ] data = new char[n]; boolean[ ] filled = new boolean[n];
Stack question: Which notation is postfix and which is infix? 7 2 * 3 5 * + 2 6 * + 19 5 - * 2 / ( 7*2 + 3*5 + 2*6 )*( 19 - 5 ) / 2
infix notation ( 7*2 + 3*5 + 2*6 )*( 19 - 5 ) / 2 postfix notation 7 2 * 3 5 * + 2 6 * + 19 5 - * 2 /
Reheap Down
int current = 0; //Index of the node be moving down int bigChildIndex; //Index of current's larger child boolean heapOK = false; while ((!heapOK) && (the current node is not a leaf)) { //Set bigChildIndex = Index of the larger child of the //current node if (data[current] < data[bigChildIndex]) { swap(data[current], data[bigChildIndex]); current = bigChildIndex; } else heapOK = true; }
The depth of a balanced binary tree with n nodes is O(______).
log(n)
What is the maximum number of comparisons needed to search for an element in a BST or to insert an element?
maximum comparisons = depth + 1
Binary Search Tree
provides an implementation of a table combining logarithmic look-up with logarithmic insertion and deletion operations.
Method removeRightmost()
public BTNode<E> removeRightmost() { if (right == null) return left; else { right = right.removeRightmost(); return this; } }
remove() for IntTreeBag
public boolean remove(int target) { //If it finds and removes the target, return true //Otherwise, return false //First search for the target //If not found, return false //Use a pointer, parentOfCursor that refers to the //parent of the cursor node //This method is implemented by dividing the //problem into 3 mutually exclusive cases //1. Target at the root and no left child root = root.getRight(); //2. Target not at the root and no left child //Example: nodes A or M if(cursor == parentOfCursor.getLeft()) { parentOfCursor.setLeft(cursor.getRight()); } else { parentOfCursor.setRight(cursor.getRight()); } //3. Target has a left child (children) or Target is at the root and Target has a left child (children). cursor.setData(cursor.getLeft().getRightmostData()); cursor.setLeft(cursor.getLeft().removeRightmost()); -->For a balanced tree, the performance of remove is logarithmic
countOccurences() for IntTreeBag
public int countOccurrences(int target) {//Starting at the root, loop as far as possible: cursor = root; //At the current node, if (target == data) count ++; if (target <= data) && (left != null) { cursor = cursor.getLeft(); } if ( target > data ) and ( right != null ) { cursor = cursor.getRight(); } } --> For a balanced tree, the performance of countOccurrences is logarithmic
Quick Sort Partition Method
public static int partition(int[ ] data, int first, int n) --> The partition method rearranges elements such that all the elements in the left part will be smaller than any of the elements in the right part. --> A value called the pivot value will end up between the elements of the two parts. --> This pivot value is >= each element of the left part and <= each element of the right part. --> Partition method returns the pivot index giving the position of the pivot value. --> Start by choosing a "pivot" value to help with the partitioning process. --> Ideally, the "pivot" value would be the median of the elements in the sort range, then the two parts would be nearly equal in size. --> However, finding the median is a O(n) operation. This is too inefficient. --> Instead, simply choose data[first] for the pivot. Later, we will improve on this guess --> Then use two indices to sweep through the data, u for "up," d for "down." --> Sweep through the data as follows: 1. Move u up and d down until the values they refer to are out of order with respect to the pivot value. 2. Then swap the u and d values and continue. 3. Stop when u and d pass each other. 4. Finally, swap data[d] with the pivot value data[first]. 5. Return index d.
Heap Sort method
public static void heapsort(int[] a, int n) 1. Note that a[0..0] is already a heap (only one element) 2. Turn a[0..(n-1)] into a heap by successively adding... a[1] to a[0..0] a[2] to a[0..1] a[3] to a[0..2] • • • a[n-1] to a[0..(n-2)] --> These steps could be written as a private helper method called makeheap: 3. Iteratively remove the largest remaining element and rebuild the heap for (int i = n-1; i > 0; i--) { Exchange a[0] with a[i] Perform "reheapification downward" on a[0..(i-1)] } --> Note: The largest remaining element is only removed from the heap logically but remains physically in the array (in the new position) --> Note: Reheapification downward could be written as a private helper method called reheapifyDown: public static void reheapifyDown(int[] a, int n)
mapHeap()
public static void makeHeap(int[] a, int n) { for (i = 1; i < n; i++) {// For all element in the array k = i; //The index of new element while (data[k] is not yet the root && data[k] is bigger than its parent) { //swap(data[k], data[k]'s parent) //k = index of data[k]'s parent } } }
add() for IntTreeBag
public void add(int element) { //Assume insert S if (root == null) root = new IntBTNode(element, null, null); else //Start from K: cursor = root { //Descend from the root until the pointer //in the desired direction is null cursor = cursor.getRight(); cursor = cursor.getRight(); //Replace the null pointer by pointer //to new IntBTNode(element, null, null); cursor.setRight() = new ('S', null, null); } } --> For a balanced tree, the performance of add is logarithmic.
May generic Java collection classes implement the generic Collection<E> interface?
yes