Add some cool queue, stacks, strings, math, bit manipulation examples (#35)

This commit is contained in:
Dr. Marina Souza, PhD 2023-07-16 17:35:14 -07:00 committed by GitHub
parent f3ee2cdf52
commit 0f455a0322
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 932 additions and 13 deletions

View File

@ -37,17 +37,10 @@
* **📖 algorithms and data structures revisited (2023)**:
* 𝟘𝟘𝟙𝟘. **[arrays, vectors, strings](arrays_and_strings)**
* 𝟘𝟘𝟙𝟘. **[arrays and strings](arrays_and_strings)**
* 𝟘𝟘𝟙𝟙. **[linked lists](linked_lists)**
* 𝟘𝟙𝟘𝟘. **[stacks and queues](stacks_and_queues)**
* 𝟘𝟙𝟘𝟙. **[bit manipulation](bit_manipulation)**
* 𝟘𝟙𝟙𝟘. **[math and logic](math_and_logic)**
* 𝟘𝟙𝟙𝟙. **[object-oriented design](object_oriented_design)**
* 𝟙𝟘𝟘𝟘. **[recursion and dynamic programming](recursion_and_dp)**
* 𝟙𝟘𝟘𝟙. **[sorting and searching](sorting_and_searching)**
* 𝟙𝟘𝟙𝟘. **[concurrency](concurrency)**
* 𝟙𝟘𝟙𝟙. **[trees and graphs](trees_and_graphs/)**
- [trees, nodes, binary trees, binary search, trees](trees_and_graphs/Trees.py)
* 𝟙𝟘𝟙𝟙. **[trees, transversals, graphs](trees_and_graphs/)**

View File

@ -0,0 +1,55 @@
## arrays and strings
<br>
### `is_palindrome.py`
<br>
```python
python3 is_palindrome.py
Testing is_palindrome()...
Is subi no onibus a palindrone?: True
Is helllo there a palindrone?: False
```
<br>
### `playing_with_strings.py`
<br>
```python
python3 playing_with_strings.py
Testing reverse_array_in_place
Array: [1, 2, 3, 4, 5]
Reversed: [5, 4, 3, 2, 1]
```
<br>
### `anagram.py`
<br>
```python
python3 anagram.py
Testing is_anagram()...
Is listen an anagram of silent?: True
```
<br>
### `permutation.py`
<br>
```python
python3 permutation.py
Testing permutation()...
Permutation of bt3gl: ['bt3gl', 'bt3lg', 'btg3l', 'btgl3', 'btl3g', 'btlg3', 'b3tgl', 'b3tlg', 'b3gtl', 'b3glt', 'b3ltg', 'b3lgt', 'bgt3l', 'bgtl3', 'bg3tl', 'bg3lt', 'bglt3', 'bgl3t', 'blt3g', 'bltg3', 'bl3tg', 'bl3gt', 'blgt3', 'blg3t', 'tb3gl', 'tb3lg', 'tbg3l', 'tbgl3', 'tbl3g', 'tblg3', 't3bgl', 't3blg', 't3gbl', 't3glb', 't3lbg', 't3lgb', 'tgb3l', 'tgbl3', 'tg3bl', 'tg3lb', 'tglb3', 'tgl3b', 'tlb3g', 'tlbg3', 'tl3bg', 'tl3gb', 'tlgb3', 'tlg3b', '3btgl', '3btlg', '3bgtl', '3bglt', '3bltg', '3blgt', '3tbgl', '3tblg', '3tgbl', '3tglb', '3tlbg', '3tlgb', '3gbtl', '3gblt', '3gtbl', '3gtlb', '3glbt', '3gltb', '3lbtg', '3lbgt', '3ltbg', '3ltgb', '3lgbt', '3lgtb', 'gbt3l', 'gbtl3', 'gb3tl', 'gb3lt', 'gblt3', 'gbl3t', 'gtb3l', 'gtbl3', 'gt3bl', 'gt3lb', 'gtlb3', 'gtl3b', 'g3btl', 'g3blt', 'g3tbl', 'g3tlb', 'g3lbt', 'g3ltb', 'glbt3', 'glb3t', 'gltb3', 'glt3b', 'gl3bt', 'gl3tb', 'lbt3g', 'lbtg3', 'lb3tg', 'lb3gt', 'lbgt3', 'lbg3t', 'ltb3g', 'ltbg3', 'lt3bg', 'lt3gb', 'ltgb3', 'ltg3b', 'l3btg', 'l3bgt', 'l3tbg', 'l3tgb', 'l3gbt', 'l3gtb', 'lgbt3', 'lgb3t', 'lgtb3', 'lgt3b', 'lg3bt', 'lg3tb']
```

View File

@ -0,0 +1,26 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: bt3gl
def is_anagram(string1, string2) -> bool:
string1 = string1.lower()
string2 = string2.lower()
if len(string1) != len(string2):
return False
for char in string1:
if char not in string2:
return False
return True
if __name__ == '__main__':
print('Testing is_anagram()...')
string1 = "listen"
string2 = "silent"
print(f'Is {string1} an anagram of {string2}?: {is_anagram(string1, string2)}')

View File

@ -0,0 +1,23 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: bt3gl
def is_palindrome(sentence):
sentence = sentence.strip(' ')
if len(sentence) < 2:
return True
if sentence[0] == sentence[-1]:
return is_palindrome(sentence[1:-1])
return False
if __name__ == '__main__':
print('Testing is_palindrome()...')
sentence ="subi no onibus"
print(f'Is {sentence} a palindrone?: {is_palindrome(sentence)}')
sentence ="helllo there"
print(f'Is {sentence} a palindrone?: {is_palindrome(sentence)}')

View File

@ -0,0 +1,22 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: bt3gl
def permutation(string) -> list:
if len(string) == 1:
return [string]
result = []
for i, char in enumerate(string):
for perm in permutation(string[:i] + string[i+1:]):
result += [char + perm]
return result
if __name__ == '__main__':
print('Testing permutation()...')
string = "bt3gl"
print(f'Permutation of {string}: {permutation(string)}')

View File

@ -0,0 +1,15 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: bt3gl
def reverse_array_in_place(array):
""" Reverse an array in place """
return array[::-1]
if __name__ == '__main__':
print('Testing reverse_array_in_place')
array = [1, 2, 3, 4, 5]
print(f'Array: {array}')
print(f'Reversed: {reverse_array_in_place(array)}')

View File

@ -0,0 +1,25 @@
## bit manipulation
<br>
### `playing_with_bits.py`
<br>
```python
> python3 playing_with_bits.py
Integer number: 144
Binary number: 10010000
Update bit: 0b10010100
Set bit: 0b10010100
Clear bit: 0b10000000
I: 144, I2: 90
B: 10010000, B2: 01011010
Count bits swapped: 4
Swap bit in place: (90, 144)
```

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: bt3gl
def set_bit(num, i):
mask = 1 << i
return bin( num | mask )
def update_bit(num, i, v):
mask = ~ (1 << i)
return bin( (num & mask) | (v << i) )
def count_bits_swapped(a, b):
count = 0
m = a^b
while m:
count +=1
m = m & (m-1)
return count
def clear_bit(num, i):
mask = ~ (1 << i) # -0b10001
return bin(num & mask)
def swap_bit_in_place(a, b):
a = a^b
b = a^b
a = a^b
return a, b
def find_how_many_1_in_a_binary(num):
counter = 0
while num:
if num & 1:
counter += 1
num >>= 1
return counter
if __name__ == '__main__':
binary_number = '10010000'
binary_number2 = '01011010'
integer_number = int(binary_number, 2)
integer_number2 = int(binary_number2, 2)
print(f'Integer number: {integer_number}')
print(f'Binary number: {binary_number}')
print(f'\nUpdate bit: {update_bit(integer_number, 2, 1)}')
print(f'Set bit: {set_bit(integer_number, 2)}')
print(f'Clear bit: {clear_bit(integer_number, 4)}')
print(f'\nI: {integer_number}, I2: {integer_number2}')
print(f'B: {binary_number}, B2: {binary_number2}')
print(f'Count bits swapped: {count_bits_swapped(integer_number, integer_number2)}')
print(f'\nSwap bit in place: {swap_bit_in_place(integer_number, integer_number2)}')
print(f'Find how many 1 in a binary: {find_how_many_1_in_a_binary(integer_number)}')

View File

@ -2,7 +2,7 @@
__author__ = "bt3"
def binary_serch_counting(lst1, k, lo=0, hi=None):
def binary_search_counting(lst1, k, lo=0, hi=None):
if hi is None: hi = len(lst1)
while lo < hi:
mid = (lo+hi)//2
@ -24,7 +24,7 @@ def find_time_occurrence_list(seq, k):
the dict is fixed. Another way, since the array is sorted, it to
use binary search, since this is only O(logn).
"""
index_some_k = binary_serch_counting(seq, k)
index_some_k = binary_search_counting(seq, k)
count = 1
sizet = len(seq)

View File

View File

@ -0,0 +1,20 @@
## math and logic
<br>
```python
python3 fibonacci.py
Testing fibonacci
Fibonacci of 10: 55
```
<br>
```python
python playing_with_math.py
Greatest common divider of 21 and 7 is 7
Prime factors of 21 are [3, 7]
```

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: bt3gl
def fibonacci(n):
""" Calculate the nth Fibonacci number """
if n == 0 or n == 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
if __name__ == '__main__':
print('Testing fibonacci')
n = 10
print(f'Fibonacci of {n}: {fibonacci(n)}')

View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: bt3gl
import math
import random
def find_greatest_common_divider(a, b) -> int:
'''Implements the greatest common divider algorithm '''
while(b != 0):
result = b
a, b = b, a % b
return result
def _is_prime(number) -> bool:
'''Check if a number is prime '''
if number < 2:
return False
for i in range(2, int(math.sqrt(number))):
if number % i == 0:
return False
return True
def find_prime_factors(number) -> list:
'''Find prime factors of a number '''
divisors = [d for d in range(2, number//2 + 1) if number % d == 0]
primes = [d for d in divisors if _is_prime(d)]
return primes
if __name__ == '__main__':
n1 = 21
n2 = 7
print(f'Greatest common divider of {n1} and {n2} is {find_greatest_common_divider(n1, n2)}')
print(f'Prime factors of {n1} are {find_prime_factors(n1)}')

View File

@ -0,0 +1,29 @@
## sorting and searching
<br>
### `sorting_algorithms.py`
<br>
```python
> python3 sorting_algorithms.py
Array: [3, 5, 1, 2, 10, 6]
Testing merge sort: [1, 2, 3, 5, 6, 10]
Testing quick sort: [1, 2, 3, 5, 6, 10]
```
<br>
### `binary_search.py`
<br>
```python
> python binary_search.py
Recursive: 6
Iterative: 6
```

View File

@ -0,0 +1,68 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: bt3gl
def binary_search_recursive(array, item, higher=None, lower=0):
higher = higher or len(array)
if higher < lower:
return False
mid = (higher + lower)//2
if item == array[mid]:
return mid
elif item < array[mid]:
return binary_search_recursive(array, item, higher=mid-1, lower=lower)
else:
return binary_search_recursive(array, item, higher=higher, lower=mid+1)
def binary_search_iterative(array, item):
lower, higher = 0, len(array)
while lower < higher:
mid = (higher+lower)//2
if array[mid] == item:
return mid
elif array[mid] > item:
higher = mid
else:
lower=mid+1
return False
def binary_search_matrix(matrix, item, lower=0, higher=None):
""" Binary search in a matrix """
if not matrix:
return None
rows = len(matrix)
cols = len(matrix[0])
higher = higher or rows*cols
if higher > lower:
mid = (higher + lower)//2
row = mid//cols
col = mid%cols
item = matrix[row][col]
if item == item:
return row, col
elif item < item:
return binary_search_matrix(matrix, item, lower, mid-1)
else:
return binary_search_matrix(matrix, item, mid+1, higher)
return None
if __name__ == '__main__':
array = [2, 3, 5, 6, 8, 10, 15, 23]
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
item = 15
print('Recursive: ', binary_search_recursive(array, item))
print('Iterative: ', binary_search_iterative(array, item))
print('Matrix: ', binary_search_matrix(matrix, item))

View File

@ -0,0 +1,64 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: bt3gl
def merge_sort(array):
"""Sort an array using merge sort"""
# part 1: recursively divide the array into subarrays
if len(array) < 2:
return array
mid = len(array) // 2
left = merge_sort(array[:mid])
right = merge_sort(array[mid:])
# part 2: merge the subarrays
result = []
i, j = 0, 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i +=1
else:
result.append(right[j])
j +=1
if left[i:]:
result.extend(left[i:])
if right[j:]:
result.extend(right[j:])
return result
def quick_sort_partition(array):
"""Sort an array using quick sort"""
pivot, array = array[0], array[1:]
lower = [i for i in array if i <= pivot]
higher = [i for i in array if i > pivot]
return lower, pivot, higher
def quick_sort_divided(array):
"""Sort an array using quick sort"""
if len(array) < 2:
return array
lower, pivot, higher = quick_sort_partition(array)
return quick_sort_divided(lower) + [pivot] + quick_sort_divided(higher)
if __name__ == '__main__':
array = [3, 5, 1, 2, 10, 6]
print(f'Array: {array}')
print(f'Testing merge sort: {merge_sort(array)}')
print(f'Testing quick sort: {quick_sort_divided(array)}')

120
stacks_and_queues/Queue.py Normal file
View File

@ -0,0 +1,120 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: bt3gl
import heapq
class Queue:
def __init__(self):
self._in = []
self._out = []
######################
# Private methods
######################
def _transfer_in_to_out(self):
while self._in:
self._out.append(self._in.pop())
def __repr__(self):
if not self._out:
self._transfer_in_to_out()
return f'{self._out}'
######################
# Properties
######################
@property
def size(self):
return len(self._in) + len(self._out)
@property
def peek(self):
if not self._out:
self._transfer_in_to_out()
if self._out:
return self._out[-1]
else:
print('❌ Queue is empty, cannot peek.')
@property
def is_empty(self):
return not (bool(self._in) or bool(self._out))
######################
# Public methods
######################
def enqueue(self, item):
self._in.append(item)
def dequeue(self):
if not self._out:
while self._in:
self.out.append(self._in.pop())
if self._out:
self._out.pop()
else:
print('❌ Queue is empty, cannot dequeue.')
class PriorityQueue:
def __init__(self):
self.queue = []
self.index = 0
def push(self, item, priority):
heapq.heappush(self.queue, (-priority, self.index, item))
self.index += 1
def pop(self):
return heapq.heappop(self.queue)[-1]
class Item:
def __init__(self, name):
self.name = name
def __repr__(self):
return f'{self.name}'
if __name__ == '__main__':
######################
# Simple Queue
######################
print('🧪 Testing Queue...')
queue = Queue()
print(f"Is the queue empty? {queue.is_empty}")
print("Adding 1 to 10 in the queue...")
for i in range(1, 11):
queue.enqueue(i)
print(f"Queue: {queue}")
print(f"\nQueue size: {queue.size}")
print(f"Queue peek : {queue.peek}")
print(f"Is the queue empty? {queue.is_empty}")
print(f"\nDequeue...")
queue.dequeue()
print(f"Queue: {queue}")
print(f"\nQueue size: {queue.size}")
print(f"Queue peek: {queue.peek}")
print(f"Is the queue empty? {queue.is_empty}")
######################
# Priority Queue
######################
print('\n\n🧪 Testing Priority Queue...')
q = PriorityQueue()
q.push(Item('Item 1'), 1)
q.push(Item('Item 4'), 4)
q.push(Item('Item 3'), 3)
print(f"Priority Queue: {q.queue}")
print(f"Pop: {q.pop()}")
print(f"Priority Queue: {q.queue}")

View File

@ -0,0 +1,59 @@
## stacks and queues
<br>
### `Queues.py`
<br>
```python
> python3 queues.py
🧪 Testing Queue...
Is the queue empty? True
Adding 1 to 10 in the queue...
Queue: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Queue size: 10
Queue peek : 1
Is the queue empty? False
Dequeue...
Queue: [10, 9, 8, 7, 6, 5, 4, 3, 2]
Queue size: 9
Queue peek: 2
Is the queue empty? False
🧪 Testing Priority Queue...
Priority Queue: [(-4, 1, Item 4), (-1, 0, Item 1), (-3, 2, Item 3)]
Pop: Item 4
Priority Queue: [(-3, 2, Item 3), (-1, 0, Item 1)]
```
<br>
### `stack.py`
<br>
```python
python3 stack.py
Testing Stack...
Stack: [12, 13, 14, 15, 16, 17, 18, 19, 20]
Stack size: 9
Stack peek: 20
Stack is empty: False
Stack min: 12
Popping...
20
19
18
17
16
Stack: [12, 13, 14, 15]
```

View File

@ -0,0 +1,79 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: bt3gl
class Stack:
def __init__(self):
self.content = []
self.min_array = []
self.min = float('inf')
######################
# Private methods
######################
def __repr__(self):
return f'{self.content}'
######################
# Properties
######################
@property
def size(self):
return len(self.content)
@property
def peek(self):
if self.content:
return self.content[-1]
else:
print('❌ Queue is empty, cannot peek.')
@property
def is_empty(self):
return not bool(self.content)
######################
# Public methods
######################
def push(self, value):
if value < self.min:
self.min = value
self.content.append(value)
self.min_array.append(self.min)
def pop(self):
if self.content:
value = self.content.pop()
self.min_array.pop()
if self.min_array:
self.min = self.min_array[-1]
return value
def find_min(self):
if self.min_array:
return self.min_array[-1]
if __name__ == '__main__':
######################
# Simple Stack
######################
print('Testing Stack...')
stack = Stack()
for i in range(12, 21):
stack.push(i)
print(f'\nStack: {stack}')
print(f'Stack size: {stack.size}')
print(f'Stack peek: {stack.peek}')
print(f'Stack is empty: {stack.is_empty}')
print(f'Stack min: {stack.find_min()}')
print('\nPopping...')
for i in range(5):
print(stack.pop())
print(f'Stack: {stack}')

View File

@ -0,0 +1,105 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# author: bt3gl
class Node(object):
def __init__(self, value):
self.value = value
self.right = None
self.left = None
def add(self, value):
new_node = Node(value)
if not self.value:
self.value = new_node
elif not self.left:
self.left = new_node
elif not self. right:
self.right = new_node
else:
self.left = self.left.add(value)
return self # without this, it doesn't add!
def search(self, item):
if self.value == item:
return True
found = False
if (self.left and self.left.search(item)) or \
(self.right and self.right.search(item)):
found = True
return found
def preorder(self):
yield self.value
if self.left:
for node in self.left.preorder():
yield node
if self.right:
for node in self.right.preorder():
yield node
def postorder(self):
yield self.value
if self.left:
for node in self.left.postorder():
yield node
if self.right:
for node in self.right.postorder():
yield node
def inorder(self):
yield self.value
if self.left:
for node in self.left.inorder():
yield node
if self.right:
for node in self.right.inorder():
yield node
class BinaryTree(object):
def __init__(self):
self.root = None
def add(self, value):
if not self.root:
self.root = Node(value)
else:
self.root.add(value)
def search(self, item):
if self.root:
return self.root.search(item)
def preorder(self):
if self.root:
return list(self.root.preorder())
def inorder(self):
if self.root:
return list(self.root.inorder())
def postorder(self):
if self.root:
return list(self.root.postorder())
if __name__ == '__main__':
print("\n\n🌳🌳🌳 Testing BinaryTree 🌳🌳🌳")
bt = BinaryTree()
array1 = [4, 1, 4, 6, 7, 9, 10, 5, 11, 5]
print(f'\n🟡 Adding {array1} to the tree...')
for i in array1:
bt.add(i)
print(f"🟢 Print the tree preorder: {bt.preorder()}")
print(f"🟢 Print the tree inorder: {bt.inorder()}")
print(f"🟢 Print the tree postorder: {bt.postorder()}")
print(f'\n🟢 Search for node 5: {bt.search(5)}')
print(f'❌ Search for node 15: {bt.search(15)}')

View File

@ -0,0 +1,93 @@
## trees
<br>
### `Tree.py`
<br>
```python
> python3 Trees.py
🌴🌴🌴 Testing SimpleTree 🌴🌴🌴
a
b
d
e
c
h
g
🌳🌳🌳 Testing BinaryTree 🌳🌳🌳
🟡 Adding [4, 1, 4, 6, 7, 9, 10, 5, 11, 5] to the tree...
🟢 Printing the tree in preorder...
4
1
6
9
5
5
11
10
7
4
🟢 Searching for node 5: True
❌ Searching for node 15: False
❌ Is root a leaf? False
🟢 Is root full? True
❌ Is the tree balanced? False
❌ Is the tree a binary search tree? False
🎄🎄🎄 Testing BinarySearchTree 🎄🎄🎄
🟡 Adding [4, 1, 4, 6, 7, 9, 10, 5, 11, 5] to the tree...
❌ Item 4 not added as BSTs do not support repetition.
❌ Item 5 not added as BSTs do not support repetition.
🟢 Printing the tree in preorder:
4
1
6
5
7
9
10
11
🟢 Searching for node 5: True
❌ Searching for node 15: False
❌ Is root a leaf? False
🟢 Is root full? True
🟢 Largest node? 11
🟢 Smallest node? 1
❌ Is the tree balanced? False
🟢 Is the tree a binary search tree? True
```
<br>
### `BinaryTree.py`
<br>
* a clean implementation adapted from the class above.
```python
> python3 BinaryTree.py
🌳🌳🌳 Testing BinaryTree 🌳🌳🌳
🟡 Adding [4, 1, 4, 6, 7, 9, 10, 5, 11, 5] to the tree...
🟢 Print the tree preorder: [4, 1, 6, 9, 5, 5, 11, 10, 7, 4]
🟢 Print the tree inorder: [4, 1, 6, 9, 5, 5, 11, 10, 7, 4]
🟢 Print the tree postorder: [4, 1, 6, 9, 5, 5, 11, 10, 7, 4]
🟢 Search for node 5: True
❌ Search for node 15: False
```

View File

@ -294,5 +294,3 @@ if __name__ == '__main__':
print(f'🟢 Smallest node? {bst.smallest_node(bst.root)}')
print(f'❌ Is the tree balanced? {bst.is_balanced(bst.root)}')
print(f'🟢 Is the tree a binary search tree? {bst.is_binary_search_tree(bst.root)}')