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.
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
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);
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
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.
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
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
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
BST - Iterative Inorder Traversal
Time complexity O(n) and space complexity is size of stack
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
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 }