├── README.md ├── array.py ├── builtin_operations.py ├── circular_linked_list.py ├── double_linked_list.py ├── double_node.py ├── grid.py ├── guess_number.py ├── linked_list.py ├── list_based_queue.py ├── music_player.py ├── node.py ├── node_based_queue.py └── stack.py /README.md: -------------------------------------------------------------------------------- 1 | # Curso de Estructuras de Datos Lineales en Python - Platzi 2 | 3 | Este es el repositorio utilizado durante el curso, podrás encontrar encontrar el código de cada clase en cada una de las ramas. 4 | Recuerda seguirme en Twitter como [@TerranigmArk](https://twitter.com/TerranigmArk) para cualquier duda o comentario. 5 | -------------------------------------------------------------------------------- /array.py: -------------------------------------------------------------------------------- 1 | """ 2 | Code used for the 'Crear un array' class. 3 | 4 | Array type class 5 | Methods: 6 | 1. Length 7 | 2. String representation 8 | 3. Membership 9 | 4. Index. 10 | 5. Replacement 11 | """ 12 | 13 | class Array(object): 14 | "Represents an array." 15 | 16 | def __init__(self, capacity, fill_value = None): 17 | """ 18 | Args: 19 | capacity (int): static size of the array. 20 | fill_value (any, optional): value at each position. Defaults to None. 21 | """ 22 | self.items = list() 23 | for i in range(capacity): 24 | self.items.append(fill_value) 25 | 26 | def __len__(self): 27 | """Returns capacity of the array.""" 28 | return len(self.items) 29 | 30 | def __str__(self): 31 | """Returns string representation of the array""" 32 | return str(self.items) 33 | 34 | def __iter__(self): 35 | """Supports traversal with a for loop.""" 36 | return iter(self.items) 37 | 38 | def __getitem__(self, index): 39 | """Subscrit operator for access at index.""" 40 | return self.items[index] 41 | 42 | def __setitem__(self, index, new_item): 43 | """Subscript operator for replacement at index.""" 44 | self.items[index] = new_item 45 | 46 | 47 | """ 48 | Code used in the shell to create an array 49 | instance and methods. 50 | """ 51 | 52 | """ 53 | from array import Array 54 | menu = Array(5) 55 | len(menu) 56 | print(menu) 57 | for i in range(len(menu)): 58 | menu[i] = i + 1 59 | menu[0] 60 | menu[2] 61 | for item in menu: 62 | print(menu) 63 | 64 | menu.__len__() 65 | menu.__str__() 66 | menu.__iter__() 67 | menu.__getitem__(2) 68 | menu.__setitem__(2, 100) 69 | menu.__getitem__(2) 70 | """ -------------------------------------------------------------------------------- /builtin_operations.py: -------------------------------------------------------------------------------- 1 | """ 2 | Code used during the class 'Operaciones esenciales en colecciones' 3 | Demonstration of common methods for data structures. 4 | """ 5 | 6 | # Creating list with different elements 7 | [] 8 | ["Isabel"] 9 | ["Isabel", "Mulan"] 10 | ["Isabel", "Mulan", 255] 11 | ["Isabel", ["Mulan", 255]] 12 | 13 | # Typical data structure operations in Python 14 | fruits = [] 15 | fruits.append("Kiwi") 16 | fruits.append("Berry") 17 | fruits.append("Melon") 18 | fruits.sort() 19 | fruits.pop() 20 | fruits.insert(0, "Apple") 21 | fruits.insert(1, "Strawberry") 22 | fruits.pop(1) 23 | fruits.remove("Apple") 24 | # fruits.remove("Dragon fruit") 25 | 26 | def pyramid_sum(lower, upper, margin = 0): 27 | """Returns the sum of the numbers from lower to upper, 28 | and outputs a trace of the arguments and return values 29 | on each call.""" 30 | blanks = " " * margin 31 | print(blanks, lower, upper) # Print the arguments 32 | 33 | if lower > upper: 34 | print(blanks, 0) # Print the returned value 35 | return 0 36 | else: 37 | result = lower + pyramid_sum(lower + 1, upper, margin + 4) 38 | print(blanks, result) # Print the returned value 39 | return result 40 | 41 | pyramid_sum(1, 4) -------------------------------------------------------------------------------- /circular_linked_list.py: -------------------------------------------------------------------------------- 1 | """ 2 | Code used for the class 'Circular Linked List'. 3 | """ 4 | 5 | class Node(object): 6 | "Represents a single linked node." 7 | def __init__(self, data, next=None): 8 | self.data = data 9 | self.next = next 10 | 11 | 12 | index = 1 13 | new_item = "ham" 14 | 15 | head = Node(None, None) 16 | head.next = head 17 | 18 | # Search for node at position index - 1 or the last position 19 | probe = head 20 | 21 | while index > 0 and probe.next != head: 22 | probe = probe.next 23 | index -= 1 24 | 25 | # Insert new node after node at position index - 1 or last position 26 | probe.next = Node(new_item, probe.next) 27 | 28 | print(probe.next.data) -------------------------------------------------------------------------------- /double_linked_list.py: -------------------------------------------------------------------------------- 1 | """ 2 | Code used for the class 'Double Linked List'. 3 | """ 4 | 5 | class Node(object): 6 | def __init__(self, data, next=None): 7 | self.data = data 8 | self.next = next 9 | 10 | class TwoWayNode(Node): 11 | def __init__(self, data, previous=None, next=None): 12 | Node.__init__(self, data, next) 13 | self.previous = previous 14 | 15 | # Create a doubly linked list with one node 16 | head = TwoWayNode(1) 17 | tail = head 18 | 19 | # Add four node to the end of the linked list 20 | for data in range(2, 6): 21 | tail.next = TwoWayNode(data, tail) 22 | tail = tail.next 23 | 24 | # Print the contents of the linked list in reverse order 25 | probe = tail 26 | 27 | while probe != None: 28 | print(probe.data) 29 | probe = probe.previous 30 | -------------------------------------------------------------------------------- /double_node.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Node(object): 4 | def __init__(self, data=None, next=None, previous=None): 5 | self.data = data 6 | self.next = next 7 | self.previous = previous 8 | 9 | class DoublyLinkedList(object): 10 | def __init__(self): 11 | self.head = None 12 | self.tail = None 13 | self.count = 0 14 | 15 | def append(self, data): 16 | """ Append an item to the list. """ 17 | new_node = Node(data, None, None) 18 | 19 | if self.head is None: 20 | self.head = new_node 21 | self.tail = self.head 22 | else: 23 | new_node.previous = self.tail 24 | self.tail.next = new_node 25 | self.tail = new_node 26 | self.cout += 1 27 | 28 | def delete(self, data): 29 | current = self.head 30 | node_deleted = False 31 | 32 | if current is None: 33 | node_deleted = False 34 | elif current.data == data: 35 | self.head = current.next 36 | self.head.previous = None 37 | node_deleted = True 38 | elif self.tail.data == data: 39 | self.tail = self.tail.previous 40 | self.tail.next = None 41 | node_deleted = True 42 | else: 43 | while current: 44 | if current.data == data: 45 | current.previous.next = current.next 46 | current.next.previous = current.previous 47 | node_deleted = True 48 | 49 | current = current.next 50 | 51 | if node_deleted: 52 | self.count -= 1 53 | 54 | def contain(self, data): 55 | for node_data in self.iter(): 56 | if data == node_data: 57 | return True 58 | 59 | return False 60 | 61 | def clear(self): 62 | """ Clear the entire list. """ 63 | self.tail = None 64 | self.head = None 65 | self.size = 0 -------------------------------------------------------------------------------- /grid.py: -------------------------------------------------------------------------------- 1 | """ 2 | Code used for the 'Crear un array de dos dimensiones' class. 3 | 4 | Grid type class 5 | Methods: 6 | 1. Initialize 7 | 2. Get height 8 | 3. Get width 9 | 4. Access item 10 | 5. String representation 11 | """ 12 | from array import Array 13 | 14 | 15 | class Grid(object): 16 | """Represents a two-dimensional array.""" 17 | def __init__(self, rows, columns, fill_value = None): 18 | self.data = Array(rows) 19 | for row in range(rows): 20 | self.data[row] = Array(columns, fill_value) 21 | 22 | def get_height(self): 23 | "Returns the number of rows." 24 | return len(self.data) 25 | 26 | def get_width(self): 27 | """Returns the number of columns.""" 28 | return len(self.data[0]) 29 | 30 | def __getitem__(self, index): 31 | """Supports two-dimensional indexing with [row][column].""" 32 | return self.data[index] 33 | 34 | def __str__(self): 35 | """Returns a string representation of the grid.""" 36 | result = "" 37 | 38 | for row in range(self.get_height()): 39 | for col in range(self.get_width()): 40 | result += str(self.data[row][col]) + " " 41 | 42 | result += "\n" 43 | 44 | return str(result) 45 | 46 | ''' 47 | Code used in the shell to instance a grid 48 | 49 | matrix = Grid(3, 3) 50 | print(matrix) 51 | for row in range(matrix.get_height()): 52 | for column in range(matrix.get_width()): 53 | matrix[row][column] = row * column 54 | 55 | print(matrix) 56 | matrix.get_height() 57 | matrix.get_width() 58 | matrix.__getitem__() 59 | matrix.__getitem__(1) 60 | matrix.__getitem__(2)[0] 61 | matrix.__str__() 62 | ''' -------------------------------------------------------------------------------- /guess_number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Code used during the class 'Elementos de la programación en Python' 3 | Guess a number game with the user. 4 | """ 5 | 6 | import random 7 | 8 | def main(): 9 | """Input the upper and lower limit of a range of numbers 10 | and lets the user guess the random number until correct. 11 | """ 12 | lower_limit = int(input("Enter the smaller number of the range: ")) 13 | upper_limit = int(input("Enter the larger number of the range: ")) 14 | secret_number = random.randint(lower_limit, upper_limit) 15 | tries = 0 16 | 17 | while True: 18 | tries += 1 19 | user_number = int(input("Enter a number to try to guess: ")) 20 | 21 | if user_number < secret_number: 22 | print("Try with a higher number.") 23 | elif user_number > secret_number: 24 | print("Try with a lower number.") 25 | else: 26 | print(f"You won! It took you {tries} tries") 27 | break 28 | 29 | if __name__ == "__main__": 30 | main() -------------------------------------------------------------------------------- /linked_list.py: -------------------------------------------------------------------------------- 1 | """ 2 | Code used for the class 'Nodos y singly linked list'. 3 | 4 | All the code but the 'Node' class is written in the shell 5 | for demonstrative purposes. 6 | 7 | The node methods should be incorporated into the Node class. 8 | """ 9 | 10 | class Node(object): 11 | "Represents a single linked node." 12 | def __init__(self, data, next=None): 13 | self.data = data 14 | self.next = next 15 | 16 | # Creating 3 differents nodes 17 | node1 = None 18 | node2 = Node("A", None) 19 | node3 = Node("B", node2) 20 | 21 | # This causes an Atribute Error 22 | # node1.next = node3 23 | 24 | node1 = Node("C", node3) 25 | 26 | # Creating a linked list 27 | head = None 28 | # Add five nodes to the beginning of the linked structure 29 | for count in range(1, 3): 30 | head = Node(count, head) 31 | # Print the contents of the structure 32 | 33 | while head != None: 34 | print(head.data) 35 | head = head.next 36 | 37 | 38 | """ Main linked lists operations """ 39 | # Traversal with 'probe' as aux. variable 40 | probe = head 41 | 42 | while probe != None: 43 | print(probe.data) 44 | probe = probe.next 45 | 46 | 47 | # Search an item 48 | probe = head 49 | target_item = 2 50 | while probe != None and target_item != probe.data: 51 | probe = probe.next 52 | 53 | if probe != None: 54 | print(f"Target item {target_item} has been found") 55 | else: 56 | print(f"Target item {target_item} is not in the linked list") 57 | 58 | 59 | # Replacement 60 | probe = head 61 | target_item = 3 62 | new_item = "Z" 63 | while probe != None and target_item != probe.data: 64 | probe = probe.next 65 | 66 | if probe != None: 67 | probe.data = new_item 68 | print(f"{new_item} replaced the old value in the node number {target_item}") 69 | else: 70 | print(f"The target item {target_item} is not in the linked list") 71 | 72 | 73 | # Insert new element at the beginning 74 | head = Node("F", head) 75 | 76 | 77 | # Insert at the end 78 | new_node = Node("K") 79 | 80 | if head is None: 81 | head = new_node 82 | else: 83 | probe = head 84 | while probe.next != None: 85 | probe = probe.next 86 | 87 | probe.next = new_node 88 | 89 | 90 | # Remove at the beginning 91 | removed_item = head.data 92 | head = head.next 93 | print(removed_item) 94 | 95 | 96 | # Remove at the end 97 | removed_item = head.data 98 | 99 | if head.next is None: 100 | head = None 101 | else: 102 | probe = head 103 | 104 | while probe.next.next != None: 105 | probe = probe.next 106 | 107 | removed_item = probe.next.data 108 | probe.next = None 109 | 110 | print(removed_item) 111 | 112 | 113 | # Insert at any position 114 | new_item = input("Enter the new item: ") 115 | index = int(input("Enter the position to inser the new item: ")) 116 | if head is None or index < 0: 117 | head = Node("Py", head) 118 | else: 119 | # Search for node at position index - 1 or the last position 120 | probe = head 121 | 122 | while index > 1 and probe.next != None: 123 | probe = probe.next 124 | index -= 1 125 | 126 | probe.next = Node(new_item, probe.next) 127 | 128 | 129 | # Remove at any position 130 | index = 3 131 | 132 | if index <= 0 or head.next is None: 133 | removed_item = head.data 134 | head = head.next 135 | print(removed_item) 136 | else: 137 | # Search for nod at position index - 1 138 | # or the next to last position 139 | probe = head 140 | 141 | while index > 1 and probe.next.next != None: 142 | probe = probe.next 143 | index -= 1 144 | 145 | removed_item = probe.next.data 146 | probe.next = probe.next.next 147 | print(removed_item) -------------------------------------------------------------------------------- /list_based_queue.py: -------------------------------------------------------------------------------- 1 | """ 2 | Code used during the class 'Queues basadas en listas'. 3 | """ 4 | 5 | class ListQueue: 6 | def __init__(self): 7 | self.items = [] 8 | self.size = 0 9 | 10 | def enqueue(self, data): 11 | self.items.insert(0, data) 12 | self.size += 1 13 | 14 | def dequeue(self): 15 | data = self.items.pop() 16 | self.size -= 1 17 | return data 18 | 19 | def traverse(self): 20 | total_items = self.size 21 | 22 | for item in total_items: 23 | print(self.items[item]) 24 | 25 | 26 | """ 27 | Code used in the shell 28 | 29 | x = ListQueue() 30 | x.enqueue('eegs') 31 | x.enqueue('ham') 32 | x.enqueue('spam') 33 | x.items 34 | 35 | for i in range(x.size): 36 | print(x.items[i]) 37 | 38 | """ -------------------------------------------------------------------------------- /music_player.py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | from node_based_queue import Queue 3 | from time import sleep 4 | 5 | class Track: 6 | def __init__(self, title=None): 7 | self.title = title 8 | self.length = randint(5, 6) 9 | 10 | class MediaPlayerQueue(Queue): 11 | def __init__(self): 12 | super(MediaPlayerQueue, self).__init__() 13 | 14 | def add_track(self, track): 15 | self.enqueue(track) 16 | 17 | def play(self): 18 | print(f"count: {self.count}") 19 | while self.count > 0 and self.head is not None: 20 | current_track_node = self.dequeue() 21 | print(f"Now playing {current_track_node.data.title}.") 22 | 23 | sleep(current_track_node.data.length) 24 | 25 | track1 = Track("white whistle") 26 | track2 = Track("butter butter") 27 | track3 = Track("Oh black star") 28 | track4 = Track("Watch that chicken") 29 | track5 = Track("Don't go") 30 | 31 | """ print(track1.length) 32 | print(track2.length) 33 | print(track3.length) """ 34 | 35 | media_player = MediaPlayerQueue() 36 | 37 | media_player.add_track(track1) 38 | media_player.add_track(track2) 39 | media_player.add_track(track3) 40 | media_player.add_track(track4) 41 | media_player.add_track(track5) 42 | media_player.play() -------------------------------------------------------------------------------- /node.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Code used for the 'Singly linked list' class. 4 | """ 5 | 6 | class Node: 7 | "Represents a single linked node." 8 | def __init__(self, data, next = None): 9 | self.data = data 10 | self.next = None 11 | 12 | def __str__(self): 13 | "String representation of the node data." 14 | return str(self.data) 15 | 16 | def __repr__(self): 17 | "Simple representation of the node." 18 | return self.data 19 | 20 | class SinglyLinkedList: 21 | "Represents a singly linked list made of several Node instances." 22 | def __init__(self): 23 | self.tail = None 24 | self.size = 0 25 | 26 | def append(self, data): 27 | "Encapsulates the data in a Node class." 28 | node = Node(data) 29 | 30 | if self.tail == None: 31 | self.tail = node 32 | else: 33 | current = self.tail 34 | 35 | while current.next: 36 | current = current.next 37 | 38 | current.next = node 39 | 40 | self.size += 1 41 | 42 | def size(self): 43 | "Returns the number of nodes in the list." 44 | return str(self.size) 45 | 46 | def iter(self): 47 | "Iters through the list." 48 | current = self.tail 49 | 50 | while current: 51 | val = current.data 52 | current = current.next 53 | yield val 54 | 55 | def delete(self, data): 56 | "Removes an element in the singly linked list." 57 | current = self.tail 58 | previous = self.tail 59 | 60 | while current: 61 | if current.data == data: 62 | if current == self.tail: 63 | self.tail = current.next 64 | else: 65 | previous.next = current.next 66 | self.size -= 1 67 | return current.data 68 | 69 | previous = current 70 | current = current.next 71 | 72 | def search(self, data): 73 | "Looks for a specific element in the list." 74 | for node in self.iter(): 75 | if data == node: 76 | print(f"Data {data} found") 77 | 78 | def clear(self): 79 | "Clear the entire list." 80 | self.tail = None 81 | self.head = None 82 | self.size = 0 83 | 84 | 85 | """ 86 | Ejemplo en shell de SinglyLinkedList con append 87 | 88 | words = SinglyLinkedList() 89 | words.append('egg') 90 | words.append('ham') 91 | words.append('spam') 92 | 93 | current = words.tail 94 | 95 | while current: 96 | print(current.data) 97 | current = current.next 98 | 99 | for word in words.iter(): 100 | print(word) 101 | 102 | words.search('eggs') 103 | """ -------------------------------------------------------------------------------- /node_based_queue.py: -------------------------------------------------------------------------------- 1 | """ 2 | Code used during the class 'Queues basadas en nodos'. 3 | """ 4 | from double_node import Node 5 | 6 | 7 | class Queue: 8 | def __init__(self): 9 | self.head = None 10 | self.tail = None 11 | self.count = 0 12 | 13 | def enqueue(self, data): 14 | new_node = Node(data, None, None) 15 | 16 | if self.head is None: 17 | self.head = new_node 18 | self.tail = self.head 19 | else: 20 | new_node.previous = self.tail 21 | self.tail.next = new_node 22 | self.tail = new_node 23 | 24 | self.count += 1 25 | 26 | def dequeue(self): 27 | current = self.head 28 | 29 | if self.count == 1: 30 | self.count -= 1 31 | self.head = None 32 | self.tail = None 33 | elif self.count > 1: 34 | self.head = self.head.next 35 | self.head.previous = None 36 | self.count -= 1 37 | 38 | return current 39 | 40 | 41 | """ 42 | Code used in the shell 43 | 44 | x = Queue() 45 | 46 | x.enqueue('eggs') 47 | x.enqueue('ham') 48 | x.enqueue('spam') 49 | x.head.data 50 | x.head.next.data 51 | x.tail.data 52 | x.count 53 | x.dequeue() 54 | x.head 55 | """ -------------------------------------------------------------------------------- /stack.py: -------------------------------------------------------------------------------- 1 | """ 2 | Code used for the class 'Crear un stack'. 3 | """ 4 | 5 | 6 | class Node: 7 | def __init__(self, data=None): 8 | self.data = data 9 | self.next = None 10 | 11 | class Stack: 12 | def __init__(self): 13 | self.top = None 14 | self.size = 0 15 | 16 | def push(self, data): 17 | """ Appends an element on top. """ 18 | node = Node(data) 19 | 20 | if self.top: 21 | node.next = self.top 22 | self.top = node 23 | else: 24 | self.top = node 25 | 26 | self.size += 1 27 | 28 | def pop(self): 29 | """ Removes and returns the element on top. """ 30 | if self.top: 31 | data = self.top.data 32 | self.size -= 1 33 | 34 | if self.top.next: 35 | self.top = self.top.next 36 | else: 37 | self.top = None 38 | 39 | return data 40 | else: 41 | return "The stack is empty" 42 | 43 | def peek(self): 44 | if self.top: 45 | return self.top.data 46 | else: 47 | return "The stack is empty" 48 | 49 | def clear(self): 50 | while self.top: 51 | self.pop() --------------------------------------------------------------------------------