DS Module 1
DS Module 1
1. Data Structures,
2. Classifications (Primitive & Non Primitive),
3. Data structure Operations
Review of Pointers:
Stack:
Data Structures:
Data Structure can be defined as the group of data elements which provides an efficient
way of storing and organizing data in the computer so that it can be used efficiently. Some
examples of Data Structures are arrays, Linked List, Stack, Queue, etc. Data Structures are
widely used in almost every aspect of Computer Science i.e. operating System, Compiler Design,
Artificial intelligence, Graphics and many more.
1. Primitive data Structures: Primitive data structures are the fundamental data types which are
supported by a programming language. Basic data types such as integer, real, character and
Boolean are known as Primitive data Structures. These data types consists of characters that
cannot be divided and hence they also called simple data types.
2. Non- Primitive data Structures: Non-primitive data structures are those data structures
which are created using primitive data structures. Examples of non-primitive data structures is
the processing of complex numbers, linked lists, stacks, trees, and graphs.
Based on the structure and arrangement of data, non-primitive data structures is further
classified into
1. Linear Data Structure: A data structure is said to be linear if its elements form a sequence or
a linear list. There are basically two ways of representing such linear structure in memory.
One way is to have the linear relationships between the elements represented by means of
sequential memory location. These linear structures are called arrays.
The other way is to have the linear relationship between the elements represented by
means of pointers or links. These linear structures are called linked lists.
The common examples of linear data structure are Arrays, Queues, Stacks, Linked lists
2. Non-linear Data Structure: A data structure is said to be non-linear if the data are not arranged
in sequence or a linear. The insertion and deletion of data is not possible in linear fashion. This
structure is mainly used to represent data containing a hierarchical relationship between elements.
Trees and graphs are the examples of non-linear data structure.
Review of Pointers:
• Pointer is a variable which holds the address of other variable. In pointer we use two operators
&(address operator) and (*)Dereference operator.
int c=300,*ptr;
ptr =&c;
Here ptr is a pointer; it can hold the address of variable c & is called reference(address) operator
#include<stdio.h>
void main()
{
int *pc;
int c;
c=22;
printf("Address of c: %d \n", &c);
printf("Value of c: %d \n", c);
pc=&c;
printf("Address of pointer pc: %d \n", pc);
printf("Content of pointer pc: %d",*pc);
}
Output:
Address of c: 1232
Value of c: 22
NULL POINTER : A NULL pointer is defined as a special pointer value that points to
'\0'(nowhere) in the memory. In other words, NULL pointer does not point to any part of the
memory.
• For ex:
int *p=NULL;
DANGLING POINTER: A pointer variable which do not contain valid address is called Dangling
Pointer.
int *p;
float *p;
char *p;
void Pointer: A void pointer is a pointer that has no associated data type with it. A void pointer
can hold an address of any type and can be type-casted to any type.
#include <stdio.h>
int main()
{
int a = 10;
char b = 'x';
malloc()
calloc()
free()
realloc()
malloc()
The name malloc stands for "memory allocation".This function is used to allocate the requirement
memory-space during execution-time. The syntax is shown below:
data_type *p;
p=(data_type*)malloc(size);
here p is pointer variable data_type can be int, float or char size is number of bytes to be allocated
If memory is successfully allocated, then address of the first byte of allocated space is returned.
If memory allocation fails, then NULL is returned.
For ex:
ptr=(int*)malloc(100*sizeof(int));
The above statement will allocate 200 bytes assuming sizeof(int)=2 bytes.
Example: Program to find sum of n elements entered by user. Allocate memory dynamically using
malloc() function.
for(i=0;i<n;++i)
{
scanf("%d",ptr+i);
}
printf("The Entered Elements are as follows\n");
for(i=0;i<n;++i)
{
printf("%d\n",*(ptr+i));
}
}
Output:
calloc()
The name calloc stands for "contiguous allocation". This function is used to allocate the blocks of
memory required during execution-time and at the same time, automatically initialize memory
with 0's. The syntax is shown below:
data_type *p;
p=(data_type*)calloc(n,size);
If memory is successfully allocated, then address of the first byte of allocate space is returned. If
memory allocation fails, then NULL is returned.
The allocated memory is initialized automatically to 0's.
For ex:
ptr=(int*)calloc(25,sizeof(int));
The above statement allocates contiguous space in memory for an array of 25 elements each of
size of int, i.e., 2 bytes.
Example: Program to find sum of n elements entered by user. Allocate memory dynamically using
calloc() function.
Program: C Program to Demonstrate calloc() function
#include <stdio.h>
#include <stdlib.h>
void main()
{
int n,i,*ptr;
printf("Enter number of elements: ");
scanf("%d",&n);
ptr=(int*)calloc(n,sizeof(int));
If the previously allocated memory is insufficient or more than sufficient. Then, you can change
memory-size previously allocated using realloc().
free()
Dynamically allocated memory with either calloc() or malloc() does not get return on its own. The
programmer must use free() explicitly to release space.
Advantages of pointers
1. Pointer reduces the code and improves the performance, it is used to retrieving strings,
trees, etc. and used with arrays, structures, and functions.
2. We can return multiple values from a function using the pointer.
3. It makes you able to access any memory location in the computer's memory.
Disadvantages of Pointer
Structure Definition: “A structure can be defined a group of related data elements of same
or different data type with a common name”.
or
“A structure can be defined as a user defined data type that helps the programmer to store and
process a group of related data elements of different data type with a common name”.
Example 1. To store and process student information like roll number, name, total marks and
grade in computer’s memory, the programmer defines own data type.
Syntax Example
Struct tagname{ struct student {
}; };
The above written code creates the new data type named struct student to store and process
student information. Now, programmer can use this data type like other built in data types to define
variables.
Now, programmer can store and process the data within the structure variable.
s.rno=101;
strcpy(s.name,”John”);
s.marks=600;
s.grade=’A’;
Structure Declaration: A Structure can be declared using three different ways as shown below.
1. Tagged Structure
2. Structure without tag
3. Type defined structures
Example1. Structure Definition to store and process student information.
struct student /* definition of structure */
{
int rno;
char name[25];
int marks;
char grade;
};
Example2. Structure Definition to store and process book information.
struct book /* structure declaration*/
{
int book_no;
char book_name[25];
int book_price;
};
o/p:
Enter student roll no: 101
Enter student name: Thomas
Enter student average marks: 69
STUDENT DETAILS ARE AS FOLLOWS
Roll no= 101
Name= Thomas
Average marks= 69
Array of Structures: The programmers can define arrays of structures variables to store and
process large volume of data i.e. a group of related data elements of dissimilar type.
Syntax: struct tag_name array_name[size];
Example:
To store student information(roll no, name & average marks) of ‘n’ students.
struct student
{
int rno;
char name[25];
int marks;
};
struct student s[25]; /* Array of size 25 */
Nested Structure: The C language permits the programmers to nest structures within one another
i.e. structure can contain another structure member.
Example:
struct date
{
int dd, mm, yy;
};
struct student
{
char name[25];
struct date dob; /* nesting of structure member*/
}s;
Example:Program to store student information and display
#include<stdio.h>
#include<conio.h>
#include<string.h>
void main()
{
struct subject
{
int marks1;
int marks2;
int marks3;
};
typedef struct
{
char name[25];
int usn;
struct subject marks;
}STUDENT;
void main()
{
STUDENT a[100], temp;
int i,n;
printf(“Enter the number of student\n”);
scanf(“%d”,&n);
printf(“Enter all details of students\n”) ;
for(i=0;i<n;i++){
printf(“Enter Name”);
scanf(“%s”,a[i].name);
printf(“Enter USN”);
scanf(“%d”,&a[i].usn);
printf(“Enter First IA Marks\n”);
scanf(“%d”, &a[i].marks.marks1);
printf(“Enter Second IA marks\n”);
scanf(“%d”,&a[i].marks.marks2);
printf(“Enter third IA marks\n”);
scanf(“%d”,&a[i].marks.marks3);
}
printf(“details of students are as follows\n”);
printf(“Name\tUSn\tIAMARKS1\t IAMARKS2\t IAMARKS3”);
for(i=0;i<n;i++){
printf (“%s”,a[i].name);
printf (“%d”,&a[i].usn);
printf (“%d”, &a[i].marks.marks1);
printf (“%d”,&a[i].marks.marks2);
printf (“%d”,&a[i].marks.marks3);
printf(“\n”);
}
}
Self Referential structures are those structures that have one or more pointers which point to the
same type of structure, as their member.
In other words, structures pointing to the same type of structures are self-referential in nature.
Example:
Self Referential Structure with Single Link: These structures can have only one self-pointer
as their member. The following example will show us how to connect the objects of a self-
referential structure with the single link and access the corresponding data members. The
connection formed is shown in the following figure.
#include <stdio.h>
struct node {
int data1;
char data2;
struct node* link;
};
int main()
{
struct node ob1; // Node1
// Initialization
ob1.link = NULL;
ob1.data1 = 10;
ob1.data2 = 20;
struct node ob2; // Node2
// Initialization
ob2.link = NULL;
ob2.data1 = 30;
ob2.data2 = 40;
Union:
Union is a user defined data type that is used to hold different data type & it doesn't occupy sum
of all the members size like structure, instead it occupies the memory of largest member only. It
shares memory of largest member to the members of the structure. The union keyword is used
to define union. The syntax to define union:
union union_name
{
data_type member1;
----------------------
--------
data_type memeberN;
};
Example to define union for employee.
union employee
{
int id;
char name[50];
float salary;
};
Ex:
#include <stdio.h>
union employee
{
int id;
char name[50];
}e1;
//declaring e1 variable for union
void main( )
{
e1.id=1; //store first employee information
strcpy(e1.name, "S");//copying string into char array
Output: employee 1 id :
employee 1 name : S
Structure allocates storage space for all Union allocates one common storage space for all its
1 its members separately. Keyword: struct members. Union finds that which of its member needs
high storage space over other members and allocates
that much space. Keyword: union
Structure occupies larger memory space. Union occupies lower memory space over structure.
2
We can access all members of structure at We can access only one member of union at a time.
3 a time.
Structure example: struct student { int Union example: union student { int mark; double
4 mark; double average; }; average; };
For above structure, memory allocation For above union, only 8 bytes of memory will be
5 will be like below. int mark – 2 Bytes allocated since double data type will occupy
double average – 8B Total memory maximum space of memory over other data types.
allocation = 2+8 = 10 Bytes Total memory allocation = 8 Bytes
Polynomials are algebraic expressions that consist of exponents and coefficients. An example of
a polynomial with one variable is x2+x-12
Representation of Polynomial in C is to define typedef structure as follows:
MAX_TERMS 100
typedef struct{
float coeff;
int expon;
}polynomial;
Polynomial terms[MAX_TERMS];
int avail=0;
The above figure shows how these polynomials are stored in the array terms. The index of the first
term of A and B is given by startA and startB, while finishA and finishB give the index of the last
term of A and B.
• The index of the next free location in the array is given by avail.
• For above example, startA=0, finishA=1, startB=2, finishB=5, & avail=6.
Polynomial Addition
• C function is written that adds two polynomials, A and B to obtain D =A + B.
• To produce D (x), padd( ) is used to add A (x) and B (x) term by term. Starting at position
avail, attach( ) which places the terms of D into the array, terms.
C Function to add two polynomials:
The time for the remaining two for loops is bounded by O(n + m) because we cannot iterate
the first loop more than m times and the second more than n times. So, the asymptotic
computing time of this algorithm is O(n +m).
SPARSE MATRIX
A matrix contains m rows and n columns of elements as illustrated in below figures. In this
figure, the elements are numbers. The first matrix has five rows and three columns and the second
has six rows and six columns. We write m x n (read "m by n") to designate a matrix
with m rows and n columns. The total number of elements in such a matrix is mn. If m equals n,
the matrix is square.
What is Sparse Matrix? A matrix which contains many zero entries or very few non-zero entries
is called as Sparse matrix. In the figure B contains only 8 of 36 elements are nonzero and that is
sparse.
Example: consider the space requirements necessary to store a 1000 x 1000 matrix that has only
2000 non-zero elements. The corresponding two-dimensional array requires space for 1,000,000
elements. The better choice is by using a representation in which only the nonzero elements are
stored.
The below figure shows the representation of matrix in the array “a” a[0].row contains the number
of rows, a[0].col contains the number of columns and a[0].value contains the total number of
nonzero entries.
• Positions 1 through 8 store the triples representing the nonzero entries. The row index is in the
field row, the column index is in the field col, and the value is in the field value. The triples are
ordered by row and within rows by columns.
a[0] 6 6 8 b[0] 6 6 8
a[1] 0 0 15 b[1] 0 0 15
a[2] 0 3 22 b[2] 0 4 91
a[4] 1 1 11 b[4] 2 1 3
a[5] 1 2 3 b[5] 2 5 28
a[6] 2 3 -6 b[6] 3 0 22
a[7] 4 0 91 b[7] 3 2 -6
a[8] 5 2 28 b[8] 5 0 15
b[0].row = numCols;
b[0].col = a[0].row;
b[0].val = numTerms;
if(numTerms>0)
{
for(i =0; i<numCols; i++)
row_terms[i] = 0;
for(i=1; i<=numTerms; i++)
row_terms[a[i].col]++;
start_pos[0]=1;
for(i=1; i<numCols; i++)
start_pos[i] = start_pos[i-1] + row_terms[i-1];
for(i=1; i<=numTerms; i++)
{
j = start_pos[a[i].col]++;
b[j].row = a[i].col;
b[j].col = a[i].row;
b[j].val = a[i].val;
}
}
STRING OPERATION
Substring
Accessing a substring from a given string requires three pieces of information:
The syntax denote the substring of a string S beginning in a position K and having a length L.
Indexing
Indexing also called pattern matching, refers to finding the position where a string pattern P first
appears in a given string text T. This operation is called INDEX
If the pattern P does not appears in the text T, then INDEX is assigned the value 0.
The arguments “text” and “pattern” can be either string constant or string variable.
Concatenation
Let S1 and S2 be string. The concatenation of S1 and S2 which is denoted by S1 // S2, is the string
consisting of the characters of S1 followed by the character of S2.
Ex:
(a) Suppose S1 = 'MARK' and S2= ‘TWAIN' then
S1 // S2 = ‘MARKTWAIN’
strcat ( ) function is part of the string.h header file; hence it must be included at the time of pre-
processing
Length
The number of characters in a string is called its length.
String length is determined in C language using the strlen( ) function, as shown below:
X = strlen ("sunrise");
Similar to strcat, strlen is also a part of string.h, hence the header file must be included at the time of
pre-processing.
Pattern matching is the problem of deciding whether or not a given string pattern P appears in a string
text T. The length of P does not exceed the length of T.
P and T are strings with lengths R and S, and are stored as arrays with one character per element. This
algorithm finds the INDEX of P in T.
Observation of algorithms
• P is an r-character string and T is an s-character string
• Algorithm contains two loops, one inside the other. The outer loop runs through each successive
R-character substring WK = T[K] T[K + 1] ... T[K+R-l] of T.
• The inner loop compares P with WK, character by character. If any character does not match, then
control transfers to Step 5, which increases K and then leads to the next substring of T.
• If all the R characters of P do match those of some WK then P appears in T and K is the INDEX of
P in T.
• If the outer loop completes all of its cycles, then P does not appear in T and so INDEX = 0.
Complexity
The complexity of this pattern matching algorithm is equal to O(n2)
P = aaba
This algorithm contains the table that is used for the pattern P = aaba.
For example, a2 is the largest Q that is a terminal substring of Q2a = a3, so f(Q2, a)
= Q2 A is the largest Q that is a terminal substring of Q1b = ab, so f(Q1, b) = Q0 a is
the largest Q that is a terminal substring of Q0a = a, so f(Q0, a) = Q1 A is the largest
Q that is a terminal substring of Q3a = a3bx, so f(Q3, x) = Q0
Although Q1 = a is a terminal substring of Q2a = a3, we have f(Q2, a) = Q2 because Q2 is also a terminal
substring of Q2a = a3 and Q2 is larger than Q1. We note that f(Qi, x) = Q0 for any Q, since x does not
appear in the pattern P Accordingly, the column corresponding to x is usually omitted from the table.
First, a node in the graph corresponding to each initial substring Qi of P. The Q's are called the states of
the system, and Q0 is called the initial state.
Second, there is an arrow (a directed edge) in the graph corresponding to each entry in the table.
Specifically, if
f(Qi, t) = Qj
then there is an arrow labeled by the character t from Qi to Qj
For notational convenience, all arrows labeled x are omitted, which must lead to the initial state Qo.
1. Some state SK = P, the desired pattern. In this case, P does appear in T and its index is K -
LENGTH(P).
2. No state S1, S2, ... , SN +1 is equal to P. In this case, P does not appear in T.
Algorithm: (PATTERN MATCHING) The pattern matching table F(Q1, T) of a pattern P is in memory, and
the input is an N-character string T = T1 T2 T3 …… TN. The algorithm finds the INDEX of P in T.
6. [Successful ?]
If SK = P, then
Else
INDEX = 0
[End of IF structure]
7. Exit.
STACKS:
Definition: A stack is a list of elements in which an element may be inserted or deleted only at
one end called top end of the stack. This means, In particular, that elements are removed from a
stack in the reverse order of that in which they were inserted into stack.
A Stack is an ordered list on which insertions (Pushes and adds) and deletions (Pops and removes)
are made at same end is called the top. Given Stack S = (a0, a1 a2 a3 a4 a5………. an-1), we say that a0
is the bottom element, an-1 is the top element. Since last element is inserted into a stack is the first
element removed, a stack is also known as a Last-In-First-Out (LIFO) list.
Representation of Stack:
Stack ADT:
ADT Stack is
Objects: a finite ordered list with zero or more elements.
Functions: for all stack ϵ Stack, item ϵ element, maxSTackSize ϵ positive
integer
1. Stack CreateS(maxStackSize)::= Create an empty stack whose maximum size is
maxStackSize.
2. Boolean isFull(stack,maxStackSize)::=
if (number of elements in stack = = maxStackSize)
return TRUE
else
return FALSE
3. Stack Push(stack,item)::=
if (isFull(stack))
stackFull
else
insert item into top of the stack and return.
4. Boolean IsEmpty(stack)::=
if (stack = = CreateS(maxStackSize()))
return TRUE
else
return FALSE
5. Element Pop(stack)::=
if (IsEmpty(stack)) return
else remove and return the element at the top of the stack.
STACK OPERATIONS
1. Push( ) operation : Write a C function to add an item in to a stack.
void push(){
int key;
}element;
Element *stack;
MALLOC(stack,sizeof(*stack));
int capacity=1;
int top=-1;
void stackFull(){
REALLOC(stack,2*capacity*sizeof(*stack))
Capacity= Capacity*2;
}
Applications of STACK:
1. POLISH Notation
2. Evaluation of a Postfix expression
3. Transforming an infix expression into Postfix expression.
Infix notation(Infix Expression): The operator symbol is placed between its two operands.
Example: (A + B) * (C - D)
(A+B)*C=[+AB]*C=*+ABC
A+(B*C)=A+[*BC]=+A*BC
(A+B)/(C-D)=[+AB]/[-CD]=/+AB-CD
*, / 3 Left to right
+, - 4 Left to right
5 6 2 + * 12 4 / - )
1 2 3 4 5 6 7 8 9 10
(1) 5 5
(2) 6 5,6
(3) 2 5,6,2
(4) + 5,8
(5) * 40
(6) 12 40,12
(7) 4 40,12,4
(8) / 40,3
(9) - 37
(10) )
(1) A ( A
(2) + (+ A
(3) ( (+( A
(4) B (+( AB
(5) * (+(* AB
(17) ) (+ ABC*DEF↑/G*-
(20) ) ABC*DEF↑/G*-H*+
void display()
{
int i;
if(top==-1) {
printf("Stack Underflow\n");
} else {
printf("Stack Contents....\n");
for(i=top;i>=0;i--) {
printf("%d\n",stack[i]);
}
}
}
Recursion:
Recursion: Suppose P is a procedure containing either a call statement to itself or a call statement
to a second procedure that may eventually result in a statement back to the original procedure P
Then P is called a recursive procedure. So that the program will not continue to run indefinitely, a
recursive procedure must have the following two properties or rules.
a) There must be a certain criteria called base criteria for which the procedure will not call
itself.
b) Each time the procedure does call itself(directly or indirectly), it must be closer to the base
criteria.
LAB PROGRAM
Solving Tower of Hanoi problem with n disks. Source code
#include<stdio.h>
#include<math.h>
void tower(int n, int source, int temp, int destination)
{
if (n == 0) return;
tower(n - 1, source, destination, temp);
printf("\nMove disc %d from %c to %c", n, source, destination);
tower(n - 1, temp, source, destination);
}
void main() {
int n;
printf("\nEnter the number of discs: \n");
scanf("%d", & n); tower(n, 'A', 'B', 'C');
printf("\n\nTotal Number of moves are: %d", (int) pow(2, n) - 1);
}