Content
Recursive Lists Tree Tree Traversals Binary Search Tree (BTS) The BinarySearchTree Interface BST-Based Set <- Go BackUniversity of Michigan at Ann Arbor
Last Edit Date: 04/09/2023
Disclaimer and Term of Use:
We do not guarantee the accuracy and completeness of the summary content. Some of the course material may not be included, and some of the content in the summary may not be correct. You should use this file properly and legally. We are not responsible for any results from using this file
This personal note is adapted from Professor Amir Kamil, Andrew DeOrio, James Juett, Sofia Saleem, and Saquib Razak. Please contact us to delete this file if you think your rights have been violated.
This work is licensed under a Creative Commons Attribution 4.0 International License.
The data representation of a linked list is an example of structural recursion: the Node
type uses itself in its own representation:
1 struct Node {
2 int datum;
3 Node *next;
4 };
This representation satisfies the requirements for a recursive abstraction:
The empty list is the base case, represented by a null pointer.
A non-empty list is a recursive case; it can be subdivided into the first node and the rest of the list, which represents a list in its own right.
Independent of its representation, a linked list can actually be defined recursively as either an empty list, or a datum followed by a smaller list.
Given the recursive definition of a list, it is natural to process a list with a recursive function. The base case of the recursive function will be the minimum-size list allowed by the function, and larger lists will be handled in the recursive case. As an example, the following is a recursive function to compute the length of a list:
1 // REQUIRES: node represents a valid list
2 // EFFECTS: Computes the length of the list that starts at the
3 // given node.
4 int length(const Node *list) {
5 if (list == nullptr) { // empty list
6 return 0;
7 } else { // non-empty list
8 return 1 + length(list->next); // list->next is a smaller list
9 }
10 }
The length of an empty list is 0. The length of a non-empty list is one more than the length of the rest of the list; the elements in the list consist of the initial datum and the elements in the rest of the list. We use the length()
function itself as an abstraction to compute the number of elements in the remainder of the list, taking the recursive leap of faith that it will compute the right answer.
Another example is to find the maximum element in a list. Unlike for length()
, the minimal list is not an empty one, since an empty list has no elements in it. Instead, the minimum required size is a list with a single datum, in which case the maximum element is just that line datum, constituting our base case. For a large list, we can break it down recursively as follows:
Find the maximum element in the rest of the list. This element is at least as large as any other element in the rest of the list.
Compare the first element to the max of the remainder. The larger of the two is transitively at least as large as the elements in the rest of the list.
The following implements this algorithm:
1 // REQUIRES: node represents a valid, non-empty list
2 // EFFECTS: Returns the maximum element in the list that starts at
3 // the given node.
4 int list_max(const Node *list) {
5 if (list->next == nullptr) { // list has only one element
6 return list->datum;
7 } else { // list has more than one element
8 return std::max(list->datum, // compare first datum to
9 list_max(list->next)); // max of rest of lest
10 }
11 }
The base case is a list with one element. Such a list has an empty next
list, so we check for that and return the list's lone datum.
The recursive case computes the max of the rest of the list and then uses std::max()
to determine the maximum of that item and the first item in the list.
As always, we take the recursive leap of faith, assuming that the recursive call to list_max()
computes the right answer for the smaller list.
A tree is a (possibly non-linear) data structure made up of nodes or verticwa and edges with only one pathway from the root node to a given node.
The tree with no nodes is called the null or empty tree. A tree that is not empty consists of a root node and potintially many levels of additional nodes that from a hierarchy.
Binary tree is a tree that is either empty (or null) or each node has a maximum of two children, left subtree and a right subtree.