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)**: * **📖 algorithms and data structures revisited (2023)**:
* 𝟘𝟘𝟙𝟘. **[arrays, vectors, strings](arrays_and_strings)** * 𝟘𝟘𝟙𝟘. **[arrays and strings](arrays_and_strings)**
* 𝟘𝟘𝟙𝟙. **[linked lists](linked_lists)** * 𝟘𝟘𝟙𝟙. **[linked lists](linked_lists)**
* 𝟘𝟙𝟘𝟘. **[stacks and queues](stacks_and_queues)** * 𝟘𝟙𝟘𝟘. **[stacks and queues](stacks_and_queues)**
* 𝟘𝟙𝟘𝟙. **[bit manipulation](bit_manipulation)** * 𝟘𝟙𝟘𝟙. **[bit manipulation](bit_manipulation)**
* 𝟘𝟙𝟙𝟘. **[math and logic](math_and_logic)** * 𝟘𝟙𝟙𝟘. **[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)** * 𝟙𝟘𝟘𝟙. **[sorting and searching](sorting_and_searching)**
* 𝟙𝟘𝟙𝟘. **[concurrency](concurrency)** * 𝟙𝟘𝟙𝟙. **[trees, transversals, graphs](trees_and_graphs/)**
* 𝟙𝟘𝟙𝟙. **[trees and graphs](trees_and_graphs/)**
- [trees, nodes, binary trees, binary search, trees](trees_and_graphs/Trees.py)

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" __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) if hi is None: hi = len(lst1)
while lo < hi: while lo < hi:
mid = (lo+hi)//2 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 the dict is fixed. Another way, since the array is sorted, it to
use binary search, since this is only O(logn). 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 count = 1
sizet = len(seq) 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'🟢 Smallest node? {bst.smallest_node(bst.root)}')
print(f'❌ Is the tree balanced? {bst.is_balanced(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)}') print(f'🟢 Is the tree a binary search tree? {bst.is_binary_search_tree(bst.root)}')