// README PLEASE // Solutions for recursive functions in class 5/17 in pseudocode // Most of these solutions will assume appropriate input (invalid input handling varies by user requests). // I've included explanations for some thought processes and important ideas. The explanations are not the // best since drawing diagrams in code is difficult. Draw out examples to visually see what happens. // Note: There are many solutions, but these are just my attempts. class Node: data Node next class DLLNode: data DLLNode prev, next // Find the sum of an int array given the array /* Find the sum of an int array given the array Each time we call a recursive function, we need to step closer to a base case. Given just the array, we could recursively call the function and pass in a subarray. My recursive helper method instead takes in an incrementing index from 0 ... arr.length-1 */ int recursiveSum(int[] arr): return recursiveSumHelper(arr) int recursiveSumHelper(int[] arr, int index): if index == length(arr): return 0 else return arr[index] + recursiveSumHelper(arr, index + 1) /* Checks to see if a singly linked list contains data. This is too similar to a Homework 1 function, so no implementation :( */ boolean recursiveContains(Node curr, data): // TODO /* Checks to see if a Singly Linked List is sorted in ascending order. Assume we pass in the head node. The base cases are either: - We stop at a node where its data is larger than the next nodes data. - We reach the end of the linked list. This means we had no trouble with the above condition implying the list is sorted To recursevly step through our linked list, we recursively call recursiveIsSorted() with the current nodes next. */ boolean recursiveIsSorted(Node curr): if curr.next == null: return true else if curr.data > curr.next.data: return false else: return recursiveIsSorted(curr.next) /* Attempts to remove the node holding data from a singly linked list. Assume we pass in the head node. This returns the new head node with the data removed if possible. The base cases are either: - we find the data, in which we'd have to remove - we don't find data This solution does something we call pointer reinforcement (I don't know the name of this technique, but we'll just call it this). This is the idea of having curr.next set to whatever node our recursive function returns. Most of the time our recursive function will just return curr, so if we have: Node nextNode = curr.next curr.next <- recursiveRemove(nextNode, data) and recursiveRemove(nextNode, data) ends up returning nextNode, our node connection will be the same in the end. curr.next <- nextNode However, we can use this opportunity to potentially have curr.next point to something else. If we find out: Node nextNode = curr.next curr.next <- recursiveRemove(nextNode, data) and within the recursive call recursiveRemove(nextNode, data) we find that: nextNode.data == data Then we can return nextNode.next. This means that when our recursive function returns, it returns nextNode's next curr.next <- nextNode.next */ Node recursiveRemove(Node curr, data): if curr == null: return null else if curr.data == data: return curr.next else: curr.next <- recursiveRemove(curr.next, data) return curr /* Remove duplicates in a sorted singly linked list. Assume we pass the head node. This returns the new head node with duplicates removed. Again we use this pointer reinforcement idea. In our else statement, we set curr.next to whatever our recursive function returns. Our recursive function returns 2 different values: - returns curr if curr and curr.next do not have the same data. Node nextNode = curr.next curr.next <- recursiveRemoveDuplicates(nextNode) if nextNode and nextNode's next are not duplicates, then the recursive function returns nextNode. curr.next will be assigned nextNode, so nothing has changed. - returns curr.next if curr and curr.next have the same data. if we have the same example as above but nextNode and nextNode's next are duplicates, then the recursive function returns nextNode's next. This gives us: curr.next <- nextNode.next and essentially removes nextNode from the chain. */ Node recursiveRemoveDuplicates(Node curr): if curr == null: return null else: curr.next <- recursiveRemoveDuplicates(curr.next) if curr.next != null AND curr.data == curr.next.data: return curr.next else: return curr /* Reverse a doubly linked list assuming you input the head of a DLL. Assume we start with the head node. The base case is: - we reach the end of our double linked list Every recursive step includes swapping the current DLLNode's references. */ DLLNode recursiveReverse(DLLNode curr): if curr == null: return curr; else: DLLNode temp <- curr.next // we swap pointers of the current node curr.next <- curr.prev curr.prev <- temp if curr.prev == null: // Base case: if we reach the old tail, the prev pointer (formally being next) will point to null now return curr return recursiveReverse(curr.prev) // Recursive case: we recursively call but traverse with curr.prev not curr.next.