Trie and Trees

| Comments

This article is about Trie and Trees data structure.

trie

In computer science, a trie, also called digital tree and sometimes radix tree or prefix tree (as they can be searched by prefixes), is an ordered tree data structure that is used to store a dynamic set or associative array where the keys are usually strings. Unlike a binary search tree, no node in the tree stores the key associated with that node; instead, its position in the tree defines the key with which it is associated. All the descendants of a node have a common prefix of the string associated with that node, and the root is associated with the empty string. Values are normally not associated with every node, only with leaves and some inner nodes that correspond to keys of interest. For the space-optimized presentation of prefix tree, see compact prefix tree.

Read more


Trie is one of the most important data structure for autocomplete.

Trie Problems

Various problems on Trie can be found here

Trie explanation

Trie code implementation is based on this article.

Trie Code

Trie.h
 1
 2typedef int trieValueT;
 3
 4typedef struct trieNodeTag {
 5    char key;
 6    int words;
 7    int prefix;
 8    trieValueT value;
 9    struct trieNodeTag *next, *children;
10} trieNodeT;
11
12typedef struct trieCDT {
13    trieNodeT *root;
14} trieCDT;
15
16typedef struct trieCDT *trieADT;
17
18// Functions
19void trieCreate(trieCDT *trie);
20void trieAdd(trieNodeT *trie, char *key, int value);
21trieNodeT* addChild(char key);
22int trieIsMember(trieCDT trie, char keys[]);
23int totalStringsWithPrefix(trieCDT trie, char keys[]);
24void trieDestroy(trieNodeT *root);
25void test1();
26void startTesting();
27void startTestingFromFile(char** stdip_v);
Trie.c Run Trie.c
  1
  2#include <stdio.h>
  3#include <stdlib.h>
  4#include "trie.h"
  5
  6// To enable debug messages uncomment #define
  7#define TEST 1
  8// To test trie by providing input from file, uncomment 'TESTFROMFILE'
  9// Compile code and while executing provide file name at command line
 10// For e.g. > ./a.out ipFile.txt
 11//
 12//#define TESTFROMFILE 1
 13//
 14// To enable debug messages uncomment 'DEBUG'
 15//#define DEBUG 1
 16
 17#ifdef DEBUG
 18#  define D(x) x
 19#else
 20#  define D(x)
 21#endif
 22
 23int main(int argc, char* argv[])
 24{
 25    #ifdef TEST
 26        startTesting();
 27    #endif
 28
 29    #ifdef TESTFROMFILE
 30        startTestingFromFile(argv);
 31    #endif
 32
 33    return 0;
 34}
 35
 36// Create root node of trie
 37void trieCreate(trieCDT *trie)
 38{
 39    trie->root = (trieNodeT*)calloc(1,sizeof(trieNodeT));
 40
 41    if (trie->root == NULL) {
 42    printf("Can not alloc memory\n");
 43    return;
 44    }
 45
 46    trie->root->key = '\0';
 47    trie->root->value = -1;
 48    trie->root->next = NULL;
 49    trie->root->children = NULL;
 50}
 51
 52// This is recursive function for adding node in trie
 53// It covers 3 cases
 54// Case 1: When only root node is present in a trie. In this
 55//         case keep on adding node one level after another.
 56//
 57//         If input given is "Good" and if 'G' is not found then
 58//         insert 'G' and return 'G' node from where next insertion
 59//         has to be done as we have already found there is no
 60//         other 'G' exist.
 61//
 62// Case 2: When matching key node is already found return the matching
 63//         node and increment key
 64//
 65// Case 3: When key does not match to existing children i.e. for
 66//         "abcd", "abef" and "abgh"
 67//         .  ----> root
 68//         |
 69//         a
 70//         |
 71//         b
 72//         |
 73//         c ===> e ===> g        (LL, children of b)
 74//         |      |      |
 75//         d      f      h
 76
 77
 78void trieAdd(trieNodeT* trie, char *key, int value) {
 79
 80    // Get root of children
 81    if (key == NULL) {
 82    return;
 83    } else if (trie->children == NULL && trie->next == NULL) {
 84
 85        // Case 1
 86    trieNodeT* child = addChild(*key);
 87    trie->children = child;
 88
 89    if (*key == '\0') {
 90        child->value = value;
 91        child->words++;
 92        return;
 93    }
 94
 95    return trieAdd(child, ++key, value);
 96    }
 97
 98    trieNodeT* level = trie->children;
 99    trieNodeT* current;
100    for (current = level; current != NULL; current = current->next) {
101
102    // Case 2
103    if (current->key == *key) {
104        current->prefix++;
105
106        if (*key == '\0') {
107        current->words++;
108        return;
109        }
110        return trieAdd(current, ++key, value);
111    }
112
113    // This is last element in LL and key is not found
114    // For e.g. for "abc" and "abd", c and d should be
115    // child of b.
116    // Since, c != d, Append d to c in LL signifying they
117    // are both child of 'b' and are on same level
118    //
119    // Case 3
120    if (current->next == NULL) {
121        //Add key
122        trieNodeT* child = addChild(*key);
123        current->next = child;
124
125        if (*key == '\0') {
126            child->words++;
127        child->value = value;
128        return;
129        }
130
131        return trieAdd(child, ++key, value);
132    }
133    }
134}
135
136trieNodeT* addChild(char key)
137{
138    trieNodeT* child = (trieNodeT*)calloc(1,sizeof(trieNodeT));
139
140    if (child == NULL) {
141    printf("Can not alloc memory\n");
142    return NULL;
143    }
144    child->key = key;
145    child->value = -1;
146    child->next = NULL;
147    child->children = NULL;
148    child->prefix = 1;
149    child->words = 0;
150
151    return child;
152}
153
154int totalStringsWithPrefix(trieCDT trie, char keys[])
155{
156    trieNodeT *level = trie.root->children;
157
158    while (keys != NULL) {
159    trieNodeT *found = NULL;
160    trieNodeT *current;
161
162    for (current = level; current != NULL; current = current->next) {
163        if (current->key == *keys) {
164        found = current;
165        break;
166        }
167    }
168
169    if (found == NULL) {
170        return 0;
171    } else if (*(keys + 1)  == '\0') {
172        return found->prefix;
173    }
174    level = found -> children;
175    keys++;
176    }
177
178    return 0;
179}
180
181int trieIsMember(trieCDT trie, char keys[])
182{
183    trieNodeT *level = trie.root->children;
184
185    while (keys != NULL) {
186    trieNodeT *found = NULL;
187    trieNodeT *current;
188
189    for (current = level; current != NULL; current = current->next) {
190        if (current->key == *keys) {
191        found = current;
192        break;
193        }
194    }
195
196    if (found == NULL) {
197        return 0;
198    } else if (*keys == '\0') {
199        return 1;
200    }
201    level = found -> children;
202    keys++;
203    }
204
205    return 0;
206}
207
208void trieDestroy(trieNodeT * root)
209{
210    if (root->children == NULL && root->next == NULL) {
211        D(printf("Destroying %d\n", root->value));
212    free (root);
213    return;
214    }
215
216    // If root have next and children free them first
217    if (root->next != NULL) {
218    trieDestroy(root->next);
219    }
220
221    if (root->children != NULL) {
222    trieDestroy(root->children);
223    }
224
225#ifdef DEBUG
226    if (root->key != '\0') {
227    printf("Destroying %c\n", root->key);
228    } else {
229    printf("Destroying Root %d\n", root->value);
230    }
231#endif
232
233    free (root);
234}
235
236void test1()
237{
238    char s[] = "ABCD";
239    char s1[] = "ABCDE";
240    int i = 0;
241    trieCDT trie;
242    trieCreate(&trie);
243    trieAdd(trie.root, "ABCD", 20);
244    trieAdd(trie.root, "ABCDE", 30);
245
246    if (trieIsMember(trie, s)) {
247    printf("Found member 'ABCD'\n");
248    }
249
250    i = totalStringsWithPrefix(trie, "ABC");
251    printf("Total words with prefix 'ABC' %d\n", i);
252
253    trieDestroy(trie.root);
254}
255
256void startTesting()
257{
258    test1();
259}
260
261void startTestingFromFile(char** stdip_v)
262{
263    FILE *fp = NULL;
264    char key[50];
265    trieCDT trie;
266    int i = 0;
267
268    fp = fopen(stdip_v[1], "r");
269    if(fp == NULL) {
270    fprintf(stderr, "Can not read file!!\n");
271    return;
272    }
273
274    trieCreate(&trie);
275
276    while(fscanf(fp, "%s", key) != EOF) {
277    trieAdd(trie.root, key, i);
278    i++;
279
280    if(!trieIsMember(trie, key)) {
281        printf("Key '%s' NOT found in trie\n", key);
282    }
283    }
284
285    printf("Total words inserted in trie %d\n", i);
286
287    i = totalStringsWithPrefix(trie, "Abe");
288
289    printf("Total prefixs with 'Abe' %d\n", i);
290
291    trieDestroy(trie.root);
292}


