Top 5 Books every newbie coder must read

In this article, we would be making a list of 5 must-read books for every newbie coder.

**Introduction to Algorithms (Eastern Economy Edition) (Cormen)**

This is a very renowned book and highly values book, often considered as a bible for data structures and algorithms and hence a must read.

This internationally acclaimed textbook provides a comprehensive introduction to the modern study of computer algorithms. It covers a broad range of algorithms in depth, yet makes their design and analysis accessible to all levels of readers. Each chapter is relatively self-contained and presents an algorithm, a design technique, an application area, or a related topic. The algorithms are described and designed in a manner to be readable by anyone who has done a little programming. The explanations have been kept elementary without sacrificing depth of coverage or mathematical rigor.

Buy Here: Buy From Amazon

**Data Structures and Algorithms Made Easy: Data Structures and Algorithmic Puzzles [Narasimha Karumanchi ]**

Narasimha Karumanchi is the founder of CareerMonk Publications and author of few books on data structures, algorithms, and design patterns. He was a software developer who has been both interviewer and interviewee over his long career. Most recently he worked for Amazon Corporation, IBM Software Labs, Mentor Graphics, and Microsoft. Narasimha holds an M.Tech. in computer science from IIT, Bombay, and B.Tech. from JNT University. He authored the following books which got translated to international languages: Chinese, Japanese, Korea and Taiwan. Also, around 58 international universities were using these books as reference for academic courses.

Buy Here: Buy From Amazon

**Data Structures Using C**

This second edition of Data Structures Using C has been developed to provide comprehensive and consistent coverage of both the abstract concepts of data structures as well as the implementation of these concepts using C language. It begins with a thorough overview of the concepts of C programming followed by the introduction of different data structures and methods to analyze the complexity of different algorithms. It then connects these concepts and applies them to the study of various data structures such as arrays, strings, linked lists, stacks, queues, trees, heaps, and graphs.

The book utilizes a systematic approach wherein the design of each of the data structures is followed by algorithms of different operations that can be performed on them, and the analysis of these algorithms in terms of their running times.

Each chapter includes a variety of end-chapter exercises in the form of MCQs with answers, review questions, and programming exercises to help readers test their knowledge.

Buy Here: Buy From Amazon

**Data Structures and Algorithms Made Easy in Java: Data Structure and Algorithmic Puzzles**

A handy guide of sorts for any computer science professional, Data Structures and Algorithms Made Easy in Java: Data Structure And Algorithmic Puzzles is a solution bank for various complex problems related to data structures and algorithms. It can be used as a reference manual by those readers in the computer science industry.

The book has around 21 chapters and covers Recursion and Backtracking, Linked Lists, Stacks, Queues, Trees, Priority Queue and Heaps, Disjoint Sets ADT, Graph Algorithms, Sorting, Searching, Selection Algorithms [Medians], Symbol Tables, Hashing, String Algorithms, Algorithms Design Techniques, Greedy Algorithms, Divide and Conquer Algorithms, Dynamic Programming, Complexity Classes, and other Miscellaneous Concepts.

Data Structures And Algorithms Made Easy in Java: Data Structure And Algorithmic Puzzles by Narasimha Karumanchi was published in 2011, and it is coded in Java language. This book serves as guide to prepare for interviews, exams, and campus work. It is also available in C/C++. In short, this book offers solutions to various complex data structures and algorithmic problems.

Buy Here: Buy From Amazon

**Data Structure and Algorithmic Thinking with Python**

Table of Contents: goo.gl/VLEUca

Sample Chapter: goo.gl/8AEcYk

Source Code: goo.gl/L8Xxdt

Errata: goo.gl/EVftls

Found issue? goo.gl/forms/uLXGYpyuzX

The sample chapter should give you a very good idea of the quality and style of our book. In particular, be sure you are comfortable with the level and with our Python coding style. This book focuses on giving solutions for complex problems in data structures and algorithm. It even provides multiple solutions for a single problem, thus familiarizing readers with different possible approaches to the same problem.

"Data Structure and Algorithmic Thinking with Python" is designed to give a jump-start to programmers, job hunters and those who are appearing for exams. All the code in this book are written in Python. It contains many programming puzzles that not only encourage analytical thinking, but also prepares readers for interviews. This book, with its focused and practical approach, can help readers quickly pick up the concepts and techniques for developing efficient and effective solutions to problems.

Buy Here: Buy From Amazon

Liked this blog? Don't miss out on any future blog posts by Subscribing Here

