Programming and Data Structure Short Notes-1
Programming and Data Structure Short Notes-1
(d) Other:
✓ void, bool
• C standard does not specify how many bits or bytes to be allocated for every type and different compiler may choose
different ranges.
• Only restriction is that short and int types are at least 16 bits, long types are at least 32 bits and short is no longer than int
which is no longer that long type.
1.2 Operators
Depending upon the number of operands, an operator in C language can be unary, binary or ternary.
Ex1.
The following are invalid
10 = a;
a + b = c;
• The result of assignment statement is the value we are assigning i.e……
int x;
x = 3 + (x = 10); is perfectly valid.
Firstly x = 10 evaluated and
(1) 10 is assigned to x (2) then the result of (x = 10) will be 10
so,
x = 3 + 10
C Programming
x = 13
Finally, 13 is assigned to x.
• Just like rational operators, the result of every logical operator is either 0 or 1.
• Logical NOT is a unary operator
• Logical NOT converts a non-zero operand into 0 and a zero operand in 1.
#include<stdio.h>
int main () {
int x = 3, y = 6;
printf (“%d\n”,x & y); // output 2
printf (“%d\n”,x|y); // output 7
printf (“%d\n”, x^y) // output 5
return 0;
}
binary representation of 3: 00000000...0011
binary representation of 6: 00000000...0110
3 & 6: 00000000...0010
3 | 6: 00000000...0111
3 ^ 6: 00000000...0101
XOR of two bits is 1 if both bits are different.
XOR of two bits is 0 if both bits are same.
• x has output as – (x + 1)
• printf (“%d\n”, ~2) has output -3 i.e., -(2 + 1)
• If left expression evaluates as true, then the value returned is middle argument otherwise the returned value is
Right expression
int a;
a = 7 > 2 ? 3 2 + 5 : 6! = 7
Left expression: 7 > 2 is true
So, the value returned would be the middle argument.
i.e., 3 2 + 5 = 11
so, a will get 11.
Note:
(a) No of ‘?’ and ‘:’ should be equal.
(b) Every colon (:) should match with just before ‘?’.
(c) Every ? followed by : not immediately but following.
Example: int a;
a = 2 > 5 ? 10 : !5! = 2 > 5 ? 20 : 30
L1 M1 R1
2 > 5 is false.
so, for Leftmost ? the value returned is its right expression.
a = ! 5 ! = 2 > 5 ? 20 : 30 :
Left expression:
!5! = 2 > 5
0! = 2 > 5
0! =0
0 i.e., false.
As left operand is false, the final value is right expression
a = 30
Operators Associativity
() [] -> . Left to right
! ++ -- + - * (type) size of Right to left
*/% Left to right
+- Left to right
<< >> Left to right
< <= > >= Left to right
== != Left to right
& Left to right
^ Left to right
| Left to right
&& Left to right
|| Left to right
?: Right to left
= += -= *= /= %= &= ^= |= <<= >>= Right to left
, Left to right
2
2.1 Switch Statement
CONTROL FLOW STATEMENTS
• The for statement evaluates 3 expressions and executes the loop body until second controlling expression
executes to false.
• It is recommended to use for loop when the number of iterations is known in advance.
• Syntax of for loop is:
for (expression – 1(optional); expression – 2(optional); expression – 3(optional))
{
statement – 1
statement – 2
statement – n
}
• for loop executes the loop body 0 or more times.
• for statements works as follows:
(a) expression – 1 is evaluated once before the first iteration of the loop.
(b) expression – 2 is a expression that determines whether to terminate the loop. expression – 2 is evaluated before every
iteration.
If the expression is true (non - zero), the loop body executed.
If the expression is false (zero), execution of the for statement is terminated.
(c) expression – 3 is evaluated after each iteration.
(d) The for statement executes until expression-2 is false (0), or until a jump statement terminates execution of the loop.
• All 3 expression can be omitted
(a) If we omit expression-2, the condition is considered as true for an example:
for (i = 0; ; i++) represent an infinite loop
statement.
statement-n
}
3 STORAGE CLASS & FUNCTION
3.3 Recursion
Definition: When the body of a function call the function itself directly or indirectly.
• Certain arguments for which the function does not call itself are called as base argument, base values.
• In general, for recursion to be non-cyclic whenever a function calls itself the formal arguments must get closer to the base
argument.
Example 1:
Consider the factorial code:
int factorial (int n)
{
if (n = = 0)
return 1;
else
return n * factorial (n - 1);
}
If we call factorial (3), it will call factorial of 2 and so on …the argument will get closer to 0 i.e., the base argument.
• Recursion code is shorter than iterative code.
• Overhead is present.
• Some standard problems are best suited to be solved by using recursion for example- Tower of Hanoi, Factorial, merge
Sort.
Example 2:
int a = 10;
void main ()
{
int a = 1;
{
Scope S1 int b;
Scope S2 printf(“%d”,a);
}
}
Output: 1
Compiler looks for ‘a’ in scope S1, because S1 does not have variable a, it will look into higher scope S2 that contains a variable
name a whose value is 1.
3.4.2 Dynamic Scoping
In this type of scoping, the compiler first searches the current block and then successively searches all calling functions.
Example:
int i;
program main ()
{
i = 10;
call f ();
}
procedure f ()
{
int c = 20;
call g();
}
Procedure g() {
print i;
}
Assuming that the above program is written in a hypothetical programming language which allows global variables
C Programming
g() is printing i, which is not present inside current block. So, because of dynamic scoping compiler will go to the function that
calls g() i.e., compiler will search f() for variable i. Hence 20 is printed.
4 ARRAYS AND POINTERS
4.1 Array
• An array is defined as the collection of similar type of data items stored at contiguous memory locations.
• Arrays are the derived data type in C programming language which can store the primitive type of data such as int, char,
double etc.
• It has the capability to store the collection of derived data types such as pointer, structure etc.
• Each element of an array is of same data type and carries the same size example int = 4 byte.
• Elements of the array are stored at contiguous memory locations, meaning, the first element is stored at the smallest
memory location.
• Elements of the array can be randomly accessed since we can calculate the address of each element of array with the given
base address and size of the data element.
Example:
Initialization of C array:
We can initialize each element of the array by using the index. Suppose array int marks [5]. Then
marks [0] = 80
marks [1] = 60;
marks [2] = 70;
marks [3] = 85;
marks [4] = 75;
80 60 70 85 75
Marks [0] Marks [4]
Marks [1]
Marks [2] Marks [3]
C Array Example:
# include <stdio.h>
int main ()
{
int i = 0;
int marks [5];
marks [0] = 80;
marks [1] = 60;
marks [2] = 70;
marks [3] = 85;
marks [4] = 75;
for(i = 0; i<5; i++)
{
printf(“%d\n”,marks[i]);
}
return 0;
}
Example:
No of rows
Initialization of 2D Array
int array Hello [4] [3] = {{1,2,3}, {3,4,5}, {4, 5, 6}};
Output: arrayHello[0][0] = 1
arrayHello[0][1] = 2
arrayHello[0][2] = 3
arrayHello[1][0] = 2
arrayHello[1][1] = 3
arrayHello[1][2] = 4
arrayHello[2][0] = 3
arrayHello[2][1] = 4
arrayHello[2][2] = 5
arrayHello[3][0] = 4
arrayHello[3][1] = 5
arrayHello[3][2] = 6
# include<stdio.h>
void helloarray(char * marks)
{
printf(“Elements of array are:”);
for(int i = 0; i < 5; i++)
{
printf(“%c”, marks[i])
}
int main()
{
char marks[5] = {‘A’, ‘B’, ‘C’, ‘D’, ‘E’};
helloarray(marks);
return 0;
}
}
Note:
Whenever you pass an array, it is always call by reference. In previous 2 programs, we passed an address & formal
argument in both the cases is a pointer internally.
How to return an Array from a function
# include<stdio.h>
int *fun()
{
int marks [5];
print f (“Enter the element in an array”);
for (int i = 1; i < 5; i++)
{
scanf(“%d”,& marks[i]);
}
return marks;
}
int main()
{
int *n;
n = fun();
printf(“\n Elements of array are:”);
for(int i = 0; i < 5; i++)
{
printf(“%d”,n[i]);
}
return 0;
}
Note:
fun() function returns a variable ‘marks’.
It returns a local variable, but it is an illegal memory location to be returned, which is allocated with a function in the
stack. Since the program control comes back to the main () function, and all the variables in the stack are fraud.
Therefore, we can say that this program is returning memory location, which is already de-allocated, so the output of the
program is a segmentation fault.
Note:
• while declaring an array, it is mandatory to provide the size of each dimension. (3), (6), (10), (11), (12) are not providing
sizes of dimensions.
• While initializing an array, you have flexibility to omit only first dimension i.e., you are allowed to other dimension (1),
(8),(14) are following this rule while (15), (16) are not following this rule.
4.1.9 Pointers
• In C, there is a strong relationship between arrays and pointers. An operation that can be achieved by arrays subscripting
also be done with pointes.
• Consider the declaration
int a[5] = {10, 20, 30, 40, 50};
int* Pa;
Pa = &a[0];
• Pointers are special variable that can hold address of other variables
Syntax: data type * Identifier
int *Pa: Pa is a pointer to integer variable
i.e., Pa can hold address of integer variable
p 1020 i, e address of x
*P value at (memory location 1020)
*p 10
q 1096 i,e address of variable p
*q value at (memory location 1096)
1020 which is again an address
*q value at (memory address 1020)
**q 10
1. Dangling pointer: The pointer pointing to a deallocated memory block is known as dangling pointer.
This situation raises an error known as dangling pointer problem. Dangling pointer occurs when a pointer pointing to a
variable goes out of scope or when a variables memory gets deallocated.
Consider the code.
int *f( ) {
int a = 10; // a is a local variable and goes out of scope after execution of f( )
return &a :
}
int main () {
int * ptr = f (); //Ptr points to something which is not valid
print (“/d”*,ptr);
return 0;
}
Ptr 100 10 a
100
• To overcome this problem, just make variable a as static when x become static it has scope throughout the program.
• int *p
• Storing a value using an uninitialized pointer has the potential to overwrite anything in your program including your
program itself.
• System may crash.
• Always initialize with NULL.
3. NULL pointer: It is a pointer which is pointing to nothing It is a specially designed pointer that stores a defined value
but not a valid address of any element or object.
NULL pointer does not hold valid address and that is why if you try to dereference it, you will get an error
int *p = NULL:
printf (“%d”,*p) : //NULL pointer dereferencing
4. void pointer: void pointer is a pointer that points to some location in memory but is does not have any specific type.
It can point to any type of data and any pointer type is convertible to a void pointer.
Its declaration:
void *ptr :
is saying that ptr is a pointer that can hold an address
cannot be dereferenced directly
i.e., void *ptr
int x = 10:
ptr = &x :
printf (“%d”, *ptr); //invalid
you need to typecast the void pointer before dereferencing.
i.e.,
void *ptr
int x = 10;
ptr = &x;
printf(“%d”,*(int*)ptr);
typecasting
Here, (int*)ptr does type costing of void
*(int*) ptr dereferences the typecasted void pointer variable
• Pointer arithmetic in not possible on void pointer.
i,e……. ptr+ +, + + ptr, – –ptr, ptr – –, ptr +1, ptr -1 is not allowed an void pointer.
• An uninitialized pointer holds a garbage value while a NULL pointer holds a defined value but not a valid address.
0 1 2 3 q
P
3. int (*P)() : P is pointer to a function that takes no argument and returns an integer.
4. int (*P) (int, int) : P is a pointer to a function that takes 2 integer arguments and returns an integer.
5. int *P (char*) : P is a pointer to a function that takes a pointer to character argument and return a pointer to integer.
P is a pointer to a function that take 2 integer arguments and returns an integer value.
• Declaration of function pointer: declaring a pointer to function is almost same as declaring the fuction except that in
function pointer are prefix is with an asterik * symbol.
For example: if the function is
int add(int, int)
Declaration of a fuction pointer for add() fuction is :
int (*ptr)(int, int);
• How to call a function through function pointer : In order to all a function using function pointer, first we need to assign
the address of function code to the pointer
Ex 1:
int add (int, int):
void main () {
int (*ptr) (int, int);
ptr = &add; // ptr is a pointer to add() function
printf (“The sum of 10 and 20 is”, (*ptr )(10, 20)); //calling add()
}
int add (int, int);
Ex 2:
void main() {
int (*ptr) (int, int);
ptr = add ; // same as ptr = & add
printf (“ The sum of 10 and 20 is”, (*ptr) (10, 20));
• Using function poitnter we are able to pass a function as an argurment to other function and can also be returned from
function.
Array of function pointer
int (*ptr[3])(int, int)
Ptr is an array of 3 pointers to a function that takes 2 arguments and returns an integer.
5
5.1 Strings
STRINGS
The above code did not print Hello Pankaj Sharma as expected because scanf halts reading as soon
as a whitespace or a newline character is encountered, and that is why it reads only Pankaj.
• In order to read a string containing space, we use gets() function. gets() ignores the whitespace & stops reading
when a newline is found.
# include<stdio.h>
void main(){
char name [20];
printf(“Enter your name :”);
gets(name);
printf(“Hello %s”, name);
}
Output :
Enter your name: Pankaj Sharma
Hello Pankaj Sharma
• A string literal always represent base address of a string. i.e address of first character.
• “Pankaj” represents address of character ‘P’
Hence “Pankaj” [0] means ‘P’
“Pankaj” [1] ≡ *(“Pankaj”+1) ≡ *(Address of ‘P’+1)
≡ *(Address of ‘a’)
≡ ‘a’
Example - 1
# include<stdio.h>
void main(){
char *ptr = “pankaj”
printf(“%s”,ptr);
}
Output : pankaj
Example – 2
# include<stdio.h>
void main(){
char *ptr = “Pankaj”
printf(“%s”,ptr+1);
}
Output: ankaj
• Array name being a constant can’t be presented at the left side of the assignment statement i.e it can’t be L-value.
You can’t re-assign another string to array.
(2) # include<stdio.h>
void main(){
char name [20] = “Pankaj” ;
name [1] = ‘u’ ;
printf(“%s”, name);
}
Output: Punkaj
• We are allowed to change content of array and hence we can update any character.
(3) # include<stdio.h>
void main(){
char * ptr = “Pankaj” ;
ptr = “Neeraj” ;
printf(“%s”, ptr);
}
Output: Neeraj
• Pointer ptr being a variable can hold different address at different time. Hence, we can assign another string to a character
pointer any time.
(4) # include<stdio.h>
void main()
{
char * ptr = “pankaj” ;
ptr [1] = ‘u’ ; // Invalid
printf(“%s”, ptr);
}
• String literals are stored in read only memory area i.e “pankaj” is stored first & then the address of character ‘p’ is given
to ptr.
• As they are stored in read only area of memory, we are not allowed to update them.
6 TYPES OF DATA STRUCTURE,
ARRAY & LINKED LIST
6.1 Introduction
6.1.1 Linear data structure
Every element can have almost 2 neighbours. Ex. arrays, linked list, stack, queue.
6.1.2 Non-Linear data structure
Element can have more than 2 neighbours. Ex. Tree, graph.
6.2 Arrays
6.2.1 1-D array
Theoretically index can start from any integer value. Let A be a 1-D array of n elements and the size of each element is w bytes,
then the address of A[i] element.
A11 0 0 0
A A22 0 0
A = 21
A31 A32 A33 0
A41 A42 A43 A44
A11 A12 0 0 0
A 0
21 A22 A23 0
0 A32 A33 A34 0
0
0 A43 A44 A45
0 0 0 A54 A55
6.2.7 Efficient method to store sparse matrix
Using Row-major order for string lower triangular matrix, the element at index (i, j) can be represented as :
i (i −1)
Index of Aij = + ( j −1 )
2
Using column-major order for storing upper triangular matrix, the element at index (i, j) is sparse matrix can be represented as:
( j − i)(i − 2 )
Index of Aij = (i − j )+ ( j −1)N −
2
Matrix order
N×N
Using Row-major order for storing upper triangular matrix, the element at index (i, j) in sparse matrix can be represented as :
(i − i)(i − 2 )
Index of Aij = ( j − i )+ (i −1)N −
2
Where N : Number of rows/columns
Using column-major order for starting upper-triangular matrix the element at index (i, j) can be represented as
j (j −1)
Index of Aij = (i −1) +
2
Struct Node {
int data;
Struct Node * Link;
}
6.4.2 Doubly Linked List
A two-way linked list in which every node contains a pointer to the next node as well as pointer to previous node in the list we
can traverse it in backward direction also.
Structure of a Node :
Struct Node {
struct Node * Prev;
int data;
};
6.4.3 Circular Linked List
A linked list in which last node points back to the first node in the list.
• Circular linked list has no beginning and no end.
Head
10 20 3 4
6.4.6 Applications
• used to implement other data structure link stack, queue data structure.
• used for dynamic memory allocation.
6.4.7 Advantages and Disadvantage
• Insertion and deletion are efficient.
• Using pointers in every node, require more memory.
• Random accessing in not possible.
• Circular linked list can be used to implement Fibonacci Heap.
❑❑❑
7
7.1 Introduction
STACK AND QUEUE
Linear data structure in which both insertion and deletion operation are performed at one end called TOP of the stack. Works
on LIFO (Last In First Out) Policy.
7.1.1 Application
To post-pone certain decision (To wait/To delay)
• Stack Permutation : Order of insertion of key is fixed but we can pop an element any time.
2n C
Number of possible stack permutation with n elements = n
n +1
• Infix to postfix
• Infix to prefix
• Prefix Evaluation
• Postfix Evaluation
• Recursion
• Tower of Hanoi
8.1.1 Terminology
(i) Internal Node : Node with atleast 1 child.
(iii) Root Node : Only node that does not have any parent.
(iv) Complete binary Tree : Binary tree in which nodes are inserted from left to right at every level and we can not insert at
node at (K+ 1)th level until all levels upto K are fully filled.
(v) Full Binary Tree : A binary tree in which every internal node has exactly two children and all the leaf nodes are at some
level.
Binary tree that contains maximum number of nodes.
(vi) Strict Binary Tree : A binary tree in which every internal node has exactly two children.
(vii) Complete K-ary tree : Tree in which every internal node has exactly K-childs.
8.1.2 Mathematical Result
(i) For a binary tree of height h
• Maximum number of nodes = 2(h+1) – 1
• Minimum number of nodes = h + 1
(ii) For a complete binary tree of height h
• Maximum number of nodes = 2(h+1) – 1
• Minimum number of nodes = 2h
(iii) For a full binary tree :
Number of nodes = 2h+1 – 1
2n C
(iv) Total number of unlabelled binary trees with n nodes = n
n +1
2n C
(v) Total number of labelled binary tree with no keys = n n!
n +1
2n C
(vi) Total number of binary trees with a given preorder (n length) = n
n +1
2n C
(vii) Total number of binary trees with a given proorder/postorder/inorder = n
n +1
(viii) Number of binary trees with a given preorder and inorder = 1
In-order
• Morrison Traversal :
In-place traversal of a binary tree
No recursion
• Inorder traversal of a binary search tree is ascending order of keys in the BST.
• Insertion in a BST
(a) O (log n) best case
(b) O (n) worst case.
• Deletion from a BST :
(a) Deletion of leaf node : can be done directly
(b) Deletion of node with one child : copy the child to the node and delete the child.
(c) Deletion of a node with two children : first find the inorder successor of the node, copy the contents of this
successor to the node and dlete the inorder successor.
We can also use inorder predecessor.
• TC : O (log n) best case
O (n) worst case
8.4 Heap
A complete binary tree in which every node satisfy heap property (min heap or max heap)
(i) Min heap : A complete binary tree in which every node satisfy the property that the value of the node is smaller than both
its children.
(ii) Max heap : A complete binary tree in which every node satisfy the property that the value in the node is greater than both
its children.
20 20
10 8 10 8
6 4 12 3
• Construction of Heap :
(i) By inserting keys one after another : O (n log n)
(ii) Using build-heap method/heapify algo : O(n)
• Number of min-heaps possible with n keys
T(n) = T(k) . T(n – k – 1) . n–1Ck
(ii) Replace root element with last element (A1 An) reduce the heap size by 1 and then apply heapify at root node.
n(0) = 1
n(1) = 2
i.e., it also forms a Fibonacci series
1, 2, 4, 7, 12, ………….
❑❑❑
09 GRAPH TRAVERSAL
9.1 Introduction
9.1.1 Breadth First Search
• Uses a queue data structure.
• To find whether a graph is connected or not.
• To find number of connected components in a given graph (Breadth First traversal is used)
• To detect cycle in a graph.
• To find whether a given graph is bipartite or not.
• T.C. = O (V + E) using Adjacency List
= O(V2) using Adjacency matrix.
• To find shortest path in undirected graph without weights.
9.1.2 Depth First Search
• Uses stack.
• To detect a cycle in a graph.
• To find whether a graph is connected or not.
• To find whether given graph is bipartite or not.
• To find number of connected components in the graph.
• To find bridges in the graph.
• To find articulation points in the graph.
• To find topological sort of a graph.
• To find biconnected components.
• To find strongly connected components.
❑❑❑
10 HASHING
10.1 Introduction
• Searching technique.
• Mapping keys into hash table using a hash function.
• Efficiency based on hash function used for mapping.
10.1.1 Terminology
(i) Collision : When two keys mapped to same location, collision occurs.
H(k1) = H(k2), where H(k) is the hash function used.
10.2 Chaining
Uses the concept of linked list (chain) when more than one element are hashed to same location (slot) then elements are inserted
into a singly linked list (chain).
❑❑❑