2 | 
3 |
4 |
5 |
6 |
7 | ## Objective
8 | A python package published at [PyPi](https://pypi.org/). The project can be viewed here => [PyPi - eduAlgo](https://pypi.org/project/eduAlgo/).
9 | **Don't forget to create an ISSUE before making a PR and always make PR to this repo - [Main eduAlgo](https://github.com/edualgo/eduAlgo)**
10 |
11 | ## Stats
12 |
13 |
14 |
15 | [](https://github.com/eduAlgo/eduAlgo/graphs/commit-activity)
16 | [](https://pypi.python.org/pypi/eduAlgo/)
17 | [](https://GitHub.com/eduAlgo/eduAlgo/graphs/contributors/)
18 |
19 |
20 | [](https://pepy.tech/project/edualgo)
21 | [](https://pepy.tech/project/edualgo)
22 | [](https://pepy.tech/project/edualgo)
23 |
24 | [](https://forthebadge.com) [](https://forthebadge.com) [](https://forthebadge.com)
25 |
26 | ## Aim Of The Package
27 |
28 | This is a very simple python package made up with python script to study different algorithms for educational purposes. This package is currently under **planning** version and aims to achieve the following :-
29 |
30 | * To put together all the available algorithms
31 | * Help students with learning space and time complexity
32 | * Visualizing Algorithms
33 | * Getting resources, articles etc. to study about python and Algorithms
34 | * Become a handy tool for the programmers while using different algorithms on daily basis
35 |
36 | ## Organization
37 |
38 | This project is a part of the organization Edualgo Academy.
39 |
40 | > We are an opensource organization having a few open-sourced projects on github related to Data structures and Algorithms in Python, Flutter Development & Frontend Development.
41 | chek the organization here - eduAlgo
42 |
43 | ## Documentation
44 | The documentation for the included methods and their implementations can be found here => eduAlgo-Documentation
45 |
46 | ## Algorithms Yet to Publish
47 |
48 | * Searching Algorithms and Visualizations
49 | * Sorting Algorithms and Visualizations
50 | * Graph Algorithms and Visualizations
51 | * Linked List Implementations and Vizualizations
52 | * Tree Types, Vizualizations and Implementations
53 |
54 | ## Installation
55 |
56 | Fast install:
57 |
58 | pip install eduAlgo
59 |
60 | Example
61 |
62 | ```python
63 |
64 | from edualgo import LinkedList as ll
65 | llist1 = ll.linkedlist()
66 | llist2 = ll.linkedlist()
67 |
68 | arr1 = list(map(int,input().split()))
69 | arr2 = list(map(int,input().split()))
70 |
71 | for i in arr1:
72 | llist1.append(i)
73 |
74 | for i in arr2:
75 | llist2.append(i)
76 |
77 | sol = ll.list_algorithms()
78 |
79 | llist3 = ll.linkedlist()
80 | llist3.head = sol.mergeTwoLists(llist1.head,llist2.head)
81 | llist3.printLL()
82 | ```
83 | Input:
84 |
85 | 1 2 3
86 | 2 3 4
87 |
88 | Output:
89 |
90 | 1 2 2 3 3 4
91 |
92 | ## Communities/Hackathon/Conferences (In which the project was a part of)
93 |
94 |
95 |
96 |
97 | 
98 | FOSS Hack - 2020 (12th & 13th September 2020)
99 | |
100 |
101 | 
102 | PyCon - 2020 Devsprint ( 04th & 05th October 2020)
103 | |
104 |
105 |
106 |
107 | 
108 | Hacktoberfest 2020 (October 2020)
109 | |
110 |
111 | 
112 | Winter of Code - DSC, NSEC
113 | |
114 |
115 |
116 |
117 |
118 |
119 | ## Latest Winter Update (Package Demo)
120 |
121 |
122 |
123 | ## Tutorials
124 |
125 |
126 |
127 |
128 | ## License
129 |
130 | This package is under **MIT License** copyright @Abhijit Tripathy. The production code can be checked at the *production* branch of this repository.
131 |
132 | ## Our sponsors
133 |
134 |
174 |
175 | ## About The Creator
176 |
177 |
178 |
179 |
180 |
181 | |
182 |
183 | Abhijit Tripathy
184 | DSA Developer and Python Programmer
185 | |
186 |
187 |
188 |
189 | ## Our contributors
190 |
191 |
192 |
193 |
194 |
195 | Made with [contrib.rocks](https://contrib.rocks).
196 |
--------------------------------------------------------------------------------
/edualgo/maths/primes.py:
--------------------------------------------------------------------------------
1 | from edualgo import print_msg_box
2 | from math import sqrt
3 | from edualgo.maths.modular_arithmetic import *
4 | from random import randint
5 | from collections import defaultdict
6 |
7 | def is_prime(x, hint=False):
8 |
9 | if hint: is_prime_hint()
10 |
11 | if x<2: return False
12 | if x==2: return True
13 | if x%2==0: return False
14 |
15 | return all([x%i!=0 for i in range(3, int(sqrt(x))+1, 2)])
16 |
17 | def is_prime_hint():
18 | message = """
19 | conditions for any number X to be prime:
20 | 1. X >= 2
21 | 2. 2 is the only even prime
22 | 3. X must not be divisible by any number in [2, X)
23 | we can optimise this check as follows:
24 | i. we need to check for only odd divisors.
25 | ii. divisors and corresponding quotients are only possible divisors left and they are unique upto sqrt(X).
26 | so we need to check for only odd divisors upto sqrt(X) i.e., from 3 to sqrt(X).
27 | """
28 | print_msg_box(message)
29 |
30 | class prime_factorisation:
31 |
32 | def __init__(self, use_sieve=True, sieve_range = int(1e6)):
33 | self.use_sieve = use_sieve
34 | self.sieve_range = sieve_range
35 | if use_sieve:
36 | spf = list(range(self.sieve_range + 1))
37 | for i in range(4, self.sieve_range+1,2):
38 | spf[i] = 2
39 | for i in range(3, int(sqrt(self.sieve_range))+1):
40 | if spf[i] == i:
41 | for j in range(i*i, self.sieve_range+1, i):
42 | if spf[j] == j:
43 | spf[j] = i
44 | self.spf = spf
45 |
46 | def factorise(self, x):
47 | if self.use_sieve and x<=self.sieve_range:
48 | return self.__factorise_fast(x)
49 | else:
50 | factors = defaultdict(int)
51 | while x%2==0:
52 | factors[2] += 1
53 | x >>= 2
54 |
55 | for i in range(3, int(sqrt(x))+1, 2):
56 | while x%i == 0:
57 | factors[i] += 1
58 | x //= i
59 |
60 | if x>2: factors[x] += 1
61 |
62 | return dict(factors)
63 |
64 | def __factorise_fast(self, x):
65 | factors = defaultdict(int)
66 | while x != 1:
67 | factors[self.spf[x]] += 1
68 | x //= self.spf[x]
69 | return dict(factors)
70 |
71 | @property
72 | def hint(self):
73 | message = """
74 |
75 | finding prime factorisation of N
76 |
77 | ----simple factorisation----
78 | 1. while N is even keep dividing N by 2 and keep adding 2 to the answer list.
79 | 2. Now that N is odd, do the following:
80 | i. run loop for i from 3 to sqrt(N) with step size 2 (taking all odd numbers).
81 | i. while i divides N, add i to asnwer list and divide N by i.
82 | 3. if N is still not 1 then its a prime, add it to the answer list.
83 |
84 | The time complexity is O(sqrt(N).log(N))
85 |
86 | ----factorisation using sieve----
87 | simple method is very slow if we have to process multiple factorisation queries.
88 | the idea is to store the smallest prime divisor of every number then use this value to find the factorisation using recursive division.
89 |
90 | 1. creating the smallest prime divisor array:
91 |
92 | pseudo code:
93 | divisor_array = [ 0, 1, 2, 3, 4, 5, ....., N ]
94 |
95 | loop for i from 4 to N with step size of 2:
96 | divisor_array[i] = 2
97 |
98 | loop for i from 3 to sqrt(N):
99 | if divisor_array[i] is i (means i is Prime):
100 | loop for j from i*i to N with step size of i:
101 | if divisor_array[j] == j:
102 | divisor_array[j] = i
103 |
104 | the time complexity is O(N.log(log(N)))
105 | needs O(N) extra space
106 |
107 | 2. finding the factorisation of X
108 |
109 | pseudo code:
110 | factors = []
111 | while X != 1:
112 | factors.append(divisor_array[X])
113 | X = X / divisor_array[X]
114 |
115 | the time complexity is O(log(N))
116 |
117 | """
118 | print_msg_box(message)
119 |
120 | class sieve_of_eratosthenes:
121 |
122 | def __init__(self, n=int(1e6)):
123 |
124 | mark = [True]*(n+1)
125 | mark[0] = mark[1] = False
126 | for i in range(2, int(sqrt(n)) +1):
127 | if mark[i]:
128 | for j in range(i*i, n+1, i):
129 | mark[j] = False
130 |
131 | self.range = n
132 | self.mark = mark
133 |
134 | def is_prime(self, arg):
135 | try:
136 | assert arg<=self.range
137 | except AssertionError:
138 | raise ValueError(f"{arg} > {self.range}")
139 |
140 | return self.mark[arg]
141 |
142 | def filter_primes(self, array):
143 | try:
144 | assert all([x<=self.range for x in array])
145 | except AssertionError:
146 | raise ValueError(f"please make sure the numbers are <= {self.range}")
147 |
148 | return list(filter(lambda x: self.mark[x], array))
149 |
150 | @property
151 | def hint():
152 | message = """
153 | it is used to find primes in range 2 to N
154 |
155 | sieve of eratosthenes algorithm generates an array in which the value at each index i is a boolean value which tells whether i is a prime number or not.
156 |
157 | we take a boolean array of size N with default True except for index 0 and 1
158 |
159 | the idea is to mark multiples of all primes from 2 to sqrt(N) as False.
160 |
161 | pseudo code:
162 | sieve_array = [ True, True, ..... ]
163 | sieve_array[0] = sieve_array[1] = False
164 |
165 | loop for i from 2 to sqrt(N):
166 | if sieve_array[i] is True (means i is Prime):
167 | loop for j from i*i to N with step size of i:
168 | sieve_array[j] = False
169 |
170 | Now, if any index i in sieve_array is true then it means i is a prime.
171 |
172 | the time complexity is O(N.log(log(N)))
173 | needs O(N) extra space
174 | """
175 | print_msg_box(message)
176 |
177 | def is_prime_big(x, hint = False):
178 |
179 | if hint: is_prime_big_hint()
180 |
181 | def miller(d,n):
182 |
183 | a = 2+randint(1,n-4)
184 |
185 | x= binary_modular_exponentiation(a,d,n)
186 | if x in [1,n-1]: return True
187 |
188 | while d!=n-1:
189 | x=binary_modular_exponentiation(x,2,n)
190 | d<<=1
191 | if x==1: return False
192 | if x==n-1: return True
193 |
194 | return False
195 |
196 | def checkprime(n, k = 4):
197 | if n<=1 or n==4:
198 | return False
199 | if n<=3: return True
200 |
201 | d=n-1
202 | while d%2==0:
203 | d//=2
204 |
205 | for _ in range(k):
206 | if not miller(d,n):
207 | return False
208 | return True
209 |
210 | return checkprime(x)
211 |
212 | def is_prime_big_hint():
213 | message = """
214 | to check primality of very large numbers (order 10^10)
215 |
216 | ------Miller Rabin test--------
217 | checks if a number n is prime
218 | k is a input parameter which measures accuracy of the test
219 | generally k = 4
220 |
221 | compute d & r such that d*(2^r) = n-1
222 |
223 | ------test logic------
224 | randomly choose 'a' in range(2,n-1)
225 | compute x = (a^d)%n
226 | if x in [1, n-1]:
227 | return true
228 | else:
229 | keep squaring (with mod n) x while d!=n-1
230 | d*=2
231 | if (x^2)%n == 1: return False
232 | else if (x^2)%n ==n-1 :return True
233 |
234 | the test logic runs k times to ensure accurate results.
235 |
236 | overall time complexity is O(k.(Log(n))^3)
237 | """
238 | print_msg_box(message)
239 |
--------------------------------------------------------------------------------
/edualgo/LinkedList.py:
--------------------------------------------------------------------------------
1 | from .__init__ import print_msg_box
2 |
3 | class Node:
4 | def __init__(self,val):
5 | self.val = val
6 | self.next = None
7 |
8 | class linkedlist:
9 | def __init__(self):
10 | self.head = None
11 | self.tail = None
12 |
13 | def append(self,val):
14 | if self.tail is None:
15 | self.head = Node(val)
16 | self.tail = self.head
17 |
18 | else:
19 | self.tail.next = Node(val)
20 | self.tail = self.tail.next
21 |
22 | def printLL(self):
23 | temp = self.head
24 | while(temp):
25 | print(temp.val, end =" ")
26 | temp = temp.next
27 |
28 | class list_algorithms:
29 |
30 | def length(self,head):
31 | temp = head
32 | count = 0
33 | while(temp):
34 | temp = temp.next
35 | count += 1
36 | return count
37 |
38 | def reverse_linked_recursive(self,head):
39 | if(head is None or head.next is None):
40 | return head
41 | small_head = self.reverse_linked_recursive(head.next)
42 | head.next = None
43 | temp = small_head
44 | while(temp.next is not None):
45 | temp = temp.next
46 | temp.next = head
47 | head = small_head
48 | return head
49 |
50 | def reverse_linked_iterative(self,head):
51 | if(head is None or head.next is None):
52 | return head
53 | prev = None
54 | curr = head
55 | while(curr):
56 | temp = curr.next
57 | curr.next = prev
58 | prev = curr
59 | curr = temp
60 | return prev
61 |
62 | def is_palindrome(self,head):
63 | stack = []
64 | temp = head
65 | while(temp):
66 | stack.append(temp.val)
67 | temp = temp.next
68 | temp = head
69 | while(temp):
70 | if(stack[-1] != temp.val):
71 | return False
72 | else:
73 | stack.pop()
74 | temp = temp.next
75 | return True
76 |
77 | def is_palindrome_optimized(self,head):
78 | len = self.length(head)
79 | if(len <= 1):
80 | return True
81 | count = 0
82 | head2 = head
83 | prev = None
84 | while(count < int(len/2)):
85 | temp = head2.next
86 | head2.next = prev
87 | prev = head2
88 | head2 = temp
89 | count+=1
90 | head = head2
91 | head2 = prev
92 | if(len % 2 == 1):
93 | head = head.next
94 | while((head2 is not None) and (head is not None)):
95 | if(head2.val != head.val):
96 | return False
97 | head = head.next
98 | head2 = head2.next
99 | return True
100 |
101 | def delete_sorted_duplicate(self,head):
102 | if(head is None or head.next is None):
103 | return head
104 | small_head = self.delete_sorted_duplicate(head.next)
105 | while((small_head is not None) and (head.val == small_head.val)):
106 | temp = small_head
107 | small_head = small_head.next
108 | temp.next = None
109 |
110 | head.next = small_head
111 | return head
112 |
113 | def delete_node_by_value(self, head, value):
114 | # if head is None
115 | if head is None:
116 | return None
117 | prev = None
118 | current = head
119 | # get node to delete
120 | while current:
121 | if current.val == value:
122 | break
123 | prev = current
124 | current = current.next
125 | # if the node is the head
126 | if prev is None:
127 | # return new head
128 | return head.next
129 | # if value not found
130 | if current is None:
131 | return head
132 | prev.next = current.next
133 | return head
134 |
135 | def middleNode(self,head):
136 | slow = fast = head
137 | while fast and fast.next:
138 | slow = slow.next
139 | fast = fast.next.next
140 | return slow
141 |
142 | def mergeTwoLists(self, l1, l2):
143 | if(l1 is None):
144 | return l2
145 | if((l2 is not None) and (l2.val < l1.val)):
146 | l1,l2 = l2,l1
147 | l1.next = self.mergeTwoLists(l1.next,l2)
148 | return l1
149 |
150 | def removeElements(self,head,val):
151 | if(head is None):
152 | return head
153 | small_head = self.removeElements(head.next,val)
154 | if(head.val == val):
155 | head = small_head
156 | else:
157 | head.next = small_head
158 | return head
159 |
160 | def getIntersectionNode(self,headA,headB):
161 | tempA = headA
162 | tempB = headB
163 |
164 | lengthA = 0
165 | lengthB = 0
166 |
167 | while(tempA):
168 | lengthA += 1
169 | tempA = tempA.next
170 | while(tempB):
171 | lengthB += 1
172 | tempB = tempB.next
173 |
174 | tempA = headA
175 | tempB = headB
176 |
177 | while(lengthA > lengthB):
178 | tempA = tempA.next
179 | lengthA -= 1
180 | while(lengthB > lengthA):
181 | tempB = tempB.next
182 | lengthB -= 1
183 |
184 | while((tempA != tempB) and (tempA is not None)):
185 | tempA = tempA.next
186 | tempB = tempB.next
187 |
188 | if((tempA == tempB) and (tempA is not None)):
189 | return tempA
190 | else:
191 | return None
192 |
193 | def getDecimalValue(self,head):
194 | temp = head
195 | length = 0
196 | while(temp):
197 | length += 1
198 | temp = temp.next
199 |
200 | num = 0
201 | temp = head
202 |
203 | while(temp):
204 | num += temp.val * (2**(length-1))
205 | length -= 1
206 | temp = temp.next
207 |
208 | return num
209 |
210 | def nextLargerNodes(self,head):
211 | result = []
212 | temp = head
213 | while(temp):
214 | result.append(temp.val)
215 | temp = temp.next
216 |
217 | stack = []
218 | n = len(result)
219 | i = n-1
220 | while(i >= 0):
221 | next = 0
222 | while(len(stack)!=0 and stack[-1] <= result[i]):
223 | stack.pop()
224 | if(len(stack)!=0 and stack[-1] > result[i]):
225 | next = stack[-1]
226 | stack.append(result[i])
227 | result[i] = next
228 | i-=1
229 | return result
230 | def removeNthNodeFromEnd(self,head,n):
231 | first = head
232 | second = head
233 | for i in range(n):
234 | if(second.next is None):
235 | if(i == n - 1):
236 | self.head = self.head.next
237 | return self.head
238 | second = second.next
239 | while(second.next is not None):
240 | second = second.next
241 | first = first.next
242 |
243 | first.next = first.next.next
244 |
245 | def removeNthNodeFromEnd_hint(self):
246 | message="""
247 | Remove Nth Node from end of a linked list
248 | ------------------------------------
249 | Purpose : to remove the Nth node from end of the linked list
250 | Approach: We use a two pointer approach. The first and second pointer both start by refering to head.
251 | We then move the second pointer by N steps without moving the first pointer.
252 | Now both the pointers have a distance of N nodes between them.
253 | Now, we move both the pointer by a step each until the second pointer reaches the end of linked list.
254 | Since both the pointers will still be at a distacne of N nodes , when the second pointer reaches the end of linked list ,
255 | the first pointer will be at a distance of N nodes from the end i.e at the Nth node from the end.
256 | So we delete the node pointed by the first pointer.
257 |
258 | Edge Case: There are 2 possible edge cases in the above mentioned approach
259 | ---------------------------------------------------
260 | While moving the second pointer by N nodes , we keep checking if the "next" of the second pointer is null
261 | If it is null then 2 cases may arise:
262 | 1) The length of linked list is exactly N and in that case the value of the loop variable i would be N-1
263 | and the Nth node from end would be the head. So in that case we update the head by setting the head to head.next
264 | 2) The length of list is < n :
265 | In this case, since we can't delete the Nth node from the end, we simply return head .
266 |
267 |
268 |
269 | Time Complexity:
270 | --------------------
271 | O(L): where L is the length of the Linked List
272 | """
273 | print(message)
274 |
275 |
276 |
277 |
278 |
279 | # ping = linkedlist()
280 | # ping.append(1)
281 | # ping.append(2)
282 | # ping.printLL()
283 |
--------------------------------------------------------------------------------
/edualgo/BinaryTree.py:
--------------------------------------------------------------------------------
1 | from .__init__ import print_msg_box
2 | import collections
3 | class Node:
4 | def __init__(self, val):
5 |
6 | self.left = None
7 | self.right = None
8 | self.val = val
9 |
10 | def insert(self, val):
11 | if self.val:
12 | if val < self.val:
13 | if self.left is None:
14 | self.left = Node(val)
15 | else:
16 | self.left.insert(val)
17 | else:
18 | if self.right is None:
19 | self.right = Node(val)
20 | else:
21 | self.right.insert(val)
22 | else:
23 | self.val = val
24 |
25 | class BinaryTreeAlgorithms:
26 | def print_tree(self,root,hint=False):
27 | if(hint is True):
28 | self.print_tree_hint()
29 | if root is None:
30 | return
31 | print(root.val,end =":")
32 | if root.left:
33 | print("L: {} ,".format(root.left.val),end ="")
34 | if root.right:
35 | print("R: {} ,".format(root.right.val),end="")
36 | print("\n")
37 | self.print_tree(root.left)
38 | self.print_tree(root.right)
39 |
40 | def print_tree_hint(self):
41 | message = """
42 | Printing A Binary Tree
43 | ------------------------------------
44 |
45 | Purpose : Printing a Binary Tree(Both Left and Right Node)
46 | Method : Recursion, Binary Tree
47 |
48 | Time Complexity : Worst Case - O(n), n = Number of nodes in a Binary Tree
49 |
50 | Hint :
51 | Print the root, use recursion and call into the left and right
52 |
53 | Pseudocode :
54 | --> if(root is None) return
55 | --> print(root.value)
56 | --> print(root.left.value)
57 | --> print(root.right.value)
58 | --> make recursion calls,
59 | print_tree(root.left)
60 | print.tree(root.right)
61 |
62 | Visualization:
63 |
64 | Given Binary Tree :
65 |
66 | +------+
67 | | 12 | <-- root
68 | +------+
69 | / \\
70 | / \\
71 | +------+ +------+
72 | root.left --> | 6 | | 14 | <-- root.right
73 | +------+ +------+
74 | / \\ / \\
75 | / \\ / \\
76 | +------+ +------+ +------+ +------+
77 | | 3 | | 7 | | 12 | | 15 |
78 | +------+ +------+ +------+ +------+
79 |
80 |
81 | Step 1: print root, root.left and root.right
82 |
83 | 12 : L:6, R: 14
84 |
85 | Step 2 : call recursive functions
86 |
87 | f(root.left) :
88 |
89 | +------+
90 | | 6 | <-- root
91 | +------+
92 | / \\
93 | / \\
94 | +------+ +------+
95 | root.left --> | 3 | | 7 | <-- root.right
96 | +------+ +------+
97 |
98 | +------------------------+
99 | | Repeat Step 1 & Step 2 | <-- recursion calls
100 | +------------------------+
101 |
102 | f(root.right) :
103 |
104 | +------+
105 | | 14 | <-- root
106 | +------+
107 | / \\
108 | / \\
109 | +------+ +------+
110 | root.left --> | 12 | | 15 | <-- root.right
111 | +------+ +------+
112 |
113 | +------------------------+
114 | | Repeat Step 1 & Step 2 | <-- recursion calls
115 | +------------------------+
116 |
117 | Finally The Output :
118 |
119 | -------------------------
120 | | 12:L: 6 ,R: 14 , |
121 | | |
122 | | 6:L: 3 ,R: 7 , |
123 | | |
124 | | 3: |
125 | | |
126 | | 7: |
127 | | |
128 | | 14:L: 12 ,R: 15 , |
129 | | |
130 | | 12: |
131 | | |
132 | | 15: |
133 | -------------------------
134 |
135 | Learn More:
136 | - Binary Trees - https://en.wikipedia.org/wiki/Binary_tree
137 | - Recursion - https://en.wikipedia.org/wiki/Recursion_(computer_science)
138 | """
139 | print_msg_box(message)
140 |
141 | def Inorder_print(self,root,hint=False):
142 | if(hint is True):
143 | self.Inorder_print_hint()
144 | if root is None:
145 | return
146 | self.Inorder_print(root.left)
147 | print(root.val,end =", ")
148 | self.Inorder_print(root.right)
149 |
150 | def Inorder_print_hint(self):
151 | message = """
152 | Printing A Binary Tree InOrder Traversal
153 | ------------------------------------
154 |
155 | Purpose : Printing a Binary Tree(InOrder Traversal)
156 | Method : Recursion, Binary Tree
157 |
158 | Time Complexity : Worst Case - O(n), n = Number of nodes in a Binary Tree
159 |
160 | Hint :
161 | print order -> LEFT -- ROOT -- RIGHT
162 | Call into left recursively till exist,Print the root, use recursion to call into the right
163 |
164 | Pseudocode :
165 | --> if(root is None) return
166 | --> print(root.left.value)
167 | --> print(root.value)
168 | --> print(root.right.value)
169 |
170 | Visualization:
171 |
172 | Given Binary Tree :
173 |
174 | +------+
175 | | 12 | <-- root
176 | +------+
177 | / \\
178 | / \\
179 | +------+ +------+
180 | root.left --> | 6 | | 14 | <-- root.right
181 | +------+ +------+
182 | / \\ / \\
183 | / \\ / \\
184 | +------+ +------+ +------+ +------+
185 | | 3 | | 7 | | 13 | | 15 |
186 | +------+ +------+ +------+ +------+
187 |
188 |
189 | step : call recursive functions on root.left, print root, call on right
190 |
191 | f(root.left) :
192 |
193 | +------+
194 | | 3 | <-- root
195 | +------+
196 | / \\
197 | / \\
198 | +------+ +------+
199 | root.left --> | None | | None | <-- root.right
200 | +------+ +------+
201 |
202 | output : LEFT -- ROOT -- RIGHT
203 | None 3 None
204 |
205 |
206 | +------+
207 | | 6 | <-- root
208 | +------+
209 | / \\
210 | / \\
211 | +------+ +------+
212 | root.left --> | 3 | | 7 | <-- root.right
213 | +------+ +------+
214 |
215 | output : LEFT -- ROOT -- RIGHT
216 | 3 6 7
217 |
218 | f(root.right) :
219 |
220 | +------+
221 | | 14 | <-- root
222 | +------+
223 | / \\
224 | / \\
225 | +------+ +------+
226 | root.left --> | 13 | | 15 | <-- root.right
227 | +------+ +------+
228 |
229 | output : LEFT -- ROOT -- RIGHT
230 | 13 14 15
231 |
232 | Finally The Output :
233 |
234 | ---------------------------------
235 | | 3, 6, 7, 12, 13, 14, 15, |
236 | ---------------------------------
237 |
238 | Learn More:
239 | - Binary Trees - https://en.wikipedia.org/wiki/Binary_tree
240 | - Recursion - https://en.wikipedia.org/wiki/Recursion_(computer_science)
241 | """
242 | print_msg_box(message)
243 |
244 | def Preorder_print(self,root,hint=False):
245 | if(hint is True):
246 | self.Preorder_print_hint()
247 | if root is None:
248 | return
249 | print(root.val,end =", ")
250 | self.Preorder_print(root.left)
251 | self.Preorder_print(root.right)
252 |
253 | def Preorder_print_hint(self):
254 | message = """
255 | Printing A Binary Tree PreOrder Traversal
256 | ------------------------------------
257 |
258 | Purpose : Printing a Binary Tree(PreOrder Traversal)
259 | Method : Recursion, Binary Tree
260 |
261 | Time Complexity : Worst Case - O(n), n = Number of nodes in a Binary Tree
262 |
263 | Hint :
264 | print order -> ROOT -- LEFT -- RIGHT
265 | Print the root, use recursion to call into the left and the right subtree
266 |
267 | Pseudocode :
268 | --> if(root is None) return
269 | --> print(root.value)
270 | --> print(root.left.value)
271 | --> print(root.right.value)
272 |
273 | Visualization:
274 |
275 | Given Binary Tree :
276 |
277 | +------+
278 | | 12 | <-- root
279 | +------+
280 | / \\
281 | / \\
282 | +------+ +------+
283 | root.left --> | 6 | | 14 | <-- root.right
284 | +------+ +------+
285 | / \\ / \\
286 | / \\ / \\
287 | +------+ +------+ +------+ +------+
288 | | 3 | | 7 | | 13 | | 15 |
289 | +------+ +------+ +------+ +------+
290 |
291 |
292 | step 1 : Print the root value
293 |
294 | +------+
295 | | 6 | <-- root
296 | +------+
297 | / \\
298 | / \\
299 | +------+ +------+
300 | root.left --> | 3 | | 7 | <-- root.right
301 | +------+ +------+
302 |
303 | output : 6
304 |
305 | f(root.left) :
306 |
307 | +------+
308 | | 3 | <-- root
309 | +------+
310 | / \\
311 | / \\
312 | +------+ +------+
313 | root.left --> | None | | None | <-- root.right
314 | +------+ +------+
315 |
316 | output : ROOT -- LEFT -- RIGHT
317 | 3 None None
318 |
319 | f(root.right) :
320 |
321 | +------+
322 | | 14 | <-- root
323 | +------+
324 | / \\
325 | / \\
326 | +------+ +------+
327 | root.left --> | 13 | | 15 | <-- root.right
328 | +------+ +------+
329 |
330 | output : ROOT -- LEFT -- RIGHT
331 | 14 13 15
332 |
333 | Finally The Output :
334 |
335 | ---------------------------------
336 | | 12, 6, 3, 7, 14, 13, 15, |
337 | ---------------------------------
338 |
339 | Learn More:
340 | - Binary Trees - https://en.wikipedia.org/wiki/Binary_tree
341 | - Recursion - https://en.wikipedia.org/wiki/Recursion_(computer_science)
342 | """
343 | print_msg_box(message)
344 |
345 | def Postorder_print(self,root,hint=False):
346 | if(hint is True):
347 | self.Postorder_print_hint()
348 | if root is None:
349 | return
350 | self.Postorder_print(root.left)
351 | self.Postorder_print(root.right)
352 | print(root.val,end =", ")
353 |
354 | def Postorder_print_hint(self):
355 | message = """
356 | Printing A Binary Tree PostOrder Traversal
357 | ------------------------------------
358 |
359 | Purpose : Printing a Binary Tree(PostOrder Traversal)
360 | Method : Recursion, Binary Tree
361 |
362 | Time Complexity : Worst Case - O(n), n = Number of nodes in a Binary Tree
363 |
364 | Hint :
365 | print order -> LEFT -- RIGHT -- ROOT
366 | use recursion to call into the left and the right subtree, Print the root
367 |
368 | Pseudocode :
369 | --> if(root is None) return
370 | --> print(root.left.value)
371 | --> print(root.right.value)
372 | --> print(root.value)
373 |
374 | Visualization:
375 |
376 | Given Binary Tree :
377 |
378 | +------+
379 | | 12 | <-- root
380 | +------+
381 | / \\
382 | / \\
383 | +------+ +------+
384 | root.left --> | 6 | | 14 | <-- root.right
385 | +------+ +------+
386 | / \\ / \\
387 | / \\ / \\
388 | +------+ +------+ +------+ +------+
389 | | 3 | | 7 | | 13 | | 15 |
390 | +------+ +------+ +------+ +------+
391 |
392 |
393 | step 1 : Print the left, print right, print root
394 |
395 | +------+
396 | | 6 | <-- root
397 | +------+
398 | / \\
399 | / \\
400 | +------+ +------+
401 | root.left --> | 3 | | 7 | <-- root.right
402 | +------+ +------+
403 |
404 |
405 | output : LEFT -- RIGHT -- ROOT
406 | 3 7 6
407 |
408 |
409 | Finally The Output :
410 |
411 | ---------------------------------
412 | | 3, 7, 6, 13, 15, 14, 12 |
413 | ---------------------------------
414 |
415 | Learn More:
416 | - Binary Trees - https://en.wikipedia.org/wiki/Binary_tree
417 | - Recursion - https://en.wikipedia.org/wiki/Recursion_(computer_science)
418 | """
419 | print_msg_box(message)
420 |
421 | def rangeSumBST(self, root,L,R):
422 | if(root is None):
423 | return 0
424 | sum1 = 0; sum2 = 0
425 | if(root.left):
426 | sum1 = self.rangeSumBST(root.left,L,R)
427 | if(root.right):
428 | sum2 = self.rangeSumBST(root.right,L,R)
429 | if((root.val >= L )and (root.val <= R)):
430 | return root.val + sum1 + sum2
431 | else:
432 | return sum1 + sum2
433 |
434 | def mergeTrees(self, t1, t2):
435 | if(t1 is None and t2 is None):
436 | return None
437 | if(t2 is None):
438 | return t1
439 | if(t1 is None):
440 | return t2
441 | t1.val = t1.val + t2.val
442 | t1.left = self.mergeTrees(t1.left,t2.left)
443 | t1.right = self.mergeTrees(t1.right,t2.right)
444 | return t1
445 |
446 | def sumOfLeftLeaves(self, root):
447 | if(root is None):
448 | return 0
449 | sum = 0
450 | if(root.left is not None and (root.left.left is None and root.left.right is None)):
451 | sum = root.left.val
452 | return sum + self.sumOfLeftLeaves(root.left)+self.sumOfLeftLeaves(root.right)
453 |
454 | def isSameTree(self, p, q):
455 | if(p is None and q is None):
456 | return True
457 | if(p is None or q is None):
458 | return False
459 | return (p.val == q.val) and (self.isSameTree(p.left,q.left)) and (self.isSameTree(p.right,q.right))
460 |
461 | def isCousins(self, root, x, y):
462 | if not root:
463 | return root
464 | queue = collections.deque([root])
465 | level = set()
466 | last = n_last = root
467 | while any(queue):
468 | node = queue.popleft()
469 | same_father = set()
470 | if node.left:
471 | level.add(node.left.val)
472 | queue.append(node.left)
473 | n_last = node.left
474 | same_father.add(node.left.val)
475 | if node.right:
476 | level.add(node.right.val)
477 | queue.append(node.right)
478 | n_last = node.right
479 | same_father.add(node.right.val)
480 | if x in same_father and y in same_father:
481 | return False
482 | if node == last:
483 | last = n_last
484 | if x in level and y in level:
485 | return True
486 | level = set()
487 | return False
488 |
489 | def countNode(self,root):
490 | '''
491 | countNode will take root node
492 | as input and return the number
493 | node present in the tree.
494 | '''
495 | if (root is None):
496 | return 0
497 | return 1 + self.countNode(root.left) + self.countNode(root.right)
498 |
499 | def KthLevel(self,root, k):
500 | '''
501 | KthLevel will take root node and level value (k),
502 | and print the element present at that level
503 | Note: level for the root node is 1
504 | '''
505 | if (root is None):
506 | return
507 | if (k ==1):
508 | print(root.data,end=', ')
509 | return
510 | self.KthLevel(root.left, k-1)
511 | self.KthLevel(root.right, k-1)
512 | return
513 |
514 |
515 | #root1 = Node(12)
516 | #root1.insert(6)
517 | #root1.insert(14)
518 | #root1.insert(3)
519 | #root1.insert(7)
520 | #root1.insert(15)
521 | #root1.insert(13)
522 | # ping = BinaryTreeAlgorithms()
523 | # ping.Inorder_print(root1)
524 | # ping.Preorder_print(root1)
525 | # ping.Postorder_print(root1)
526 |
527 |
528 |
--------------------------------------------------------------------------------