Data Structures Introduction
Data Structures Introduction
Dr Deepak Gupta
Assistant Professor, SMIEEE
CSED, MNNIT Allahabad, Prayagraj
Email: deepakg@mnnit.ac.in
Course Description
This course introduces the student’s fundamentals of data structures and takes
them forward to software design along with the course on Algorithms. It details
how the choice of data structures impacts the performance of programs for given
software application. This is a precursor to DBMS and Operating Systems. A lab
course is associated with it to strengthen the concepts.
Syllabus
UNIT 1: UNIT-1: Introduction: Basic Terminology, Elementary Data Organization,
Algorithm, Efficiency of an Algorithm, Time and Space Complexity, Asymptotic
notations: Theta, Big-O, and Omega, Time-Space trade-off. Abstract Data Types (ADT)
UNIT II: Arrays: Definition, Single and Multidimensional Arrays, Representation of
Arrays: Row Major Order, and Column Major Order, Application of arrays, Sparse
Matrices and their representations.
Linked Lists: Array Implementation and Dynamic Implementation of Singly Linked
Lists, Doubly Linked List, Circularly Linked List, Operations on a Linked List.
Insertion, Deletion, Traversal, Polynomial Representation and Addition, Generalized
Linked List
Stacks: Abstract Data Type, Primitive Stack operations: Push & Pop, Array and Linked
Implementation of Stack in C, Application of stack: Prefix and Postfix Expressions,
Evaluation of postfix expression, Recursion, Tower of Hanoi Problem, Simulating
Recursion, Principles of recursion, Tail recursion, Removal of recursion
Queues: Abstract Data Type, Operations on Queue: Create, Add, Delete, Full and
Empty, Circular queues, Array and linked implementation of queues in C, Deque and
Priority Queue.
Syllabus
UNIT III: Basic terminology, k-ary trees, Binary Trees, Binary Tree Representation: Array
Representation and Dynamic Representation, Complete Binary Tree, Algebraic Expressions,
Extended Binary Trees, Array and Linked Representation of Binary trees, Tree Traversal
algorithms: In order, Preorder and Post order, Binary Search Trees, Threaded Binary trees,
Traversing Threaded Binary trees, Forest, Huffman algorithm, Heap, B/B+ Tree, AVL tree
UNIT IV: Sequential search, Binary Search, Comparison and Analysis Internal Sorting:
Bubble Sort, Selection Sort, Insertion Sort, Two Way Merge Sort, Heap Sort, Quick Sort,
Hashing
Unit V: Terminology, Sequential and linked Representations of Graphs: Adjacency Matrices,
Adjacency List, Adjacency Multi list, Graph Traversal: Depth First Search and Breadth First
Search, Connected Component, Spanning Trees, Minimum Cost Spanning Trees: Prims and
Kruskal algorithm. Shortest Path algorithm: Dijikstra Algorithm
Books
Text Books:
Reference Books:
1. Horowitz and Sahani, “Fundamentals of Data Structures”, Galgotia
Publication
2. Donald Knuth, “The Art of Computer Programming”, vol. 1 and vol. 3.
3. Jean Paul Trembley and Paul G. Sorenson, “An Introduction to Data
Structures with applications”, McGraw Hill
4. R. Kruse et al, “Data Structures and Program Design in C”, Pearson
Education
5. Lipschutz, “Data Structures” Schaum’s Outline Series, TM
Time Table
Introduction
Data: Data is the plural of “datum” (which is rarely used) and may be thought
of as representing numbers, words, facts, figures, images, etc.
Data Type: A data type is a collection of objects and a set of operations that
act on those objects.
For example in C, int data type can take values in a range and operations that
can be performed are addition, subtraction, multiplication, division, bitwise
operations etc.
Data type or Primitive Data types are the predefined data types that are
supported in the programming language. The size depends upon the type of
data type. Primitive Data types can hold only a single value in one specific
location.
int marks[10];
marks[0] marks[1] marks[2] marks[3] marks[4] marks[5] marks[6] marks[7] marks[8] marks[9]
Dynamic Data Structures:
The data structures having a dynamic size are known as Dynamic Data
Structures. The memory of these data structures is allocated at the run time,
and their size varies during the run time of the code. Moreover, the user
can change the size as well as the data elements stored in these data
structures at the run time of the code.
Linked Lists
A Linked List is another example of a linear data structure used to store a
collection of data elements dynamically. Data elements in a linked list are
represented by the nodes, connected using links or pointers.
Stack
A Stack is a Linear Data Structure that follows the LIFO (Last In, First Out)
principle that allows operations like insertion and deletion from one end of
the Stack, i.e., Top.
Real-life examples of Stacks are piles of books,
a deck of cards, piles of money, and many
more.
Queue
It follows the First-In-First-Out (FIFO) principle. Elements are inserted at the
back of the queue and removed from the front.
Non-Linear Data Structures
Non-Linear Data Structures are data structures where the data elements are
not arranged in sequential order. Here, the insertion and removal of data are
not feasible in a linear manner. There exists a hierarchical relationship
between the individual data items.
G = (V, E)
Algorithm: An algorithm is a finite set of instructions that, if followed,
accomplishes a particular task.
In addition, all algorithms must satisfy the following criteria:
1. Input: There are zero or more quantities that are externally supplied.
The fixed part includes space needed for storing instructions, constants,
variables, and structured variables.
float abc(float a, float b, float c)
{ Sabc(I) = 0.
return a+b+b*c+(a+b-c)/(a+b)+4
}
Variable part includes space needed for the recursion stack, and for
structured variables that are allocated space dynamically during the run-
time of the program.
Type Name Number of bytes
Ex: Recursive function for summing a list
Parameter: array pointer list[] 4
of numbers
float rsum(float list[], int n) Parameter: integer n 4
{
return address 4
if (n) return rsum(list, n-1)+list(n-1);
return 0; Total per recursive call 12
}
Srsum(Max_size) = 12*Max_size.
Ex: Iterative function for summing a list of numbers
float sum(float list[], int n)
{
float tempsum = 0;
int i; Sabc(I) = 0.
for(i=0; i<n; i++)
tempsum += list[i];
return tempsum
} Time Complexity
1 1 1 1 1 1 1 2
2 1 1 2 2 4 8 4
4 1 2 4 8 16 64 8
8 1 3 8 24 64 512 256
data_type name[size];
data_type - what kind of values it can store. For example, int, char, float
name - to identify the array
size - the maximum number of values that the array can hold
int marks[10];
marks[0] marks[1] marks[2] marks[3] marks[4] marks[5] marks[6] marks[7] marks[8] marks[9]
The symbolic constants can be used to specify the size of an array. However,
we can’t use the variables for specifying the size of array in the declaration.
#define SIZE 10
main()
{
int size = 15;
int marks[SIZE]; /*valid*/
Int marks[size]={2,3,5}; /*not valid*/
…
}
Accessing Elements of 1-D Arrays
int i, marks[10];
for(i=0;i<10;i++)
printf(“%d ”,marks[i]);
For example:
int marks[5]={99,78,55,23,91};
int marks[ ]={99,78,55,23,91};
int marks[5]={99,78};
Here, the size of the array is 5 while there are only 2 initializers. The value of
the elements are:
marks[0]=99 marks[1]=78 marks[2]=0 marks[3]=0 marks[4]=0
We will have to copy all elements of the array one by one by using a for
loop:
for(i=0;i<5;i++)
b[i]=marks[i];
WAP to Read and Display N Numbers using an Array
#include<stdio.h>
#include<conio.h>
int main()
{
int i=0, n, arr[20];
clrscr();
printf(“\n Enter the number of elements : ”);
scanf(“%d”, &n);
printf(“\n Enter the elements : ”);
for(i=0;i<n;i++)
{
printf(“\n arr[%d] = ”, i);
scanf(“%d”, &num[i]);
}
printf(“\n The array elements are ”);
for(i=0; i<n; i++)
printf(“arr[%d] = %d\t”, i, arr[i]);
return 0;
}
Inserting an Element in an Array
(0,0) (0, 1) (0,2) (0,3) (1,0) (1,1) (1,2) (1,3) (2,0) (2,1) (2,2) (2,3)
In the column-major order, the elements of the first column are stored
before the elements of the second and third columns. That is, the elements
of the array are stored column by column where n elements of the first
column will occupy the first nth locations.
(0,0) (1,0) (2,0) (3,0) (0,1) (1,1) (2,1) (3,1) (0,2) (1,2) (2,2) (3,2)
Initializing Two-dimensional Arrays
A two-dimensional array is initialized in the same way as a 1-D array is
initialized.
For example,
int *ptr;
ptr = &arr[0];
If pointer variable ptr holds the address of the first element in the array, then
the address of the successive elements can be calculated by writing ptr++.
int arr[2][2][2]={1,2,3,4,5,6,7,8};
int (*parr)[2][2];
parr=arr;
arr[i][j][k]= *(*(*(arr+i)+j)+k)
Assigning address to a pointer variable
When we declare a pointer variable it contain garbage value i.e. it may be
pointing anywhere in the memory.
int *iptr, age=30;
float *fptr, sal = 1500.5;
iptr = &age;
fptr = &sal;
One can initialize the pointer at the time of declaration, but the variable
should be declared before the pointer. For example:
int age=30;
int *iptr = &age;
Dereferencing Pointer Variables
One can access a variable indirectly using pointers. For this, we will use the
indirection operator (*). The indirection operator can be read as ‘value at
the address’.
int a = 87;
float b = 4.5;
int *p1 = &a;
float *p2 = &b;
Here,
*p1 = 9; is equivalent to a=9;
(*p1)++; is equivalent to a++;
x=*p2 + 10; is equivalent to x=b + 10;
printf(“%d %f”, *p1, *p2); is equivalent to printf(“%d %f”, a, b);
scanf(“%d %f”, p1, p2); is equivalent to scanf(“%d %f”, &a, &b);
Pointer to Pointer
The syntax of declaring a pointer to pointer is as:
data_type **ptr;
Example:
int a = 5; ppa pa a
int *pa = &a; 3000 2000 5
int **ppa = &pa; 4000 3000 2000
Program to print the value and address of elements of an array using
pointer notation:
# include <stdio.h>
main()
{
int i, arr[5] = {5, 10, 15, 20, 25};
for(i=0; i<5; i++)
printf(“value of arr[%d] = %d\t”, i, *(arr + i) );
printf(“Address of arr[%d] = %p\n”, i, (arr + i) );
printf(“/n”);
}
Pointers and Functions
Call by value
# include <stdio.h>
void value(int x, int y);
main( )
{
int a=5; b=8;
printf(“Before calling the function, a = %d and b=%d\n”, a, b);
value(a, b);
printf(“After calling the function, a = %d and b=%d\n”, a, b);
}
void value(int x, int y)
{
x++;
y++;
printf(“Inside function x = %d, y = %d\n”, x, y);
}
Pointers and Functions
Call by reference
# include <stdio.h>
void value(int *p, int *q);
main( )
{
int a=5; b=8;
printf(“Before calling the function, a = %d and b=%d\n”, a, b);
value(&a, &b);
printf(“After calling the function, a = %d and b=%d\n”, a, b);
}
void value(int *p, int *q)
{
(*p)++;
(*q)++;
printf(“Inside function *p = %d, *q = %d\n”, *p, *q);
}
Returning more than one value from a function:
Program to show how to return more than one value from a function
using call by reference:
# include <stdio.h>
func (int x, int y, int *ps, int *pd, int *pp)
main()
{
int a, b, sum, diff, prod;
a = 6;
b = 4;
func(a, b, &sum, &diff, &prod);
printf(“Sum = %d, Difference = %d, Product = %d\n”, sum, diff, prod);
}
# include <stdio.h>
int *func (int *p, int n);
main()
{
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, n, *ptr;
n = 5;
ptr = func(arr, n);
printf(“arr = %p, ptr = %p, *ptr = %d\n”, arr, ptr, *ptr);
}
int *func(int *p, int n)
{
p = p+n;
return p;
}
Applications of Arrays
The number of values to be stored is less than the size of the array and
hence there is a wastage of memory.
Our program fails if we want to store more values than the size of an array.
malloc( ) returns a pointer to the first byte of allocated memory. The return
pointer is of type void, which can be type cast to the appropriate type of
pointer.
If there is not sufficient memory available in the heap then malloc returns
NULL.
The function realloc( ) is used to change the size of memory block. This
function takes two arguments:
First is a pointer to the block of memory that was previously allocated by
malloc( ) or calloc( ).
Second one is the new size for that block.
For example:
ptr = (int *)malloc(size);
ptr = (int*)realloc(ptr, newsize);
/*Program to understand the use of realloc()*/
# include <stdio.h>
# include <stdlib.h>
main()
{
int *ptr, i;
ptr = (int*)malloc(5*sizeof(int));
if(ptr = = NULL)
{
printf(“Sufficient memory is not available\n”);
exit(1);
}
printf(“Enter 5 integers : ”);
for(i=0; i<5; i++)
scanf(“%d”, ptr+i);
/* Allocate memory for 4 more integers*/
ptr = (int*)realloc(ptr, 9*sizeof(int));
if(ptr = = NULL)
{
printf(“Sufficient memory is not available\n”);
exit(1);
}
printf(“Enter 4 more integers : ”);
for(i=5; i<9; i++)
scanf(“%d”, ptr+i);
for(i=0; i<9; i++)
printf(“%d\t”, *(ptr+i));
}
free( )
For example:
free(ptr);
Structure
Structure is a user-defined data type that can store related information
(even of different data types) together.
For example, if we have two structure variables stud1 and stud2 of type
struct student
struct student stud1 = {01, "Rahul", "BCA", 45000};
struct student stud2;
Then to assign one structure variable to another, we will write:
stud2 = stud1;
Array of Structures
The array of structures can be defined as:
struct student stud[10];
For example:
struct student stuarr[3] = {
{“Mary”, 12, 98.5},
{“John”, 11, 97.5},
};
Nested Structures
A structure can be placed within another structure.
Such a structure that contains another structure as its member is called a
nested structure.
typedef struct
{ int x;
int y;
}POINT;
POINT p1={2,3};
display(p1); //passing entire structure p1 to function display()
Passing Structures through Pointers
C allows to create a pointer to a structure.
Like in other cases, a pointer to a structure is never itself a structure, but
merely a variable that holds the address of a structure.
OR