INTRODUCTION TO DATA STRUCTURES AND ALGORITHMS WITH PYTHON.
Tags: beginners, python, codenewbie, algorithms
Published: 2022-02-21 12:51:09

**What are data structures**-  What comes in your mind when you hear data structures? Data structures are containers that organize and group data according to type. They differ based on mutability and order. Mutability refers to the ability to change an object after creation. We have two types of data structures built in Data structures and user defined data structures.

**what are data algorithms**- Is a sequence of steps executed by a computer that takes an input and transforms it into a target output.

**Built in data structures**

**lists**
 
 A list is defined using square brackets and holds data that is separated by commas. The list is mutable and ordered. it can contain a mix of different data types.
`months=['january','february','march','april','may','june','july','august','september','october','november','december']`
`print(months[0])#print the element  with index 0`
`print(months[0:7])#all the elements from index 0 to 6`
`months[0]='birthday #exchange the value in index 0 with the word birthday`
`print(months)`

**Tuples**

A tuple is another container. It's a data type for immutable ordered sequences of elements. Immutable because you can't add and remove elements from tuples, or sort them in place.
`length, width, height =9,3,1 #We can assign multiple variables in one shot`
`print("The dimensions are {} * {} * {}".format(length, width, height))`

**Set**
Set is a mutable and unordered collection of unique elements. It  can permit us to remove duplicate quickly from  a list.
`numbers=[1,2,3,4,6,3,3]`

`unique_nums = set(numbers)`
`print(unique_nums)`


`models ={'declan','gift','jabali','viola','kinya','nick',betty'`}

`print('davis' in models)#check if there is turner in the set models`
`models.add('davis')`
`print(model.pop())remove the last item#`
**Dictionaries**

dictionaries are mutable and unordered data structure. It permits storing a pair of items (i.e. keys and values)
The example below shows its possible to include containers into other containers to create compound data structures.
```
music={'jazz':{"coltrane": "In a sentiment mood",
                       "M.Davis":Blue in Green",
                       "T.Monk":"Don't Blame Me"},
          "classical":{"Bach": "cello suit",
                     "Mozart": "lacrimosa",
                     "satle": "Gymnopedie"}}
print(music["jazz"]["coltrane'])#we select the value of the key coltrane
print(music["classical"] ['mozart"])
```
**User-defined data structures**

**stacks using arrays** the stack is a linear data structure where elements are arranged sequentially. It follows the mechanism L.I.F.O which means last in first out. So, the last elements inserted will be removed as the first. The operations are:

- push- inserting an elements into the stack.

- Pop- deleting an element from the stack.

**The conditions to check**

Overflow condition- this condition occurs when we try to put one more element into a stack that is already having maximum elements.
Underflow condition-This condition occurs when we try to delete an element from an empty stack.

```
class mystack:
    
    def __init__(self):
        self.data =[]
        
    def length(self): #length of the list
        return len(self.data)
    
    def is_full(self): #check if the list is full or not
        if len(self.data) == 5:
            return True
        else:
            return False
        
    def push(self, element):# insert a new element
        if len(self.data) < 5:
            self.data.append(element)
        else:
            return "overflow"
        
    def pop(self): # # remove the last element from a list
        if len(self.data) == 0:
            return "underflow"
        else:
            return self.data.pop()

a = mystack() # I create my object
a.push(10) # insert the  element
a.push(23)
a.push(25)
a.push(27)
a.push(11)
print(a.length())
print(a.is_full())
print(a.data)
print(a.push(31)) # we try to insert one more element in the list - the output will be overflow
print(a.pop())
print(a.pop())
print(a.pop())
print(a.pop())
print(a.pop())
print(a.pop()) # try to delete an element in a list without elements - the output will be underflow
```
**Queue using arrays**

The queue is a linear data structure  where elements are in  a sequential manner. It follows the F.I.F.O  mechanism that means first in first out.
**Aspects that characterize a queue**
Two ends:

Front-points to starting element.
Rear-points to the last element.

There are two operations:

- Enqueue- Inserting an element into the queue. It will be done at the Rear.

- Dequeue- Deleting an element from the queue. It will be done at the front.
There are two conditions.
- Overflow- Insertion into a queue that is full.

- Underflow- Deletion from the empty queue.

```
class myqueue:
    
    def __init__(self):
        self.data = []
        
    def length(self):
        return len(self.data)
    
    def enque(self, element): # put the element in the queue
        if len(self.data) < 5:
            return self.data.append(element)
        else:
            return "overflow"
        
    def deque(self): # remove the first element that we have put in queue
        if len(self.data) == 0:
             return "underflow"
        else:
            self.data.pop(0)
            
b = myqueue()
b.enque(2) # put the element into the queue
b.enque(3)
b.enque(4)
b.enque(5)
print(b.data)
b.deque()# # remove the first element that we have put in the queue
print(b.data)
```
**Tree(general tree)**

Trees are used to define hierarchy. It starts with the root node and goes further down, the last nodes are called child nodes.
In this article, I focus on the binary tree. The binary tree is a tree data structure in which each node has at most two children, which are referred to as the left child and the the right child.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tfrwc4ex7a60bwyywg3g.png)
 
```
# create the class Node and the attrbutes 
class Node:
    def __init__(self, letter):
        self.childleft = None
        self.childright = None
        self.nodedata = letter

# create the nodes for the tree
root = Node('A')
root.childleft = Node('B')
root.childright = Node('C')
root.childleft.childleft = Node('D')
root.childleft.childright = Node('E')
```

**Linked list**
It is a linear data that have a series of connected nodes. Each node stores data and shows the route to the next node. They used to implement the undo function and dynamic memory allocation.

```
class LinkedList:
    def __init__(self):
        self.head = None

    def __iter__(self):
        node = self.head
        while node is not None:
            yield node
            node = node.next

    def __repr__(self):
        nodes = []
        for node in self:
            nodes.append(node.val)
        return " -> ".join(nodes)

    def add_to_tail(self, node):
        if self.head == None:
            self.head = node
            return
        for current_node in self:
            pass
        current_node.set_next(node)

    def remove_from_head(self):
        if self.head == None:
            return None
        temp = self.head
        self.head = self.head.next
        return temp


class Node:
    def __init__(self, val):
        self.val = val
        self.next = None

    def set_next(self, node):
        self.next = node

    def __repr__(self):
        return self.val
```



**Graphs**
It's a data structure that collects nodes that have data are connected to other nodes.
It consists of:
- A collection of vertices V.
- A collection of edges E, represented as ordered pairs of vertices(u, v)

**Algorithms**
In algorithms i will not go so deep will just states the approaches and types:

- Divide and conquer- known for dividing the problem into sub-parts and solve each one separately.

- Dynamic- It divides the problem into sub-parts remembers the results of the sub-parts and applies it to similar ones.

- Greedy algorithms- Involves taking the easiest step while solving a problem without worrying about the complexity of the future.
**Types of Algorithms**

- Tree traversal algorithms- are non-linear data structures. Characterized by roots and nodes. Here there are three types In-order traversal, pre-order traversal and post-order traversal.

- Sorting algorithms- is use to sort data in some given order. Can be classified in merge sort and Bubble sort.

- Searching algorithms- are used to seek for  some elements present in a given dataset. some types of search algorithms are: linear search, Binary search and exponential search.

**Conclusion**
Having the little overview above you can commit yourself to a deeper understanding of Data structures and Algorithms.

THANKYOU FOR READING.