Infix to Postfix




Postfix to Infix



Evaluate Postfix expression

Valid operators are +, -, *, /.
Each operand may be an integer or another expression.

Some examples:
["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9
["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6

Postfix
 1
 2class Solution {
 3    public:
 4    Solution(){};
 5    ~Solution() {};
 6
 7    int evalRPN(vector<string> &tokens) {
 8        int num = 0;
 9        vector<string>::const_iterator cii;
10
11        for(int ii=0; ii < tokens.size(); ii++)
12        {
13        num = atoi(tokens.at(ii).c_str());
14        if (!((tokens[ii] == "+") || (tokens[ii] == "-") ||
15                (tokens[ii] == "*") || (tokens[ii] == "/"))) {
16            mystack.push(num);
17        } else {
18            if (mystack.empty()) {
19            return 0;
20            }
21
22            num = mystack.top();
23            mystack.pop();
24
25            if (mystack.empty()) {
26            return 0;
27            }
28
29            if (tokens[ii] == "+") {
30            num += mystack.top();
31            } else if (tokens[ii] == "-") {
32            num = mystack.top() - num;
33            } else if (tokens[ii] == "*") {
34            num *= mystack.top();
35            } else if (tokens[ii] == "/") {
36            if (num == 0)  {
37                return 0;
38            }
39            num = mystack.top() / num;
40            } else {
41            return 0;
42            }
43
44            mystack.pop();
45            mystack.push(num);
46        }
47        }
48
49        return mystack.top();
50    }
51
52    std::stack<int> mystack;
53};


Tree Problems

Find BST is balanced or not

Balanced tree is defined to be a tree such that no two leaf nodes differ in distance from the root by more than one.

Balance BST Run
  1
  2#include <stdio.h>
  3#include <stdlib.h>
  4
  5int arrLen = 5;
  6int maxdepth = 0;
  7int mindepth = 10;
  8int totalElem = 8;
  9
 10typedef struct BST {
 11    int data;
 12    struct BST *left;
 13    struct BST *right;
 14} nodeBST;
 15
 16void balanceBST(int arr[]);
 17nodeBST* addNode(int data);
 18void addNodeToBST(nodeBST *root, nodeBST *node);
 19void traverse(nodeBST *root);
 20void maxDepth(nodeBST *root, int depth);
 21void minDepth(nodeBST *root, int depth);
 22
 23int maxDepthWithoutGlobalVar(nodeBST *root, int depth, int maxDeep);
 24int minDepthWithoutGlobalVar(nodeBST *root, int depth, int minDeep);
 25
 26int main()
 27{
 28    int arr[10] = {5,3,7,10,6,12,2,1};
 29
 30    (void)balanceBST(arr);
 31
 32    return 0;
 33}
 34
 35void balanceBST(int arr[])
 36{
 37    nodeBST *node;
 38    nodeBST *root;
 39    int max = 0;
 40    int min = 100000;
 41
 42    for (int i = 0; i < totalElem; i++) {
 43    node = addNode(arr[i]);
 44    if (node == NULL) {
 45        return;
 46    }
 47
 48    if (i == 0) {
 49        root = node;
 50        continue;
 51    }
 52
 53    addNodeToBST(root, node);
 54    }
 55
 56    printf("Nodes created\n");
 57    traverse(root);
 58    maxDepth(root, 0);
 59    printf("\nMax Depth %d\n", maxdepth);
 60    minDepth(root, 0);
 61    printf("Min Depth %d\n\n", mindepth);
 62
 63    max = maxDepthWithoutGlobalVar(root, 0, max);
 64    printf("Max Depth %d\n", max);
 65
 66    min = minDepthWithoutGlobalVar(root, 0, min);
 67    printf("Min Depth %d\n", min);
 68
 69    if ((max - min) > 1) {
 70    printf("Binary search tree is not Balanced\n");
 71    } else {
 72    printf("Binary search tree is Balanced\n");
 73    }
 74}
 75
 76nodeBST* addNode(int data)
 77{
 78    nodeBST *node = (nodeBST*)calloc(1, sizeof(nodeBST));
 79
 80    if (node == NULL) {
 81    return NULL;
 82    }
 83
 84    node->data = data;
 85    node->left = NULL;
 86    node->right = NULL;
 87
 88    return node;
 89}
 90
 91void addNodeToBST(nodeBST *root, nodeBST *node)
 92{
 93    while(root != NULL) {
 94    if (node->data < root->data) {
 95        if (root->left != NULL) {
 96        root = root->left;
 97        } else {
 98        root->left = node;
 99        return;
100        }
101    } else {
102        if (root->right != NULL) {
103        root = root->right;
104        } else {
105        root->right = node;
106        return;
107        }
108    }
109    }
110
111    return;
112}
113
114void traverse(nodeBST *root)
115{
116    if (root == NULL) {
117    return;
118    } else {
119    traverse(root->left);
120    printf("%d ", root->data);
121    traverse(root->right);
122    }
123
124    return;
125}
126
127void maxDepth(nodeBST *root, int depth)
128{
129    if (root == NULL) {
130    if (maxdepth < depth) {
131        maxdepth = depth;
132    }
133    } else {
134    maxDepth(root->left, (depth + 1));
135    maxDepth(root->right, (depth + 1));
136    }
137}
138
139void minDepth(nodeBST *root, int depth)
140{
141    if (root == NULL) {
142    if (mindepth > depth) {
143        mindepth = depth;
144    }
145    } else {
146    minDepth(root->left, (depth + 1));
147    minDepth(root->right, (depth + 1));
148    }
149}
150
151int maxDepthWithoutGlobalVar(nodeBST *root, int depth, int maxDeep)
152{
153    if (root == NULL) {
154    if (maxDeep <= depth) {
155        maxDeep = depth;
156    }
157    return maxDeep;
158    } else {
159        maxDeep = maxDepthWithoutGlobalVar(root->left, (depth + 1), maxDeep);
160    maxDeep = maxDepthWithoutGlobalVar(root->right, (depth + 1), maxDeep);
161    }
162
163    return maxDeep;
164}
165
166int minDepthWithoutGlobalVar(nodeBST *root, int depth, int minDeep)
167{
168    if (root == NULL) {
169    if (minDeep >= depth) {
170        minDeep = depth;
171    }
172    return minDeep;
173    } else {
174        minDeep = minDepthWithoutGlobalVar(root->left, (depth + 1), minDeep);
175    minDeep = minDepthWithoutGlobalVar(root->right, (depth + 1), minDeep);
176    }
177
178    return minDeep;
179}


Find Binary Tree is BST or not

A binary search tree (BST) is a node based binary tree data structure which has the following properties.
• The left subtree of a node contains only nodes with keys less than the node’s key.
• The right subtree of a node contains only nodes with keys greater than the node’s key.
• Both the left and right subtrees must also be binary search trees.

Method 1

Perform inorder traversal on tree and store it in temporary array. By property of inorder traversal the numbers stored should be sorted sequence of it’s a BST else it’s not BST.

The only caveat is that this method require O(n) space

Verify BST
 1
 2
 3int temp[TREESIZE];
 4
 5void traverse(nodeBST *root)
 6{
 7    static int n = 0;
 8
 9    if (root == NULL) {
10        return;
11    } else {
12        traverse(root->left);
13        temp[n++] = root->data;
14        traverse1(root->right);
15    }
16
17    return;
18}
19
20for (int i = 0; i < TREESIZE; i++) {
21    if (temp[i] > temp [i + 1]) {
22        return 0; // Binary tree is not BST
23    }    
24}
25return 1;



Method 2

Verify BST
 1
 2int isBSTUtil(nodeBST* node, int min, int max);
 3 
 4/* Returns true if the given tree is a binary search tree 
 5 (efficient version). */
 6int isBST(nodeBST* node) 
 7{ 
 8  return(isBSTUtil(node, INT_MIN, INT_MAX)); 
 9} 
10 
11/* Returns true if the given tree is a BST and its 
12   values are >= min and <= max. */
13int isBSTUtil(nodeBST* node, int min, int max) 
14{ 
15  /* an empty tree is BST */
16  if (node==NULL) 
17     return 1;
18       
19  /* false if this node violates the min/max constraint */ 
20  if (node->data < min || node->data > max) 
21     return 0; 
22 
23  /* otherwise check the subtrees recursively, 
24   tightening the min or max constraint */
25  return
26    isBSTUtil(node->left, min, (node->data - 1)) &&  // Allow only distinct values
27    isBSTUtil(node->right, (node->data + 1), max);  // Allow only distinct values
28} 



BST - Recursive Inorder Traversal

Time complexity O(n) and space complexity is size of stack for function calls

Recursive Inorder Run Code
 1
 2 // Recursive inorder traverse
 3 void traverse(nodeBST *root)
 4 {
 5     if (root == NULL) {
 6         return;
 7     } else {
 8         traverse(root->left);
 9         printf("%d ", root->data);
10         traverse(root->right);
11     }
12 
13     return;
14 }



BST - Iterative Inorder Traversal

Time complexity O(n) and space complexity is size of stack

Iterative Inorder Run Code
 1
 2 // Iterative
 3 // 1) Create an empty stack S.
 4 // 2) Initialize current node as root
 5 // 3) Push the current node to S and set current = current->left until curt is NULL
 6 // 4) If current is NULL and stack is not empty then$
 7 //      a) Pop the top item from stack.
 8 //      b) Print the popped item, set current = current->right
 9 //      c) Go to step 3.
10 // 5) If current is NULL and stack is empty then we are done.
11 
12 void iterativeInorder(nodeBST *root)
13 {
14     createStack();
15 
16     while(1) {
17         if (root != NULL) {
18             // Keep pushing in the stack
19             push(root);
20             root = root->left;
21         } else {
22             if (isStackEmpty()) {
23                 break;
24             }
25 
26             root = pop();
27             printf("%d ", root->data);
28 
29             root = root->right;
30         }
31     }
32 }



BST - Morris Inorder Traversal

Morris Inorder Traversal run without using recursion and without extra stack space.

Morris Inorder runs in O(NlogN) time and O(1) space

Morris Inorder Run Code
 1
 2  void MorrisInorder(nodeBST *root) {
 3      nodeBST* current,*pre;
 4      current=root;
 5      while(current!=NULL) {
 6          if(current->left==NULL) {
 7              printf("%d ",current->data);
 8              current=current->right;
 9          }
10          else {
11              pre=current->left;
12              while(pre->right != NULL && pre->right !=current)
13                  pre=pre->right;
14              if(pre->right==NULL) {
15                  printf("Link %d, %d\n", pre->data, current->data);
16                  pre->right=current;
17                  current=current->left;
18              }
19              else {
20                  pre->right=NULL;
21                  printf("%d ",current->data);
22                  current=current->right;
23              }
24          }
25      }
26  }


Comments