ordered versus unordered: we usually, but not necessarily, think of the children of a node as ordered, from left to right, say
nodes: the “places” where data items are kept in the tree
path: a sequence of links between nodes (and the nodes along the way, depending on context)
sub-tree: a node in a tree considered as a root of its own tree
internal nodes: nodes which have a child
fringe: the set of all leaves of a tree, considered as a sequence
A tree is a collection structure which can hold elements in positions called nodes;
a tree is a linked structure, but unlike a linked list, each node may have several linked nodes
links: the connections between nodes (represented as references/“pointers” in Java)
root: the top node of a tree
parent: the node immediately above a given node (similarly for grandparent, ancestors, etc.)
height: the number of links between the root of a tree and its furthest descendant
leaf or external node: nodes which have no children (or all null children, in a Java implementation)
sharing and cycles: in a proper tree, no node had two parents (no sharing) and no links go back “up” from a node to one of its ancestors (or cousins, etc.): such paths would be called cycles
children: the nodes immediately below a given node (similarly for grandchildren, descendants, etc.)
in a graph, by contrast, nodes are connected by links in arbitrary ways: possibly no root, possibly sharing and cycles, possibly even multiple sets of disconnected nodes (sub-graphs)
General trees
in a general tree, any node may have an arbitrary number of children
we could represent children in a general tree using any (ordered) collection, but a linked list might be best
we can also use a first-child/next-sibling representation, which shows that a binary-tree structure can be used to represent a general tree (in this case the “next sibling” links form a kind of linked list)
Binary trees
when every node in a tree has at most two children and they are distinguished as left- and right-children
in other words, when every node has a left and right child, either of which may be null
Tree traversals
if we substitute a queue for the stack, we get breadth-first traversals (also known as level-order)
a tree traversal is a process visiting all the nodes (or elements thereof) in a tree
typical traversals are implemented recursively: we “visit” the node and recursively traverse the sub-trees, in some order
by varying the relative order of node visitation and sub-tree traversal, we get different standard orders:
left-right inorder: traverse left, visit node, traverse right
… and so on, for three others but right-to-left (6 possible permutations all together)
left-right pre-order: visit node, traverse left, traverse right
if we don’t want to use recursion, we can use an explicit stack instead
Binary search trees
binary search trees (BSTs) implement the Dictionary<K,V> interface, allowing values to be looked up by key
insertion and lookup in a BST can be very efficient (O(log n)) if the tree is sufficiently “bushy”:
compare value being inserted (or sought) to the element in the root, go left or right as appropriate
height of a bushy tree is O(log n) where n is the total number of elements
a binary search tree is a binary tree whose elements support some ordering, and where:
equal values can be handled in several ways (keep counts in nodes, or just ignore if duplication is not important)
all the nodes to the left of the root hold values that are less than the the one in the root
all the nodes to the right of the root hold values that are greater than the the one in the root
similarly for all sub-trees (i.e., same rule throughout the tree)
int the worst case, successive insertion of items already in order (or in reverse order) will result in a long, skinny, “tilted” tree with O(n) lookups