Presentation is loading. Please wait.

Presentation is loading. Please wait.

Tree 1 2 3 A tree is a data structure in which each node is comprised of some data as well as node pointers to child nodes. 4 5 6 7 8 9.

Similar presentations


Presentation on theme: "Tree 1 2 3 A tree is a data structure in which each node is comprised of some data as well as node pointers to child nodes. 4 5 6 7 8 9."— Presentation transcript:

1 Tree 1 2 3 A tree is a data structure in which each node is comprised of some data as well as node pointers to child nodes. 4 5 6 7 8 9

2 Root 1 2 3 4 5 6 7 Leaves We'll refer to node 1 as the root node, and external nodes like 5, 6, 7, 8, and 9 as leaves. It's also convention to use the following terms to describe relationships between nodes: nodes 2 and 3 are siblings of each other nodes 5, 6, and 7 are children of node 3 node 2 is the parent of node 4 8 9

3 Binary Tree 33 99 77 A binary tree is a type of tree in which each node is comprised of some data as well as node pointers to at most two children. 88 22 11 66

4 typedef struct node { int n; struct node* left; struct node* right; }
55 Here's an example of a binary tree node implementation. Note how each node in a binary tree is comprised of two node pointers and some data. n is the data stored in this node, and left and right are pointers either to the node's children (or to NULL if no children exist).

5 Binary Search Tree 55 33 77 33 77 A binary search tree is a special type of binary tree that simplifies searching. For each node in a binary search tree, every value on its left child's side is less than its own value, and every value on its right is greater. Notice how all values to the left of the root (55) are less than 55, and all the values to the right are greater than 55. 22 44 66 88 22 44 66 88

6 bool search(node* root, int val) { if root is NULL return false.
if root->n is val return true. if val is less than root->n search left child if val is greater than root->n search right child } Here's some pseudocode to search a binary search tree for a particular value val. If the current node's value is less than the value you're looking for, recursively search its right child. If the current node's value is greater than the value you're looking for, recursively search its left child.

7 Tries A trie is another type of tree structure. The word “trie” comes from the word “retrieval,” but is usually pronounced like “try.” For our purposes, the nodes in a trie are arrays. We might use a trie to store a dictionary of words, as this diagram suggests. In this trie, each index in the array stands for a letter of the alphabet. Each of those indices also points to another array of letters. In the above, we’re storing the names of famous scientists, e.g. Mendel, Mendeleev, Pavlov, Pasteur, and Turing. The Δ symbol denotes the end of a name. We have to keep track of where words end so that if one word actually contains another word (e.g. Mendeleev and Mendel), we know that both words exist. In code, the Δ symbol could be a Boolean flag in each node.

8 // marker for end of word bool is_word; // pointers to other nodes
typedef struct node { // marker for end of word bool is_word; // pointers to other nodes struct node* children[27]; } node; Here’s a definition of a node. Note that we’re not actually storing words in the trie, we’re simply storing a series of pointers and a Boolean value.

9 // pointers to other nodes struct node* children[26]; };
is_word struct node { /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o This simple trie contains two words: “bat” and “zoom”. Let’s walk through an example of looking up the key “bat” in this trie. m

10 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o We’ll begin our lookup at the root node. We’ll take the first letter of our key, “b,” and find the corresponding spot in our children array. We’ll look at the second index -- index 1 -- for “b”. In general, if we have an alphabetic character c, we could determine the corresponding spot in the children array using a calculation like this: int index = tolower(c) - ‘a’; In this case, the pointer in our children array at index 1 is not NULL, so we’ll continue looking up the key “bat”. If we ever encountered a NULL pointer at the proper spot in the children array while looking up a key, we’d have to say that we couldn’t find anything for that key. m

11 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o Now we’ll take the second letter of our key, “a”, and continue following pointers in this way, until we reach the end of our key. m

12 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o Now we’ll take the third letter of our key, “t”, and continue following pointers in this way, until we reach the end of our key. m

13 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o If we reach the end of the key without hitting any dead ends (NULL pointers), as is the case here, then we only have to check one more thing: was that key actually stored in the trie? In our diagram, this is represented by a check mark signifying that bool is_word is true. m

14 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o Note how the key “zoo” is not in the dictionary, even though we could reach the end of this key without hitting a dead end? m

15 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o Similarly, if we tried to look up the key “bath”, the second-to-last node’s array index corresponding to the letter H would have held a NULL pointer, so “bath” isn’t in the dictionary. m

16 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o So how do we insert something into a trie? Let’s insert “zoo”. In some ways, the process to insert something is similar to looking something up. We’ll start with the root node again, following pointers corresponding to the letters of our key. m

17 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o Luckily, we’re able to follow pointers all the way until we reach the end of the key. m

18 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o Luckily, we’re able to follow pointers all the way until we reach the end of the key. m

19 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o Since “zoo” is a prefix of the word “zoom”, which is stored in our dictionary, we don’t need to allocate any new nodes. We can just set is_word to true at the appropriate node. m

20 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o If we wanted to insert the key “bath” into the trie, we’d start at the root node and follow the pointers again. In this situation, we hit a dead end before we’re able to get to the end of the key. m

21 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o So, we’ll need to allocate one new node for each remaining letter of our key. In this case, we’ll just need to allocate one new node. m

22 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o Then we’ll need to make the h index of the previous node reference this new node. h m

23 // pointers to other nodes struct node* children[26]; };
{ /* data */ // pointers to other nodes struct node* children[26]; }; b z a o t o And lastly, we set the new node’s is_word bool to true. So, if we assume that key length is bounded by a fixed constant, both insertion and lookup are constant time operations for a trie. Notice that the number of items stored in the trie doesn’t affect the lookup or insertion time; it’s only impacted by the length of the key. By contrast, adding entries to a hash table tends to make future lookups slower. While this may sound appealing at first, we should keep in mind that a favorable asymptotic complexity doesn’t mean that in practice, the data structure is necessarily beyond reproach. We must also consider that to store a word in a trie, we need, in the worst case, a number of nodes proportional to the length of the word itself. Tries tend to use a lot of space. That’s in contrast to a data structure like a hash table, where we only need one new node to store some key-value pair. h m


Download ppt "Tree 1 2 3 A tree is a data structure in which each node is comprised of some data as well as node pointers to child nodes. 4 5 6 7 8 9."

Similar presentations


Ads by Google