Both of these algorithms are giving same output but the first one takes nearly double time (>.67) compared to second one (.36). How is this possible? Can you tell me the time complexity of both algorithms? If they're the same, why is the time different?

Both of these algorithms are giving same output but the first one takes nearly double time (>.67) compared to second one (.36). How is this possible? Can you tell me the time complexity of both algorithms? If they're the same, why is the time different?

1st algorithm:

for (int i =0 ;i<n;i++){ cin>>p[i]; if(i>0){ if(p[i-1]>p[i]){ cout<<p[i]<<" "; } else{ cout<<"-1"<<" "; } } }

2nd algorithm:

for (int i =0 ;i<n;i++){ cin>>p[i];`} for (int i =0 ; i<n-1;i++){ if(p[i]>p[i+1]){ cout<<p[i]<<" "; } else{ cout<<"-1"<<" "; } }`

Dijkstra's algorithm can find for you the shortest path between two nodes on a graph. It's a must-know for any programmer. There are nice gifs and history in its <a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm" target="_blank">Wikipedia page</a>.

Dijkstra's algorithm can find for you the shortest path between two nodes on a graph. It's a must-know for any programmer. There are nice gifs and history in its Wikipedia page.

In this post I'll use the time-tested implementation from Rosetta Codechanged just a bit for being able to process weighted and unweighted graph data, also, we'll be able to edit the graph on the fly. I'll explain the code block by block.

The algorithmThe algorithm is pretty simple. Dijkstra created it in 20 minutes, now you can learn to code it in the same time.

- Mark all nodes unvisited and store them.
- Set the distance to zero for our initial node and to infinity for other nodes.
- Select the unvisited node with the smallest distance, it's current node now.
- Find unvisited neighbors for the current node and calculate their distances through the current node. Compare the newly calculated distance to the assigned and save the smaller one.
*For example, if the node A has a distance of 6, and the A-B edge has length 2, then the distance to B through A will be 6 + 2 = 8. If B was previously marked with a distance greater than 8 then change it to 8.* - Mark the current node as visited and remove it from the unvisited set.
- Stop, if the destination node has been visited (when planning a route between two specific nodes) or if the smallest distance among the unvisited nodes is infinity. If not, repeat steps 3-6.

First, imports and data formats. The original implementations suggests using namedtuple for storing edge data. We'll do exactly that, but we'll add a default value to the cost argument. There are many ways to do that, find what suits you best.

from collections import deque, namedtuple we'll use infinity as a default distance to nodes.inf = float('inf')

Edge = namedtuple('Edge', 'start, end, cost')def make_edge(start, end, cost=1):

return Edge(start, end, cost)

Let's initialize our data:

class Graph:

definit(self, edges):

# let's check that the data is right

wrong_edges = [i for i in edges if len(i) not in [2, 3]]

if wrong_edges:

raise ValueError('Wrong edges data: {}'.format(wrong_edges))`self.edges = [make_edge(*edge) for edge in edges]`

Let's find the vertices. In the original implementation the vertices are defined in the _ _ init _ _, but we'll need them to update when edges change, so we'll make them a property, they'll be recounted each time we address the property. Probably not the best solution for big graphs, but for small ones it'll go.

@property

def vertices(self):

return set(

# this piece of magic turns ([1,2], [3,4]) into [1, 2, 3, 4]

# the set above makes it's elements unique.

sum(

([edge.start, edge.end] for edge in self.edges), []

)

)

Now, let's add adding and removing functionality.

def get_node_pairs(self, n1, n2, both_ends=True):

if both_ends:

node_pairs = [[n1, n2], [n2, n1]]

else:

node_pairs = [[n1, n2]]

return node_pairs`def remove_edge(self, n1, n2, both_ends=True): node_pairs = self.get_node_pairs(n1, n2, both_ends) edges = self.edges[:] for edge in edges: if [edge.start, edge.end] in node_pairs: self.edges.remove(edge) def add_edge(self, n1, n2, cost=1, both_ends=True): node_pairs = self.get_node_pairs(n1, n2, both_ends) for edge in self.edges: if [edge.start, edge.end] in node_pairs: return ValueError('Edge {} {} already exists'.format(n1, n2)) self.edges.append(Edge(start=n1, end=n2, cost=cost)) if both_ends: self.edges.append(Edge(start=n2, end=n1, cost=cost))`

Let's find neighbors for every node:

@property

def neighbours(self):

neighbours = {vertex: set() for vertex in self.vertices}

for edge in self.edges:

neighbours[edge.start].add((edge.end, edge.cost))`return neighbours`

It's time for the algorithm! I renamed the variables so it would be easier to understand.

def dijkstra(self, source, dest):

assert source in self.vertices, 'Such source node doesn't exist'`# 1. Mark all nodes unvisited and store them. # 2. Set the distance to zero for our initial node # and to infinity for other nodes. distances = {vertex: inf for vertex in self.vertices} previous_vertices = { vertex: None for vertex in self.vertices } distances[source] = 0 vertices = self.vertices.copy() while vertices: # 3. Select the unvisited node with the smallest distance, # it's current node now. current_vertex = min( vertices, key=lambda vertex: distances[vertex]) # 6. Stop, if the smallest distance # among the unvisited nodes is infinity. if distances[current_vertex] == inf: break # 4. Find unvisited neighbors for the current node # and calculate their distances through the current node. for neighbour, cost in self.neighbours[current_vertex]: alternative_route = distances[current_vertex] + cost # Compare the newly calculated distance to the assigned # and save the smaller one. if alternative_route < distances[neighbour]: distances[neighbour] = alternative_route previous_vertices[neighbour] = current_vertex # 5. Mark the current node as visited # and remove it from the unvisited set. vertices.remove(current_vertex) path, current_vertex = deque(), dest while previous_vertices[current_vertex] is not None: path.appendleft(current_vertex) current_vertex = previous_vertices[current_vertex] if path: path.appendleft(current_vertex) return path`

Let's use it.

graph = Graph([The whole code from above:

("a", "b", 7), ("a", "c", 9), ("a", "f", 14), ("b", "c", 10),

("b", "d", 15), ("c", "d", 11), ("c", "f", 2), ("d", "e", 6),

("e", "f", 9)])print(graph.dijkstra("a", "e"))

>>> deque(['a', 'c', 'd', 'e'])

from collections import deque, namedtuple we'll use infinity as a default distance to nodes.inf = float('inf')

Edge = namedtuple('Edge', 'start, end, cost')def make_edge(start, end, cost=1):

return Edge(start, end, cost)class Graph:

definit(self, edges):

# let's check that the data is right

wrong_edges = [i for i in edges if len(i) not in [2, 3]]

if wrong_edges:

raise ValueError('Wrong edges data: {}'.format(wrong_edges))`self.edges = [make_edge(*edge) for edge in edges] @property def vertices(self): return set( sum( ([edge.start, edge.end] for edge in self.edges), [] ) ) def get_node_pairs(self, n1, n2, both_ends=True): if both_ends: node_pairs = [[n1, n2], [n2, n1]] else: node_pairs = [[n1, n2]] return node_pairs def remove_edge(self, n1, n2, both_ends=True): node_pairs = self.get_node_pairs(n1, n2, both_ends) edges = self.edges[:] for edge in edges: if [edge.start, edge.end] in node_pairs: self.edges.remove(edge) def add_edge(self, n1, n2, cost=1, both_ends=True): node_pairs = self.get_node_pairs(n1, n2, both_ends) for edge in self.edges: if [edge.start, edge.end] in node_pairs: return ValueError('Edge {} {} already exists'.format(n1, n2)) self.edges.append(Edge(start=n1, end=n2, cost=cost)) if both_ends: self.edges.append(Edge(start=n2, end=n1, cost=cost)) @property def neighbours(self): neighbours = {vertex: set() for vertex in self.vertices} for edge in self.edges: neighbours[edge.start].add((edge.end, edge.cost)) return neighbours def dijkstra(self, source, dest): assert source in self.vertices, 'Such source node doesn\'t exist' distances = {vertex: inf for vertex in self.vertices} previous_vertices = { vertex: None for vertex in self.vertices } distances[source] = 0 vertices = self.vertices.copy() while vertices: current_vertex = min( vertices, key=lambda vertex: distances[vertex]) vertices.remove(current_vertex) if distances[current_vertex] == inf: break for neighbour, cost in self.neighbours[current_vertex]: alternative_route = distances[current_vertex] + cost if alternative_route < distances[neighbour]: distances[neighbour] = alternative_route previous_vertices[neighbour] = current_vertex path, current_vertex = deque(), dest while previous_vertices[current_vertex] is not None: path.appendleft(current_vertex) current_vertex = previous_vertices[current_vertex] if path: path.appendleft(current_vertex) return path`

graph = Graph([

("a", "b", 7), ("a", "c", 9), ("a", "f", 14), ("b", "c", 10),

("b", "d", 15), ("c", "d", 11), ("c", "f", 2), ("d", "e", 6),

("e", "f", 9)])print(graph.dijkstra("a", "e"))

P.S. For those of us who, like me, read more books about the Witcher than about algorithms, it's Edsger Dijkstra, not Sigismund.

<em>Photo by Ishan @seefromthesky on Unsplash</em>

Dijkstra's algorithm can find for you the shortest path between two nodes on a graph. It's a must-know for any programmer. There are nice gifs and history in its Wikipedia page.

In this post I'll use the time-tested implementation from Rosetta Codechanged just a bit for being able to process weighted and unweighted graph data, also, we'll be able to edit the graph on the fly. I'll explain the code block by block.

The algorithmThe algorithm is pretty simple. Dijkstra created it in 20 minutes, now you can learn to code it in the same time.

- Mark all nodes unvisited and store them.
- Set the distance to zero for our initial node and to infinity for other nodes.
- Select the unvisited node with the smallest distance, it's current node now.
- Find unvisited neighbors for the current node and calculate their distances through the current node. Compare the newly calculated distance to the assigned and save the smaller one.
*For example, if the node A has a distance of 6, and the A-B edge has length 2, then the distance to B through A will be 6 + 2 = 8. If B was previously marked with a distance greater than 8 then change it to 8.* - Mark the current node as visited and remove it from the unvisited set.
- Stop, if the destination node has been visited (when planning a route between two specific nodes) or if the smallest distance among the unvisited nodes is infinity. If not, repeat steps 3-6.

First, imports and data formats. The original implementations suggests using namedtuple for storing edge data. We'll do exactly that, but we'll add a default value to the cost argument. There are many ways to do that, find what suits you best.

```
from collections import deque, namedtuple
# we'll use infinity as a default distance to nodes.
inf = float('inf')
Edge = namedtuple('Edge', 'start, end, cost')
def make_edge(start, end, cost=1):
return Edge(start, end, cost)
```

Let's initialize our data:

```
class Graph:
def __init__(self, edges):
# let's check that the data is right
wrong_edges = [i for i in edges if len(i) not in [2, 3]]
if wrong_edges:
raise ValueError('Wrong edges data: {}'.format(wrong_edges))
self.edges = [make_edge(*edge) for edge in edges]
```

Let's find the vertices. In the original implementation the vertices are defined in the _ _ init _ _, but we'll need them to update when edges change, so we'll make them a property, they'll be recounted each time we address the property. Probably not the best solution for big graphs, but for small ones it'll go.

```
@property
def vertices(self):
return set(
# this piece of magic turns ([1,2], [3,4]) into [1, 2, 3, 4]
# the set above makes it's elements unique.
sum(
([edge.start, edge.end] for edge in self.edges), []
)
)
```

Now, let's add adding and removing functionality.

```
def get_node_pairs(self, n1, n2, both_ends=True):
if both_ends:
node_pairs = [[n1, n2], [n2, n1]]
else:
node_pairs = [[n1, n2]]
return node_pairs
def remove_edge(self, n1, n2, both_ends=True):
node_pairs = self.get_node_pairs(n1, n2, both_ends)
edges = self.edges[:]
for edge in edges:
if [edge.start, edge.end] in node_pairs:
self.edges.remove(edge)
def add_edge(self, n1, n2, cost=1, both_ends=True):
node_pairs = self.get_node_pairs(n1, n2, both_ends)
for edge in self.edges:
if [edge.start, edge.end] in node_pairs:
return ValueError('Edge {} {} already exists'.format(n1, n2))
self.edges.append(Edge(start=n1, end=n2, cost=cost))
if both_ends:
self.edges.append(Edge(start=n2, end=n1, cost=cost))
```

Let's find neighbors for every node:

```
@property
def neighbours(self):
neighbours = {vertex: set() for vertex in self.vertices}
for edge in self.edges:
neighbours[edge.start].add((edge.end, edge.cost))
return neighbours
```

It's time for the algorithm! I renamed the variables so it would be easier to understand.

```
def dijkstra(self, source, dest):
assert source in self.vertices, 'Such source node doesn\'t exist'
# 1. Mark all nodes unvisited and store them.
# 2. Set the distance to zero for our initial node
# and to infinity for other nodes.
distances = {vertex: inf for vertex in self.vertices}
previous_vertices = {
vertex: None for vertex in self.vertices
}
distances[source] = 0
vertices = self.vertices.copy()
while vertices:
# 3. Select the unvisited node with the smallest distance,
# it's current node now.
current_vertex = min(
vertices, key=lambda vertex: distances[vertex])
# 6. Stop, if the smallest distance
# among the unvisited nodes is infinity.
if distances[current_vertex] == inf:
break
# 4. Find unvisited neighbors for the current node
# and calculate their distances through the current node.
for neighbour, cost in self.neighbours[current_vertex]:
alternative_route = distances[current_vertex] + cost
# Compare the newly calculated distance to the assigned
# and save the smaller one.
if alternative_route < distances[neighbour]:
distances[neighbour] = alternative_route
previous_vertices[neighbour] = current_vertex
# 5. Mark the current node as visited
# and remove it from the unvisited set.
vertices.remove(current_vertex)
path, current_vertex = deque(), dest
while previous_vertices[current_vertex] is not None:
path.appendleft(current_vertex)
current_vertex = previous_vertices[current_vertex]
if path:
path.appendleft(current_vertex)
return path
```

Let's use it.

```
graph = Graph([
("a", "b", 7), ("a", "c", 9), ("a", "f", 14), ("b", "c", 10),
("b", "d", 15), ("c", "d", 11), ("c", "f", 2), ("d", "e", 6),
("e", "f", 9)])
print(graph.dijkstra("a", "e"))
>>> deque(['a', 'c', 'd', 'e'])
```

The whole code from above:
```
from collections import deque, namedtuple
# we'll use infinity as a default distance to nodes.
inf = float('inf')
Edge = namedtuple('Edge', 'start, end, cost')
def make_edge(start, end, cost=1):
return Edge(start, end, cost)
class Graph:
def __init__(self, edges):
# let's check that the data is right
wrong_edges = [i for i in edges if len(i) not in [2, 3]]
if wrong_edges:
raise ValueError('Wrong edges data: {}'.format(wrong_edges))
self.edges = [make_edge(*edge) for edge in edges]
@property
def vertices(self):
return set(
sum(
([edge.start, edge.end] for edge in self.edges), []
)
)
def get_node_pairs(self, n1, n2, both_ends=True):
if both_ends:
node_pairs = [[n1, n2], [n2, n1]]
else:
node_pairs = [[n1, n2]]
return node_pairs
def remove_edge(self, n1, n2, both_ends=True):
node_pairs = self.get_node_pairs(n1, n2, both_ends)
edges = self.edges[:]
for edge in edges:
if [edge.start, edge.end] in node_pairs:
self.edges.remove(edge)
def add_edge(self, n1, n2, cost=1, both_ends=True):
node_pairs = self.get_node_pairs(n1, n2, both_ends)
for edge in self.edges:
if [edge.start, edge.end] in node_pairs:
return ValueError('Edge {} {} already exists'.format(n1, n2))
self.edges.append(Edge(start=n1, end=n2, cost=cost))
if both_ends:
self.edges.append(Edge(start=n2, end=n1, cost=cost))
@property
def neighbours(self):
neighbours = {vertex: set() for vertex in self.vertices}
for edge in self.edges:
neighbours[edge.start].add((edge.end, edge.cost))
return neighbours
def dijkstra(self, source, dest):
assert source in self.vertices, 'Such source node doesn\'t exist'
distances = {vertex: inf for vertex in self.vertices}
previous_vertices = {
vertex: None for vertex in self.vertices
}
distances[source] = 0
vertices = self.vertices.copy()
while vertices:
current_vertex = min(
vertices, key=lambda vertex: distances[vertex])
vertices.remove(current_vertex)
if distances[current_vertex] == inf:
break
for neighbour, cost in self.neighbours[current_vertex]:
alternative_route = distances[current_vertex] + cost
if alternative_route < distances[neighbour]:
distances[neighbour] = alternative_route
previous_vertices[neighbour] = current_vertex
path, current_vertex = deque(), dest
while previous_vertices[current_vertex] is not None:
path.appendleft(current_vertex)
current_vertex = previous_vertices[current_vertex]
if path:
path.appendleft(current_vertex)
return path
graph = Graph([
("a", "b", 7), ("a", "c", 9), ("a", "f", 14), ("b", "c", 10),
("b", "d", 15), ("c", "d", 11), ("c", "f", 2), ("d", "e", 6),
("e", "f", 9)])
print(graph.dijkstra("a", "e"))
```

P.S. For those of us who, like me, read more books about the Witcher than about algorithms, it's Edsger Dijkstra, not Sigismund.