DS Unit 1
DS Unit 1
Unit-1
Syllabus
Unit-I: Data Structures, Stacks , Queues
Unit-II: Trees
Unit-IV:Graphs
Unit-V:Hashing
Text Books:
1. Data Structures Using C, Second Edition Reema Thereja
OXFORD higher Education
2. Data Structures, A Pseudo code Approach with C, Richard
F.Gillberg & Behrouz A. Forouzan, Cengage Learning, India
Edition, Second Edition, 2005.
Course Outcomes:
At the end of the course student would be able to
1. Understand the concepts of Stacks and Queues with their
applications.
2. Analyze Various operations on Binary trees.
3. Examine of various concepts of binary trees with real time
applications.
4. Analyze the shortest path algorithm on graph data
structures.
5. Outline the concepts of hashing, collision and its resolution
methods using hash functions
Unit-1 Data Structure
Data structure is a representation of data and the operations
allowed on that data
2) Inserting a new element in an array of elements is expensive because the room has to
be created for the new elements and to create room existing elements have to be shifted.
Linked List
Advantages over arrays
1) Dynamic size
2) Ease of insertion/deletion
Drawbacks of Linked list:
1) Random access is not allowed. We have to access elements
sequentially starting from the first node. So we cannot do binary
search with linked lists efficiently with its default implementation.
2) Extra memory space for a pointer is required with each element
of the list.
3) Not cache friendly. Since array elements are contiguous locations,
there is locality of reference which is not there in case of linked lists.
Linked List Representation
A linked list is represented by a pointer to the first node of the linked list.
The first node is called the head.
If the linked list is empty, then the value of the head is NULL.
Each node in a list consists of at least two parts:
1) data
2) Pointer (Or Reference) to the next node
Traverse
To traverse all the nodes one after another.
Insertion
Insertion at the beginning:
If the list is empty, the new node becomes the head of the
list. Otherwise, connect the new node to the current head of
the list and make the new node, the head of the list.
Insertion
Insertion at end:
Traverse the list until find the last node. Then insert the new
node to the end of the list.
In case of a list being empty, return the updated head of the
linked list because in this case, the inserted node is the first as
well as the last node of the linked list.
Insertion
Insertion after a given node
We are given the reference to a node, and the new node is
inserted after the given node.
Deletion
Delete a beginning node:
First node is pointed by the head, move the head to the next
node, then free the first node
If there is only one node then free the node and head becomes
NULL
Deletion
Delete the end node:
Move the pointer to the last node and free the node.
Keep the NULL in the before that node
Deletion
Delete a particular node
To delete a node from linked list, do following steps.
1) Find previous node of the node to be deleted.
2) Change the next of previous node.
3) Free memory for the node to be deleted.
Search
To search any value in the linked list, traverse the linked list
and compares the value present in the node.
Traverse
•To traverse all the nodes one after another.
•Start with the head of the list. Access the content of the head node
if it is not null.
•Then go to the next node(if exists) and access the node
information
•Continue until no more nodes (that is, you have reached the null
node)
Double Linked List
A Doubly Linked List contains an extra memory to store the
address of the previous node, together with the address of the
next node and data which are there in the singly linked list. So,
here we are storing the address of the next as well as the
previous nodes.
Double Linked List
The nodes are connected to each other in this form where
the first node has prev = NULL and the last node has next
= NULL.
Traverse
•To traverse all the nodes one after another.
•Start with the head of the list. Access the content of the head node
if it is not null.
•Then go to the next node(if exists) and access the node
information
•Continue until no more nodes (that is, you have reached the null
node)
Circular Linked List
Circular linked list is a linked list where all nodes are
connected to form a circle. There is no NULL at the end.
A circular linked list can be a singly circular linked list or
doubly circular linked list.
POP:
Pop operation Removes an element from the stack
The top of the element is removed
PEEK:
Get the top data element of the stack, without removing it.
Implementation of Stack
Stack can be implemented in two ways:
1.Using Array
2. Using Linked List
Array Implementation:
PUSH Operation:
The size of the stack is specified at the beginning
Initially stack is empty and top=-1
When a new element is pushed it checks the condition whether
the stack is full,if it is true it gives “Overflow”
Otherwise the element is inserted from top end
Top variable is increased by 1
Array Implementation-PUSH
Step 1 - Check whether stack is FULL. (top == SIZE-1)
Step 2 - If it is FULL, then display "Stack is FULL!!! Insertion
is not possible!!!" and terminate the function.
Step 3 - If it is NOT FULL, then increment top value by one
(top++) and set stack[top] to value (stack[top] = value).
Array Implementation-POP
Pop():
To delete an element from any , it checks whether the stack is
empty, if it is true it gives “Underflow”
Otherwise top of the element is removed from the stack
Top is decreased by 1
If there are no more elements top will becomes -1
Pop
Step 1 - Check whether stack is EMPTY. (top == -1)
Step 2 - If it is EMPTY, then display "Stack is EMPTY!!!
Deletion is not possible!!!" and terminate the function.
Step 3 - If it is NOT EMPTY, then delete stack[top] and
decrement top value by one (top--).
Display
Step 1 - Check whether stack is EMPTY. (top == -1)
Step 2 - If it is EMPTY, then display "Stack is EMPTY!!!" and
terminate the function.
Step 3 - If it is NOT EMPTY, then define a variable 'i' and
initialize with top. Display stack[i] value and decrement i value
by one (i--).
Step 3 - Repeat above step until i value becomes '0'.
Array Implementation-PEEK
Peek:
If the stack is empty it displays “ Stack is empty”
Otherwise it displays the top of the element in the stack
Linked List Representation
The main advantage of using linked list over an arrays is that
it is possible to implements a stack that can shrink or grow as
much as needed.
In using array will put a restriction to the maximum capacity
of the array which can lead to stack overflow.
Here each new node will be dynamically allocate.
so overflow is not possible.
The stack implemented using linked list can work for an
unlimited number of values.
Linked List Representation
A stack can be easily implemented
through the linked list.
In stack Implementation, a stack
contains a top pointer. which is “head”
of the stack where pushing and
popping items happens at the head of
the list.
First node have null in link field and
second node link have first node
address in link field and so on and last
node address in “top” pointer.
PUSH
Step 1 - Create a newNode with given value.
Step 2 - Check whether stack is Empty (top == NULL)
Step 3 - If it is Empty, then set newNode →
next = NULL.
Step 4 - If it is Not Empty, then set newNode →
next = top.
Step 5 - Finally, set top = newNode.
POP
Step 1 - Check whether stack is Empty (top == NULL).
Step 2 - If it is Empty, then display "Stack is Empty!!!
Deletion is not possible!!!" and terminate the function
Step 3 - If it is Not Empty, then define a Node pointer
'temp' and set it to 'top'.
Step 4 - Then set 'top = top → next'.
Step 5 - Finally, delete 'temp'. (free(temp)).
Display
Step 1 - Check whether stack is Empty (top == NULL).
Step 2 - If it is Empty, then display 'Stack is
Empty!!!' and terminate the function.
Step 3 - If it is Not Empty, then define a Node
pointer 'temp' and initialize with top.
Step 4 - Display 'temp → data --->' and move it to the
next node. Repeat the same until temp reaches to the first
node in the stack. (temp → next != NULL).
Step 5 - Finally! Display 'temp → data ---> NULL'.
Applications of Stack
Stacks can be used for expression evaluation.
Stacks can be used to check parenthesis matching in an
expression.
Stacks can be used for Conversion from one form of
expression to another.
Stacks can be used for Memory Management.
Stack data structures are used in backtracking problems.
Representation of an expression
An expression can be represented in three ways
Infix expression
Prefix expression
Postfix expression
Infix Notation
Operators are written in-between their operands
This is the usual way we write expressions
Eg: A * ( B + C ) / D
Post fixNotation
Operators are written after their operands
The postfix notation is called as suffix notation and is also referred to
reverse polish notation.
Eg: A B C + * D /
Prefix Notation
Operators are written before their operands
The prefix notation is called as polish notation
Eg: / * A + B C D
Algorithm to convert Infix to Postfix
1. Read all the symbols one by one from left to right in the given
Infix Expression.
2. If the reading symbol is operand, then directly print it to the
result (Output).
3. If the reading symbol is left parenthesis '(', then Push it on to the
Stack.
4. If the reading symbol is right parenthesis ')', then Pop all the
contents of stack until respective left parenthesis is poped and
print each poped symbol to the result.
5. If the reading symbol is operator (+ , - , * , / etc.,), then Push it
on to the Stack. However, first pop the operators which are
already on the stack that have higher or equal precedence than
current operator and print them to the result.
6. Repeat the process until the last symbol
Infix Exp: (A+(B*C-(D/E^F)*G)*H)
Infix to Prefix
More Problems
The following infix expressions convert to Postfix and Prefix
expressions
1. (A + B) * (C + D)
2. (A - B/C) * (A/K-L)
3.(1+4/2*1+2)*3/2
4.9*(12+4)/5*6
5.(a*b/c)-(d^e+f)
Postfix Evaluation
A postfix expression can be evaluated using the Stack data
structure. Follow the below steps
1. Read all the symbols one by one from left to right in the given
Postfix Expression
2. If the reading symbol is operand, then push it on to the Stack.
3. If the reading symbol is operator (+ , - , * , / etc.,), then
perform TWO pop operations and store the two popped
oparands in two different variables (operand1 and operand2).
Then perform reading symbol operation using operand1 and
operand2 and push result back on to the Stack.
4. Finally! perform a pop operation and display the popped value
as final result.
Postfix Evaluation
456*+
Prefix Evaluation
Step 1: Put a pointer P at the end of the end
Step 2: If character at P is an operand push it to Stack
Step 3: If the character at P is an operator pop two elements
from the Stack. Operate on these elements according to the
operator, and push the result back to the Stack
Step 4: Decrement P by 1 and go to Step 2 as long as there
are characters left to be scanned in the expression.
Step 5: The Result is stored at the top of the Stack, return it
Step 6: End
Prefix Evaluation
Queue
Queue is a linear data structure in which the insertion and
deletion operations are performed at two different ends.
In a queue data structure, adding and removing elements are
performed at two different positions.
The insertion is performed at one end and deletion is
performed at another end.
In a queue data structure, the insertion operation is performed
at a position which is known as 'rear' and the deletion
operation is performed at a position which is known as 'front'.
In queue data structure, the insertion and deletion operations
are performed based on FIFO (First In First Out) principle.
Operations on a Queue
The following operations are performed on a queue data
structure...
enQueue(value) - To insert an element into the
queue
deQueue() - To delete an element from the queue
display() - (To display the elements of the queue)
Implementation of Queue
Queue data structure can be implemented in two ways. They
are as follows...
1.Using Array
2.Using Linked List
•In the above situation, even though we have empty positions in the
queue we can not make use of them to insert the new element.
• This is the major problem in a normal queue data structure.
•To overcome this problem we use a circular queue data structure.
Circular Queue
A circular queue is a linear data structure in which the
operations are performed based on FIFO (First In First Out)
principle and the last position is connected back to the first
position to make a circle.
Graphical representation of a circular queue is as follows..
Implementation of Circular Queue
To implement a circular queue data structure using an array
Step 1 - Include all the header files which are used in the
program and define a constant 'SIZE' with specific value.
Step 2 - Declare all user defined functions used in
circular queue implementation.
Step 3 - Create a one dimensional array with above defined
SIZE (int cQueue[SIZE])
Step 4 - Define two integer variables 'front' and 'rear' and
initialize both with '-1'. (int front = -1, rear = -1)
Step 5 - Implement main method by displaying menu of
operations list and make suitable function calls to perform
operation selected by the user on circular queue.
enQueue(value) - Inserting value into
the Circular Queue
In a circular queue, enQueue() is a function which is used to insert
an element into the circular queue.
In a circular queue, the new element is always inserted
at rear position.
Step 1 - Check whether queue is FULL. ((rear == SIZE-1 &&
front == 0) || (front == rear+1))
Step 2 - If it is FULL, then display "Queue is FULL!!!
Insertion is not possible!!!" and terminate the function.
Step 3 - If it is NOT FULL, then check rear == SIZE - 1 &&
front != 0 if it is TRUE, then set rear = -1.
Step 4 - Increment rear value by one (rear++),
set queue[rear] = value and check 'front == -1' if it is TRUE,
then set front = 0.
deQueue() - Deleting a value from the
Circular Queue
In a circular queue, deQueue() is a function used to delete an
element from the circular queue.
In a circular queue, the element is always deleted
from front position.
Step 1 - Check whether queue is EMPTY. (front == -1 &&
rear == -1)
Step 2 - If it is EMPTY, then display "Queue is EMPTY!!!
Deletion is not possible!!!" and terminate the function.
Step 3 - If it is NOT EMPTY, then display queue[front] as
deleted element and increment the front value by one (front
++). Then check whether front == SIZE, if it is TRUE, then
set front = 0. Then check whether both front - 1 and rear are
equal (front -1 == rear), if it TRUE, then set
both front and rear to '-1' (front = rear = -1).
display() - Displays the elements of a
Circular Queue
Step 1 - Check whether queue is EMPTY. (front == -1)
Step 2 - If it is EMPTY, then display "Queue is EMPTY!!!" and
terminate the function.
Step 3 - If it is NOT EMPTY, then define an integer variable 'i' and set
'i = front'.
Step 4 - Check whether 'front <= rear', if it is TRUE, then display
'queue[i]' value and increment 'i' value by one (i++). Repeat the same
until 'i <= rear' becomes FALSE.
Step 5 - If 'front <= rear' is FALSE, then display 'queue[i]' value
and increment 'i' value by one (i++). Repeat the same until'i <= SIZE
- 1' becomes FALSE.
Step 6 - Set i to 0.
Step 7 - Again display 'cQueue[i]' value and increment i value by one
(i++). Repeat the same until 'i <= rear' becomes FALSE.
Double Ended Queue-Deque
Double Ended Queue is also a Queue data structure in which
the insertion and deletion operations are performed at both
the ends (front and rear).
That means, we can insert at both front and rear positions
and can delete from both front and rear positions.
Operations on Deque
Mainly the following four basic operations are performed on
queue:
insertFront(): Adds an item at the front of Deque.
insertLast(): Adds an item at the rear of Deque.
deleteFront(): Deletes an item from front of Deque.
deleteLast(): Deletes an item from rear of Deque.
Deque
Double Ended Queue can be represented in TWO ways,
those are as follows...