C&DS Unit-VII and VIII (Data Structures)
C&DS Unit-VII and VIII (Data Structures)
DATA STRUCTURES
A data structure is an organized collection of data along with the allowed operations on that. In
other words a data structure is an arrangement of data in a computer's memory or even disk
storage. An example of several common data structures are arrays, linked lists, queues, stacks
and binary trees.
Binary Search Quick search, Quick inserts and Quick Deletion algorithm is complex
Tree deletes (If the tree remains balanced)
NOTE: The data structures shown above (with the exception of the array) can be thought
of as Abstract Data Types (ADTs).
Classifications of Data Structures can be done in many ways. One way is to classify
based on their linearity.
Linear Data Structures
In a Linear Data Structure the data items are arranged in a linear sequence.
Ex: Array, stack, queue, linked list
Non Linear Data Structures
The data items are not in a linear sequence.
Ex: Tree, graph
Arrays
→ An array is a group of logically related data items of the same data-type addressed by a
common name and all the items are stored in contiguous memory locations.
→ The computer does not need to keep track of the address of every element of the array but
needs to keep track only of the address of the first element of the array, using that address
the computer calculates the address of any element of array by the following formula,
→ Required location=starting address of array + (data type * scale factor)
→ Access the content of any specified location without scanning any other element of an
array. The elements are accessed by specifying the subscript or index.
→ It is very fast to access.
→ Programming length decreases i.e., single operation changes all the data of an array.
→ It holds the data as well as addresses of structures.
→ Multi-dimensional arrays are very powerful for several functions.
→ Searching is done very fast.
Some of the basic operations that can be performed on the arrays are:
• Creating an array.
• Deleting or inserting an element in the array.
• Sort the elements of the array.
• Search an element in an array.
• Displaying (visiting) the elements of array.
• Insertion or deletion at the specified location.
Linked Lists
Memory is allocated statically for an array. An estimation of the maximum size of the list
is required which wastes lot of space if not used. This also limits the user not to store
more than maximum size specified. Insertion and deletion are expensive because
insertion at first requires first pushing the entire array down one spot to make a room,
similarly deletion requires pushed up the list.
To avoid the disadvantages of arrays introduced a new concept called linked list, in
which elements are not stored in a contiguously locations. Linked list is also called as
self-referential class or one-way list.
The linked list consists of a series of structures, which are not necessarily adjacent in
memory. Each structure contains the element and a pointer to a structure containing its
successor. The Previous element to the tail of the list is called its predecessor. Clearly
head does not have a predecessor and tail (last element) does not have successor. We call
this the Next pointer.
The last cells Next pointer points to NULL. Combination of data and pointer to next
structure is also called as node.
Create a list
Search for an element in a list
Delete an element from a list ( at beg, at end, at given location)
Add an element at a specified location of a list ( at beg, at end, at given location).
Sort the list
Display (Traversal) the elements the list
Determine the size or no of elements in a list
struct node
{
Element_type data;
struct node *next; //self referential structure
};
typedef struct node NODE;
NODE *list;
We can form a linked list using pointers the structure of the list may be as shown below.
The linked list in which the last element (or tail) points back to the head (or first element)
is called Circular Linked List.
Note: Please refer Lab Exercise 13 and 14 for Singly Linked List and Doubly Linked List
Stack
It is a list of elements to which additions and deletions can only be made at one end-the
top.
Consequently, the stack becomes a last-in-first-out (LIFO) data structure; the last
element added is the first to be removed.
When we add an item to the top of the stack, it is called a PUSH operation and when we
remove an item from the top, it is called a POP operation.
The stack data structure maintains a stack pointer always pointing to its top.
After pushing an item, the stack pointer moves up to point always to the last item added.
Similarly, after popping an item, the stack pointer moves down to the next last item in the
stack.
Stack Model
→ Stack can be implemented in either fixed size stack or Dynamic size stack.
→ In fixed size stack we use arrays and for dynamic size stack we use linked list or pointers
to implement stacks
A sample Stack
Top 3
4
Top
3
Top 3
Eg:
A sample Stack
Applications of Stacks:
• Compilers will take the help of stack for checking syntax errors (Symbol Balancing)
• Stacks were used in evaluating postfix expressions (Reverse polish notation).
• Stacks are used in conversion of infix expressions to postfix expressions.
• Stacks are used for matching brackets in an expression.
• Stacks are for memory management during the function call. When there is a function
call, all the important information that needs to be saved, such as register values and the
return addresses are saved onto the stack. The information saved is called either an
activation record or stack frame.
Queue
→ Like Stacks, Queues are lists. With a queue, however, insertion is done at one end called
rear end, where as deletion is performed at the other end called front end.
→ Queue can be called FIFO (First in First out) List.
→ The basic operations on a queue are
o Insertion (Enqueue), which inserts an element at the end of the list called the rear
o Deletion (Dequeue), which deletes the elements at the start of the list called front.
→ Queues can also be implemented using arrays (static size) or linked lists (dynamic size).
After Create
0 1 2 3 4
Front = 0, Rear = 0
5 7 9
0 1 2 3 4
Front Rear
7 9
0 1 2 3 4
Front Rear
Applications of queues:
Uses of Queues in operating systems: Operating system maintains several queues like
ready queue, device queue etc. for handling multiple processes.
Use of Queue in Network Ex: for Queuing jobs in file Server.
A Whole branch of mathematics, known as queuing theory, deals with computing,
probabilistically, how long users expect to wait on a line, how long the line gets, and
other such questions.
Note: Please refer to Lab Exercise 16 for implementation of Queue.
Circular Queue
There is one potential problem with the linear queue. Once the queue is full, even after some
deletion operations the Queue appears to be full. (In the above illustration, suppose rear = 4 and
front = 2 for 5 cell queue the queue appears to be full but not). Then you cannot insert until the
queue is completely empty.
The Simple solution is that whenever front and rear gets to the end of the array, it is
wrapped around to the beginning. This is known as circular Queue.
0 1 2 3 4
Front Rear
Font=0 and Rear = 4
0 1 2 3 4
Front Rear
Font=1 and Rear = 4
Now insertion can be done at rear because in circular queue once the rear or front reaches the
maximum they wrap around. Therefore rear will wrap around to 0 (Front should not be 0).
0 1 2 3 4
Rear Front
Font=1 and Rear = 0
#include<stdio.h>
#include<stdlib.h>//for exit(0) function
#define MAX 5
int q[MAX],f=-1,r=-1; //declare an array for queue and 2 variables for front and rear end.
void insert(int n) //a function to insert element into the queue at the front end
{
if((r+1)%MAX==f) //if rear pointer reaches maximum index of variable, insertion cannot be done
printf("\n\nQue is full insertion cannot be done at this stage");
else
{
if(f==-1) //if queue is empty point front to first element
f=0;
r=(r+1)%MAX; //increment the rear pointer and add the new element to array
q[r]=n;
printf("\n\nElement %d is inserted successfully\n",n);
}
}
void del() //function to delete a element from front end
{
if(f==-1) //queue is empty when f=-1
printf("\n\nThere are no elements in Que to delete.The que is empty\n");
else
{
printf("\n\n The element deleted is %d.",q[f]); //display the deleted front element and
increment front
if(f==r) //only one element is present in queue and it is deleted
f=r=-1; //queue is empty so initialize f and r
else
f=(f+1)%MAX;
}
}
void disp() //function to traverse the queue and display the values of it
{
int i;
if(f==-1) //check if the queue is empty
printf("\n\nThe queue is empty.");
else //if queue is not empty
{
printf("\n\nThe elements of the Queue are:\n\n");
for(i=f;i!=r;i=(i+1)%MAX) //start from front and move till rear but not rear element
printf("%d ",q[i]); //display each element
printf("%d ",q[r]); //display the last element
}
}
void main()
{
char ch;
int n;
while(1)
{
clrscr();
printf("\n\n\n\n\t*****MENU*****\n\n\n\n");
printf(" 1: Insert at rear end.\n\n 2: Delete at front end.\n\n 3: Dispaly the elements.\n\n 4:
Terminate the program\n\n\n\nPlease enter ur choice: ");
ch=getch();
clrscr();
switch(ch)
{
case '1': printf("\n\n\n\n\n\n\t****INSERTION*****\n\n\nEnter the element to inserted: ");
scanf("%d",&n);
insert(n);
break;
case '2': printf("\n\n\n\n\n\n\t****DELETION*****\n\n\n");
del();
break;
case '3': printf("\n\n\n\n***DISPLAY***\n\n\n");
disp();
break;
case '4': printf("\n\n\n\n\tARE U SURE TO EXIT?\n\n\tPress 'n' if no : ");
ch=getch(); //take confirmation of exiting
if(ch!='n') //if user enter n to indicate not to exit, skip exiting and continue to menu
exit(0);
break;
default : printf("\n\n\n\tINVALID OPTION entered");
}
printf("\n\n\n\n\nPress any key for main MENU....");
getch();
}
}
Trees
Def: A tree is a collection of nodes. A Tree consists of a distinguished node r, called the root,
and zero or more nonempty (sub) trees T1, T2…Tk each of whose roots are connected by a
directed edge from r. The root of each subtree is said to be child of r, and r is the parent of each
sub root.
• A Tree of n nodes will consist of n-1 edges (An edge is connecting line or link between
two nodes).
• Node with no children is called Leaf. Nodes with same parent are called Siblings.
• A Path from n1 to nk is defined as a sequence of nodes n1,n2,----,nk such that ni is the
parent of ni + 1 for 1 <= i<= k. the Length of the path is the no of edges on the path.
• There is a path of length zero from every node to itself.
• In a tree there is only one path from root to each node.
• For any node ni, the depth of ni is the length of the unique path from the root.
• The Height of ni is the longest path from ni to a leaf.
• If there is path from n1 to n2, there n1 is an ancestor of n2 and n2 is a descendent of n1.
If n1 n2 then n1 is a proper ancestor of n2 and n2 is a proper descendent of n1.
Applications of Trees
• Help analyze electrical circuits and to represent the structure of mathematical formulas.
• Trees are used to represent the syntactic structure of source programs in compilers.
• Trees are used in expression evaluation.
• Trees are used in storing records into the database (e.g. B-Trees). This improves the
performance of data storage and retrieval.
• Trees are used in maintaining the directory and file system within the operating systems.
• Used to represent web page structures.
struct node
{
Element_Type data;
struct node * Child_1;
struct node * Child_2;
struct node * Child_3;
. . . .
struct node * Child_N;
};
A Sample Tree:
Binary Trees:
A Binary tree is a tree in which no node can have more than two children. The first
subset contains a single element called the ‘root’ of the tree. The other two subsets themselves
binary tree, called the ‘left’ and ‘right’ sub trees of the original tree.
Eg:
If every non-leaf node in a binary tree has nonempty left and right sub trees, the tree is
termed a ‘strictly binary tree’. It is also called 2-tree.
A complete binary tree is a tree with n levels, where for each level d; the number of
existing nodes at level d except for the maximum level (nth level) is equal to 2d. This
means all possible nodes exist at these levels. An additional requirement for a complete
binary tree is that for the nth level, while every node does not have to exist, the nodes that
do exist must fill from left to right.
A binary tree is said to be balanced tree when the depth of the tree (maximum level) is
equal to log2N where N is the number of nodes.
Eg:
6
2 8
1 4
Insert Operation:
Inserting 5:
5<6 6
5>2 2 8
1 4 5>4
3 5 Inserted
Staff: Janaki Ram Dept of IT Page:14
C & DS for I MCA Unit- 7 and 8 (Data Structures) VVIT
Once we have found the node to be removed, we need to consider several possibilities
If node is a leaf, it can be deleted immediately and its parent is updated with null in its
place.
If the node has one child, the node can be removed after its parent adjusts a pointer to
bypass the node. Notice that the removed node is now unreferenced and can be deleted
only if a pointer to it has been saved (in a temporary variable).
The complicated case is when a node has two children the general strategy is to replace
the key of this node will the smallest key of the right sub tree and remove that smallest
key from the right sub tree.
Eg:
Consider a BST
6
2 8
1 4
3
3.5
6
Minimum of
3 8
Right sub Tree →
1 4
3.5
Where 3 is the minimum of sub tree and 3 is deleted from right sub tree.
Let T be a binary tree. There are different methods that differ in the order in which they visit the
nodes. The three different traversal methods are:
Inorder
Preorder
Postorder
Inorder Traversal:
B C
D E F
Preorder Traversal:
It follows the general strategy of left-right-node (L-R-N). In this traversal, if T is not empty.
• Traverse the left sub tree in Post order,
• Traverse the right sub tree in Post order,
• Visit the root.
Graphs
Eg:
V (G) = { A, B, C }
E (G) = { (A, B) (A, C) (B, C) }
Representation of Graphs:
1. Adjacency Matrix
2. Adjacency Lists
The Choice of representative depends on the application and function to be performed on the
graph.
Adjacency Matrix:
The Adjacency Matrix A for a graph G = (V, E) with n vertices, is an n x n Matrix if bits,
such that A
Aij = 0 If otherwise
Eg:
Let us consider a graph
1 2 3 4
A= 1 0 1 0 1
2 0 0 1 0
3 0 0 0 0
4 0 0 1 0
In this representation, we store a graph as a linked structure. We store all the vertices in a
list and then for each vertex, we have a linked list of the adjacent vertices.
1
2 4 NULL
2
3 NULL
3
NULL
4
3 NULL
Graph Traversals:
Given Undirected graph G and a vertex V in V(G) we are interested in visiting all vertices in G
that are reachable from V1 we shall look at two ways of doing this
1. Depth first Search
2. Breadth first Search
The search terminates when no unvisited vertex can be reached from any of the visited
ones.
Pseudo Code
Void DFS(Vertex V)
{
visited[v] = True;
for each Vertex W adjacent to V
if(! Visited[W])
DFS(W);
}
Breadth-First-Search:
Pseudo code
Void BFS(Vertex V)
{
initialize Q to be Empty //Q is a Queue
while(1)
{
for each vertex W adjacent to V
if(visited[W] = false)
{
Enqueue(Q, W);
Visited[W] = True;
}
if(Q is Empty)
return;
V = Dequeue(Q);
}
}