Python Dsa
Python Dsa
i
Python Data Structures
Data structures deal with how the data is organised and held in the memory, when a
program processes it. It is important to note that, the data that is stored in the disk as
part of persistent storages (like relational tables) are not referred as data structure here.
An Algorithm is step by step set of instruction to process the data for a specific purpose.
So, an algorithm utilises various data structures in a logical way to solve a specific
computing problem.
In this tutorial, we will cover these two fundamental concepts of computer science using
the Python programming language.
Audience
This tutorial is designed for Computer Science graduates as well as Software Professionals
who are willing to learn data structures and algorithm programming in simple and easy
steps using Python as a programming language.
Prerequisites
Before proceeding with this tutorial, you should have a basic knowledge of writing code in
Python programming language, using any python integrated development environment
(IDE) and execution of Python programs. If you are completely new to python, then please
refer our Python tutorial to get a sound understanding of the language.
All the content and graphics published in this e-book are the property of Tutorials Point (I)
Pvt. Ltd. The user of this e-book is prohibited to reuse, retain, copy, distribute or republish
any contents or a part of contents of this e-book in any manner without written consent
of the publisher.
We strive to update the contents of our website and tutorials as timely and as precisely as
possible, however, the contents may contain inaccuracies or errors. Tutorials Point (I) Pvt.
Ltd. provides no guarantee regarding the accuracy, timeliness or completeness of our
website or its contents including this tutorial. If you discover any errors on our website or
in this tutorial, please notify us at contact@[Link]
ii
Python Data Structures
Table of Contents
About the Tutorial ........................................................................................................................................... ii
Audience .......................................................................................................................................................... ii
Prerequisites .................................................................................................................................................... ii
iii
Python Data Structures
Updating Tuples............................................................................................................................................. 18
Updating Dictionary....................................................................................................................................... 21
Compare Sets................................................................................................................................................. 35
Removing an Item.......................................................................................................................................... 45
Updating Dictionary....................................................................................................................................... 59
Shell Sort........................................................................................................................................................ 90
Selection Sort................................................................................................................................................. 91
vii
1. Python Data Structures – Introduction Python Data Structures
Here, we will understand what is data structure with regards to Python programming
language.
In this chapter, we are going to study a short overview of some frequently used data
structures in general and how they are related to some specific python data types. There
are also some data structures specific to python which are listed as another category.
Array: It is a sequential arrangement of data elements paired with the index of the
data element.
Linked List: Each data element contains a link to another element, along with the
data present in it.
Stack: It is a data structure, which follows only to specific order of operation. LIFO
(last in First Out) or FILO(First in Last Out).
Queue: It is similar to Stack, but the order of operation is only FIFO (First In First
Out).
Matrix: It is two dimensional data structure in which, the data element is referred
by a pair of indices.
1
Python Data Structures
Binary Tree: It is a data structure, where each data element can be connected to
maximum two other data elements and it starts with a root node.
Heap: It is a special case of Tree data structure, where the data in the parent node
is either strictly greater than/ equal to the child nodes or strictly less than its child
nodes.
Hash Table: It is a data structure, which is made of arrays associated with each
other using a hash function. It retrieves values using keys rather than, index from
a data element.
Graph: It is an arrangement of vertices and nodes, where some of the nodes are
connected to each other through links.
List: It is similar to array with the exception, that the data elements can be of
different data types. You can have both numeric and string data in a python list.
Tuple: Tuples are similar to lists, but they are immutable which means, the values
in a tuple cannot be modified they can only be read.
Dictionary: The dictionary contains Key-value pairs as its data elements.
In the next chapters, we are going to learn the details of how each of these data structures
can be implemented using Python.
2
2. Python Data Structures – Environment Python Data Structures
Python is available on a wide variety of platforms, including Linux and Mac OS X. Let's
understand, how to set up our Python environment.
Getting Python
The most up-to-date and current source code, binaries, documentation, news, etc., is
available on the official website of Python which is available at [Link]
You can download Python documentation from this website given herewith,
[Link] The documentation is available in HTML, PDF, and
PostScript formats.
Installing Python
Python distribution is available for a wide variety of platforms. You need to download only
the binary code applicable for your platform and install Python.
3
Python Data Structures
If the binary code for your platform is not available, you need a C compiler to compile the
source code manually. Compiling the source code offers, more flexibility in terms of choice
of features that you require in your installation.
Windows Installation
Here, are the steps to install Python on Windows machine.
Macintosh Installation
Recent Macs come with Python installed, but it may be several years out of date.
See [Link] for instructions on getting the current
version along with extra tools to support development on the Mac. For older Mac
OS's before Mac OS X 10.3 (released in 2003), MacPython is available.
Jack Jansen maintains it and you can have full access to the entire documentation
at his website, which is available at [Link] You
can find complete installation details for Mac OS installation.
4
Python Data Structures
Setting up PATH
Programs and other executable files can be in many directories, so operating systems
provide a search path that, lists the directories that the OS searches for executables.
The path is stored in an environment variable, which is a named string maintained by the
operating system. This variable contains information available to the command shell and
other programs.
The path variable is named as PATH in Unix or Path in Windows (Unix is case sensitive;
Windows is not).
In Mac OS, the installer handles the path details. To invoke the Python interpreter from
any particular directory, you must add the Python directory to your path.
1 PYTHONPATH
It has a role similar to PATH. This variable tells the Python interpreter, where to locate
the module files imported into a program. It should include the Python source library
directory and the directories containing Python source code. PYTHONPATH is
sometimes, preset by the Python installer.
5
Python Data Structures
2 PYTHONSTARTUP
It contains the path of an initialisation file containing Python source code. It is executed
every time; you start the interpreter. It is named as .[Link] in Unix and it
contains commands that load utilities or modify PYTHONPATH.
3 PYTHONCASEOK
4 PYTHONHOME
Running Python
There are three different ways to start Python, which are as follows:
Interactive Interpreter
You can start Python from Unix, DOS, or any other system, that provides you a
command - line interpreter or shell window.
Enter python the command line.
Start coding right away in the interactive interpreter.
$python # Unix/Linux
or
python% # Unix/Linux
or
C:> python # Windows/DOS
Here, is the list of all the available command line options, which is as mentioned below:
1 -d
2 -O
6
Python Data Structures
3 -S
4 -v
5 -X
disable class-based built-in exceptions (just use strings); obsolete starting with version
1.6.
6 -c cmd
7 file
or
or
7
Python Data Structures
Macintosh − The Macintosh version of Python, along with the IDLE IDE is available
from the main website, downloadable as either MacBinary or BinHex'd files.
If you are not able to set up the environment properly, then you can take help from your
system admin. Make sure the Python environment is properly set up and working perfectly
fine.
Note − All the examples given in subsequent chapters are executed with Python
2.4.3 version available on CentOS flavor of Linux.
We already have set up Python Programming environment online, so that, you can execute
all the available examples online at the same time, when you are learning theory. Feel
free to modify any example and execute it online.
8
3. Python Data Structures – Arrays Python Data Structures
Array is a container, which can hold a fix number of items and these items should be of
the same type. Most of the data structures make use of arrays to implement their
algorithms. The important terms to understand the concept of Array are as follows:
Array Representation
Arrays can be declared in various ways in different languages. An illustration is given
below:
As per the above illustration, following are the important points to be considered:
Basic Operations
The basic operations supported by an array are as stated below:
9
Python Data Structures
Array is created in Python by importing array module to the python program. Then, the
array is declared as shown below:
Typecode are the codes that are used to define the type of value the array will hold. Some
common typecodes used are as follows:
Typecode Value
Before looking at various array operations, lets create and print an array using python.
for x in array1:
print(x)
Output
When we compile and execute the above program, it produces the following result:
10
20
30
10
Python Data Structures
40
50
print (array1[0])
print (array1[2])
Output
When we compile and execute the above program, it produces the following result, which
shows the element is inserted at index position 1.
10
30
Insertion Operation
Insert operation is, to insert one or more data elements into an array. Based on the
requirement, a new element can be added at the beginning, end, or any given index of
array.
Here, we add a data element at the middle of the array, using the python in-built insert()
method.
[Link](1,60)
for x in array1:
print(x)
Output
11
Python Data Structures
When we compile and execute the above program, it produces the following result which
shows the element is inserted at index position 1.
10
60
20
30
40
50
Deletion Operation
Deletion refers to removing an existing element from the array and re-organising all
elements of an array.
Here, we remove a data element at the middle of the array, using the python in-built
remove() method.
[Link](40)
for x in array1:
print(x)
Output
When we compile and execute the above program, it produces the following result, which
shows the element is removed from the array.
10
20
30
50
Search Operation
You can perform a search for an array element based on its value or its index.
Here, we search a data element, by using the python in-built index() method.
12
Python Data Structures
print ([Link](40))
Output
When we compile and execute the above program, it produces the following result which
shows the index of the element. If the value is not present in the array, then the program
returns an error.
Update Operation
Update operation refers to updating an existing element from the array at a given index.
Here, we simply reassign a new value to the desired index we want to update.
array1[2] = 80
for x in array1:
print(x)
Output
When we compile and execute the above program, it produces the following result, which
shows the new value at the index position 2.
10
20
80
40
50
13
4. Python Data Structures – Lists Python Data Structures
The list is a most versatile datatype available in Python, which can be written as a list of
comma-separated values (items) between square brackets. An important thing about the
list is that, items in a list need not be of the same type.
For example:
Similar to string indices, list indices start at 0, and lists can be sliced, concatenated and
so on.
Accessing Values
To access values in lists, use the square brackets for slicing along with the index or indices
to obtain value available at that index.
For example:
#!/usr/bin/python
list1[0]: physics
list2[1:5]: [2, 3, 4, 5]
Updating Lists
You can update single or multiple elements of lists, by giving the slice on the left-hand
side of the assignment operator, and you can add to elements in a list with the append()
method.
For example:
14
Python Data Structures
#!/usr/bin/python
For example:
#!/usr/bin/python
15
Python Data Structures
In fact, lists respond to all of the general sequence operations we used on strings in the
prior chapter.
16
5. Python Data Structures – Tuples Python Data Structures
A tuple is a sequence of immutable Python objects, just like lists. The differences between
tuples and lists are, the tuples cannot be changed unlike lists and tuples use parentheses,
whereas lists use square brackets.
For example:
tup1 = ();
To write a tuple containing a single value, you have to include a comma. Even though,
there is only one value.
tup1 = (50,);
Like string indices, tuple indices start at 0, and they can be sliced, concatenated, and so
on.
For example:
#!/usr/bin/python
tup1[0]: physics
tup2[1:5]: [2, 3, 4, 5]
17
Python Data Structures
Updating Tuples
Tuples are immutable, which means you cannot update or change the values of tuple
elements. You are able to take portions of existing tuples, to create new tuples as the
following example demonstrates:
#!/usr/bin/python
For example:
#!/usr/bin/python
Note: An exception raised, because after del tup, tuple does not exist anymore.
18
Python Data Structures
In fact, tuples respond to all of the general sequence operations, we used on strings in the
prior chapter.
19
6. Python Data Structures – Dictionary Python Data Structures
In Dictionary each key is separated from its value by a colon (:), the items are separated
by commas, and the whole thing is enclosed in curly braces. An empty dictionary without
any items is written with just two curly braces, like this: {}.
Keys are unique within a dictionary while values may not be. The values of a dictionary
can be of any type, but the keys must be of an immutable data type, such as strings,
numbers, or tuples.
#!/usr/bin/python
dict['Name']: Zara
dict['Age']: 7
If we attempt to access a data item with a key, which is not part of the dictionary, we get
an error as follows:
#!/usr/bin/python
dict['Alice']:
Traceback (most recent call last):
File "[Link]", line 4, in <module>
print "dict['Alice']: ", dict['Alice'];
KeyError: 'Alice'
20
Python Data Structures
Updating Dictionary
You can update a dictionary by adding a new entry or a key-value pair, modifying an
existing entry, or deleting an existing entry as shown below in the simple example:
#!/usr/bin/python
dict['Age']: 8
dict['School']: DPS School
To explicitly remove an entire dictionary, just use the del statement. A simple example is
as mentioned below:
#!/usr/bin/python
Note that an exception is raised, because after del dict dictionary does not exist
anymore.
dict['Age']:
Traceback (most recent call last):
21
Python Data Structures
More than one entry per key not allowed. Which means, no duplicate key is allowed.
When duplicate keys are encountered during assignment, the last assignment wins.
For example:
#!/usr/bin/python
dict['Name']: Manni
Keys must be immutable. Which means you can use strings, numbers or tuples as
dictionary keys, but something like ['key'] is not allowed.
An example is as follows:
#!/usr/bin/python
22
7. Python Data Structures – 2D Array Python Data Structures
Two dimensional array is an array within an array. It is an array of arrays. In this type of
array, the position of a data element is referred by two indices instead of one. So, it
represents a table with rows and columns of data.
In the below example of a two dimensional array, observe that each array element itself
is also an array.
Consider an example of recording temperatures four times a day, every day. Sometimes,
the recording instrument may be faulty and we fail to record data. Such data for four days
can be presented as a two dimensional array as below.
Day 1 - 11 12 5 2
Day 2 - 15 6 10
Day 3 - 10 8 12 5
Day 4 - 12 15 8 6
Accessing Values
The data elements in two dimensional arrays can be accessed using two indices. One index
referring to the main or parent array and another index referring to the position of the
data element in the inner array. If we mention only one index, then the entire inner array
is printed for that index position.
print(T[0])
print(T[1][2])
[11, 12, 5, 2]
10
23
Python Data Structures
To print out the entire two dimensional array, we can use python for loop as shown below.
We use end of line to print out the values in different rows.
11 12 5 2
15 6 10
10 8 12 5
12 15 8 6
Inserting Values
We can insert new data elements at specific position, by using the insert() method and
specifying the index.
[Link](2, [0,5,11,13,6])
for r in T:
for c in r:
print(c,end = " ")
print()
11 12 5 2
15 6 10
0 5 11 13 6
10 8 12 5
12 15 8 6
24
Python Data Structures
Updating Values
We can update the entire inner array or some specific data elements of the inner array,
by reassigning the values using the array index.
T[2] = [11,9]
T[0][3] = 7
for r in T:
for c in r:
print(c,end = " ")
print()
11 12 5 7
15 6 10
11 9
12 15 8 6
del T[3]
for r in T:
for c in r:
print(c,end = " ")
print()
11 12 5 2
25
Python Data Structures
15 6 10
10 8 12 5
26
8. Python Data Structures – Matrix Python Data Structures
Matrix is a special case of two dimensional array, where, each data element is of strictly
same size. So, every matrix is also a two dimensional array but not, vice versa.
Matrices are very important data structures for many mathematical and scientific
calculations. As we have already discussed, two dimensional array data structure in the
previous chapter, we will be focusing on data structure operations specific to matrices in
this chapter.
We will also use the numpy package for matrix data manipulation.
Matrix Example
Consider the case of recording temperature for one week measured in the morning, mid-
day, evening and mid-night. It can be presented as a 7X5 matrix, using an array and the
reshape method available in numpy.
m = reshape(a,(7,5))
print(m)
Accessing Values
The data elements in a matrix can be accessed by using the indexes. The access methods
are same, as the way data is accessed in two dimensional array.
27
Python Data Structures
m = array([['Mon',18,20,22,17],['Tue',11,18,21,18],
['Wed',15,21,20,19],['Thu',11,20,22,21],
['Fri',18,17,23,22],['Sat',12,22,20,18],
['Sun',13,15,19,16]])
Adding a row
Use the below mentioned code to add a row in a matrix.
m_r = append(m,[['Avg',12,15,13,11]],0)
print(m_r)
28
Python Data Structures
Adding a column
We can add column to a matrix using the insert() method. Here, we have to mention the
index, where we want to add the column and an array containing the new values of the
columns added. In the below example, we add to a new column at the fifth position from
the beginning.
m_c = insert(m,[5],[[1],[2],[3],[4],[5],[6],[7]],1)
print(m_c)
Delete a row
We can delete a row from a matrix by using the delete() method. We have to specify the
index of the row and also the axis value, which is 0 for a row and 1 for a column.
m = delete(m,[2],0)
print(m)
29
Python Data Structures
Delete a column
We can delete a column from a matrix using the delete() method. We have to specify the
index of the column and also the axis value, which is 0 for a row and 1 for a column.
m = delete(m,s_[2],1)
print(m)
Update a row
To update the values in the row of a matrix, we simply re-assign the values at the index
of the row. In the below example, all the values for Thursday’s data is marked as zero.
The index for this row is 3.
['Wed',15,21,20,19],['Thu',11,20,22,21],
['Fri',18,17,23,22],['Sat',12,22,20,18],
['Sun',13,15,19,16]])
m[3] = ['Thu',0,0,0,0]
print(m)
31
9. Python Data Structures – Sets Python Data Structures
Mathematically, a set is a collection of items not in any particular order. A Python set is
similar to this mathematical definition with below additional conditions.
Set Operations
The sets in python are typically used for mathematical operations like union, intersection,
difference and complement etc. We can create a set, access its elements and carry out
these mathematical operations as shown below.
Creating a set
A set is created by using the set() function or placing all the elements within a pair of curly
braces.
Days=set(["Mon","Tue","Wed","Thu","Fri","Sat","Sun"])
Months={"Jan","Feb","Mar"}
Dates={21,22,17}
print(Days)
print(Months)
print(Dates)
When the above code is executed, it produces the following result. Please note, how the
order of the elements has changed in the result.
Days=set(["Mon","Tue","Wed","Thu","Fri","Sat","Sun"])
32
Python Data Structures
for d in Days:
print(d)
Wed
Sun
Fri
Tue
Mon
Thu
Sat
Days=set(["Mon","Tue","Wed","Thu","Fri","Sat"])
[Link]("Sun")
print(Days)
Days=set(["Mon","Tue","Wed","Thu","Fri","Sat"])
[Link]("Sun")
print(Days)
33
Python Data Structures
Union of Sets
The union operation on two sets produces a new set containing all the distinct elements
from both the sets. In the below example, the element “Wed” is present in both the sets.
DaysA = set(["Mon","Tue","Wed"])
DaysB = set(["Wed","Thu","Fri","Sat","Sun"])
AllDays = DaysA|DaysB
print(AllDays)
When the above code is executed, it produces the following result. Please note the result
has only one “wed”.
Intersection of Sets
The intersection operation on two sets produces a new set containing only the common
elements from both the sets. In the below example, the element “Wed” is present in both
the sets.
DaysA = set(["Mon","Tue","Wed"])
DaysB = set(["Wed","Thu","Fri","Sat","Sun"])
AllDays = DaysA & DaysB
print(AllDays)
When the above code is executed, it produces the following result. Please note the result
has only one “wed”.
set(['Wed'])
Difference of Sets
The difference operation on two sets produces a new set containing only the elements
from the first set and none from the second set. In the below example, the element “Wed”
is present in both the sets so it will not be found in the result set.
DaysA = set(["Mon","Tue","Wed"])
DaysB = set(["Wed","Thu","Fri","Sat","Sun"])
AllDays = DaysA - DaysB
print(AllDays)
When the above code is executed, it produces the following result. Please note the result
has only one “wed”.
set(['Mon', 'Tue'])
34
Python Data Structures
Compare Sets
We can check, if a given set is a subset or superset of another set. The result is True or
False depending on the elements present in the sets.
DaysA = set(["Mon","Tue","Wed"])
DaysB = set(["Mon","Tue","Wed","Thu","Fri","Sat","Sun"])
SubsetRes = DaysA <= DaysB
SupersetRes = DaysB >= DaysA
print(SubsetRes)
print(SupersetRes)
True
True
35
10. Python Data Structures – Maps Python Data Structures
Python Maps also called ChainMap is a type of data structure to manage multiple
dictionaries together as one unit. The combined dictionary contains the key and value pairs
in a specific sequence eliminating any duplicate keys. The best use of ChainMap is to
search through multiple dictionaries at a time and get the proper key-value pair mapping.
We also see that these ChainMaps behave as stack data structure.
Creating a ChainMap
We create two dictionaries and club them using the ChainMap method from the collections
library. Then, we print the keys and values of the result of the combination of the
dictionaries. If there are duplicate keys, then only the value from the first key is preserved.
import collections
print('Keys = {}'.format(list([Link]())))
print('Values = {}'.format(list([Link]())))
print()
elements:
day1 = Mon
day3 = Wed
day2 = Tue
Map Reordering
If we change the order of the dictionaries while clubbing them in the above example, we
see that, the position of the elements get interchanged as if, they are in a continuous
chain. This again shows the behaviour of Maps as stacks.
import collections
print([Link],'\n')
print([Link],'\n')
37
Python Data Structures
Updating Map
When the element of the dictionary is updated, the result is instantly updated in the result
of the ChainMap. In the below example, we see that the new updated value reflects in the
result without explicitly applying the ChainMap method again.
import collections
print([Link],'\n')
dict2['day4'] = 'Fri'
print([Link],'\n')
38
11. Python Data Structures – Linked Lists Python Data Structures
A linked list is a sequence of data elements, which are connected together via links. Each
data element contains a connection to another data element in form of a pointer. Python
does not have linked lists in its standard library. We implement the concept of linked lists
using the concept of nodes as discussed in the previous chapter.
We have already seen, how we create a node class and how to traverse the elements of a
node. In this chapter, we are going to study the types of linked lists known as singly linked
lists. In this type of data structure, there is only one link between any two data elements.
We create such a list and create additional methods to insert, update and remove elements
from the list.
class Node:
def __init__(self, dataval=None):
[Link] = dataval
[Link] = None
class SLinkedList:
def __init__(self):
[Link] = None
list1 = SLinkedList()
[Link] = Node("Mon")
e2 = Node("Tue")
e3 = Node("Wed")
# Link first Node to second node
[Link] = e2
39
Python Data Structures
class Node:
def __init__(self, dataval=None):
[Link] = dataval
[Link] = None
class SLinkedList:
def __init__(self):
[Link] = None
def listprint(self):
printval = [Link]
while printval is not None:
print ([Link])
printval = [Link]
list = SLinkedList()
[Link] = Node("Mon")
e2 = Node("Tue")
e3 = Node("Wed")
[Link]()
Mon
Tue
Wed
40
Python Data Structures
class Node:
def __init__(self, dataval=None):
[Link] = dataval
[Link] = None
class SLinkedList:
def __init__(self):
[Link] = None
list = SLinkedList()
[Link] = Node("Mon")
e2 = Node("Tue")
e3 = Node("Wed")
41
Python Data Structures
[Link] = e2
[Link] = e3
[Link]("Sun")
[Link]()
Sun
Mon
Tue
Wed
class Node:
def __init__(self, dataval=None):
[Link] = dataval
[Link] = None
class SLinkedList:
def __init__(self):
[Link] = None
42
Python Data Structures
list = SLinkedList()
[Link] = Node("Mon")
e2 = Node("Tue")
e3 = Node("Wed")
[Link] = e2
[Link] = e3
[Link]("Thu")
[Link]()
Mon
Tue
Wed
Thu
class Node:
def __init__(self, dataval=None):
[Link] = dataval
[Link] = None
class SLinkedList:
43
Python Data Structures
def __init__(self):
[Link] = None
NewNode = Node(newdata)
[Link] = middle_node.nextval
middle_node.nextval = NewNode
list = SLinkedList()
[Link] = Node("Mon")
e2 = Node("Tue")
e3 = Node("Thu")
[Link] = e2
[Link] = e3
[Link]([Link],"Fri")
[Link]()
Mon
Tue
Fri
44
Python Data Structures
Thu
Removing an Item
We can remove an existing node using the key for that node. In the below program, we
locate the previous node of the node which is to be deleted. Then, point the next pointer
of this node to the next node of the node to be deleted.
class Node:
def __init__(self, data=None):
[Link] = data
[Link] = None
class SLinkedList:
def __init__(self):
[Link] = None
HeadVal = [Link]
45
Python Data Structures
if (HeadVal == None):
return
[Link] = [Link]
HeadVal = None
def LListprint(self):
printval = [Link]
while (printval):
print([Link]),
printval = [Link]
llist = SLinkedList()
[Link]("Mon")
[Link]("Tue")
[Link]("Wed")
[Link]("Thu")
[Link]("Tue")
[Link]()
Thu
Wed
Mon
46
12. Python Data Structures – Stack Python Data Structures
In the English dictionary, the word stack means arranging objects one over another. It is
the same way; memory is allocated in this data structure. It stores the data elements in
a similar fashion as a bunch of plates are stored one above another in the kitchen. So,
stack data structure allows operations at one end, which can be called top of the stack.
We can add elements or remove elements only form this end of the stack.
In a stack the element inserted last in sequence, will come out first as we can remove only
from the top of the stack. Such feature is known as Last in First Out(LIFO) feature. The
operations of adding and removing the elements is known as PUSH and POP. In the
following program, we implement it as add and remove functions. We declare an empty
list and use the append() and pop() methods, to add and remove the data elements.
class Stack:
def __init__(self):
[Link] = []
def peek(self):
return [Link][-1]
AStack = Stack()
[Link]("Mon")
[Link]("Tue")
[Link]()
47
Python Data Structures
print([Link]())
[Link]("Wed")
[Link]("Thu")
print([Link]())
Tue
Thu
class Stack:
def __init__(self):
[Link] = []
AStack = Stack()
[Link]("Mon")
[Link]("Tue")
48
Python Data Structures
[Link]("Wed")
[Link]("Thu")
print([Link]())
print([Link]())
Thu
Wed
49
13. Python Data Structures – Queue Python Data Structures
We are familiar with queue in our day to day life as we wait for a service. The queue data
structure also means the same, where the data elements are arranged in a queue. The
uniqueness of queue lies in the way items are added and removed. The items are allowed
at on end, but removed from the other end. So, it is a First-in-First out method.
A queue can be implemented using python list, where we can use the insert() and pop()
methods to add and remove elements. There is no insertion as data elements are always
added at the end of the queue.
Adding Elements
In the below example, we create a queue class, where we implement the First-in-First-Out
method. We use the in-built insert method for adding data elements.
class Queue:
def __init__(self):
[Link] = list()
def addtoq(self,dataval):
# Insert method to add element
if dataval not in [Link]:
[Link](0,dataval)
return True
return False
def size(self):
return len([Link])
TheQueue = Queue()
[Link]("Mon")
[Link]("Tue")
[Link]("Wed")
print([Link]())
50
Python Data Structures
Removing Element
In the below example, we create a queue class, where we insert the data and then remove
the data using the in-built pop method.
class Queue:
def __init__(self):
[Link] = list()
def addtoq(self,dataval):
# Insert method to add element
if dataval not in [Link]:
[Link](0,dataval)
return True
return False
# Pop method to remove element
def removefromq(self):
if len([Link])>0:
return [Link]()
return ("No elements in Queue!")
TheQueue = Queue()
[Link]("Mon")
[Link]("Tue")
[Link]("Wed")
print([Link]())
print([Link]())
Mon
Tue
51
14. Python Data Structures – Dequeue Python Data Structures
A double-ended queue, or deque, supports adding and removing elements from either
end. The more commonly used stacks and queues are degenerate forms of deques, where
the inputs and outputs are restricted to a single end.
import collections
DoubleEnded = [Link](["Mon","Tue","Wed"])
[Link]("Thu")
[Link]("Sun")
[Link]()
[Link]()
52
Python Data Structures
53
15. Python Data Structutres – Advanced Linked Python Data Structures
List
We have already seen Linked List in earlier chapter, in which it is possible only to travel
forward. In this chapter we see another type of linked list in which it is possible to travel
both forward and backward. Such a linked list is called Doubly Linked List. Following is the
features of doubly linked list.
Doubly Linked List contains a link element called first and last.
Each link carries a data field(s) and two link fields called next and prev.
Each link is linked with its next link using its next link.
Each link is linked with its previous link using its previous link.
The last link carries a link as null to mark the end of the list.
class Node:
def __init__(self, data):
[Link] = data
[Link] = None
[Link] = None
class doubly_linked_list:
def __init__(self):
[Link] = None
54
Python Data Structures
dllist = doubly_linked_list()
[Link](12)
[Link](8)
[Link](62)
[Link]([Link])
62 8 12
def __init__(self):
[Link] = None
55
Python Data Structures
NewNode = Node(NewVal)
[Link] = [Link]
if [Link] is not None:
[Link] = NewNode
[Link] = NewNode
dllist = doubly_linked_list()
[Link](12)
[Link](8)
[Link](62)
[Link]([Link], 13)
[Link]([Link])
62 8 13 12
56
Python Data Structures
def __init__(self):
[Link] = None
NewNode = Node(NewVal)
[Link] = None
if [Link] is None:
[Link] = None
[Link] = NewNode
return
last = [Link]
while ([Link] is not None):
last = [Link]
[Link] = NewNode
[Link] = last
return
dllist = doubly_linked_list()
[Link](12)
[Link](9)
[Link](8)
[Link](62)
[Link](45)
[Link]([Link])
62 8 12 9 45
Please note the position of the elements 9 and 45 for the append operation.
58
16. Python Data Structures – Hash Table Python Data Structures
Hash tables are a type of data structure, in which the address or the index value of the
data element is generated from a hash function. That makes accessing the data faster, as
the index value behaves as a key for the data value. In other words, Hash table stores
key-value pairs but the key is generated through a hashing function.
So, the search and insertion function of a data element becomes much faster as the key
values themselves become the index of the array which stores the data.
In Python, the Dictionary data types represent the implementation of hash tables. The
Keys in the dictionary satisfy the following requirements.
The keys of the dictionary are hashable, i.e. they are generated by hashing
function, which generates unique result for each unique value supplied to the hash
function.
The order of data elements in a dictionary is not fixed.
So, we see the implementation of hash table by using the dictionary data types as below.
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Name']: Zara
dict['Age']: 7
Updating Dictionary
You can update a dictionary by adding a new entry or a key-value pair, modifying an
existing entry, or deleting an existing entry as shown below in the simple example:
# Declare a dictionary
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
59
Python Data Structures
dict['Age']: 8
dict['School']: DPS School
This produces the following result. Note, that an exception is raised because after del dict
dictionary does not exist anymore.
dict['Age']:
Traceback (most recent call last):
File "[Link]", line 8, in
print "dict['Age']: ", dict['Age'];
TypeError: 'type' object is unsubscriptable
60
17. Python Data Structures – Binary Tree Python Data Structures
Tree represents the nodes connected by edges. It is a non-linear data structure. It has the
following properties:
We create a tree data structure in python by using the concept of node discussed earlier.
We designate one node as root node and then add more nodes as child nodes. Below is
program to create the root node.
Create Root
We just create a Node class and add assign a value to the node. This becomes tree with
only a root node.
class Node:
[Link] = None
[Link] = None
[Link] = data
def PrintTree(self):
print([Link])
root = Node(10)
[Link]()
10
61
Python Data Structures
class Node:
[Link] = None
[Link] = None
[Link] = data
root = Node(12)
[Link](6)
[Link](14)
[Link](3)
[Link]()
3 6 12 14
Traversing a Tree
The tree can be traversed by deciding on a sequence to visit each node. As we can clearly
see we can start at a node then visit the left sub-tree first and right sub-tree next. Or we
can also visit the right sub-tree first and left sub-tree next. Accordingly, there are different
names for these tree traversal methods.
In-order Traversal
Pre-order Traversal
Post-order Traversal
In-order Traversal
In this traversal method, the left subtree is visited first, then the root and later the right
sub-tree. We should always remember that every node may represent a subtree itself.
In the below python program, we use the Node class to create place holders for the root
node as well as the left and right nodes. Then, we create an insert function to add data to
the tree. Finally, the In-order traversal logic is implemented by creating an empty list and
adding the left node first followed by the root or parent node.
At last the left node is added to complete the In-order traversal. Please note that this
process is repeated for each sub-tree until all the nodes are traversed.
class Node:
[Link] = None
63
Python Data Structures
[Link] = None
[Link] = data
# Insert Node
def insert(self, data):
if [Link]:
if data < [Link]:
if [Link] is None:
[Link] = Node(data)
else:
[Link](data)
elif data > [Link]:
if [Link] is None:
[Link] = Node(data)
else:
[Link](data)
else:
[Link] = data
# Inorder traversal
# Left -> Root -> Right
def inorderTraversal(self, root):
res = []
if root:
res = [Link]([Link])
[Link]([Link])
res = res + [Link]([Link])
return res
64
Python Data Structures
root = Node(27)
[Link](14)
[Link](35)
[Link](10)
[Link](19)
[Link](31)
[Link](42)
print([Link](root))
Pre-order Traversal
In this traversal method, the root node is visited first, then the left subtree and finally the
right subtree.
In the below python program, we use the Node class to create place holders for the root
node as well as the left and right nodes. Then, we create an insert function to add data to
the tree. Finally, the Pre-order traversal logic is implemented by creating an empty list
and adding the root node first followed by the left node.
At last, the right node is added to complete the Pre-order traversal. Please note that, this
process is repeated for each sub-tree until all the nodes are traversed.
class Node:
[Link] = None
[Link] = None
[Link] = data
# Insert Node
def insert(self, data):
if [Link]:
if data < [Link]:
if [Link] is None:
[Link] = Node(data)
else:
[Link](data)
65
Python Data Structures
# Preorder traversal
# Root -> Left ->Right
def PreorderTraversal(self, root):
res = []
if root:
[Link]([Link])
res = res + [Link]([Link])
res = res + [Link]([Link])
return res
root = Node(27)
[Link](14)
[Link](35)
[Link](10)
[Link](19)
[Link](31)
[Link](42)
print([Link](root))
66
Python Data Structures
Post-order Traversal
In this traversal method, the root node is visited last, hence the name. First, we traverse
the left subtree, then the right subtree and finally the root node.
In the below python program, we use the Node class to create place holders for the root
node as well as the left and right nodes. Then, we create an insert function to add data to
the tree. Finally, the Post-order traversal logic is implemented by creating an empty list
and adding the left node first followed by the right node.
At last the root or parent node is added to complete the Post-order traversal. Please note
that, this process is repeated for each sub-tree until all the nodes are traversed.
class Node:
[Link] = None
[Link] = None
[Link] = data
# Insert Node
def insert(self, data):
if [Link]:
if data < [Link]:
if [Link] is None:
[Link] = Node(data)
else:
[Link](data)
elif data > [Link]:
if [Link] is None:
[Link] = Node(data)
else:
[Link](data)
else:
[Link] = data
67
Python Data Structures
def PrintTree(self):
if [Link]:
[Link]()
print( [Link]),
if [Link]:
[Link]()
# Postorder traversal
# Left ->Right -> Root
def PostorderTraversal(self, root):
res = []
if root:
res = [Link]([Link])
res = res + [Link]([Link])
[Link]([Link])
return res
root = Node(27)
[Link](14)
[Link](35)
[Link](10)
[Link](19)
[Link](31)
[Link](42)
print([Link](root))
68
18. Python Data Structures – Search Tree Python Data Structures
A Binary Search Tree (BST) is a tree, in which all the nodes follow the below-mentioned
properties. The left sub-tree of a node has a key less than or equal to its parent node's
key. The right sub-tree of a node has a key greater than to its parent node's key. Thus,
BST divides all its sub-trees into two segments; the left sub-tree and the right sub-tree.
class Node:
[Link] = None
[Link] = None
[Link] = data
if [Link]:
if data < [Link]:
if [Link] is None:
[Link] = Node(data)
else:
[Link](data)
elif data > [Link]:
if [Link] is None:
[Link] = Node(data)
else:
[Link](data)
69
Python Data Structures
else:
[Link] = data
# findval method to compare the value with nodes
def findval(self, lkpval):
if lkpval < [Link]:
if [Link] is None:
return str(lkpval)+" Not Found"
return [Link](lkpval)
elif lkpval > [Link]:
if [Link] is None:
return str(lkpval)+" Not Found"
return [Link](lkpval)
else:
print(str([Link]) + ' is found')
# Print the tree
def PrintTree(self):
if [Link]:
[Link]()
print( [Link]),
if [Link]:
[Link]()
root = Node(12)
[Link](6)
[Link](14)
[Link](3)
print([Link](7))
print([Link](14))
7 Not Found
14 is found
70
19. Python Data Structures – Heaps Python Data Structures
Heap is a special tree structure in which each parent node is less than or equal to its child
node. Then, it is called a Min Heap. If each parent node is greater than or equal to its child
node, then it is called a max heap. It is very useful is implementing priority queues, where
the queue item with higher weightage is given more priority in processing.
A detailed discussion on heaps is available in our website here. Please study it first, if you
are new to head data structure. In this chapter, we will see the implementation of heap
data structure using python.
Create a Heap
A heap is created by using python’s inbuilt library named heapq. This library has the
relevant functions to carry out various operations on heap data structure. Below, is a list
of these functions.
heapify - This function converts a regular list to a heap. In the resulting heap the
smallest element gets pushed to the index position 0. But rest of the data elements
are not necessarily sorted.
heappush – This function adds an element to the heap without altering the current
heap.
heappop - This function returns the smallest data element from the heap.
heapreplace – This function replaces the smallest data element with a new value
supplied in the function.
Creating a Heap
A heap is created by simply using a list of elements with the heapify function. In the below
example, we supply a list of elements and the heapify function rearranges the elements
bringing the smallest element to the first position.
import heapq
H = [21,1,45,78,3,5]
# Use heapify to rearrange the elements
[Link](H)
print(H)
71
Python Data Structures
import heapq
H = [21,1,45,78,3,5]
# Covert to a heap
[Link](H)
print(H)
# Add element
[Link](H,8)
print(H)
import heapq
H = [21,1,45,78,3,5]
# Create the heap
[Link](H)
print(H)
print(H)
72
Python Data Structures
Replacing in a Heap
The heapreplace function always removes the smallest element of the heap and inserts
the new incoming element at some place not fixed by any order.
import heapq
H = [21,1,45,78,3,5]
# Create the heap
[Link](H)
print(H)
# Replace an element
[Link](H,6)
print(H)
[1, 3, 5, 78, 21, 45]
[3, 6, 5, 78, 21, 45]
73
20. Python Data Structures – Graphs Python Data Structures
A graph is a pictorial representation of a set of objects where some pairs of objects are
connected by links. The interconnected objects are represented by points termed as
vertices, and the links that connect the vertices are called edges. The various terms and
functionalities associated with a graph is described in great detail in our tutorial here.
In this chapter, we are going to see how to create a graph and add various data elements
to it using a python program. Following are the basic operations we perform on graphs.
A graph can be easily presented using the python dictionary data types. We represent the
vertices as the keys of the dictionary and the connection between the vertices also called
edges as the values in the dictionary.
V = {a, b, c, d, e}
E = {ab, ac, bd, cd, de}
{'c': ['a', 'd'], 'a': ['b', 'c'], 'e': ['d'], 'd': ['e'], 'b': ['a', 'd']}
class graph:
def __init__(self,gdict=None):
if gdict is None:
gdict = []
[Link] = gdict
g = graph(graph_elements)
print([Link]())
75
Python Data Structures
class graph:
def __init__(self,gdict=None):
if gdict is None:
gdict = {}
[Link] = gdict
def edges(self):
return [Link]()
# Find the distinct list of edges
def findedges(self):
edgename = []
for vrtx in [Link]:
for nxtvrtx in [Link][vrtx]:
if {nxtvrtx, vrtx} not in edgename:
[Link]({vrtx, nxtvrtx})
return edgename
g = graph(graph_elements)
print([Link]())
76
Python Data Structures
[{'b', 'a'}, {'b', 'd'}, {'e', 'd'}, {'a', 'c'}, {'c', 'd'}]
Adding a vertex
Adding a vertex is straight forward, where we add another additional key to the graph
dictionary.
class graph:
def __init__(self,gdict=None):
if gdict is None:
gdict = {}
[Link] = gdict
def getVertices(self):
return list([Link]())
g = graph(graph_elements)
[Link]("f")
print([Link]())
77
Python Data Structures
Adding an edge
Adding an edge to an existing graph involves treating the new vertex as a tuple and
validating if the edge is already present. If not, then the edge is added.
class graph:
def __init__(self,gdict=None):
if gdict is None:
gdict = {}
[Link] = gdict
def edges(self):
return [Link]()
# Add the new edge
78
Python Data Structures
"e" : ["d"]
}
g = graph(graph_elements)
[Link]({'a','e'})
[Link]({'a','c'})
print([Link]())
[{'e', 'd'}, {'b', 'a'}, {'b', 'd'}, {'a', 'c'}, {'a', 'e'}, {'c', 'd'}]
79
21. Python Data Structures – Algorithm Design Python Data Structures
From the data structure point of view, following are some important categories of
algorithms:
Characteristics of an Algorithm
Not all procedures can be called an algorithm. An algorithm should have the following
characteristics:
As we know that all programming languages share basic code constructs like loops (do,
for, while), flow-control (if-else), etc. These common constructs can be used to write an
algorithm.
80
Python Data Structures
We write algorithms in a step-by-step manner, but it is not always the case. Algorithm
writing is a process and is executed after the problem domain is well-defined. That is, we
should know the problem domain, for which we are designing a solution.
Example
Let's try to learn algorithm-writing by using an example.
Problem − Design an algorithm to add two numbers and display the result.
step 1 − START
step 6 − print c
step 7 − STOP
Algorithms tell the programmers how to code the program. Alternatively, the algorithm
can be written as:
step 3 − c ← a + b
step 4 − display c
step 5 − STOP
In design and analysis of algorithms, usually the second method is used to describe an
algorithm. It makes it easy for the analyst to analyse the algorithm ignoring all unwanted
definitions. He can observe what operations are being used and how the process is flowing.
81
Python Data Structures
Hence, many solution algorithms can be derived for a given problem. The next step is to
analyse those proposed solution algorithms and implement the best suitable solution.
82
22. Python Data Structures – Divide and Conquer Python Data Structures
In divide and conquer approach, the problem in hand, is divided into smaller sub-problems
and then each problem is solved independently. When, we keep on dividing the sub
problems into even smaller sub-problems, we may eventually reach a stage where no
more division is possible. Those "atomic" smallest possible sub-problem (fractions) are
solved. The solution of all sub-problems is finally merged in order to obtain the solution of
an original problem.
Divide/Break
This step involves breaking the problem into smaller sub-problems. Sub-problems should
represent a part of the original problem. This step generally takes a recursive approach to
divide the problem until no sub-problem is further divisible. At this stage, sub-problems
become atomic in nature but still represent some part of the actual problem.
Conquer/Solve
This step receives a lot of smaller sub-problems to be solved. Generally, at this level, the
problems are considered 'solved' on their own.
Merge/Combine
When the smaller sub-problems are solved, this stage recursively combines them until
they formulate a solution of the original problem. This algorithmic approach works
recursively and conquer & merge steps works so close that they appear as one.
83
Python Data Structures
Examples
The following program is an example of divide-and-conquer programming approach
where the binary search is implemented using python.
This is possible as the list is sorted and it is much quicker than linear search. Here, we
divide the given list and conquer by choosing the proper half of the list. We repeat this
approach till we find the element or conclude about its absence in the list.
list_size = len(list) - 1
idx0 = 0
idxn = list_size
# Find the middle most value
if list[midval] == val:
return midval
# Compare the value the middle most value
if val > list[midval]:
idx0 = midval + 1
else:
idxn = midval - 1
print(bsearch(list,72))
print(bsearch(list,11))
5
None
85
23. Python Data Structures – Recursion Python Data Structures
Recursion allows a function to call itself. Fixed steps of code get executed again and again
for new values. We also have to set criteria for deciding when the recursive call ends. In
the below example we see a recursive approach to the binary search. We take a sorted
list and give its index range as input to the recursive function.
list = [8,11,24,56,88,131]
print(bsearch(list, 0, 5, 24))
print(bsearch(list, 0, 5, 51))
2
None
86
24. Python Data Structures – Backtracking Python Data Structures
Backtracking is a form of recursion. But, it involves choosing only option out of any
possibilities. We begin by choosing an option and backtrack from it, if we reach a state
where we conclude that this specific option does not give the required solution. We repeat
these steps by going across each available option until we get the desired solution.
Below is an example of finding all possible order of arrangements of a given set of letters.
When we choose a pair we apply backtracking to verify if that exact pair has already been
created or not. If not already created, the pair is added to the answer list else it is ignored.
print(permute(1, ["a","b","c"]))
print(permute(2, ["a","b","c"]))
87
25. Python Data Structures – Sorting Algorithms Python Data Structures
Sorting refers to arranging data in a particular format. Sorting algorithm specifies the way
to arrange data in a particular order. Most common orders are in numerical or
lexicographical order.
The importance of sorting lies in the fact that data searching can be optimized to a very
high level, if data is stored in a sorted manner. Sorting is also used to represent data in
more readable formats. Below we see five such implementations of sorting in python.
Bubble Sort
Merge Sort
Insertion Sort
Shell Sort
Selection Sort
Bubble Sort
It is a comparison-based algorithm in which each pair of adjacent elements is compared
and the elements are swapped if they are not in order.
def bubblesort(list):
list = [19,2,31,45,6,11,121,27]
bubblesort(list)
print(list)
88
Python Data Structures
Merge Sort
Merge sort first divides the array into equal halves and then combines them in a sorted
manner.
def merge_sort(unsorted_list):
if len(unsorted_list) <= 1:
return unsorted_list
# Find the middle point and devide it
middle = len(unsorted_list) // 2
left_list = unsorted_list[:middle]
right_list = unsorted_list[middle:]
left_list = merge_sort(left_list)
right_list = merge_sort(right_list)
return list(merge(left_list, right_list))
def merge(left_half,right_half):
res = []
while len(left_half) != 0 and len(right_half) != 0:
if left_half[0] < right_half[0]:
[Link](left_half[0])
left_half.remove(left_half[0])
else:
[Link](right_half[0])
right_half.remove(right_half[0])
if len(left_half) == 0:
res = res + right_half
else:
res = res + left_half
return res
print(merge_sort(unsorted_list))
89
Python Data Structures
Insertion Sort
Insertion sort involves finding the right place for a given element in a sorted list. So in
beginning we compare the first two elements and sort them by comparing them. Then, we
pick the third element and find its proper position among the previous two sorted
elements. This way, we gradually go on adding more elements to the already sorted list
by putting them in their proper position.
def insertion_sort(InputList):
for i in range(1, len(InputList)):
j = i-1
nxt_element = InputList[i]
# Compare the current element with next one
list = [19,2,31,45,30,11,121,27]
insertion_sort(list)
print(list)
Shell Sort
Shell Sort involves sorting elements, which are away from each other. We sort a large
sublist of a given list and go on reducing the size of the list until all elements are sorted.
The below program finds the gap by equating it to half of the length of the list size and
then starts sorting all elements in it. Then, we keep resetting the gap until the entire list
is sorted.
def shellSort(input_list):
gap = len(input_list) // 2
while gap > 0:
90
Python Data Structures
gap = gap//2
list = [19,2,31,45,30,11,121,27]
shellSort(list)
print(list)
Selection Sort
In selection sort we start by finding the minimum value in a given list and move it to a
sorted list. Then, we repeat the process for each of the remaining elements in the unsorted
list. The next element entering the sorted list is compared with the existing elements and
placed at its correct position. So, at the end all the elements from the unsorted list are
sorted.
def selection_sort(input_list):
min_idx = idx
for j in range( idx +1, len(input_list)):
if input_list[min_idx] > input_list[j]:
min_idx = j
91
Python Data Structures
l = [19,2,31,45,30,11,121,27]
selection_sort(l)
print(l)
92
26. Python Data Structures – Searching Python Data Structures
Algorithms
Searching is a very basic necessity when you store data in different data structures. The
simplest approach is to go across every element in the data structure and match it with
the value you are searching for. This is known as Linear search. It is inefficient and rarely
used, but creating a program for it gives an idea about how we can implement some
advanced search algorithms.
Linear Search
In this type of search, a sequential search is made over all items one by one. Every item
is checked and if a match is found then that particular item is returned, otherwise the
search continues till the end of the data structure.
return search_res
True
False
Interpolation Search
This search algorithm works on the probing position of the required value. For this
algorithm to work properly, the data collection should be in a sorted form and equally
distributed. Initially, the probe position is the position of the middle most item of the
93
Python Data Structures
collection. If a match occurs, then the index of the item is returned. If the middle item is
greater than the item, then the probe position is again calculated in the sub-array to the
right of the middle item. Otherwise, the item is searched in the subarray to the left of the
middle item. This process continues on the sub-array as well until the size of subarray
reduces to zero.
There is a specific formula to calculate the middle position, which is indicated in the
program below:
def intpolsearch(values,x ):
idx0 = 0
idxn = (len(values) - 1)
while idx0 <= idxn and x >= values[idx0] and x <= values[idxn]:
if values[mid] < x:
idx0 = mid + 1
return "Searched element not in the list"
Found 2 at index 0
94
27. Python Data Structures – Graph Algorithms Python Data Structures
Graphs are very useful data structures in solving many important mathematical
challenges. For example, computer network topology or analysing molecular structures of
chemical compounds. They are also used in city traffic or route planning and even in human
languages and their grammar. All these applications have a common challenge of
traversing the graph using their edges and ensuring that all nodes of the graphs are
visited. There are two common established methods to do this traversal which is described
below.
class graph:
def __init__(self,gdict=None):
if gdict is None:
gdict = {}
[Link] = gdict
# Check for the visisted and unvisited nodes
def dfs(graph, start, visited = None):
if visited is None:
visited = set()
[Link](start)
print(start)
for next in graph[start] - visited:
dfs(graph, next, visited)
return visited
95
Python Data Structures
dfs(gdict, 'a')
a b d e c
We implement BFS for a graph in python using queue data structure discussed earlier.
When we keep visiting the adjacent unvisited nodes and keep adding it to the queue. Then
we start deque only the node which is left with no unvisited nodes. We stop the program
when there is no next adjacent node to be visited.
import collections
class graph:
def __init__(self,gdict=None):
if gdict is None:
gdict = {}
[Link] = gdict
def marked(n):
print(n)
96
Python Data Structures
bfs(gdict, "a")
a c b d e
97
28. Python Data Structures – Algorithm Analysis Python Data Structures
Algorithm Complexity
Suppose X is an algorithm and n is the size of input data, the time and space used by the
algorithm X are the two main factors, which decide the efficiency of X.
Time Factor − Time is measured by counting the number of key operations such
as comparisons in the sorting algorithm.
Space Factor − Space is measured by counting the maximum memory space
required by the algorithm.
The complexity of an algorithm f(n) gives the running time and/or the storage space
required by the algorithm in terms of n as the size of input data.
Space Complexity
Space complexity of an algorithm represents the amount of memory space required by
the algorithm in its life cycle. The space required by an algorithm is equal to the sum of
the following two components:
A fixed part that is a space required to store certain data and variables, that are
independent of the size of the problem. For example, simple variables and
constants used, program size, etc.
A variable part is a space required by variables, whose size depends on the size of
the problem. For example, dynamic memory allocation, recursion stack space, etc.
Space complexity S(P) of any algorithm P is S(P) = C + SP(I), where C is the fixed part
and S(I) is the variable part of the algorithm, which depends on instance characteristic I.
Following is a simple example that tries to explain the concept −
Algorithm: SUM(A, B)
98
Python Data Structures
Step 1 - START
Step 2 - C ← A + B + 10
Step 3 - Stop
Here, we have three variables A, B, and C and one constant. Hence S(P) = 1 + 3. Now,
space depends on data types of given variables and constant types and it will be multiplied
accordingly.
Time Complexity
Time complexity of an algorithm represents the amount of time required by the algorithm
to run to completion. Time requirements can be defined as a numerical function T(n),
where T(n) can be measured as the number of steps, provided each step consumes
constant time.
For example, addition of two n-bit integers takes n steps. Consequently, the total
computational time is T(n) = c ∗ n, where c is the time taken for the addition of two bits.
Here, we observe that T(n) grows linearly as the input size increases.
99
29. Python Data Structures – Algorithm Types Python Data Structures
The efficiency and accuracy of algorithms have to be analysed to compare them and
choose a specific algorithm for certain scenarios. The process of making this analysis is
called Asymptotic analysis. It refers to computing the running time of any operation in
mathematical units of computation.
For example, the running time of one operation is computed as f(n) and may be for another
operation it is computed as g(n2). This means the first operation running time will increase
linearly with the increase in n and the running time of the second operation will increase
exponentially when n increases. Similarly, the running time of both operations will be
nearly the same if n is significantly small.
Asymptotic Notations
The commonly used asymptotic notations to calculate the running time complexity of an
algorithm are as follows:
Ο Notation
Ω Notation
θ Notation
Big Oh Notation, Ο
The notation Ο(n) is the formal way to express the upper bound of an algorithm's running
time. It measures the worst case time complexity or the longest amount of time an
algorithm can possibly take to complete.
Ο(f(n)) = { g(n) : there exists c > 0 and n 0 such that f(n) ≤ c.g(n) for all n
> n0. }
Omega Notation, Ω
The notation Ω(n) is the formal way to express the lower bound of an algorithm's running
time. It measures the best case time complexity or the best amount of time an algorithm
can possibly take to complete.
Ω(f(n)) ≥ { g(n) : there exists c > 0 and n 0 such that g(n) ≤ c.f(n) for all n
> n0. }
Theta Notation, θ
The notation θ(n) is the formal way to express both the lower bound and the upper bound
of an algorithm's running time. It is represented as follows:
θ(f(n)) = { g(n) if and only if g(n) = Ο(f(n)) and g(n) = Ω(f(n)) for all n >
n0. }
101
Python Data Structures
constant − Ο(1)
logarithmic − Ο(log n)
linear − Ο(n)
quadratic − Ο(n2)
cubic − Ο(n3)
polynomial − nΟ(1)
exponential − 2Ο(n)
102
30. Python Data Structures – Algorithm Classes Python Data Structures
Greedy Algorithms
Greedy algorithms try to find a localized optimum solution, which may eventually lead to
globally optimized solutions. However, generally greedy algorithms do not provide globally
optimized solutions.
So greedy algorithms look for an easy solution at that point in time without considering
how it impacts the future steps. It is similar to how; humans solve problems without going
through the complete details of the inputs provided.
Most networking algorithms use the greedy approach. Here, is a list of few of them:
Merge Sort
Quick Sort
Kruskal's Minimal Spanning Tree Algorithm
Binary Search
Dynamic Programming
Dynamic programming involves dividing the bigger problem into smaller ones but, unlike
divide and conquer it does not involve solving each sub-problem independently. Rather
the results of smaller sub-problems are remembered and used for similar or overlapping
sub-problems.
Mostly, these algorithms are used for optimization. Before solving the in-hand sub-
problem, dynamic algorithm will try to examine the results of the previously solved sub-
103
Python Data Structures
problems. Dynamic algorithms are motivated for an overall optimization of the problem
and not the local optimization.
104
31. Python Data Structures – Amortized Analysis Python Data Structures
Amortized analysis involves estimating the run time for the sequence of operations in a
program without taking into consideration the span of the data distribution in the input
values. A simple example is finding a value in a sorted list is quicker than in an unsorted
list.
If the list is already sorted, it does not matter how distributed the data is. But of course,
the length of the list has an impact as it decides the number of steps the algorithm has to
go through to get the final result.
So, we see that, if the initial cost of a single step of obtaining a sorted list is high, then
the cost of subsequent steps of finding an element becomes considerably low. So
Amortized analysis helps us find a bound on the worst-case running time for a sequence
of operations. There are three approaches to amortized analysis.
In the reverse scenario, it will be negative credit. To keep track of these accumulated
credits, we use a stack or tree data structure. The operations which are carried out
early (like sorting the list) have high amortized cost but the operations that are late in
sequence have lower amortized cost as the accumulated credit is utilized. So the
amortized cost is an upper bound of actual cost.
Potential Method − In this method the saved credit is utilized for future
operations as mathematical function of the state of the data structure. The
evaluation of the mathematical function and the amortized cost should be equal.
So when the actual cost is greater than amortized cost there is a decrease in
potential and it is used utilized for future operations which are expensive.
Aggregate analysis − In this method, we estimate the upper bound on the total
cost of n steps. The amortized cost is a simple division of total cost and the number
of steps (n).
105
32. Python Data Structures – Algorithm Python Data Structures
Justification
In order to make claims about an Algorithm being efficient, we need some mathematical
tools as proof. These tools help us on providing a mathematically satisfying explanation
on the performance and accuracy of the algorithms. Below, is a list of some of those
mathematical tools which can be used for justifying one algorithm over another.
Direct Proof
It is direct verification of the statement by using the direct calculations. For example, sum
of two even numbers is always an even number. In this case just add the two numbers
you are investigating and verify the result as even.
Proof by induction
Here, we start with a specific instance of a truth and then generalize it to all possible
values which are part of the truth. The approach is to take a case of verified truth, then
prove it is also true for the next case for the same given condition. For example, all positive
numbers of the form 2n-1 are odd. We prove it for a certain value of n, then prove it for
the next value of n. This establishes the statement as generally true by proof of induction.
Proof by contraposition
This proof is based on the condition, If Not A implies Not B, then, A implies B. A simple
example is, if square of n is even, then n must be even. Because, if square on n is not
even, then n is not even.
Proof by exhaustion
This is similar to direct proof, but it is established by visiting each case separately and
proving each of them. An example of such proof is the four colour theorem.
106