Cs3353c Programming and Data Structures
Cs3353c Programming and Data Structures
3 0 0 3
COURSE OBJECTIVES:
To introduce the basics of C programming language.
To learn the concepts of advanced features of C.
To understand the concepts of ADTs and linear data structures.
To know the concepts of non-linear data structure and hashing.
To familiarize the concepts of sorting and searching techniques.
TOTAL 45 PERIODS
COURSE OUTCOMES:
CO1: Develop C programs for any real world/technical application.
CO2: Apply advanced features of C in solving problems.
CO3: Write functions to implement linear and non–linear data structure operations.
CO4: Suggest and use appropriate linear/non–linear data structure operations for
solving a givenproblem.
CO5: Appropriately use sort and search algorithms for a given application.
CO6: Apply appropriate hash functions that result in a collision free scenario for data
storage andretrieval.
TEXT BOOKS:
1. Mark Allen Weiss, “Data Structures and Algorithm Analysis in C”, Second
Edition, PearsonEducation, 1997.
2. ReemaThareja, “Programming in C”, Second Edition, Oxford University Press,
2016.
REFERENCES:
1. Brian W. Kernighan, Rob Pike, “The Practice of Programming”, Pearson
Education, 1999.
2. Paul J. Deitel, Harvey Deitel, “C How to Program”, Seventh Edition,
Pearson Education,2013.
C PROGRAMMING AND DATA STRUCTURES Mr.r.subramanian.me (cse)
3. Alfred V. Aho, John E. Hopcroft, Jeffrey D. Ullman, “Data Structures
and Algorithms”,Pearson Education,1983.
4. Ellis Horowitz, SartajSahni and Susan Anderson, “Fundamentals of Data
Structures”,Galgotia, 2008.
paradigm consist of several statements and after execution of all the result is
stored.
Advantage
1. Very simple to implement
2. It contains loops, variables etc.
Disadvantage
1. Complex problem cannot be solved
2. Less efficient and less productive
3. Parallel programming is not possible
Examples of Imperative programming paradigm: C, FORTAN, Basic
Program 1.1
/* Program to find the area of a circle */ /* Documentation Section
*/ # include<stdio.h> /* Preprocessor Section */
# include<conio.h>
# define PI 3.14 /* Definition Section */
void main() /* main( ) function */
{
float area,r; /* Local variable declaration */
clrscr(); // Executable part of the program
printf("\n Enter the radius:\
n"); scanf("%f",&r);
area= PI*(r*r);
printf("\n Area of the Circle = %8.2f", area);
getch();
}
Output
Enter the radius: 4.5
Area of the Circle = 63.58
Program 1.2
/* Program to find the sum of two numbers using function */
/*Documentation Section */
# include<stdio.h> /* Preprocessor Section
*/ # include<conio.h>
int a,b; /* Global Variable declaration */
int add(int,int); /* Function declaration */
void main() /* main( ) function */
{
int c; /* Local Variable declaration */
clrscr(); // Executable part of the main()
program printf("\n Enter the values for a and b:\n");
scanf("%d
%d",&a,&b); c =
add(a,b);
printf("\n Sum of %d + %d = %d",
a,b,c); getch();
}
int add(int a,int b) /* Subprogram of add() function definition */
{
int c; /* Local Variable declaration */
c=a+b; // Executable part of the
function return(c);
}
Output
Enter the values for a and b: 5 3
Sum of 5 + 3 = 8
Documentation section
The documentation section is included in the comments, which contains the
author name, the date of development and the program details.
Preprocessor section
The preprocessor section provides preprocessor statements which direct the
compiler to link functions from the system library.
Definition section
The definition section defines all symbolic constants refer to assigning a macro
of a name to a constant. The general syntax of a symbolic constant is
#define constant_name constant_value
Global declaration section
The global declaration section contains variable declarations which can be
accessed anywhere within the program.
Main section
Main section is divided into two portions, the declaration part and the executable
part. The declaration part used to declare any variables in the main block of the
program. The executable part contains set of statements within the open and close
braces. Execution of the program begins at the opening braces and ends at the closing
braces.
User defined function section
The user defined function section (or) the Sub program section contains user
defined functions which are called by the main function. Each user defined function
contains the function name, the argument and the return value.
1.5.6 Constants
1.6 OPERATORS IN C
Operator: An operator is a symbol that specifies an operation to be performed on
operands. Eg: x= a+b; where + is an operator.
Operands: An operand is an entity on which an operation is to be performed. An
operand can be a variable name, a constant, a function call or a macro name.
Eg. x= a+b; where x, a, b are the operands.
Expression: An expression is a sequence of operands and operators that specifies the
computations of a value. An expression is made up of one or more operands. Eg. x=
a+b.
Example:
void main()
{
int a=5, b=4, c;
c=a-b;
printf(“%d”,
c);
}
The following table show the division operator on various data types.
Operation Result Example
int/int int 2/5=0
real/int real 5.0/2=2.5
int/real real 5/2.0=2.5
real/real real 5.0/2.0=2.5
Arithmetic operators can be classified as
o Unary arithmetic – it requires only one operand.
Example: +a, -b
o Binary arithmetic – it requires two operands.
Example: a+b, a-b, a/b, a%b
o Integer arithmetic – it requires both operands to be integer type for
arithmetic operation.
Example:
a=4, b=3
a+b =4+3 =7
a-b =4-3=1
o Floating Point arithmetic – It requires both operands to be float type for
arithmetic operation.
Example:
a=6.5, b=3.5
a+b =6.5+3.5 =10.0
a-b =6.5-3.5=3.0
Program 1.3
#include<stdio.h>
#include<conio.h
> void main()
{
int b,c;
int sum, sub,
mul; float div;
clrscr();
printf(“enter the value of
b,c:”); scanf(“%d%d”, &b,
&c); sum=b+c;
sub=b-c;
mul=b*c
;
div=b/c;
printf(“\n sum=%d,sub=%d,mul=%d,div=
%f”,sum,sub,mul,div); getch();
}
Output:
Enter the value of b,c: 8 4
sum=12,sub=4,mul=32,div=
2
Syntax
AE1 operator AE2
where, AE- Arithmetic Expression or Variable or Value.
These operators provide the relationship between two expressions.
If the condition is true it returns a value 1, otherwise it returns 0.
These operators are used in decision making process. They are generally used in
conditional or control statement.
1.6.1.3 Logical Operators
Logical Operators are used to combine the result of two or more conditions.
The logical relationship between the two expressions is checked with logical
operators.
After checking the condition, it provides logical true (1) or false (0).
Operators Descriptions Example Return Value
&& Logical AND 5>3 && 1
5<10
|| Logical OR 8>5 || 8<2 1
!= Logical NOT 8!=8 0
&& - This operator is usually used in situation where two or more expressions
must be true.
Syntax:
(exp1) && (exp2)
|| – This is used in situation, where at least one expression is true.
Syntax:
(exp1) || (exp2)
! – This operator reverses the value of the expression it operates on. (i.e.,) it
makes a true expression false and false expression true.
Syntax:
!(exp1)
Program 1.4
/* Program using Logical operators */
#include<stdio.h>
#include<conio.h>
void main( )
{
clrscr( );
printf("\n Condition : Return values ");
printf("\n 5<=8 && 4>2: %5d",5<=8 && 4>2);
printf("\n 5>=3 || 6<8: %5d",5>=3 || 6<8);
printf("\n !(7==7): %5d",!(7==7));
getch( );
}
Output
Condition : Return values
5<=8 && 4>2 : 1
5>=3 || 6<8 : 1
!(7==7) : 0
Program 1.5
/* Program using Assignment and Short-hand Assignment operators */
#include<stdio.h>
#include<conio.h
> void main( )
{
int a=20,b=10,c=15,d=25,e=34,x=5;
clrscr( );
printf("\n Value of a=
%d",a); printf("\n Value of
b=%d",b); a+=x;
b- =x;
c*=x;
d/=x;
e
%=x;
printf("\n Value of a=
%d",a); printf("\n Value of
b=%d",b); printf("\n Value
of c=%d",c); printf("\n Value
of d=%d",d); printf("\n
Value of e=%d",e); getch();
Outpu }
t
Value of a = 20
Value of b = 10
Value of a = 25
Value of b = 5
Value of c = 75
Value of d = 5
Value of e = 4
Pre-increment operator
This operator increment the value of a variable first and then perform other
actions.
Program 1.6
#include
<stdio.h> void
main()
{
int
a,b;
a=10;
b=++a;
printf(“a=
%d”,a);
printf(“b=%d”,b);
}
output: a=11
b=11 #include
<stdio.h> void
main()
{
int
a,b;
a=10;
b=—a; printf(“a=
%d”,a);
printf(“b=%d”,b);
}
Output:
a=9 b=9
Post-increment operator
This operator perform other actions first and then increment the value of a
variable.
Program 1.7
#include
<stdio.h> void
main()
{
int
a,b;
a=10;
b=a++;
printf(“a=
%d”,a);
printf(“b=%d”,b);
}
Output:
a=11 b=10
Program 1.8
#include
<stdio.h> void
main()
{
int
a,b;
a=10;
b=a--; printf(“a=
%d”,a);
printf(“b=%d”,b);
}
Output:
a=9 b=10
a) Comma operator(,):
The comma operator is used to separate the statement elements such as
variables, constants or expression etc.,
This operator is used to link the related expression together.
Such expression can be evaluated from left to right and the value of right most
expression is the value of combined expression.
Example:
val=(a=3,b=9,c=77,a+c);
Where,
First assigns the value 3 to a
Second assigns the value 9 to b
Third assigns the value 77 to c
Last assigns the value 80.
b) The sizeof() operator:
The sizeof() is a unary operator that returns the length in bytes of the specified
variable and it is very useful to find the bytes occupied by the specified variable
in memory.
Syntax:
sizeof(var);
Example:
void main()
{
int a;
printf(“size of variable a is…%d”, sizeof(a));
}
Output:
size of variable a is…….2
c) Pointer operator:
& : This symbol specifies the address of the variable.
* : This symbol specifies the value of the variable.
d) Member selection operator:
. and — >: These symbols are used to access the elements from a structure.
1.7 EXPRESSIONS AND STATEMENTS
1.7.1 Expressions
An expression represents data item such as variables, constants and are
interconnected with operators as per the syntax of the language.
An expression is evaluated using assignment operators.
Syntax
Variable = expression;
Example: 1
x=a*b-c;
In example 1, the expression evaluated from left to right. After the evaluation of
the expression the final value is assigned to the variable from right to left.
Example: 2
a++;
In example 2, the value of variable a is incremented by 1, i.e, this expression is
equivalent to a = a + 1.
1.7.2 Statements
A statement is an instruction given to the computer to perform an action. There
are three different types of statements in C:
1. Expression Statements
2. Compound Statements
3. Control Statements
Expression Statement
An expression statement or simple statement consists of an expression followed
by a semicolon (;).
Example
a=100;
b=20;
c=a/b;
Compound Statement
A compound statement also called a block, consists of several individual
statements enclosed within a pair of braces { }.
Example
{
a=3;
b=10;
c=a+b;
}
Control Statement
A single statement or a block of statements can be executed depending upon a
condition using control statements like if, if-else, etc.
Example
a=10;
if (a>5)
{
b= a+10;
}
else
{
statements4;
}
In this statement, if the expression1 is true, statements1 will be executed,
otherwise the expression2 is evaluated, if it is true then statements2 is executed,
otherwise the expression3 is evaluated, if it is true then statements3 is executed,
otherwise statements4 is executed.
Program 1.20
/* Program to Generate the Even numbers to a given limit*/
#include<stdio.h>
#include<conio.h
> void main()
{
int n,i;
printf(“\n Enter the
limit:”); scanf(“%d”,&n);
i=1;
while(i<=n)
{ if(i
%2==0)
printf(“%d\
t”,i); i++;
}
getch( );
}
Output
Enter the limit: 10
2 4 6 8 10
Do While Statement
The do while loop varies from the while loop in the checking condition. The
condition of the loop is not tested until the body of the loop has been executed
once. If the condition is false, after the first loop iteration the loop terminates.
The statements are executed atleast once even if the condition fails for the first
time itself. It is otherwise called as exit control loop.
return_type function_name(argument_list)
{
//function body
}
Example
int add(int x, int y)
{
int z;
z=x+y
;
return(z);
}
Program 1.26
#include<stdio.h>
// function prototype, also called function
declaration float square ( float x );
// main function, program starts from
here int main( )
{
float m, n ;
printf ( "\nEnter some number for finding square \
n"); scanf ( "%f", &m ) ;
// function call
n = square ( m ) ;
printf ( "\nSquare of the given number %f is %f",m,n );
}
float square ( float x ) // function definition
{
float p ;
p=x*x;
return ( p ) ;
}
Output
Before swapping:
num1 value is 35
num2 value is 45
After swapping:
num1 value is 45
num2 value is 35
1.11 ARRAYS
Introduction to Arrays
An Array is a collection of similar data elements
These data elements have the same data type
The elements of the array are stored in consecutive memory locations and are
referenced by an index
Definition
An array is a data structure that is used to store data of the same type. The
position of an element is specified with an integer value known as index or
subscript.
Example
type name[size]
Here the type can be either int, float, double, char or any other valid data type. The
number within the brackets indicates the size of the array, i.e., the maximum number of
elements that can be stored in the array.
Example: i) int marks[10]
ii) int a[5]={10,20,5,56,100}
The declaration of an array tells the compiler that, the data type, name of the
array, size of the array and for each element it occupies memory space. Like for int data
type occupies 2 bytes for each element and for float occupies 4 bytes for each element
etc. The size of the array operates the number of elements that can be stored in an array.
1.11.2 Initialization of arrays
Elements of the array can also be initialized at the time of declaration as in the
case of every other variable. When an array is initialized, we need to provide a value for
every element in the array. Arrays are initialized using the following syntax:
type array_name [size] = { list of values};
The values are written with curly brackets and every value is separated by a comma.
It is a compiler error to specify more number of values than the number of elements in
the array.
Example: int marks [5] = {90, 92, 78, 82, 58};
Example
int a[4]; // a is an array of 4 integers
char b[6]; //b is an array of 6
characters
1.12.2 Initialization of single dimensional array
Elements of an array can also be initialized. After declaration, the array elements
must be initialized otherwise they hold garbage value. An array can be initialized
at compile time or at run time.
Elements of an array can be initialized by using an initialization list. An
initialization list is a comma separated list of initializers enclosed within braces.
Example
1. int a[3]={1,3,4};
2. int i[5] ={1, 2, 3, 4, 5};
3. float a[5]={1.1, 2.3, 5.5, 6.7, 7.0};
4. int b[ ]={1,1,2,2};
In the fourth example the size has been omitted (it can be) and have been
declared as an array with 4 elements having 1, 1, 2 and 2 as initial values.
Character arrays that hold strings allow a shortcut initialization of the form:
char array_name[size]=”string”
For example,
char mess[ ]={‘w’,‘e’,‘l’,‘c’,‘o’,‘m’,‘e’};
If the number of initializers in the list is less than array size, the leading array
locations gets initialized with the given values. The rest of the array locations
gets initialized to
0 - for int array
0.0 - for float array
\0 - for character array
Example
int a[2]={1}; a
1 0
char b[5]={‘A’.’r’,’r’}; b
‘A’ ‘r’ ‘r’ ‘\0’ ‘\0’
Example Programs
Program 1.32
/*Program to find the maximum number in an array * /
#include<stdio.h
> void main( )
{
int a[5], i, max;
printf(“Enter 5 numbers one by one \
n”); for(i=0;i<5;i++)
{
scanf(“%d”, & a[i]);
}
max=a[0];
for(i=1;i<5;i+
+)
{
if (max<a[i])
max =a[i];
}
printf(“\n The maximum number in the array is %d”,max);
getch( ) ;
}
Output:
Enter 5 numbers one by one
57364
The maximum number in the array is 7
Program 1.33
/*Program for reversing an array*/
#include<stdio.h
> void main( )
{
int a[10],
i; int n;
printf(“Enter the maximum number of elements\
n”); scanf(“%d”, &n);
for(i=0; i<n; i++)
{
scanf(“%d”,&a[i]);
}
printf(“Array in the reverse order\
n”); for(i=n–1; i>=0; i--)
{
printf(“%d\t”, a[i]);
}
getch( );
}
Output
Enter the maximum number of elements
5 11 12 13 14 15
Array in the reverse order
15 14 13 12 11
Program 1.34
/* Program to calculate sum of array content */
#
include<stdio.h>
void main( )
{
int a[20], n, i, sum = 0;
print f(“\n Enter the size of the array:”);
scanf(“%d”, &n)
printf (“\n Enter the %d numbers one by
one:”); for (i=0; i<n; i++)
{
scanf(“%d”,
&a[i]); sum = sum
+ a[i];
}
printf (“The sum of array content = %d”,
sum); getch( );
}
Output
Declaration
datatype arrayname [row size][column size]
a 1 4 6
2 0 0
}
}
/* Program module to sum colwise
*/ for(i=0;i<n;i++)
{
colsum=0;
for(j=0;j<n1;j+
+) colsum+=a[j]
[i];
printf(“col no=%d sum=%d\n “,i,colsum);
}
/ * Program module to sum principle diagonal * /
diasum=0;
for(i=0;i<n;i++)
for(j=0;j<n1;j++)
if(i==j) diasum+=a[i]
[j];
printf(“Principle diagonal sum %d\n”,diasum);
/ * Program module to sum off diagonal */
diasum=0;
for(i=0;i<n;i+
+)
{
j= -n1;
diasum +=a[i][j];
} }
Output printf(“Off diagonal sum%d\n”,diasum);
Enter order [row][col] of the matrix
33
Enter 9 elements
123456789
Sum of all elements 45
row no = 0 sum = 6
row no = 1 sum = 15
row no = 2 sum = 24
col no = 0 sum = 12
col no = 1 sum = 15
col no = 2 sum = 18
Principle diagonal sum 15
Off diagonal sum 15
1.13.2 Three-Dimensional
Arrays Initialization of a 3d
array
Initialize a three-dimensional array in a similar way to a two-dimensional array.
Example
int test[2][3][4] = {
{{3, 4, 2, 3}, {0, -3, 9, 11}, {23, 12, 23, 2}},
{{13, 4, 56, 3}, {5, 9, 3, 5}, {3, 1, 4, 9}}};
Program 1.36
Write a C Program to store and print 12 values entered by the user
#include <stdio.h>
int main()
{
int test[2][3][2];
printf("Enter 12 values: \n");
for (int i = 0; i < 2; ++i)
{
for (int j = 0; j < 3; ++j)
{
for (int k = 0; k < 2; ++k)
{
scanf("%d", &test[i][j][k]);
}
}
}
// Printing values with the proper index.
printf("\nDisplaying values:\n");
for (int i = 0; i < 2; ++i)
{
for (int j = 0; j < 3; ++j)
{
for (int k = 0; k < 2; ++k)
{
printf("test[%d][%d][%d] = %d\n", i, j, k, test[i][j][k]);
}
}
}
return 0;
}
Output
Enter 12 values:
1
2
3
4
5
6
7
8
9
10
11
12
Displaying Values:
test[0][0][0] = 1
test[0][0][1] = 2
test[0][1][0] = 3
test[0][1][1] = 4
test[0][2][0] = 5
test[0][2][1] = 6
test[1][0][0] = 7
test[1][0][1] = 8
test[1][1][0] = 9
test[1][1][1] = 10
test[1][2][0] = 11
test[1][2][1] = 12
REVIEW QUESTIONS
PART-A
1. List down the Primary Data Types in C
Integer – We use these for storing various whole numbers, such as 5, 8, 67,
2390, etc.
Character – It refers to all ASCII character sets as well as the single alphabets,
such as ‘x’, ‘Y’, etc.
Double – These include all large types of numeric values that do not come
under either floating-point data type or integer data type.
Floating-point – These refer to all the real number values or decimal points,
such as 40.1, 820.673, 5.9, etc.
Void – This term refers to no values at all. We mostly use this data type when
defining the functions in a program.
2. What is Variable?
Variables are containers for storing data values.
Its value can be changed, and it can be reused many times.
Syntax for creating variables
type variableName = value;
Example: int a = 5;
3. What is Operator?
An operator is a special symbol that tells the compiler to perform specific
mathematical or logical operations.
Operators in programming languages are taken from mathematics.
C language supports a rich set of built-in operators.
4. List the types of operators supported in C
Arithmetic operators
Relational operators
Logical operators
Bitwise operators
Assignment operators
Type Information Operators(Special operators)
5. What is Ternary operators or Conditional operators?
Ternary operators is a conditional operator with symbols? and :
Syntax: variable = exp1 ? exp2 : exp3
If the exp1 is true variable takes value of exp2. If the exp2 is false, variable
takes the value of exp3.
6. What is an Operator and Operand?
An operator is a symbol that specifies an operation to be performed on
operands.
Example: *, +, -, / are called arithmetic operators.
The data items that operators act upon are called operands.
7. What is type casting?
Type casting is the process of converting the value of an expression to a
particular data type.
Example: int x,y.
c = (float) x/y; where a and y are defined as integers. Then the result of x/y is
converted into float.
8. What is the difference between while loop and do while loop?
while do while
In the while loop the condition is first In the do…while loop first the
executed. statement is executed and then the
condition is checked.
If the condition is true, then it executes The do…while loop will execute at
the body of the loop. When the least one time even though the
condition is false it comes of the loop. condition is false at the very first time.
Interpreters usually take less amount of Compilers usually take a large amount
time to analyze the source code. of time to analyze the source code.
However, the overall execution time is However, the overall execution time is
comparatively slower than compilers. comparatively faster than interpreters.
No Object Code is generated, hence are Generates Object Code which
memory efficient. further requires linking, hence
requires more memory.
Programming languages like Programming languages like C, C++,
JavaScript, Python, Ruby use Java use compilers.
interpreters.
PART-B
1. Explain the different types of operators with neat examples.
2. Illustrate the different conditional statements available in C with syntax and
examples
3. Explain the looping statements with neat examples.
4. What is an Array? Explain Single and Multi-Dimensional arrays with neat examples.
5. Write a C program for Matrix Multiplication with a 3*3 matrix.
6. Create a C program for Matrix Addition.
7. Write a C program to calculate the total, average and grade for 50 Students.
8. Write a C program to calculate the factorial of a given number.
9. Write a C program to check whether a given number is odd or even.
10. Write a C program to check whether a given number is prime or not.
11. Write a C program to check whether a given number is a palindrome or not.
12. Write a C program to check whether a given number is a Armstrong number or not.
II
PROGRAMMING - ADVANCED FEATURES
Structures – Union – Enumerated Data Types – Pointers: Pointers to Variables, Arrays
and Functions – File Handling – Preprocessor Directives.
2.1 INTRODUCTION
Structures, unions and enumerations are known as user defined data types.
These data types are used to create a flexible new data type.
Structure can be used for the storage of different data types. The similarity
between structure and array is both contain a finite number of elements.
Union is similar to structures in all aspects except the manner in which their
constituent elements are stored.
In structures, separate memory is allocated to each element, while in unions all
the elements are share the same memory.
Enumeration helps to define a data type whose objects can take a limited set of
values.
2.2 STRUCTURE
Definition
A Structure is a collection of variables of different data types under a single
name and provides a convenient way of grouping several of related information
together.
Unlike arrays, it can be used for the storage of heterogeneous data (data of
different data types).
2.3 UNION
Union can be defined as a user-defined data type which is a collection of
different variables of different data types in the same memory location. The
union can also be defined as many members, but only one member can contain a
value at a particular point in time. Unions provide an efficient way of using the
same memory location for multiple-purpose.
Union is a user-defined data type, but unlike structures, they share the same
memory location.
Defining a Union
To define a union, you must use the union statement in the same way as did
while defining a structure. The union statement defines a new data type with
more than one member for your program. The format of the union statement is
as follows:
union [union tag] {
member definition;
member definition;
...
member definition;
} [one or more union variables];
The union tag is optional and each member definition is a normal variable
definition, such as int i; or float f; or any other valid variable definition. At the end
of the union's definition, before the final semicolon, you can specify one or more
union variables but it is optional. Here is the way you would define a union type
named Data having three members i, f, and str.
union Data {
int i;
float f;
char str[20];
} data;
Now, a variable of Data type can store an integer, a floating-point number, or a
string of characters. It means a single variable, i.e., same memory location, can be
used to store multiple types of data. You can use any built-in or user defined data
types inside a union based on your requirement.
Example Program 2.9 Illustration of Union
#include <stdio.h>
#include <string.h>
union Data {
int i;
float f;
char str[20];
};
void main( ) {
union Data data;
data.i = 10;
printf( "data.i : %d\n", data.i);
data.f = 220.5;
printf( "data.f : %f\n", data.f);
strcpy( data.str, "Charulatha publication");
printf( "data.str : %s\n", data.str);
}
Output
data.i : 10
data.f : 220.500000
data.str : Charulatha publication
Difference between Structure and Union
Sl.No Structure Union
1 The member of a structure occupies The member of union share same
its own memory space. memory space.
2 The keyword struct is used to define The keyword union is used to define a
a structure structure
3 All the members of a structure can Only the first member of a union can
be initialized. be initialized.
4 In structure, each member is stored In union, all members are stored in
in a separate memory location. So the same memory locations. So, need
need more memory space. less memory space.
2.4 POINTERS
2.4.1 Pointers to Variables
A pointer is a variable that stores an address of another variable of same type.
Pointer can have any name that is legal for other variable.
Pointer variables are declared with prefix of ‘*’ operator.
Using a pointer variable, we can access the value of another variable assigned
to it.
Syntax
data_type *pointer_name;
Example
int *a;
variable *a can store the address of any integer type variable.
A pointer is a variable whose value is also an address.
Each variable has two attributes
Value
Address
We can define pointers in two ways.
i) First a pointer is a variable and assigns different values to a pointer variable.
ii) Second the value contained by a pointer must be an address which indicates the
location of another variable in the memory. So, pointer is called as “address
variable”.
Example
int
a=50;
int *ptr;
ptr=&a;
Here ‘a’ is a variable holds a value 50 and stored in a memory location 1001.
‘*ptr’ is pointer variable holds a address of a variable ‘a’.
Advantages of Using Pointers
Pointers are more compact and efficient code.
Pointers can be used to achieve clarity and simplicity.
Pointers are used to pass information between function and its reference point.
A pointer provides a way to return multiple data items from a function using its
function arguments.
Pointers also provide an alternate way to access an array element.
A pointer enables us to access the memory directly.
Example Program 2.10
/*C program for printing value and address of a variable using pointer variable*/
#include<stdio.h>
#include<conio.h
> void main()
{
int i=3;
int
*ptr;
ptr=&i
;
clrscr()
;
printf(“Address of i=%u\
n”,ptr); printf(“value of i=%d\
n”,*ptr); getch();
}
Output:
Address of i=65524
value of i=3
Example Program 2.11
/*C program for printing value and address of a variable using pointer variable
by various methods*/
#include<stdio.h>
#include<conio.h
> void main()
{
int i=4;
int *j;
j=&i;
clrscr()
;
printf(“Address of i=%u\n”,&i);
printf(“Address of i=%u\n”,j);
printf(“Address of j=%u\n”,&j);
printf(“value of j=%u\n”,j);
printf(“value of i=%d\n”,i);
printf(“value of i=%d\
n”,*(&i)); printf(“value of i=
%d\n”,*j); getch();
}
Output
Address of i=65524
Address of i=65524
Address of j=65522
value of j=65524
value of i=4
value of i=4
value of i=4
Example Program 2.12
/*C program to add two numbers using pointers*/
#include<stdio.h>
#include<conio.h
>
void main()
{
int
a,b,*p,*q,sum;
clrscr();
printf(“Enter two
integers”); scanf(“%d
%d”,&a,&b); p=&a;
q=&b;
sum=*p+*q
;
printf(“sum=
%d”,sum); getch();
}
Output
Enter two integers 2 3
sum=5
1. fopen () : It creates a new file for use or opens an existing file for use.
2. fclose (): It closes a file which has been opened for use.
3. fscanf( file pointer, format string, address of the
variable) Example: fscanf(fptr,”%d”, &num);
4. fprintf(console output, “format string”, file pointer);
Example: fprintf(stdout, “%f \n”, f); /*note: stdout refers to screen */
5. getw (): This function returns the integer value from a given file and increment the
file pointer position to the next message.
Syntax: getw (fptr);
Where fptr is a file pointer which takes the integer value from file.
6. putw (): This function is used for writing an integer value to a given
file. Syntax: putw (value,fptr);
Where fptr is a file pointer Value is an integer value which is written to a given file.
Example Program for getw() and putw()
Program 2.24: Write a program to read integer data from the user and write it
into the file using putw() and read the same integer data from the file using getw()
and display it on the output screen.
#include<stdio.h>
#include<conio.h
> void main()
{
FILE *fp;
int n;
clrscr()
;
fp=fopen(“c.dat”, “wb+”);
printf(“Enter the integer
data”); scanf(“%d”,&n);
while(n!=0)
{
putw(n,fp)
; scanf(“%d”,&n);
}
rewind(fp);
printf(“Reading data from
file”); while((n=getw(fp))!
=EOF)
{
printf(“%d\n”,n);
}
fclose(fp)
; getch();
}
7. fwrite()
This function is used for writing an entire block to a given file.
Syntax: fwrite(ptr,size,nst,fptr);
ptr is a pointer ,it points to the array of structure.
Size is the size of the structure
nst is the number of the structure
fptr is a filepointer.
8. fread()
fread(ptr,size,position,fptr);similar to fwrite
9. fflush(stdin);To clean the input stream
Program 2.25: program for fwrite():
Write a program to read an employee details and write them into the file at a time
using fwrite().
#include<stdio.h>
#include<conio.h
> void main()
{
struct emp
{
int eno;
char
ename[20];
float sal;
}e;
FILE *fp;
fp=fopen(“emp.dat”,
“wb”); clrscr();
printf(“Enter employee
number”); scanf(“&d”,&e.eno);
printf(“Enter employee name”);
fflush(stdin);
scanf(“%s”,e.ename);
printf(“Enter employee salary”);
scanf(“%f”,&e.sal);
fwrite(&e,sizeof(e),1,fp);
printf(“One record stored
successfully”); getch();
}
Operations for Search data in a file
1. fseek()
2. ftell()
3. rewind()
fseek() : Getting data using fseek()
When many records inside a file and need to access a record at a specific
position, you need to loop through all the records before it to get the record. This
will waste a lot of memory and operation time. An easier way to get to the
required data can be achieved using fseek().
Syntax of fseek()
fseek(FILE * stream, long int offset, int whence)
fseek(file pointer, displacement, pointer position);
The first parameter stream is the pointer to the file. The second parameter is the
position of the record to be found, and the third parameter specifies the location
where the offset starts.
This function is used for seeking the pointer position in the file at the specified
byte.
Syntax: fseek( file pointer, displacement, pointer position);
file pointer - It is the pointer which points to the file.
displacement -It is positive or negative.
This is the number of bytes which are skipped backward (if negative) or forward
(if positive) from the current position. This is attached with L because this is a
long integer.
Pointer position: This sets the pointer position in the file.
Value Pointer position Value Pointer position
0 Beginning of file.
1 Current position
2 End of file
Example:
1. fseek( p,10L,0)
This 0 means pointer position is on beginning of the file, from this statement
pointer position is skipped 10 bytes from the beginning of the file.
2. fseek( p,5L,1)
This 1 means current position of the pointer position. From this statement
pointer position is skipped 5 bytes forward from the current position.
3. fseek(p,-5L,1):
From this statement pointer position is skipped 5 bytes backward from the
current position.
User can only use the function but User can use this type of function.
cannot change (or) modify this function. User can also modify this function.
PART-B
Figure 3.1 shows the ADT model. There are two types of models in the ADT
model, i.e., the public function and the private function. The ADT model also contains
the data structures that we are using in a program. In this model, first encapsulation is
performed, i.e., all the data is wrapped in a single unit, i.e., ADT. Then, the abstraction
is performed means showing the operations that can be performed on the data structure
and what are the data structures that we are using in a program
Space Complexity
In array, space complexity for worst case is O(n).
2. Space Complexity
Operation Space complexity
Insertion O(n)
Deletion O(n)
Search O(n)
Fig. 3.5
Fig. 3.5: Sample node in a doubly linked list
A doubly linked list containing three nodes having numbers from 1 to 3 in their
data part, is shown in Fig 3.6
Fig. 3.13: Deletion of a specified node in Doubly Linked List at the end
3.6.2.5 Searching
Searching in circular singly linked list needs traversing across the list.
The item which is to be searched in the list is matched with each node data of
the list once.
If the match found then the location of that item is returned otherwise -1 is
returned.
Algorithm 3.13
STEP 1: SET PTR = HEAD
STEP 2: Set I = 0
STEP 3: IF PTR = NULL
WRITE "EMPTY LIST"
GOTO STEP 8
END OF IF
STEP 4: IF HEAD → DATA = ITEM
WRITE i+1 RETURN [END OF IF]
STEP 5: REPEAT STEP 5 TO 7 UNTIL PTR->next != head
STEP 6: if ptr → data = item
write i+1
RETURN
End of IF
STEP 7: I = I + 1
STEP 8: PTR = PTR → NEXT
[END OF LOOP]
STEP 9: EXIT
3.6.2.5 Searching
Traversing in circular singly linked list can be done through a loop.
Initialize the temporary pointer variable temp to head pointer and run the while
loop until the next pointer of temp becomes head.
Algorithm 3.14
STEP 1: SET PTR = HEAD
STEP 2: IF PTR = NULL
WRITE "EMPTY LIST"
GOTO STEP 8
END OF IF
STEP 4: REPEAT STEP 5 AND 6 UNTIL PTR → NEXT != HEAD
STEP 5: PRINT PTR → DATA
STEP 6: PTR = PTR → NEXT
[END OF LOOP]
STEP 7: PRINT PTR→ DATA
STEP 8: EXIT
elements.
Fig. 3.20: Working principle of a Stack
Let's take the example of Converting an infix expression into a postfix expression
In the above example, the only change from the postfix expression is that the
operator is placed before the operands rather than between the operands.
Evaluating Postfix expression
Stack is the ideal data structure to evaluate the postfix expression because the
top element is always the most recent operand. The next element on the Stack is
the second most recent operand to be operated on.
Before evaluating the postfix expression, the following conditions must be
checked. If any one of the conditions fails, the postfix expression is invalid.
When an operator encounters the scanning process, the Stack must contain a pair
of operands or intermediate results previously calculated.
When an expression has been completely evaluated, the Stack must contain
exactly one value.
Example 3.7
Now let us consider the following infix expression 2 * (4+3) - 5.
Its equivalent postfix expression is 2 4 3 + * 5.
The following step illustrates how this postfix expression is evaluated.
For tracing the algorithm let us assume that the input is () (() [()])
Input Symbol Operation Stack Output
( Push ( (
) Pop (
Test if ( and A[i] match? YES
( Push ( (
( Push ( ((
) Pop ( (
Test if ( and A[i] match? YES
[ Push [ ([
( Push ( ([(
) Pop ) )
Test if ( and A[i] match? YES
] Pop [ (
Test if [ and A[i] match? YES
) Pop (
Test if ( and A[i] match? YES
Test if Stack is Empty? YES TRUE
3.9.4 Backtracking
Backtracking is used in algorithms in which there are steps along some path
(state) from some starting point to some goal. It uses recursive calling to find the
solution by building a solution step by step increasing values with time. It
removes the solutions that doesn't give rise to the solution of the problem based
on the constraints given to solve the problem.
Let’s see how Stack is used in Backtracking in the N-Queens Problem
For the N-Queens problem, one way we can do this is given by the following:
For each row, place a queen in the first valid position (column), and then
move to the next row
If there is no valid position, then one backtracks to the previous row and try
the next position
If one can successfully place a queen in the last row, then a solution is found.
Now backtrack to find the next solution
We can use a stack to indicate the positions of the queens. Importantly, notice
that we only have to put the column positions of the queens on the stack. We can
determine each queen's coordinates given only the stack. We simply combine
the position of an element in the stack (the row) with the value of that element
(the column) for each queen.
Two examples of this are shown below:
Starting with a queen in the first row, first column (represented by a stack
containing just "0"), we search left to right for a valid position to place another
queen in the next available row.
If we find a valid position in this row, we push this position (i.e., the column
number) to the stack and start again on the next row.
If we don't find a valid position in this row, we backtrack to the previous row --
that is to say, we pop the col position for the previous row from the stack and
search for a valid position further down the row.
Note, when the stack size gets to n, we will have placed n queens on the board,
and therefore have a solution.
Of course, there is nothing that requires there be only one solution. To find the
rest, every time a solution is found, we can pretend it is not a solution, backtrack
to the previous row, and proceed to find the next solution.
Ultimately, every position in the first row will be considered. When there are not
more valid positions in the first row and we need to backtrack, that's our cue that
there are no more solutions to be found. Thus, we may stop searching when we
try to pop from the stack, but can't as it is empty.
Putting all this into pseudo-code form, we have the following algorithm...
Create empty stack and set current position to 0
Repeat {
loop from current position to the last position until valid position found //current
row
if there is a valid position {
push the position to stack, set current position to 0 // move to next row
}
if there is no valid position {
if stack is empty, break // stop search
else pop stack, set current position to next position // backtrack to previous
row
}
if stack has size N { // a solution is found
pop stack, set current position to next position // backtrack to find next
solution
}
}
3.11.6 Heap
A heap is a tree-based data structure that forms a complete binary tree, and
satisfies the heap property.
If A is a parent node of B, then A is ordered with respect to the node B for all
nodes A and B in a heap.
It means that the value of the parent node could be more than or equal to the
value of the child node, or the value of the parent node could be less than or
equal to the value of the child node.
Therefore, we can say that there are two types of heaps:
Then, heapify operation is implemented. After which, the heap will look like this:
3.11.7.2 Removing the minimum element from the priority queue
In a max heap, the maximum element is the root node. When we remove the root
node, it creates an empty slot. The last inserted element will be added in this empty slot.
Then, this element is compared with the child nodes, i.e., left-child and right child, and
swap with the smaller of the two. It keeps moving down the tree until the heap property
is restored.
Algorithm 3.19:
START
If node that needs to be deleted is a leaf node:
Remove the node
Else:
Swap node that needs to be deleted with the last leaf node present.
Remove the node
Heapify
END
Let us now see with an example how this works:
Example: 3.11
Let’s say the elements are 1,4,2,7,8,5,6. The max-heap of these elements would look like:
Now, let’s try to delete an element, 6. Since this is not a leaf node, we swap it with the
last leaf node so it looks like this:
Then, we remove the leaf node so it looks like this:
Then, heapify operation is implemented. After which, the heap will look like this:
Understandability: ADT specifies what is to be done and does not specify the
implementation details. Hence code becomes easy to understand due to ADT.
Reusability: the ADT can be reused by some program in future.
20. What is queue ADT?
Queue is an abstract data structure, somewhat like Stacks. Unlike stacks, a
queue is open at both its ends. One end is always used to insert data (enqueue)
and the other is used to remove data (dequeue). Queue follows First-In-First-
Out methodology, i.e., the data item stored first will be accessed first.
21. What is priority queue
A priority queue is a special type of queue in which each element is associated
with a priority value. Elements are served on the basis of their priority. That is,
higher priority elements are served first. However, if elements with the same
priority occur, they are served according to their order in the queue.
22. What is stack?
Stack is an abstract data type that serves as a collection of elements, with two
main operations: Push, which adds an element to the collection, and Pop,
which removes the most recently added element that was not yet removed.
23. How is Stack represented in Data Structure?
A stack may be represented in the memory in various ways. There are two
main ways: using a one-dimensional array and a single linked list.
24. List some applications of queue data structure.
Managing requests on a single shared resource such as CPU scheduling and
disk scheduling.
Handling hardware or real-time systems interrupts.
Handling website traffic.
Routers and switches in networking.
Maintaining the playlist in media players.
25. List some applications of stack data structure.
A Stack can be used for evaluating expressions consisting of operands and
operators.
Stacks can be used for Backtracking, i.e., to check parenthesis matching in an
expression.
C Programming and Data Structures 3.81
It can also be used to convert one form of expression to another form. It can be
used for systematic Memory Management.
PART B
Here,
Node A is the root node
B is the parent of D and E
4.2 Non – Linear Data Structures
Here, the root node is A. All the nodes on the left of A are a part of the left
subtree whereas all the nodes on the right of A are a part of the right subtree.
Thus, according to preorder traversal, we will first visit the root node, so A
will print first and then move to the left subtree.
B is the root node for the left subtree. So B will print next, and we will visit
the left and right nodes of B. In this manner, we will traverse the whole left
subtree and then move to the right subtree. Thus, the order of visiting the
nodes will be A→B→C→D→E→F→G→H→I.
Algorithm for Preorder Traversal
o for all nodes of the tree:
Step 1: Visit the root node.
Step 2: Traverse left subtree recursively.
Step 3: Traverse right subtree recursively.
Pseudo-code for Preorder Traversal
void Preorder(struct node* ptr)
{
if(ptr != NULL)
{
printf("%d", ptr->data);
Preorder(ptr->left);
Preorder(ptr->right);
}
}
Uses of Preorder Traversal
o If we want to create a copy of a tree, we make use of preorder
traversal.
o Preorder traversal helps to give a prefix expression for the
expression tree.
Inorder Traversal
In an inorder traversal, we first visit the left subtree, then the root node and
then the right subtree in an inorder manner.
Consider the following tree:
In this case, as we visit the left subtree first, we get the node with the value
30 first, then 20 and then 40. After that, we will visit the root node and print
it. Then comes the turn of the right subtree. We will traverse the right
subtree in a similar manner. Thus, after performing the inorder traversal, the
order of nodes will be 30→20→40→10→50→70→60→80.
Algorithm for Inorder Traversal
o for all nodes of the tree:
Step 1: Traverse left subtree recursively.
Step 2: Visit the root node.
Step 3: Traverse right subtree recursively.
Pseudo-code for Inorder Traversal
void Inorder(struct node* ptr)
{
if(ptr != NULL)
{
Inorder(ptr->left);
printf("%d", ptr-
>data); Inorder(ptr-
>right);
}
}
Uses of Inorder Traversal
o It helps to delete the tree.
o It helps to get the postfix expression in an expression tree.
Postorder Traversal
Postorder traversal is a kind of traversal in which we first traverse the left
subtree in a postorder manner, then traverse the right subtree in a postorder
manner and at the end visit the root node.
For example, in the following tree:
The postorder traversal will be 7→5→4→20→60→30→10.
Algorithm for Postorder Traversal
o or all nodes of the tree:
Step 1: Traverse left subtree recursively.
Step 2: Traverse right subtree recursively.
Step 3: Visit the root node.
Pseudo-code for Postorder Traversal
void Postorder(struct node* ptr)
{
if(ptr != NULL)
{
Postorder(ptr->left);
Postorder(ptr->right);
printf(“%d”, ptr->data);
}
}
Uses of Postorder Traversal
o It helps to delete the tree.
o It helps to get the postfix expression in an expression tree.
4.4 EXPRESSION TREES
The expression tree is a tree used to represent the various expressions. The tree
data structure is used to represent the expressional statements. In this tree, the
internal node always denotes the operators. The leaf nodes always denote the
operands.
For example, expression tree for 3 + ((5+9)*2) would be:
o Next, read a'+' symbol, so two pointers to tree are popped, a new tree is
formed and push a pointer to it onto the stack.
o Next, 'c' is read, we create one node tree and push a pointer to it onto the
r
stack.
o Finally, the last symbol is read ' * ', we pop two tree pointers and form a
new tree with a, ' * ' as root, and a pointer to the final tree remains on
the stack.
In the above figure, we can observe that the root node is 40, and all the nodes of
the left subtree are smaller than the root node, and all the nodes of the right
subtree are greater than the root node.
Similarly, we can see the left child of root node is greater than its left child and
smaller than its right child. So, it also satisfies the property of binary search tree.
Therefore, we can say that the tree in the above image is a binary search tree.
Step 6 - Insert 55
o 55 is larger than 45 and smaller than 79, so it will be inserted as the left
subtree of 79.
Step 7 - Insert 12
o 12 is smaller than 45 and 15 but greater than 10, so it will be inserted as the
right subtree of 10.
Step 8 - Insert 20
o 20 is smaller than 45 but greater than 15, so it will be inserted as the right
subtree of 15.
Step 9 - Insert 50.
o 50 is greater than 45 but smaller than 79 and 55. So, it will be inserted as a
left subtree of 55.
Step2:
Step3:
4.5.3.1.2 Algorithm to search an element in Binary search tree
Search (root, item)
Step 1 - if (item = root → data) or (root = NULL)
return root
else if (item < root → data)
return Search(root → left, item)
else
return Search(root → right, item)
END if
Step 2 - END
4.6 HASHING
Hashing in the data structure is a technique of mapping a large chunk of data
into small tables using a hashing function. It is also known as the message digest
function. It is a technique that uniquely identifies a specific item from a
collection of similar items.
It uses hash tables to store the data in an array format. Each value in the array
has been assigned a unique index number. Hash tables use a technique to
generate these unique index numbers for each value stored in an array
format. This technique is called the hash technique.
You only need to find the index of the desired item, rather than finding the data.
With indexing, you can quickly scan the entire list and retrieve the item you
wish. Indexing also helps in inserting operations when you need to insert data at
a specific location. No matter how big or small the table is, you can update and
retrieve data within seconds.
The hash table is basically the array of elements, and the hash techniques of
search are performed on a part of the item i.e. key. Each key has been mapped to
a number, the range remains from 0 to table size 1
Types of hashing in data structure is a two-step process.
o The hash function converts the item into a small integer or hash value. This
integer is used as an index to store the original data.
o It stores the data in a hash table. You can use a hash key to locate data
quickly.
4.6.1 Examples
In schools, the teacher assigns a unique roll number to each student. Later, the
teacher uses that roll number to retrieve information about that student.
A library has an infinite number of books. The librarian assigns a unique number
to each book. This unique number helps in identifying the position of the books
on the bookshelf.
The lookup cost will be scanning all the entries of the selected linked list for the
required key. If the keys are uniformly distributed, then the average lookup cost
will be an average number of keys per linked list.
Step 2: Now we will insert all the keys in the hash table one by one. First key to
be inserted is 24. It will map to bucket number 0 which is calculated by using
hash function 24%6=0.
Step 3: Now the next key that is need to be inserted is 75. It will map to the
bucket number 3 because 75%6=3. So insert it to bucket number 3.
Step 4: The next key is 65. It will map to bucket number 5 because 65%6=5. So,
insert it to bucket number 5.
Step 5: Now the next key is 81. Its bucket number will be 81%6=3. But bucket 3
is already occupied by key 75. So separate chaining method will handles the
collision by creating a linked list to bucket 3.
Step 6: Now the next key is 42. Its bucket number will be 42%6=0. But bucket 0
is already occupied by key 24. So separate chaining method will again handles
the collision by creating a linked list to bucket 0.
Step 7: Now the last key to be inserted is 63. It will map to the bucket number
63%6=3. Since bucket 3 is already occupied, so collision occurs but separate
chaining method will handle the collision by creating a linked list to bucket 3.
In this way the separate chaining method is used as the collision resolution
technique.
4.10.1 Solution
Although, the quadratic probing eliminates the primary clustering, it still has the
problem.
When two keys hash to the same location, they will probe to the same alternative
location. This may cause secondary clustering. In order to avoid this secondary
clustering, double hashing method is created where we use extra multiplications
and divisions
The problem with linear probing is primary clustering. This means that even if
the table is empty, any key that hashes to table requires several attempt to
resolve the collision because it has to cross over the blocks of occupied cell.
These blocks of occupied cell form the primary clustering. If any key falls into
clustering, then we cannot predict the number of attempts needed to resolve the
collision. These long paths affect the performance of the hash table.
4.13 RE-HASHING
Rehashing is the process of re-calculating the hashcode of already stored entries
(Key-Value pairs), to move them to another bigger size hashmap when the
threshold is reached/crossed.
A binary tree is a tree data structure composed of nodes, each of which has
utmost, two children, referred to as left and right nodes. The tree starts off with
a single node known as the root.
2. What are the two methods of binary tree implementation?
Linear representation.
Linked representation
3. What are the applications of binary tree?
Binary tree is used in data processing.
o File index schemes
o Hierarchical database management system
4. List out few of the Application of tree data-structure?
The manipulation of Arithmetic expression
Used for Searching Operation
Used to implement the file system of several popular operating systems
Symbol Table construction
Syntax analysis
5. Define expression tree?
Expression tree is also a binary tree in which the leaf’s terminal nodes or
operands and non-terminal intermediate nodes are operators used for traversal.
6. Define tree– traversal and mention the type of traversals?
Three types of tree traversal
Inorder traversal
Preoder traversal
Postorder traversal.
7. Define in -order traversal?
In-order traversal entails the following steps;
Traverse the left subtree
Visit the root node
Traverse the right subtree
8. What is pre-order traversal?
In preorder traversal, first, root node is visited, then left sub-tree and after that
right sub-tree is visited. The process of preorder traversal can be represented
as: root → left → right
9. Define threaded binary tree.
A binary tree is threaded by making all right child pointers that would normally
be null point to the in order successor of the node, and all left child pointers
that would normally be null point to the in-order predecessor of the node.
10. What are the types of threaded binary tree?
Right-in threaded binary tree
Left-in threaded binary tree
Fully-in threaded binary tree
11. Define Binary Search Tree.
Binary search tree is a binary tree in which for every node X in the tree, the
values of all the keys in its left subtree are smaller than the key value in X and
the values of all the keys in its right subtree are larger than the key value in X.
12. What is AVL Tree?
AVL stands for Adelson-Velskii and Landis. An AVL tree is a binary search
tree which has the following properties:
The sub-trees of every node differ in height by at most one.
Every sub-tree is an AVL tree.
13. List out the steps involved in deleting a node from a binary search tree.
Deleting a node is a leaf node (ie) No children
Deleting a node with one child.
Deleting a node with two Childs.
14. Define complete binary tree.
If all its levels, possible except the last, have maximum number of nodes and if
all the nodes in the last level appear as far left as possible
15. Write short notes on Expression Trees.
A binary expression tree is a specific kind of a binary tree used to represent
expressions.
Two common types of expressions that a binary expression tree can represent
are algebraic and boolean. These trees can represent expressions that contain
both unary and binary operators.
16. What is Hashing?
Hashing is a technique of mapping a large chunk of data into small tables using
a hashing function. It is also known as the message digest function. It is a
technique that uniquely identifies a specific item from a collection of similar
items.
17. What is Hash Function?
A hash function is a function that takes a set of inputs of any arbitrary size and
fits them into a table or other data structure that contains fixed-size elements.
18. List the advantages of hashing in data structure
Hash provides better synchronization than other data structures. Hash tables are
more efficient than search trees or other data structures. Hash provides constant
time for searching, insertion and deletion operations on average.
19. What is separate chaining?
Separate Chaining is one of the techniques that is used to resolve the collision.
It is implemented using linked lists.
This method combines a linked list with a hash table in order to resolve the
collision. In this method, we put all the elements that hash to the same slot in
the linked list.
20. What is open addressing in hashing?
In open addressing,
Unlike separate chaining, all the keys are stored inside the hash table.
No key is stored outside the hash table.
21. List the techniques used in open addressing.
Linear Probing
Quadratic Probing
C Programming and Data Structures 4.49
Double Hashing
22. What is Linear Probing?
Linear probing is a scheme in computer programming for resolving collisions
in hash tables, data structures for maintaining a collection of key–value pairs
and looking up the value associated with a given key.
23. Write short notes on Quadratic Probing?
Quadratic probing is an open addressing scheme in computer programming for
resolving hash collisions in hash tables.
Quadratic probing operates by taking the original hash index and adding
successive values of an arbitrary quadratic polynomial until an open slot is
found.
24. Explain about Double Hashing.
Double hashing is a collision resolving technique in Open Addressed Hash
tables. Double hashing uses the idea of applying a second hash function to key
when a collision occurs.
25. What is rehashing in data structure?
Rehashing is a technique in which the table is resized, i.e., the size of table is
doubled by creating a new table.
26. List the advantages of Double hashing
The advantage of Double hashing is that it is one of the best form of probing,
producing a uniform distribution of records throughout a hash table.
This technique does not yield any clusters.
It is one of effective method for resolving collisions.
4.50 Non – Linear Data Structures
PART-B
The above steps represents how insertion sort works. Insertion sort works like
the way we sort playing cards in our hands. It always starts with the second
element as key. The key is compared with the elements ahead of it and is put it
in the right place.
At the first step, 40 has nothing before it. Element 10 is compared to 40 and is
inserted before 40. Element 9 is smaller than 40 and 10, so it is inserted before
10 and this operation continues until the array is sorted in ascending order.
5.2.3 Analysis of Insertion Sort:
Time Complexity
Best O(n)
Worst O(n2)
Average O(n2)
Space Complexity O(1)
Stability Yes
5.2.4 Applications
The insertion sort is used when:
The array is has a small number of elements
There are only a few elements left to be sorted
Example Program 5.1
#include <stdio.h>
int main()
{
int n, array[1000], c, d, t;
printf("Enter number of elements\n");
scanf("%d", &n);
printf("Enter %d integers\n", n);
for (c = 0; c < n; c++)
{
scanf("%d", &array[c]);
}
for (c = 1 ; c <= n - 1; c++)
{
d = c;
while ( d > 0 && array[d] < array[d-1])
{
t = array[d];
array[d] = array[d-1];
array[d-1] = t;
d--;
}
}
printf("Sorted list in ascending order:\n");
for (c = 0; c <= n - 1; c++)
{
printf("%d\n", array[c]);
}
return 0;
}
Output
Enter the number of elements
5
Enter 5 integers
40
30
20
10
40
Sorted list in ascending order
10
20
30
40
40
Next step is to delete the root element (89) from the max heap. To delete this
node, swap it with the last node, i.e. (11). After deleting the root element, again
heapify it to convert it into max heap.
After swapping the array element 89 with 11, and converting the heap into max-
heap, the elements of array are
After swapping the array element 81 with 54 and converting the heap into max-
heap, the elements of array are
In the next step, delete the root element (76) from the max heap again. To delete
this node, swap it with the last node, i.e. (9). After deleting the root element,
again heapify it to convert it into max heap.
After swapping the array element 76 with 9 and converting the heap into max-
heap, the elements of array are
In the next step, again delete the root element (54) from the max heap. To delete
this node, swap it with the last node, i.e. (14). After deleting the root element,
again heapify it to convert it into max heap.
After swapping the array element 54 with 14 and converting the heap into max-
heap, the elements of array are
In the next step, again delete the root element (22) from the max heap. To delete
this node, swap it with the last node, i.e. (11). After deleting the root element,
again heapify it to convert it into max heap.
After swapping the array element 22 with 11 and converting the heap into max-
heap, the elements of array are
In the next step, again delete the root element (14) from the max heap. To delete
this node, swap it with the last node, i.e. (9). After deleting the root element,
again heapify it to convert it into max heap.
After swapping the array element 14 with 9 and converting the heap into max-
heap, the elements of array are
In the next step, again delete the root element (11) from the max heap. To delete
this node, swap it with the last node, i.e. (9). After deleting the root element,
again heapify it to convert it into max heap.
After swapping the array element 11 with 9, the elements of array are
Now, heap has only one element left. After deleting it, heap will be empty.
heapify(a, n, largest);
}
}
/*Function to implement the heap sort*/
void heapSort(int a[], int n)
{
for (int i = n / 2 - 1; i >= 0; i--)
heapify(a, n, i);
// One by one extract an element from heap
for (int i = n - 1; i >= 0; i--) {
/* Move current root element to end*/
// swap a[0] with a[i]
int temp = a[0];
a[0] = a[i];
a[i] = temp;
heapify(a, i, 0);
}
}
/* function to print the array elements */
void printArr(int arr[], int n)
{
for (int i = 0; i < n; ++i)
{
printf("%d", arr[i]);
printf(" ");
}
}
int main()
{
int a[] = {42, 8, 26, 39, 28, 23, 7};
int n = sizeof(a) / sizeof(a[0]);
printf("Before sorting array elements are - \n");
printArr(a, n);
heapSort(a, n);
printf("\nAfter sorting array elements are - \n");
printArr(a, n);
return 0;
}
Output
Before sorting array elements are
42, 8, 26, 39, 28, 23, 7
After sorting array elements are
7, 8, 23, 26, 28, 39, 42
5.5.1 Algorithm
Merge sort keeps on dividing the list into equal halves until it can no more be
divided. By definition, if it is only one element in the list, it is sorted. Then,
merge sort combines the smaller sorted lists keeping the new list sorted too
Step 1 − if it is only one element in the list it is already sorted, return.
Step 2 − divide the list recursively into two halves until it can no more be divided.
Step 3 − merge the smaller lists into new list in sorted order.
First divide the given array into two equal halves. Merge sort keeps dividing the
list into equal parts until it cannot be further divided.
As there are eight elements in the given array, so it is divided into two arrays of
size 4.
Now, again divide these two arrays into halves. As they are of size 4, so divide
them into new arrays of size 2.
Now, again divide these arrays to get the atomic value that cannot be further
divided.
Now, combine them in the same manner they were broken. First compare the
element of each array and then combine them into another array in sorted order.
So, first compare 12 and 31, both are in sorted positions. Then compare 25 and
8, and in the list of two values, put 8 first followed by 25. Then compare 32 and 17, sort
them and put 17 first followed by 32. After that, compare 40 and 42, and place them
sequentially.
In the next iteration of combining, now compare the arrays with two data
values and merge them into an array of found values in sorted order.
Now, there is a final merging of the arrays. After the final merging of above
arrays, the array will look like
5.7.2 Algorithm
Linear_Search(a, n, val) // 'a' is the given array, 'n' is the size of given array, 'val'
is the value to search
Step 1: set pos = -1
Step 2: set i = 1
Step 3: repeat step 4 while i <= n
Step 4: if a[i] == val
set pos = i
print pos
go to step 6
[end of if]
set ii = i + 1
[end of loop]
Step 5: if pos = -1
print "value is not present in the array "
[end of if]
Step 6: exit
The value of K, i.e., 41, is not matched with the first element of the array. So, move to
the next element. And follow the same process until the respective element is found.
Now, the element to be searched is found. So algorithm will return the index of
the element matched.
5.8.1 Algorithm
Binary_Search(a, lower_bound, upper_bound, val) // 'a' is the given array,
'lower_bound' is the index of the first array element, 'upper_bound' is the index of the
last array element, 'val' is the value to search
Step 1: set beg = lower_bound, end = upper_bound, pos = - 1
Step 2: repeat steps 3 and 4 while beg <=end
Step 3: set mid = (beg + end)/2
Step 4: if a[mid] = val
set pos = mid
print pos
go to step 6
else if a[mid] > val
set end = mid - 1
else
set beg = mid + 1
[end of if]
[end of loop]
Step 5: if pos = -1
print "value is not present in the array"
[end of if]
Step 6: exit
The elements of the array are - 21, 14, 35, 30, 40, 51, 55, 57, 70
Element to be searched is – 40
Element is present at 5 position of array
12. Why quick sort is preferred for arrays and merge sort for linked lists?
Quick sort is an in-place sorting algorithm, i.e. which means it does not require
any additional space, whereas Merge sort does, which can be rather costly. In
merge sort, the allocation and deallocation of the excess space increase the
execution time of the algorithm.
Unlike arrays, in linked lists, we can insert elements in the middle in O(1) extra
space and O(1) time complexities if we are given a reference/pointer to the
previous node. As a result, we can implement the merge operation in the merge
sort without using any additional space.
13. In which case insertion sort is used?
Insertion sort has a fast best-case running time and is a good sorting algorithm
to use if the input list is already mostly sorted.
14. What is the advantage of using Quick sort algorithm?
Quick sort reduces unnecessary swaps and moves an item to a greater distance,
in one move.
15. Mention the various types of searching techniques in C.
Linear search
Binary search
16. Define
Searching.
Searching in data structure refers to the process of finding the required
information from a collection of items stored as elements in the computer
memory.
These sets of items are in different forms, such as an array, linked list, graph,
or tree.
17. Compare Quick sort and Merge Sort.
Basis for comparison Quick Sort Merge Sort
Efficiency Inefficient for larger arrays More efficient
Sorting method Internal External
Stability Not Stable Stable
Preferred for for Arrays for Linked Lists
18. Mention the different ways to select a pivot element.
o Pick the first element as pivot
o Pick the last element as pivot
o Pick the Middle element as pivot
o Median-of-three elements
o Pick three elements, and find the median x of these elements
o Use that median as the pivot.
o Randomly pick an element as pivot.
19. What is divide-and-conquer strategy?
Divide a problem into two or more sub problems
Solve the sub problems recursively
Obtain solution to original problem by combining these solutions
PART B