Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
14 views215 pages

Notes

Uploaded by

Brown Girls
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views215 pages

Notes

Uploaded by

Brown Girls
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 215

DATA STRUCTURES AND APPLICATIONS DEPT.

OF AIML

Module-1
Define Data:
Data item refers to single unit of values. Considering any employee, EID, Name, Phone No,
years_of__experience, designation are all examples of data.

Types of Data:
Data can be classified as grouped or elementary data based on the possibility of subdivision.
Grouped data can be further subdivided into components. Eg. Name of any employee can be
subdivided into First_Name, Middle_Name and Last_Name. However, elementary data cannot be
further subdivided. SSN or ID of any employee cannot be further subdivided and is an example for
Elementary data.
Each elementary data or component of a grouped data will have a data type.

Problem:
Identifiy the type of data for following:
(i)Aadhar_Card_Number (ii)Name (iii) Age (iv) Weight (v) Address

Solution:
(i) Aadhar_Card_Number - Elementary and Data Type: Long
(ii) Name: Grouped Data with components First_Name,
Middle_Name and Last_Name and data type is character array.
(iii) Age: Elementary Data and Data Type: Integer
(iv) Weight: Elementary Data and Data Type: Float
(v) Address: Grouped Data with components Street, City, State,
Country, Zip_Code and data type is character array.

Define Entity, Attributes and Entity Set:


Entity is defined as an object of physical or conceptual existence. Eg. Person is an entity of
physicial existence and Department is an entity of conceptual existence
Attributes – properties that further describe an entitiy. Eg. Person entity has attributes ID,
Name, Phone_No, Email_ID etc.
Entity Set- set of instances of an entity providing values to the attributes of an entity.
Eg:
ID Name Age Weight Address
001 Eena 23 66.2 Hasmukh Nagar, Shimoga, Karnataka,
577202
002 Meena 25 55.1 Ajeeb Nagar, Shimoga, Karnataka,
577203
003 Dika 19 100 Daamu Nagar, Shimoga, Karnataka,
577204

Data vs Information:
Parameter Data Information
Definition Raw facts Data with context
Context required Not required as any value starts as Always required
data
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Operations No operations required Any processing operation like


analysis, organization or
summarization on data yields
information
Relationship between Every data need not be an Every information should be
each other information on a data
Examples 9900201045, 35, “AIML”, 52.6 are If 9900201045 is given
all data context as Phone Number, it
becomes information.
Likewise possible context for
35 is age, “AIML” is branch,
52.6 is weight

Files, Records and fields


The data or information collected always need to be physically stored. Such a physical storage is
referred as file and referred by a filename. Each file consists of records, where each record captures
one entity set. Fields represent attributes of an entity and each record fills the values fieldwise.
Hierarchy of files, records and fields is:

Some fields distinguish each record and uniquely define a record. Such fields are called key-fields.
Eg: A Student file can be created which captures records of each student in the college. Each student
record will have values for fields like USN, Name, Dept, Sem, and Sex. USN is unique for each
student and is considered as keyfield.

Fixed-length vs Variable-length records


Parameter Fixed-length Variable-length
Definition Each record is of the same size The size of each record varies
Fields All fields should provide fixed One variable length field
length makes record variable length
Storage Easy to store and acesss Delimiters are required to
separate each record and
coding is required for
processing.
Efficiency Fixed length can either waste Highly efficient mechanism
memory or may some times be for storage
insufficient
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Examples If fields like USN, Sem and Sex is If field Name is used in for
used for Student file, then each Student file, then each Name
record is fixed-length as USN is variable-length and hence
occupies 10 chars, Sem is int, and also makes variable-length
Sex is 1charachter record file.

Problem:
In Hospital patient file: Name, Admission Date, Social Security Number, Room Number, Bed
Number, Doctor, identify primary key and identify each data item as grouped or elementary
with their types

Social Security Number is unique for each patient and hence can be a primary key
Name – Grouped data with components First_Name, Middle_Name and Last_Name with type
character array
Admission Date – Grouped data with components Day, Month and Year with type character array
Social Security Number – Elementary data with type unsigned long
Room Number – Elementary Data with type Integer
Bed Number – Elementary Data with type Integer
Doctor – Grouped data with components First_Name, Middle_Name and Last_Name with type
character array

Problem:
Which of following data items may lead to variable-length records when included as items in
the record:
(a) Age (b) Sex (c) Name of the spouse (d) Names of children (e) Education (f) Previous
employers

Age is fixed size – unsigned integer


Sex – fixed size - one character to store (M, F, and T representing Male, Female and Transgender)
Name of the spouse – variable size
Names of children – variable size
Education – variable size
Previous employers – variable size

Definition of Data Structures


Data structures is defined as a logical or mathematical organization of the data. It can be logical w.r.t
numerical index representation in case of arrays or link to next element in case of Linked List. It can
be mathematical w.r.t pointer representation in case of trees and graphs.

Selection of Data Structures:


Depends on following 2 factors:
(i) Rich enough to represent real world
(ii) Simple enough to process effectively
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Classification of Data Structures:

Linear Data Structures have concept of previous and next for any element. In case of arrays, element
at any index has previous at (index-1) and next at (index+1). For linked list, there is a link from one
element to next element. It is called linear due to contiguous organization in memory. In case of non-
linear data structures elements are not connected linearly (contiguously) and exhibit hierarchical
relationship.

Differentiate Linear and Non-Linear Data Structures;

Array Data Structures:


Array is a collection of homogenous data elements. Each array has a dimension. Set of numbers can
be represented by a 1D array and matrix of numbers can be represented as 2D Arrays. Each array
element is accessed through an index that starts with 0. For 1D, one index is used and for 2D arrays,
2 indices are used. Hence number of indices is proportional to number of dimensions of an array.

Real world examples:


Ticket numbers of friends watching movie is an example of 1D array.
Marks of students in various subjects as in:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Here, 2 1D arrays are used:


char names[5][20] – to represent names of students
char subjects[4][20] – to represent names of subjects.
int marks[5][4] – to represent marks of each student (row) subjectwise (col)

Linked List:
Linked List is a data structure where each element is connected through other element using pointers.
If there are set of elements, one element is connected to another in a sequence and last element is
connected to NULL.

Realword example:
Consider the following file containing customer and the handling sales person:

One way of organizing is use an array for sales person and pointer in the customer file
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Problem with this approach is, if one needs to find all customers of a given sales person, they need to
completely traverse the customer file which is highly inefficient when volume of records increases.

Second way of organizing is use an array for sales person and pointer to customers

Problem with this approach is, that whenever a new customer is added, pointers maintained in
salesperson should be changed. Further whenever an existing customer is deleted, pointers need to be
removed. The pointer manipulation is a complex operation and hence not efficient.

Hence most efficient way of organization is to use Linked List as shown below:

This approach provides advantages like (i) need not traverse entire customer file for searching records
and (ii) multiple pointers need not be maintained which is efficient. Hence it overcomes the
drawbacks of both previous array based approaches.

Tree data structure:


It is a hierarchical data structure representing ancestral relationship (parent, child, grandchild). It
has direction from parent to child. The tree logically grows from top to bottom with a master parent
called root at the top. Parent of the same children are called siblings. However no direction connection
exists between siblings.

Real world examples:


Tree data structure can be applied to capture hierarchical real world scenarios like family tree,
organization chart, payment mechanisms, roadmaps and others.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Problem:
Write a tree for:
Employee (SSN, Name, Address, Age, Salary)

Solution:

This is a 4 level tree. Each subdivision of a field creates a level in the tree.

Problem:
Write a tree for:
(2*x+y)*((a-7*b)^3)

Solution:

While writing tree for expressions, BODMAS rule is used as priority. B-Brackets, O-Order (power),
D-Division, M-Multiplication, A-Addition and S-Subtraction.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Stack Data Structures:


A Stack is a special data structure where insertion and deletion happens at one end called TOP. There
are many real world scenarios where stack is used like Stack of Disks, Stack of Books, Stack of Plates,
Stack of Biscuits and others. Insertion of an element to TOP of the stack is called PUSH and Deletion
of an element from the Stack is called POP. It follows LIFO order (Last In First Out).

Queue Data Structure:


Queue is a special data structure where insertion happens at REAR end and deletion happens
at FRONT end. There are many real world scenarios where Queue is used like Queue of people for
Tickets, Queue of Students near FEE Counter, Queue of People for Lunch, Queue of jobs for printing
documents and others. Insertion operation is called ENQUEUE and deletion operation is called
DEQUEUE.

Graph Data Structure:


Graph is a special data structure where there can be many to many connections between nodes
(elements). The connections can be bidirectional or unidirectional. This data structure is used in
Social Networking like Facebook, LinkedIn, Instagram to represent relationship between users.

Difference between Graph and Trees:


Parameter Trees Graph
Relationship Hierarchical – one way from parent One to many and many to one
to child relationship between elements
Direction From parent to child Both bidirectional in which
case it is undirected or
directional where direction
will be explicitly shown
Path from Source to One unique path Multiple paths possible
Destination
Cycles No cycles can be formed. Tree is Cycles quite possible
hence called Directed Acyclic
Graph
Applications Hierarchical scenarios like Social Networking
organization chart, family tree, applications like Facebook,
tournament ties copy and others Instagram, LinkedIn and
others between users.

Data Structure Operations:


Following are the prominent data structure operations:
(i) Searching – search for occurrence of an element in a given set of elements. Result is
usually finding existence or not of a given element.
(ii) Traversing – an operation in which one starts with first element, then visits second
element, and subsequently all the elements in the order.
(iii) Insertion – an operation to add a new element to a given set of elements. This operation
increases the number of elements.
(iv) Deletion – an operation to delete an existing element from a given set of elements. This
operation decreases the number of elements.
(v) Updation – an operation to update the value of an existing element in a given set of
elements. This operation neither increases nor decreases the number of elements.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

(vi) Sorting – Operation for arranging set of elements in increasing (ascending) or decreasing
(descending) order.
(vii) Merging – An operation for joining the elements of one set to another.

Problem:
Gym center maintains membership file which contains following information (Name, Address,
TelephoneNumber, Age, Sex). Demonstrate all possible operations : Searching, Traversing,
Insertion, Deletion, Updation, Sorting and Merging

Solution:
Searching – search for Gym members based on Name or Address or Age or combination of many
fields.
Traversing – visit all members from beginning to end stored in the membership file one by one.
Insertion – Add a new member to the Gym
Deletion – Remove an existing member from Gym.
Updation – update the profile of a given member in the Gym
Sorting – Order the members in the Gym in the alphabetical order of Names
Merging – In case Gym has multiple centers, merge records of each file maintained into a single file.

Strings:
Strings are defined as sequence (array) of characters. In C, strings data type does not exist, rather it a
character array. In C, all strings are null terminated. Strings are constructed from characters in the
character set. Character set followed in C is ASCII (American Standard Code for Information
Interchange). ASCII character set is made of alphabets (both upper and lower case), digits and special
characters(?,: etc).

Points on Strings:
A finite sequence of zero or more characters is called Strings.
String of zero length is called empty string and denoted by “”;
Characters are denoted by single quotes (‘A’) and strings are denoted by double quotes
(“AIML”)

String Operations:
- Concatenation: An operation in which second string is appended to the end of first string
Notation: S1//S2
Eg: “Hello/World”
- Substring: An operation in which existence of a string inside another string is checked.
Notation: X//Y//Z
Where Y is called substring.
If X is empty, Y is called initial substring
If Z is empty, Y is called terminal substring

- Eg: In a string “Artificial”, “Art” is an initial substring, “cial” is terminal substring and “ifi”
is a substring which is neither initial not terminal substring.
- Size of a character in C is 1 byte which is found by calling sizeof(char)

String Storage Options:


Strings are stored in memory in 3 ways:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

(i) Record Oriented Fixed Length


(ii) Variable Length storage with fixed maximum
(iii) Linked Storage

Consider the following example program to demonstrate all 3 options:

Each line is called record.

(i) Record oriented Fixed Length


In this storage, each line of program is stored in one record of fixed length. Usually the length
is fixed as 80, due to many terminals are of 80 columns. If line length exceeds fixed length, it
is stored as multiple records.
Advantages:
- Easy to access any record by providing index value. Further direct access is possible using
indexing.
- Ease of updation of any record using index value. This is provided the new record length does
not fixed record length.
Drawbacks:
- If a record has lot of blank spaces, lot of time and space wastage occurs.
- In case of records which are lengthy, insertion would require all records to be shifted down.
- Same scenario occurs when records are to be updated and new record length exceeds fixed
length.

Eg:

Solution is to maintain a separate POINT array. Whenever new record is added, POINT array
can be updated to point to the suitable record.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

In this example, new record int x; has to be added before printf, This can be adjusted in the
POINT array without updating original record lines.

(ii) Variable Length storage with Fixed maximum.


In this approach, each line can be of any length but bounded by fixed maximum. Hence
while reading records, only record till its length will be read than fixed length which saves
time while accessing it. There are 2 ways of implementing variable length storage:
1. Using markers – Store a marker $$ at end of each record. Markers are also called
as sentinels.
2. Using length- Store length separately in POINT array. POINT array has length in
first dimension and index in second dimension.

Eg: Using markers

Using lengths

But with this kind of storage, since fixed maximum is used, space is still wasted when record length
is very less than fixed maximum. Hence solution is to use variable length storage with markers and
variable size. Such an example is shown below:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Hence each record can accommodate any number of lines and each occurrence of $$ marks one
record.

(iii) Linked Storage


In the Linked storage, a linked list is maintained for storage. Linked list consists of node
and each node points to a next node. Every node has ‘n’ number of characters, where ‘n’
is decided by application.
Eg: Given string is “ALL IS WELL” and for 1 character per node:

In case, 4 character per node is used, then:

The advantage of Linked Storage is it is both time and space efficient.

String operations:
- SUBSTRING(string, initial, length)
Extracts a substring from main string, starting at initial position till number of characters
defined by length parameter.
Eg: SUBSTRING(“PANIPURI”,3,3) => “NIP”
SUBSTRING(“QUEUE”,2,8)=> “UEUE”

- INDEX(string, pattern)
Checks whether pattern is available in the string. If found, returns location of starting character
in the pattern. If multiple occurences of same pattern exists, location of first occurrence is
returned. If the pattern does not exist, 0 is returned.
Eg: INDEX(“GOBIMANCHURI”, “MAN”) => Returns 5
INDEX(“QUEUE”, “UE”) => Returns 2
INDEX(“GOBIMANCHURI”, “WOMAN”) => Returns 0

- CONCAT (S1, S2)


String S2 is appended to end of S1.
Eg: CONCAT(“TOM”, “JERRY”) => TOMJERRY
CONCAT(“JERRY”, “TOM”) =>JERRYTOM
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

- LENGTH(STRING)
Returns the number of characters in the String
Eg: LENGTH(“SAMSUNG”) returns 7

Pattern Matching Algorithms:


Pattern Matching Algorithms are used check whether a pattern exists in the main string. Such
algorithms returns INDEX of occurrence of pattern in main string. In case, pattern is not
found, they return 0.

Following assumptions are common for all pattern matching algorithms:

Algorithm of First Pattern Matching scheme:


Input: T-Text, P-Pattern, S-LENGTH(T), R-LENGTH(P)
Step 1: Initialize : K=1 and MAX=S-R+1
Step 2: REPEAT STEP 3 to 5 WHILE K<=MAX
Step 3: FOR L=1 to R
IF P[L]≠ T[K+L-1] THEN GOTO STEP 5
Step 4: SET INDEX=K and EXIT
Step 5: K=K+1
Step 6: INDEX=0
Step 7: EXIT

Tracing:
1. T-“JAMBOON”, P-“BOON”

S- LENGTH(T)=7
R- LENGTH(P)=4

Step1: K=1, MAX=S-R+1=7-4+1=4


Step2: WHILE K<=MAX
1<=4=>TRUE
FOR L=1 to R=> FOR L=1 to 4
L=1, P[L] ≠T[K+L-1] => P[1] ≠ T[1+1-1]=> P[1] ≠ T[1]=>B ≠J => EXIT

K=K+1 => K=1+1=2


2<=4 => TRUE
FOR L=1 to R=> FOR L=1 to 4
L=1, P[L] ≠T[K+L-1] => P[1] ≠ T[2+1-1]=> P[1] ≠ T[2]=>B ≠A => EXIT
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

K=K+1 => K=2+1=3


3<=4 => TRUE
FOR L=1 to R=> FOR L=1 to 4
L=1, P[L] ≠T[K+L-1] => P[1] ≠ T[3+1-1]=> P[1] ≠ T[3]=>B ≠M => EXIT

K=K+1 => K=3+1=4


4<=4 => TRUE
FOR L=1 to R=> FOR L=1 to 4
L=1, P[L] ≠T[K+L-1] => P[1] ≠ T[4+1-1]=> P[1] ≠ T[4]=>B =B
L=2, P[L] ≠T[K+L-1] => P[2] ≠ T[4+2-1]=> P[2] ≠ T[5]=>O =O
L=3, P[L] ≠T[K+L-1] => P[3] ≠ T[4+3-1]=> P[3] ≠ T[6]=>O =O
L=4, P[L] ≠T[K+L-1] => P[4] ≠ T[4+4-1]=> P[4] ≠ T[7]=>N =N

SET INDEX=K => INDEX=4

K=K+1 => K=4+1=5


5<=4 => FALSE

RETURN INDEX which is 4

2. T-“JAMBOON”, P-“BONE”

S- LENGTH(T)=7
R- LENGTH(P)=4

Step1: K=1, MAX=S-R+1=7-4+1=4


Step2: WHILE K<=MAX
1<=4=>TRUE
FOR L=1 to R=> FOR L=1 to 4
L=1, P[L] ≠T[K+L-1] => P[1] ≠ T[1+1-1]=> P[1] ≠ T[1]=>B ≠J => EXIT

K=K+1 => K=1+1=2


2<=4 => TRUE
FOR L=1 to R=> FOR L=1 to 4
L=1, P[L] ≠T[K+L-1] => P[1] ≠ T[2+1-1]=> P[1] ≠ T[2]=>B ≠A => EXIT

K=K+1 => K=2+1=3


3<=4 => TRUE
FOR L=1 to R=> FOR L=1 to 4
L=1, P[L] ≠T[K+L-1] => P[1] ≠ T[3+1-1]=> P[1] ≠ T[3]=>B ≠M => EXIT

K=K+1 => K=3+1=4


4<=4 => TRUE
FOR L=1 to R=> FOR L=1 to 4
L=1, P[L] ≠T[K+L-1] => P[1] ≠ T[4+1-1]=> P[1] ≠ T[4]=>B =B
L=2, P[L] ≠T[K+L-1] => P[2] ≠ T[4+2-1]=> P[2] ≠ T[5]=>O =O
L=3, P[L] ≠T[K+L-1] => P[3] ≠ T[4+3-1]=> P[3] ≠ T[6]=>N ≠O =>EXIT
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

K=K+1 => K=4+1=5


5<=4 => FALSE

RETURN INDEX which is 0

Second Pattern Matching Algorithm:


In first algorithm, pattern is checked in the text and compared iteratively to check pattern
exists or not. In second algorithm, text is compared with pattern.
For each pattern, a pattern matching table is created in which columns are unique symbols of
table along with an ‘x’ which represents a symbol not in the pattern. Rows of the table corresponds
to the states, where initial state is Qo and final state is P. Number of states is equal to the number of
characters in the pattern.

Eg: P=aaba
Construction of Pattern matching table:

State a b x
QO Q1 QO QO
Q1 Q2 QO QO
Q2 Q2 Q3 QO
Q3 P QO QO

Corresponding pattern matching graph:

Check for patterns:


(i) T=aabcaba

Since, it lands at an intermediate state, pattern is not found

(ii) T=abcaabaca
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Since, it lands at final state P, pattern is found.

Algortihm:

Input: T-Text, P-Pattern, S-LENGTH(T), R-LENGTH(P)


Step 1: Initialize : K=1 and S1= 𝑸𝟎
Step 2: REPEAT STEP 3 to 5 WHILE 𝑺𝑲 ≠P and K<=N
Step 3: READ 𝑻𝑲
Step 4: SET 𝑺𝑲+𝟏 = 𝑭(𝑺𝑲 , 𝑻𝑲 )
Step 5: SET K=K+1
Step 6: IF 𝑺𝑲 = 𝑷 𝒕𝒉𝒆𝒏
INDEX=K
ELSE
INDEX=0
Step 7: EXIT

Knuth-Morris-Pratt Algorithm
KMP Algorithm is one of the most popular patterns matching algorithms. KMP stands for Knuth
Morris Pratt. KMP algorithm was invented by Donald Knuth and Vaughan Pratt together and
independently by James H Morris in the year 1970. In the year 1977, all the three jointly published
KMP Algorithm. KMP algorithm was the first linear time complexity algorithm for string matching.
KMP algorithm is used to find a "Pattern" in a "Text". This algorithm compares character by
character from left to right. But whenever a mismatch occurs, it uses a preprocessed table
called "Prefix Table" to skip characters comparison while matching. Some times prefix table is also
known as LPS Table. Here LPS stands for "Longest proper Prefix which is also Suffix".

Steps for Creating LPS Table (Prefix Table)


• Step 1 - Define a one dimensional array with the size equal to the length of the Pattern.
(LPS[size])
• Step 2 - Define variables i & j. Set i = 0, j = 1 and LPS[0] = 0.
• Step 3 - Compare the characters at Pattern[i] and Pattern[j].
• Step 4 - If both are matched then set LPS[j] = i+1 and increment both i & j values by one.
Goto to Step 3.
• Step 5 - If both are not matched then check the value of variable 'i'. If it is '0' then set LPS[j]
= 0 and increment 'j' value by one, if it is not '0' then set i = LPS[i-1]. Goto Step 3.
• Step 6- Repeat above steps until all the values of LPS[] are filled.

Eg:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

How to use LPS Table


We use the LPS table to decide how many characters are to be skipped for comparison when a
mismatch has occurred. When a mismatch occurs, check the LPS value of the previous character of
the mismatched character in the pattern. If it is '0' then start comparing the first character of the pattern
with the next character to the mismatched character in the text. If it is not '0' then start comparing the
character which is at an index value equal to the LPS value of the previous character to the
mismatched character in pattern with the mismatched character in the Text.
Eg working of KMP algorithm:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Linear Arrays:
Linear Arrays are a list of finite number of n homogeneous elements such that:
(a) Elements referred by index of n consecutive numbers
(b) Elements stored in contiguous memory allocation
Eg: int a[4] is a linear array as:
it is finite (4 elements), homogeneous as each element is integer, referred by index set {0,1,2,3} and
allocated contiguously in stack. If array a starts with address 1012, next element will be at 1016, then
1020 and last element at 1024.

Number of elements in linear array is computed using formula:


Length=UB-LB+1
where,
UB – Upper Bound is the highest index of the array
LB – Lower Bound is the lowest index of the array ( 0 in many languages, whereas 1 in other
langauges. Can also be negative if language supports negative indexing)

Eg for int a[4], UB=3 and LB=0 Hence Length=UB-LB+1=3-0+1=4

Further, for linear arrays, concept of subscript and subscripted variables exists.
In case of int a[4], one can access third element of an array as a[2].
Here 2 is the subscript and a[2] is called subscripted variable.

Linear Array Declaration:


Each declaration of an array has 3 pieces of information:
(1) Name of the array
(2) Data type of the array
(3) Index set of the array
Eg:
For array declaration float points[5],
Name is points, data type is float and index set is {0,1.2.3.4}
Linear Arrays can be accessed in constant time, means to access any element in the array same time
is required. Eg. int a[100], to access first element (a[0]). Fiftieth element (a[49]) and 100th element
(a[99]) same time is required.

Representation of Linear Array in Memory:


There are two types of declaration of Linear Arrays: (i) Static and (ii) Dynamic.
In case of static memory allocation, stack is used and in case of dynamic, heap is used.
Eg;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Differences between Static and Dynamic memory allocation of Linear Arrays:

Parameter Static Memory Allocation Dynamic Memory Allocation


Memory Area Stack is used Stack is used to store pointer to
the array and array is stored in
heap
Number of elements Fixed during compile time Can be changed during runtime
Need of any functions No, just mention the number of Yes, malloc() for memory
elements while declaring then allocation and free() to clear the
arrays same
Garbage formation No, as the stack is cleared If free() is not called, the array in
when the function/program the heap becomes garbage after
exits function/program exits
Space Efficiency Becomes fixed and can lead to Consumes as much space required
either too much or too less
Overhead No overheads Maintaining an additional pointer
in the stack to refer to array in the
heap
Example int A[4] int *A;
A=malloc(sizeof(int)*4);

Dynamic Memory Allocation Functions


The concept of dynamic memory allocation in c language enables the C programmer to allocate
memory at runtime. Dynamic memory allocation in c language is possible by 4 functions of stdlib.h
header file.
1. malloc()
2. calloc()
3. realloc()
4. free()

malloc() allocates single block of requested memory.


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

calloc() allocates multiple block of requested memory.

realloc() reallocates the memory occupied by malloc() or calloc() functions.

free() frees the dynamically allocated memory.

malloc() function in C
The malloc() function allocates single block of requested memory. It doesn't initialize memory
at execution time, so it has garbage value initially. It returns NULL if memory is not sufficient.
The syntax of malloc() function is given below:
ptr=(cast-type*)malloc(byte-size)
Eg:
ptr=(int *)malloc(sizeof(int)*5); //Allocates 5 blocks of integers and returns pointer to first
block and all blocks contain garbage.

calloc() function in C
The calloc() function allocates multiple block of requested memory. It initializes all bytes to
zero. It returns NULL if memory is not sufficient.
The syntax of calloc() function is given below:
ptr=(cast-type*)calloc(number, byte-size)
Eg:
ptr=(int *)calloc(5,sizeof(int)); //Allocates 5 blocks of integers and returns pointer to first
block. Further all blocks are set to NULL

realloc() function in C
If memory is not sufficient for malloc() or calloc(), you can reallocate the memory by realloc()
function. In short, it changes the memory size.
Let's see the syntax of realloc() function.
ptr=realloc(ptr, new-size)
Eg:
ptr=(int *)ralloc(ptr,sizeof(int)*7); //Resizes ptr to contain 7 blocks of memory

free() function in C
The memory occupied by malloc() or calloc() functions must be released by calling free() function.
Otherwise, it will consume memory until program exit.
Let's see the syntax of free() function.
free(ptr)

Programs/Algorithms on Linear Array Operations:


1. Creating and Displaying Array:

Algorithm for Creating Array:


Step 1: Start
Step 2: Read the size of the array (N) as input from the user
Step 3: Allocate the required memory (Specified size * Data type size) and store pointer as ARR
Step 4:For I=0 to N-1
4.1: Read element from keyboard
4.2: Store the element in ARR[I]
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Step 5: Return

Algorithm for Displaying the Array:


Step 1: Start
Step 2: For I=0 to N-1
2.1: Print the element in ARR[I]
Step 3: Return

#include<stdio.h>
void create_array(int *arr,int n)
{
printf("Enter %d array elements one by one\n",n);
int i;
for(i=0;i<n;i++)
{
scanf("%d",&arr[i]);
}
}

void display_array(int *arr,int n)


{
printf("Array Elements are \n");
int i;
for(i=0;i<n;i++)
{
printf("%d\n",arr[i]);
}
}

void main()
{
int choice,n,sum,min;
int *arr;
while(1)
{
printf("***********Array Menu Operations*******\n");
printf("1. Create\n");
printf("2. Display\n");
printf("3. Exit\n");
printf("Enter your choice\n");
scanf("%d",&choice);

switch(choice)
{
case 1: printf("Create an array\n");
printf("Enter the value of n\n");
scanf("%d",&n);
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

arr=malloc(sizeof(int)*n);
create_array(arr,n);
break;
case 2:printf("Display the array\n");
display_array(arr,n);
break;
case 3:exit(0);
default:printf("Enter 1 2 or 3\n");

}
}
}

2. Bubble Sort
Algorithm:
Step 1: Start
Step 2: Initialize an array ARR of ‘N’ elements
Step 3: For I=0 to N-1 //Passes
Step 3.1: FOR J=0 to N-1-I //Comparisons
Step 3.1.1: IF ARR[J] > ARR[J+1]
SWAP ARR[J] and ARR[J+1]
Step 4: FOR I=0 to N-1
Step 4.1 PRINT ARR[I]
Step 5: Return

C Program:
#include<stdio.h>
void main()
{

int a[5]={1,3,2,4,0};
int N=5,i,j,t;
//Loop for passes
for(i=0;i<N-1;i++)
{
//Loop for comparisons
for(j=0;j<N-i-1;j++)
{
//Check for swapping
if(a[j]>a[j+1])
{
//Do swapping
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}

}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

//Print sorted array


for(i=0;i<N;i++)
{
printf("%d\n",a[i]);
}
}

3. Linear Search
Algorithm:
Step 1: Start
Step 2: Initialize an array ARR of ‘N’ elements
Step 3: Read key KEY from the user
Step 4: For I=0 to N-1 //Searching Loop
Step 4.1: IF ARR[I]==KEY THEN
PRINT “SUCCESSFUL SEARCH”
RETURN
Step 5: PRINT “UNSUCCESSFUL SEARCH”
Step 6: Return

C Program:
#include<stdio.h>
void main()
{

int a[5]={1,3,2,4,0};
int KEY,i,N=5;
printf("Enter the key\n");
scanf("%d",&KEY);
//Loop for passes
for(i=0;i<N;i++)
{
if(a[i]==KEY)
{
printf("Succesful Search\n");
exit(0);
}
}
printf("Unsuccesful Search\n");
}
Multidimensional Arrays:
Multidimensional Arrays are the linear arrays with number of dimensions more than 1. Few examples
are matrix of 2 dimension (with rows and columns), image of 3 dimension (channels, rows, columns),
video of 4 dimension (frame, channels, rows, columns).
Representation of 2D Arrays in memory:
There are 2 representations: Row-major order and Column-major order.
In the row-major order, the elements are stored row by row. First row elements are filled,
subsequently second row elements till last row.
In the column-major order, the elements are stored column by column. First column elements are
filled, subsequently second column elements till last column.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Eg:

Programs/Algorithms on 2D Arrays:
1. Creating 2D array statically, reading input from keyboard, displaying matrix and
computing trace

Algorithm:
Step 1: Start
Step 2: Create 2D array MAT with size M and N
Step 3: FOR I=0 to M-1
Step 3.1: FOR J=0 to N-1
Step 3.1.1: Read element from keyboard and store into MAT[I][J]
Step 4: FOR I=0 to M-1
Step 4.1: FOR J=0 to N-1
Step 4.1.1: PRINT MAT[I][J]
Step 5: FOR I=0 to M-1
Step 5.1: SUM=SUM+ MAT[I][I]
Step 6: PRINT SUM
Step 7: Return

C Program:
#include<stdio.h>
void main()
{
int M=3,N=3;
int mat[M][N],i,j;

int sum=0;
printf("Enter the matrix elements\n");
for(i=0;i<M;i++)
{
for(j=0;j<N;j++)
{
scanf("%d",&mat[i][j]);

}
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

printf("Matrix:\n");
for(i=0;i<M;i++)
{
for(j=0;j<N;j++)
{
printf("%d ",mat[i][j]);

}
printf("\n");
}
for(i=0;i<M;i++)
{
sum=sum+mat[i][i];
}
printf("Trace of matrix=%d\n",sum);

2. Creating 2D array dynamically, reading input from keyboard, displaying matrix and
computing trace

Algorithm:
Step 1: Start
Step 2: Get M (no of rows) and N (no of cols) from user
Step 3: Create a pointer to point to a pointer array MAT
Step 4: FOR I=0 to M-1
Step 4.1: Allocate memory for each element of MAT[i]

Step 5: FOR I=0 to M-1


Step 3.1: FOR J=0 to N-1
Step 3.1.1: Read element from keyboard and store into MAT[I][J]
Step 6: FOR I=0 to M-1
Step 4.1: FOR J=0 to N-1
Step 4.1.1: PRINT MAT[I][J]
Step 7: FOR I=0 to M-1
Step 5.1: SUM=SUM+ MAT[I][I]
Step 8: PRINT SUM
Step 9: Return

C Program:
#include<stdio.h>
void main()
{
int **mat,i,j,M,N;
printf("Enter the value of M and N\n");
scanf("%d%d",&M,&N);
mat=malloc(sizeof(int*)*M);
for(i=0;i<M;i++)
{
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

mat[i]=malloc(sizeof(int)*N);
}
int sum=0;
printf("Enter the matrix elements\n");
for(i=0;i<M;i++)
{
for(j=0;j<N;j++)
{
scanf("%d",&mat[i][j]);

}
}
printf("Matrix:\n");
for(i=0;i<M;i++)
{
for(j=0;j<N;j++)
{
printf("%d ",mat[i][j]);

}
printf("\n");
}
for(i=0;i<N;i++)
{
sum=sum+mat[i][i];
}
printf("Trace of matrix=%d\n",sum);

3. C Program to compute trace of a dynamically allocated 2D Array

Algorithm:
Step 1: Start
Step 2: Set M to no of rows and N to no of cols
Step 3: Create a pointer to point to a pointer array MAT
Step 4: FOR I=0 to M-1
Step 4.1: Allocate memory for each element of MAT[i]

Step 5: FOR I=0 to M-1


Step 3.1: FOR J=0 to N-1
Step 3.1.1: Read element from keyboard and store into MAT[I][J]
Step 6: FOR I=0 to N-1 //Iterate till no of columns
Step 4.1: FOR J=0 to M-1 //Iterate till no of rows
Step 4.1.1: PRINT MAT[J][I] //Change of row and column index
Step 7: Return

#include<stdio.h>
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

void main()
{
int **mat;
int i,j,m=3,n=2;
mat=malloc(sizeof(int*)*m);
for(i=0;i<m;i++)
{
mat[i]=malloc(sizeof(int)*n);
}
printf("Enter the matrix values one by one\n");
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
scanf("%d",&mat[i][j]);
}
}
printf("Transpose of matrix\n");
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
printf("%d ",mat[j][i]);
}
printf("\n");
}
}
Address computation of an array element:
Address of any element of an array can be computed using formulae:

𝑨𝒅𝒅𝒓𝒆𝒔𝒔 𝒐𝒇 𝑨[𝒌] = 𝑩𝑨(𝑨) + 𝒘(𝒌 − 𝑳𝑩)


where,
k – subscript
BA – Base Address
w – word length- 2bytes for int, 4bytes for float (32 bit compilers)
LB – lower bound

Eg. Consider array declaration: int A[10] and base address=1012


Address of A[7]=1012+2*(7-0) = 1012 + 14 =1026

Storing the values of an array:


There are three techniques to store array values:
(i) Declaration with initialization:
Eg: int a[4]={1,2,3,4} OR int a[]={1,2,3,4}. Both syntax are correct. In first case, programmer
specifies the size and in latter case compiler automatically computes the size.

(ii) Read from keyboard:


Loops are used with indexing to read all the values of an array from keyboard.
Eg: for(i=0;i<n;i++)
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

scanf(“%d”,&a[i]);

(iii) Assign individually


The subscript of the array can be used to store each element individually.
Eg: int a[4];
a[0]=10;
a[1]=20;
a[2]=14;
a[3]=22;

Write a C program to demonstrate full array copying:


#include<stdio.h>

void main()
{
int i;

int a[]={1,2,3,4,5,6,7,8};
int b[8];
for(i=0;i<8;i++)
{
b[i]=a[i]; //Copying code
}
for(i=0;i<8;i++)
printf("%d\n",b[i]);

}
Write a C program to demonstrate selective copying of an array
#include<stdio.h>

void main()
{
int i;

int a[]={1,2,3,4,5,6,7,8};
int b[4],j=0;
for(i=0;i<8;i++)
{
if(a[i]%2==0) //Only copy Even number
{
b[j++]=a[i];
}
}
for(i=0;i<4;i++)
printf("%d\n",b[i]);

Jagged Arrays:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

A double pointer can be created in stack which can point to Pointer Arrays. Each pointer in the
pointer array can point to arrays of variable size. An array in which each row contains variable number
of columns is called “Jagged Arrays”.

C Program to demonstrate jagged arrays:


#include<stdio.h>
void main()
{
char **jag; //Jagged Array
int i,j;
jag=malloc(sizeof(char*)*4); //Allocate memory for rows
for(i=0;i<4;i++)
{
jag[i]=malloc(sizeof(char)*(i+1)); //Allocate memory for columns of each row

}
for(i=0;i<4;i++)
{
for(j=0;j<=i;j++) // j depends on i
{
jag[i][j]='*';
}

}
for(i=0;i<4;i++)
{
for(j=0;j<=i;j++)
{
printf("%c ",jag[i][j]);
}
printf("\n");
}
}

C Program to create following patterns using jagged arrays:


*
* *
* * *
* * * *

#include<stdio.h>
void main()
{
char **jag; //Jagged Array
int i,j;
jag=malloc(sizeof(char*)*4); //Allocate memory for rows
for(i=0;i<4;i++)
{
jag[i]=malloc(sizeof(char)*(i+1)); //Allocate memory for columns of each row
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

}
for(i=0;i<4;i++)
{
for(j=0;j<=i;j++) // j depends on i
{
jag[i][j]='*';
}
}
for(i=0;i<4;i++)
{
for(j=0;j<=i;j++)
{
printf("%c ",jag[i][j]);
}
printf("\n");
}
}

Structures:
Structures are collection of heterogeneous elements. Arrays are collection of homogeneous
elements. Heterogeneity of structures is with respect to different type of data packed in a structure.
Eg:
struct person
{
char name[10];
int age;
float salary;
};
Here person is called tag of structure and name, age and salary are called fields.

Hence a structure in this example holds different types of data like character array, integer and floating
point.

To create a variable of structure type, syntax is:


struct person p1;

To assign the values to fields of structure use “.” operator:


strcpy(p1.name,”manu”) //Note strings cant be directly assigned, You have to use strcpy
p1.age=22;
p1.salary=25000.0;

To create an alias for a structure, typedef is used.


Eg: instead of struct person one can alias it to person with following syntax:
typedef struct
{
char name[10];
int age;
float salary;
}person;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Note: while computing the size of structure, for a character array take size in multiple of word
boundary (multiple of 4)

C program to check whether 2 persons are identical:

#include<stdio.h>
typedef struct
{
char name[20];
int age;
float salary;

}person;

void comparePersons(person p1, person p2)


{
if(strcmp(p1.name,p2.name)==0 && p1.age==p2.age && p1.salary==p2.salary)
{
printf("Both are same\n");
}
else
{
printf("Both are different");
}
}
void main()
{
person p1={"ramu",22,20000};
person p2={"ramu",22,20000};
comparePersons(p1,p2);
}

Write a C program to create an array of 3 persons, read the data and print the same – Use
static allocation

#include<stdio.h>

typedef struct
{
char name[20];
int age;
float salary;

}person;

void main()
{
int i;
person p[3]; //Static allocation by Declaration
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

//Read the data


printf("Enter details of 3 person\n");
for(i=0;i<3;i++)
{
scanf("%s%d%f",p[i].name,&p[i].age,&p[i].salary);
}
//Print the data
for(i=0;i<3;i++)
{
printf("%s,%d,%f\n",p[i].name,p[i].age,p[i].salary);
}
}

Write a C program to create an array of n persons, read the data and print the same – Use
dynamic allocation.

#include<stdio.h>
typedef struct
{
char name[20];
int age;
float salary;
}person;

void main()
{
int i,n;
printf("Enter the value of n \n");
scanf("%d",&n);
person *p; //Declaration
p=malloc(sizeof(person)*n);
//Read the data
printf("Enter details of %d person\n",n);
for(i=0;i<n;i++)
{
scanf("%s%d%f",p[i].name,&p[i].age,&p[i].salary);
}
//Print the data
for(i=0;i<n;i++)
{
printf("%s,%d,%f\n",p[i].name,p[i].age,p[i].salary);
}
free(p);//Ensures no garbages are created
}

Nested Structures:
One can put a structure inside another and this concept is called Nested structures.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Previous program can be modified with person structure containing a structure for date of
birth as follows:

#include<stdio.h>
typedef struct
{
int day;
int month;
int year;
}dob;
typedef struct
{
char name[20];
int age;
float salary;
dob d; //Since aliased dob can be directly used instead of struct dob
}person; //Person is a nested structure containing DOB

void main()
{
int i,n;
printf("Enter the value of n \n");
scanf("%d",&n);
person *p; //Declaration
p=malloc(sizeof(person)*n);
//Read the data
printf("Enter details of %d person\n",n);
for(i=0;i<n;i++)
{
scanf("%s%d%f%d%d%d",p[i].name,&p[i].age,&p[i].salary,
&p[i].d.day,&p[i].d.month,&p[i].d.year);
}
//Print the data
for(i=0;i<n;i++)
{
printf("%s,%d,%f,%d,%d,%d\n",p[i].name,p[i].age,p[i].salary ,
p[i].d.day,p[i].d.month,p[i].d.year);
}

free(p);//Ensures no garbages are created


}
Structures v/s Unions
Sl. Parameter Structure Union
No.
3. Keyword struct keyword is used to define union keyword is used to
structures define union
4. Memory size The total size of a structure is The total size of a union is
equal to the sum of the different equal to the maximum of the
fields in a structure different fields in a union
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

5. Memory Allocation Separate block of memory is Single block of memory is


allotted to each field allocated which is shared by
all the fields
6. Example size typedef struct typedef union
computation { {
char name[22]; char name[22];
int age; int age;
int rank; int rank;
}person; }uperson;
Size=24(due to multiple of 4 Size=24(due to multiple of 4
rule)+4+4=32 rule)

7. Access Simultaneous access of multiple Only one member can be


members is possible accessed at each time. Other
fields become garbages at
that time
8. Change of value Multiple members value can be Only one member value can
changed. be changed at any time and
other members then become
garbage.

Self Referential Structures:


Structures in which a field refers the defined structure is called Self Referrential structures. Eg:
typedef struct
{
int data;
struct list *next;
} list;

void main()
{
list *l1,*l2,*l3;
l1=malloc(sizeof(list));
l2=malloc(sizeof(list));
l3=malloc(sizeof(list));
l1->data=20;
l1->next=l2;
l2->data=40;
l2->next=l3;
l3->data=10;
l3->next=NULL;

Here structure list contains a pointer next which refers to structure list itself and hence the structure
is called Self Referential structure. Further this structure represents one node and multiple nodes (l1,
l2,l3) is created. Dynamically memory is allocated for each node. The pointers create a link between
nodes and resulting structure is called linked list.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Sparse Matrix Representation using Arrays


Sparse Matrix is a special matrix which consists of most of zero elements and few non-zero elements.
Hence instead of 2D representation for sparse matrix, a structure based representation can be used to
efficiently represent the matrix, The structure consists of fields namely row, column and value,

Eg. Consider a sparse matrix of size 4X4


0001
1002
0300
0040

The corresponding sparse storage is:

First row corresponds to number of rows, number of columns and number of non-zero elements. Rest
of the rows are filled row-wise and in each row column-wise. Only non-zero elements are considered
and for each non-zero element, row index, column index and value is recorded.

Using this sparse storage, transpose can be computed by copying from first entry of sparse storage
with row and column values being swapped. Then from subsequent entries in sparse storage, lowest
column number is found. For each such entry, row and column indices are swapped, value is retained
in an entry created in transpose. For the example discussed above, corresponding transpose is:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

This transpose computation is inefficient as the complexity = (number of terms)*(number of


columns). This multiplicative increase is due to the nested for loops used while computing transpose.

Alternative fast transpose technique:


Row terms array is constructed where number of entries equal to number of columns. Row terms give
frequency count of each column index in sparse storage. Row terms is initially initialzed to 0. Later
based on the frequency of occurrence of each column index, increment is done.

Initially After frequency count updation

Starting position of each column index is recorded using formula:


startingpos[index]=startingpos[index-1]+rowterms[index-1]
startingpos[0] is set to 1.

The resulting starting position of the above example is:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Fast transpose is computed by finding position of each column index using startingpos array. Then
row and column values are swapped and value entry of column index in sparse storage is copied to a
position in the fast transpose array indicated by startingpos value.

Resulting fast transpose for the above example is:

The complexity of this transpose is = 2*(numterms+numofcolumns). Hence it is an additive increase


and do not have any nested loops. This transpose is thus faster than the conventional transpose
computation.

Implementation of sparse matrix, transpose and fast transpose:


typedef struct
{
int row;
int col;
int value;
} term;

void read_matrix(int mat[10][10],int m,int n)


{
int i,j;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

{
scanf("%d",&mat[i][j]);
}
}
}
void print_matrix(int mat[10][10],int m,int n)
{
int i,j;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
printf("%d ",mat[i][j]);
}
printf("\n");
}
}

int create_sparse(int mat[10][10],int m,int n, term a[10])


{
int nzi=0,i,j;
a[0].row=m;
a[0].col=n;
int cnt=1;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
if(mat[i][j]!=0)
{
a[cnt].row=i;
a[cnt].col=j;
a[cnt].value=mat[i][j];
cnt++;
}
}
}
a[0].value=cnt-1;
return (cnt-1);
}
void display_sparse(term a[10], int nzi)
{
int i;
for(i=0;i<=nzi;i++)
{
printf("%d %d %d\n",a[i].row,a[i].col,a[i].value);
}

}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

void transpose_sparse(term a[20],term b[20])


{
int i,j,cb;
b[0].row=a[0].col;
b[0].col=a[0].row;
b[0].value=a[0].value;
cb=1;
for(i=0;i<a[0].col;i++) //Column indices
{
for(j=1;j<=a[0].value;j++)
{
if(a[j].col==i)
{
b[cb].row=a[j].col;
b[cb].col=a[j].row;
b[cb].value=a[j].value;
cb++;
}
}
}

void fast_transpose(term a[10],term b[10])


{
int i,j;
int rowTerms[10],startingPos[10];
//Fill the first row of transpose
b[0].row=a[0].col;
b[0].col=a[0].row;
b[0].value=a[0].value;
//Initialize rowterms array elements to 0
for(i=0;i<a[0].col;i++)
rowTerms[i]=0;
//For each column in sparse, increment rowterm entry by 1
for(j=1;j<=a[0].value;j++)
{
rowTerms[a[j].col]++;
}
//Initialize statring position first element to 1
startingPos[0]=1;
//Update starting position by forumla: sp[i]=sp[i-1]+rowterms[i-1]
for(i=1;i<a[0].col;i++)
{
startingPos[i]=startingPos[i-1]+rowTerms[i-1];
}
//For each column in sparse, find its location in transpose
for(i=1;i<=a[0].value;i++)
{
j=startingPos[a[i].col];
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

b[j].row=a[i].col;
b[j].col=a[i].row;
b[j].value=a[i].value;
j++;
}

}
void main()
{
int mat[10][10],m,n,nzi;
term a[10],b[10];
m=3,n=4;
read_matrix(mat,m,n);
print_matrix(mat,m,n);
nzi=create_sparse(mat,m,n,a);
display_sparse(a,nzi);
transpose_sparse(a,b);
printf("TRanspose.....\n");
display_sparse(b,nzi);
fast_transpose(a,b);
printf("Fast TRanspose.....\n");
display_sparse(b,nzi);

Polynomials using Arrays:


A polynomial is composed of different terms where each of them holds a coefficient and an
exponent. A polynomial p(x) is the expression in variable x which is in the form (axn + bxn-1 + …. +
jx+ k), where a, b, c …., k fall in the category of real numbers and 'n' is non negative integer, which
is called the degree of polynomial.
An essential characteristic of the polynomial is that each term in the polynomial expression consists
of two parts:
• one is the coefficient
• other is the exponent
Example:
10x2 + 26x, here 10 and 26 are coefficients and 2, 1 is its exponential value.

Two ways to implement Polynomials:


(i) Using Single structure for entire polynomial
(ii) Using a structure for each term of the polynomial

(i) Using Single structure for entire polynomial


Consider polynomials A and B:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Degree of SUM is computed as highest degree of A and B


Then for each polynomial highest exponent is computed if not already computed. If both polynomials
have same highest exponent, sum of coefficients is performed. Else only coefficient of polynomial
with highest exponent is recorded into SUM. In case some of terms in a polynomial remains unvisited,
they are called residual terms and are transferred as it is to SUM.

Implementation using C:
#include<stdio.h>

#define MAXTERMS 10
typedef struct
{
int degree;
int coeff[MAXTERMS];
} polynomial;

//Zeroing a polynomial
polynomial Zero(polynomial p)
{
int i;
p.degree=0;
for(i=0;i<MAXTERMS;i++)
p.coeff[i]=0;
return p;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

//Function to check whether polynomial is zero


int isZero(polynomial p)
{
int i;
for(i=p.degree;i>=0;i--)
{
if(p.coeff[i]!=0)
return 0;//No;
}
return 1;//Yes
}

//Find the leading exponent


int leadExp(polynomial p)
{
int i;
for(i=p.degree;i>=0;i--)
{
if(p.coeff[i]!=0)
return i;
}
return 0;
}

//Find the coefficient of a given exponent


int Coef(polynomial p, int exp)
{
return p.coeff[exp];

//Attach
polynomial attach(polynomial p, int e, int c)
{
p.coeff[e]=c;
return p;
}
//Detach
polynomial detach(polynomial p, int e)
{
p.coeff[e]=0;
return p;
}
//Adding 2 polynomials
polynomial add(polynomial a, polynomial b, polynomial c)
{
int sum;
c.degree=leadExp(a)>leadExp(b)?leadExp(a):leadExp(b);
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

while(!isZero(a) && !isZero(b))


{
if(leadExp(a)>leadExp(b))
{
c=attach(c,leadExp(a),Coef(a,leadExp(a)));
a=detach(a,leadExp(a));
}
else if(leadExp(a)<leadExp(b))
{
c=attach(c,leadExp(b),Coef(b,leadExp(b)));
b=detach(b,leadExp(b));
}
else
{
sum=Coef(a,leadExp(a))+Coef(b,leadExp(b));
c=attach(c,leadExp(a),sum);
a=detach(a,leadExp(a));
b=detach(b,leadExp(b));
}
}
//Residual case for A
while(!isZero(a))
{
c=attach(c,leadExp(a),Coef(a,leadExp(a)));
a=detach(a,leadExp(a));
}
//Residual case for B
while(!isZero(b))
{
c=attach(c,leadExp(b),Coef(b,leadExp(b)));
b=detach(b,leadExp(b));
}
return c;
}

//Displaying polynomial
void display(polynomial p)
{
int i;
for(i=p.degree;i>=0;i--)
{
printf("%dx^%d +",p.coeff[i],i);
}
printf("\b \n");
}
void main()
{
polynomial a,b,c;
a=Zero(a);
a.degree=2;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

a.coeff[2]=4;
a.coeff[1]=6;
a.coeff[0]=1;

b=Zero(b);
b.degree=1;
b.coeff[1]=5;
b.coeff[0]=5;
display(a);
display(b);
c=add(a,b,c);
display(c);
}

(ii) Using a structure for each term of the polynomial


Consider the example polynomials A and B:

Structure to be used:

Filling of Polynomial A:

Filling of Polynomial B:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Construction of polynomial SUM

Implementation using C:
#define MAXTERMS 100
typedef struct
{
float coeff;
int expon;
}polynomial;

polynomial terms[MAXTERMS];
int startA,startB,finishA,finishB,avail=0;

//Attaching value to a term of polynomial


void attach(float coeff, int exp)
{

terms[avail].coeff=coeff;
terms[avail].expon=exp;
avail++;
}

void add(int startA,int finishA, int startB, int finishB, int *startD, int *finishD)
{
float sum;
avail=finishB+1;
*startD=avail;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

while((startA<=finishA)&& (startB<=finishB))
{
if(terms[startA].expon>terms[startB].expon)
{
attach(terms[startA].coeff,terms[startA].expon);
startA++;
}
else if(terms[startA].expon<terms[startB].expon)
{
attach(terms[startB].coeff,terms[startB].expon);
startB++;
}
else
{
float sum=terms[startA].coeff+terms[startB].coeff;
attach(sum,terms[startA].expon);
startA++;
startB++;
}
}
while((startA<=finishA))
{
attach(terms[startA].coeff,terms[startA].expon);
startA++;
}
while((startB<=finishB))
{
attach(terms[startB].coeff,terms[startB].expon);
startB++;
}
*finishD=avail-1;
}

void display(int start, int finish)


{
int i;
for(i=start;i<=finish;i++)
{
printf("%fx^%d +",terms[i].coeff,terms[i].expon);

}
printf("\b \n");
}

void main()
{
int startD,finishD;
terms[0].coeff=2;
terms[0].expon=1000;
terms[1].coeff=1;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

terms[1].expon=0;
terms[2].coeff=1;
terms[2].expon=4;

terms[3].coeff=10;
terms[3].expon=3;
terms[4].coeff=3;
terms[4].expon=2;
terms[5].coeff=1;
terms[5].expon=0;

add(0,1,2,5,&startD,&finishD);
display(0,1);
display(2,5);
display(startD,finishD);
}

Lab Component:
1. Design, Develop and Implement a menu driven Program in C for the following Array
Operations
a. Creating an Array of N Integer Elements
b. Display of Array Elements with Suitable Headings
c. Exit.
Support the program with functions for each of the above operations.

#include<stdio.h>
void create_array(int *arr,int n)
{
printf("Enter %d array elements one by one\n",n);
int i;
for(i=0;i<n;i++)
{
scanf("%d",&arr[i]);
}
}

void display_array(int *arr,int n)


{
printf("Array Elements are \n");
int i;
for(i=0;i<n;i++)
{
printf("%d\n",arr[i]);
}
}

void main()
{
int choice,n,sum,min,max;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

int *arr;
while(1)
{
printf("***********Array Menu Operations*******\n");
printf("1. Create\n");
printf("2. Display\n");
printf("3. Exit\n");
printf("Enter your choice\n");
scanf("%d",&choice);

switch(choice)
{
case 1: printf("Create an array\n");
printf("Enter the value of n\n");
scanf("%d",&n);
arr=malloc(sizeof(int)*n);
create_array(arr,n);
break;
case 2:printf("Display the array\n");
display_array(arr,n);
break;
case 3:exit(0);
default:printf("Enter 1 2 or 3\n");

}
}
}

2. Design, Develop and Implement a menu driven Program in C for the following Array
operations
a. Inserting an Element (ELEM) at a given valid Position (POS)
b. Deleting an Element at a given valid Position POS)
c. Display of Array Elements
d. Exit. Support the program with functions for each of the above operations.

Program:
#include<stdio.h>
void create_array(int *arr,int N)
{

printf("Enter array elements one by one\n");


int i;
for(i=0;i<N;i++)
scanf("%d",&arr[i]);

}
void display_array(int *arr, int N)
{
int i;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

for(i=0;i<N;i++)
printf("%d\n",arr[i]);

int sum_array(int *arr, int N )


{
int i,sum=0;
for(i=0;i<N;i++)
sum=sum+arr[i];
return sum;
}

int min_array(int *arr, int N )


{
int i,min=arr[0];
for(i=1;i<N;i++)
{
if(arr[i]<min)
min=arr[i];
}
return min;
}
void insert_array(int *arr,int N,int ELEM, int POS)
{
int i;
for(i=N-1;i>POS;i--)
{
arr[i]=arr[i-1];
}
arr[POS]=ELEM;

}
void delete_array(int *arr, int N, int POS)
{
int i;
for(i=POS;i<N-1;i++)
{
arr[i]=arr[i+1];
}
}

void main()
{
int N=0,choice,sum,min,ELEM,POS;
int *arr;
while(1)
{
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

printf("*****************Menu****************\n");
printf("1: Create\n");
printf("2: Display\n");
printf("3: Sum\n");
printf("4: Minimum\n");
printf("5: Insert\n");
printf("6: Delete\n");
printf("7: Exit\n");
printf("Enter your choice\n");
scanf("%d",&choice);
switch(choice)
{
case 1:printf("Enter the value of N\n");
scanf("%d",&N);
arr=(int*)malloc(sizeof(int)*N);
create_array(arr,N);
break;
case 2:if(N>0)
display_array(arr,N);
else
printf("Nothing to display\n");
break;
case 3:sum=sum_array(arr,N);
printf("Sum of the array=%d\n",sum);
break;
case 4: min=min_array(arr,N);
printf("Sum of the array=%d\n",min);
break;
case 5: printf("Enter the ELEMENT \n");
scanf("%d",&ELEM);
printf("Enter the POSITION\n");
scanf("%d",&POS);
N=N+1;
arr=realloc(arr,N*sizeof(int));
insert_array(arr,N,ELEM,POS);
break;
case 6:printf("Enter the POSITION\n");
scanf("%d",&POS);
delete_array(arr,N,POS);
N=N-1;
arr=realloc(arr,N*sizeof(int));
break;
case 7:exit(0);
default:printf("Invalid choice \n");
break;

}
}
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Module-2
Stacks
Stacks are a special kind of data structure in which insertion and deletion happens at the same end
called top of the stack. Stack follows a Last-In-First-Out data structure. Books arranged on top of
each other, plates arranged in a reception, box of pringles potato chips and many others are real time
examples of the stack.
Stack Operations:
1. CREATE – used to create an empty stack of specific size.
2. PUSH – used to insert an element to the top of the stack
3. POP – used to remove an element from the top of the stack.
4. DISPLAY – display all the elements of the stack.

Stack States:
Stack can enter a state called “Overflow” when one tries to push an element to the stack beyond
its capacity. Stack can also enter a state called “Underflow” when one tries to pop an element from
an empty stack.
Stacks are static, if the size is fixed during compile time and once stack reaches this size, more
elements cannot be pushed. The memory for such a stack is allocated in the stack area of the memory.
Stacks can also be dynamic. Memory for such a stacks is allocated in the heap area of the memory.
Once size of the stack reaches max size, memory is doubled and reallocated.

Implementation of static stacks:


#define MAXSIZE 5
typedef struct
{
int data;
}stack;
int top=-1;
int isFull(stack arr[MAXSIZE])
{
if(top==MAXSIZE-1)
{
return 1; //Stack is full
}
return 0; //Stack is not full
}

int isEmpty(stack arr[MAXSIZE])


{
if(top==-1)
{
return 1; //Stack is empty
}
return 0; //Stack is not empty
}

void push(stack arr[MAXSIZE],int ele)


{
if(isFull(arr))
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

{
printf("Stack overflow\n");
return;
}
arr[++top].data=ele;
}

void pop(stack arr[MAXSIZE])


{
if(isEmpty(arr))
{
printf("Stack underflow\n");
return;
}
printf("Element popped=%d\n",arr[top].data);
top--;
}
void display(stack arr[MAXSIZE])
{
int i;
if(isEmpty(arr))
{
printf("Stack empty\n");
return;
}
for(i=top;i>=0;i--)
{
printf("%d\n",arr[i].data);
}
}

void main()
{
stack arr[MAXSIZE];
push(arr,10);
push(arr,20);
push(arr,30);
display(arr);
push(arr,40);
push(arr,50);
push(arr,60);
push(arr,70);
display(arr);
pop(arr);
pop(arr);
pop(arr);
pop(arr);
pop(arr);
pop(arr);
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Implementation of dynamic stacks:


typedef struct
{
int ele;
}stack;
int MAXSIZE=3;
int top=-1;
void isFull(stack *arr)
{
if(top==(MAXSIZE-1))
{
MAXSIZE=2*MAXSIZE;
printf("Stack overflow size increased to %d\n",MAXSIZE);
arr=realloc(arr,sizeof(stack)*MAXSIZE);
}

int isEmpty()
{
if(top==-1)
return 1;
return 0;
}
void push(stack *arr,int ele)
{
isFull(arr);
arr[++top].ele=ele;
}
void pop(stack *arr)
{
if(isEmpty())
{
printf("Stack Underflow..\n");
return;
}
printf("Popped Element=%d\n",arr[top].ele);
top--;
}
void display(stack *arr)
{
int i;
if(isEmpty(arr))
{
printf("Stack Empty..\n");
return;
}
for(i=top;i>=0;i--)
{
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

printf("%d\n",arr[i].ele);
}
}

void main()
{
stack *arr;
arr=malloc(sizeof(stack)*MAXSIZE);
push(arr,10);
push(arr,20);
push(arr,30);
push(arr,40);
push(arr,50);
push(arr,60);
push(arr,70);
push(arr,50);
push(arr,60);
push(arr,70);
pop(arr);
pop(arr);
display(arr);
}

System Stack:
- A special stack used by programs to process function calls.
- Each function is allotted an area called “Activation Record” or “Stack frame”
- Only one function can execute at any time. Hence function to be selected is one at the top of
stack
- PUSH- whenever a function is called, new stack frame is pushed on top of stack
- POP – whenever a function execution is completed, stack frame from top is popped

Working of System Stack:


As shown in the following example, 2 functions are called- main and f1. First main function is
called, and for main an activation record (stack frame) is allocated. The activation record
consists of:
➢ previous frame pointer which points to address from where it was called and it has to report
back
➢ local variables – variables declared inside the function
➢ parameters- inputs passed to function
➢ return address – each function’s return address.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Queue:
Queue is a data structure that follows First In First Out Order (FIFO). Elements are inserted at “rear
end” and elements are deleted from “front end”. Such a queue is also called Single Ended Queue.
There are many applications of queue like:
(i) People waiting in queue for ticket booking
(ii) People waiting in queue to get vaccine
(iii) People waiting in queue for lunch during reception
(iv) Students waiting in a queue to collect library books

There are 2 types of Queue: Static Queue (fixed size) and Dynamic Queue (flexible size).
In Static Queue, max size of the queue (number of elements) is fixed during compilation. When the
size limit reaches, “Queue Overflow” state occurs. Similarly, when queue is empty, no element can
be deleted. If an attempt to deletion is done, it leads to a state called “Queue Underflow”. Further
memory for static queue is allocated in stack.

C Program demonstrating static queue:

#define MAXSIZE 5
typedef struct
{
int data;
}queue;
int rear=-1,front=-1; //Pointers used in Single Ended Queue
int isFull(queue arr[MAXSIZE])
{
if(rear==MAXSIZE-1)
{
return 1; //Queue is full
}
return 0; //Queue is not full
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

int isEmpty(queue arr[MAXSIZE])


{
if(rear==front)
{
return 1; //Queue is empty
}
return 0; //Queue is not empty
}

void addq(queue arr[MAXSIZE],int ele)


{
if(isFull(arr))
{
printf("Queue overflow\n");
return;
}
arr[++rear].data=ele;
}

void deleteq(queue arr[MAXSIZE])


{
if(isEmpty(arr))
{
printf("Queue underflow\n");
return;
}
printf("Element popped=%d\n",arr[++front].data);

}
void display(queue arr[MAXSIZE])
{
int i;
if(isEmpty(arr))
{
printf("Queue empty\n");
return;
}
for(i=front+1;i<=rear;i++)
{
printf("%d\n",arr[i].data);
}
}

void main()
{
queue arr[MAXSIZE];
addq(arr,20);
addq(arr,30);
addq(arr,50);
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

addq(arr,60);
addq(arr,120);
addq(arr,130);
display(arr);
deleteq(arr);
deleteq(arr);
deleteq(arr);

Limitations of Single Ended Queue:


- Rear pointer is incremented during element insertion and front pointer is incremented during
element deletion. Hence once all elements are deleted rear and front become same which leads
to both overflow and underflow. Hence even though queue is empty, no more elements can
be added.
- Possible solutions to such a problem include, shifting of elements during each deletion or
resetting front and rear, when they become equal during element deletion. Instead of this an
efficient mechanism is to use Circular Queue.
-
Circular Queue:
In Circular Queue, after last element is added, new insertions can begin again from beginning,
provided deletion of some elements are done. This solves the problems of single ended queue. To
implement circular queue, modulus addition is used for both rear and front, instead of simple
increment. Further, a counter is used for tracking number of elements in the queue at any time.
Counter is incremented, as a new element is added to the circular queue. Once the count reaches
maximum size, “Queue Overflow” occurs. Counter is also decremented when element is deleted from
queue. Once the count reduces to -1, “Queue Underflow” occurs.

C Program for implementation of Circular Queue:


#define MAXSIZE 5
typedef struct
{
int data;
} queue;
int front=-1,rear=-1,cnt=0;
int isFull(queue arr[MAXSIZE])
{
if(cnt==MAXSIZE)
return 1;//Queue overflow
return 0;//Queue still free
}

int isEmpty(queue arr[MAXSIZE])


{
if(cnt==0)
return 1; //Empty
return 0; //Non Empty
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

void addq(queue arr[MAXSIZE], int ele)


{
if(isFull(arr))
{
printf("Queue overflow\n");
return;
}
rear=(rear+1)%MAXSIZE;
arr[rear].data=ele;
cnt++;
}

void deleteq(queue arr[MAXSIZE])


{
if(isEmpty(arr))
{
printf("Queue underflow\n");
return;
}
front=(front+1)%MAXSIZE;
printf("Element deleted=%d\n",arr[front].data);
cnt--;

}
void display(queue arr[MAXSIZE])
{
int i,j;
j=front+1;
for(i=0;i<cnt;i++)
{
printf("%d\n",arr[j].data);
j=(j+1)%MAXSIZE;
}
}
void main()
{
queue arr[MAXSIZE];
addq(arr,20);
addq(arr,30);
addq(arr,40);
display(arr);
addq(arr,50);
addq(arr,60);
addq(arr,70);
display(arr);
deleteq(arr);
deleteq(arr);
// display(arr);
addq(arr,100);
addq(arr,110);
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

addq(arr,120);
display(arr);
}

Circular Queue using Dynamic Arrays (Dynamic Circular Queues):


Static Circular Queues have the issues of Overflow whenever number of elements in the queue equals
the max size of the queue. Further, static circular queues use stack which has limited memory. Hence,
dynamic circular queues are used, where memory is allocated in the heap and size doubles each time
limit is reached. Dynamic memory allocation function malloc is used to create a circular queue with
some maximum size. Once limit is reached, realloc function is used to double the current size.

C Program to implement Dynamic Circular Queues:


int MAXSIZE=5;
typedef struct
{
int data;
} queue;
int front=-1,rear=-1,cnt=0;
void isFull(queue *arr)
{
if(cnt==MAXSIZE)
{
MAXSIZE=2*MAXSIZE;
arr=realloc(arr,sizeof(queue)*MAXSIZE);
}
}

int isEmpty(queue *arr)


{
if(cnt==0)
return 1; //Empty
return 0; //Non Empty
}

void addq(queue *arr, int ele)


{
isFull(arr);
rear=(rear+1)%MAXSIZE;
arr[rear].data=ele;
cnt++;
}

void deleteq(queue *arr)


{
if(isEmpty(arr))
{
printf("Queue underflow\n");
return;
}
front=(front+1)%MAXSIZE;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

printf("Element deleted=%d\n",arr[front].data);
cnt--;

}
void display(queue *arr)
{
int i,j;
j=front+1;
for(i=0;i<cnt;i++)
{
printf("%d\n",arr[j].data);
j=(j+1)%MAXSIZE;
}
}
void main()
{
//queue arr[MAXSIZE];
queue *arr=malloc(sizeof(queue)*MAXSIZE);
addq(arr,20);
addq(arr,30);
addq(arr,40);
display(arr);
addq(arr,50);
addq(arr,60);
addq(arr,70);
display(arr);
deleteq(arr);
deleteq(arr);
// display(arr);
addq(arr,100);
addq(arr,110);
addq(arr,120);
display(arr);
}

Dequeue (Deck or Double Ended Queue):


Dequeue is a data structure that supports addition and deletion of elements at either ends
(front/rear). Hence it uses 2 pointers left and right side of the queue. When elements are inserted to
left end, left pointer is incremented (++left) and when elements are inserted to the right end, right
pointer is decremented (right--). Relationship between stack, single ended/circular queue and
dequeue is as follows:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Browser history is a memory maintained by each browser. Whenever user browses a page, it is
added to the history. Pages can be added to both ends and also removed from either end. Hence
double ended queue is used for browser history management.

Working of a dequeue is illustrated below:

Variations of Dequeue:
There are two variations of dequeue: (i) Input Restricted dequeue (Input-Rear end no insertion only,
deletion, but at front end both insertion and deletion can be done)
(ii) Output Restricted dequeue: (Output- front end no deletion, only insertion. However insertion and
deletion can be done at rear end)
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Priority Queues:
A Priority Queue is a collection of elements with each element assigned a priority. Deletion
of an element is based on following rules:
1. An element of higher priority before lower priority
2. For same priority elements, FIFO
Timesharing systems with high priority programs first and programs with normal priority into
standard queue

There are 2 ways to represent priority queues in memory:


(i) As a Linear List.
(ii) Using Arrays

In Linear List, it is a collection of nodes connected with link. Each node contains INFO
(Information/data), PRN (Priority Number) and Link (pointer to the next node). For last node, pointer
is null.
❑ Rule: Lower numbers indicate higher priority
❑ Higher priority nodes are behind lower priority
❑ Same priority nodes are arranged in the order added

Insertion:
For insertion search for a node whose priority is greater than this node

Deletion:
Deletion is always done by removing first node

Eg:
(AAA,1), (BBB,1), (CCC,4), (DDD,3), (EEE,2)
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Hence with linear list, elements need to be shuffled each time, a new element of higher priority is to
be added. Instead of shuffling elements again and again, another solution is to use multiple queues.
A separate queue is maintained for each priority level. Separate front and rear pointers are maintained
for each such queue. The front and rear pointers are captured in separate arrays. Arrays for front and
rear, contains position of front and rear for each queue represented by the priority level. Further, these
arrays are used to construct a matrix . Rows of the matrix represents priority level and columns contain
the elements of the queue.
Eg:

Here, consider row 1, front is 2 and rear is 2. Hence element currently is AAA. In case new element
is to be added to row 1(Queue with priority 1), it will be added at position 3. Similarly for row 2, new
element will be added at position 4 (rear is 3) and element will be deleted from position 1 (front is 1).

Algorithm for deletion:


1. Find smallest K such that FRONT[K]!=NULL
2. Delete and process front element in row K of Queue
3. Exit
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Algorithm for Insertion of an ITEM with priority M:


1. Insert ITEM to rear element in row M of Queue
2. Exit

Stack Applications – Expressions


Expressions contain operators and operands. Arithmetic expressions are evaluated. While evaluation,
BEDMAS rule is used. Precedence of operator determines which sub expression is first evaluated. In
case of same precedence, associativity determines the order of evaluation (Left to right or Right to
Left).

Eg: Evaluate the expression: x=a/b-c+d*e-a*c, where a=4, b=c=2, d=e=3

x=a/b-c+d*e-a*c
=4/2-2+3*3-4*2
=2-2+3*3-4*2
=2-2+9-4*2
=2-2+9-8
=2+7-8
=9-8
=1

Precedence of unary, binary and ternary operators are shown below:

If number of operands is 1, operator is unary. Likewise, if operands is 2, operator is binary and for 3
operands, operator is ternary.

Types of Expressions:
There are 3 types of expressions based on the position of operator. If operator is inbetween operands,
expression is called “Infix Expression”. If operator comes before operands, expression is “Prefix”
and if operator comes after operands, expression is “Postfix”. Prefix expressions are also called
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

“Polish” and postfix expressions are also called “Reverse Polish or suffix”. Postfix and Prefix
expressions are used by compilers due to efficiency concerns during evaluation.

Algorithm for converting Infix to Postfix:


STEP 1: SCAN EXPRESSION FROM LEFT TO RIGHT
STEP 2: IF CURRENT TOKEN IS NUMBER/CHAR, PRINT IT. GOTO STEP 1
STEP 3: IF CURRENT TOKEN IS OPERATOR O:
3.1: IF PRECEDENCE(O) <= PRECEDENCE (TOS)
POP TOS SYMBOL and PRINT
REPEAT 3.1
3.2: ELSE PUSH O to STACK
GOTO STEP 1
STEP 4: IF CURRENT TOKEN IS ‘(‘, PUSH TO STACK. GO TO STEP 1
STEP 5: IF CURRENT TOKEN IS ‘)’, POP AND PRINT ALL SYMBOLS UNTIL YOU
GET ‘(‘. GOTO STEP 1
STEP 6: POP ANY RESIDUAL SYMBOLS AND PRINT
STEP 7: IF CURRENT TOKEN IS EOS, EXIT

Eg:
𝒂∗𝒃∗𝒄
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

−𝒂 + 𝒃 − 𝒄 + 𝒅

𝒂 ∗ −𝒃 + 𝒄
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

(𝒂 + 𝒃) ∗ 𝒅 + 𝒆/(𝒇 + 𝒂 ∗ 𝒅) +c
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Algorithm for converting Infix to Prefix:


STEP 1: REVERSE THE GIVEN EXPRESSION
STEP 2: SCAN EXPRESSION FROM LEFT TO RIGHT
STEP 3: IF CURRENT TOKEN IS NUMBER/CHAR, PRINT IT. GOTO STEP 1
STEP 4: IF CURRENT TOKEN IS OPERATOR O:
4.1: IF PRECEDENCE(O) <= PRECEDENCE (TOS)
POP TOS SYMBOL and PRINT
REPEAT 4.1
4.2: ELSE PUSH O to STACK
GOTO STEP 1
STEP 5: IF CURRENT TOKEN IS ‘)‘, PUSH TO STACK. GO TO STEP 1
STEP 6: IF CURRENT TOKEN IS ‘(’, POP AND PRINT ALL SYMBOLS UNTIL YOU
GET ‘)‘. GOTO STEP 1
STEP 7: POP ANY RESIDUAL SYMBOLS AND PRINT
STEP 8: IF CURRENT TOKEN IS EOS, REVERSE OUTPUT and EXIT
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Algorithm for the Evaluation of Postfix Expressions:


ALGORTITHM:
STEP 1: SCAN EXPRESSION FROM LEFT TO RIGHT
STEP 2: IF CURRENT TOKEN IS NUMBER/CHAR, PUSH NUMBER/CHAR. GOTO STEP 1
STEP 3: IF CURRENT TOKEN IS OPERATOR O:
3.1: POP TOS SYMBOL –NUM2
POP TOS SYMBOL – NUM1
PUSH (NUM1 OP NUM2)
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

GOTO STEP 1
STEP 4: IF CURRENT TOKEN IS EOS, PRINT TOS and EXIT
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

C program for Evaluation:


#define MAX 20
typedef struct
{
int data;
}stack;
int top=-1;
void push(stack arr[MAX],int ele)
{
arr[++top].data=ele;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

}
int pop(stack arr[MAX])
{
return arr[top--].data;
}
void main()
{
char expr[MAX];
stack arr[MAX];
int num1,num2,i;
printf("Enter the valid postfix expression\n");
scanf("%s",expr);
for(i=0;i<strlen(expr);i++)
{
if(isdigit(expr[i])) //digit
{
push(arr,expr[i]-'0');
}
else
{
num2=pop(arr);
num1=pop(arr);
switch(expr[i])
{
case '+':push(arr,num1+num2);
break;
case '-':push(arr,num1-num2);
break;
case '*':push(arr,num1*num2);
break;
case '/':push(arr,num1/num2);
break;
}
}
}
printf("Ans=%d\n",arr[top].data);
}

Algorithm for the Evaluation of Prefix Expressions:


ALGORTITHM:
STEP 1: REVERSE THE GIVEN EXPRESSION
STEP 2: SCAN EXPRESSION FROM LEFT TO RIGHT
STEP 3: IF CURRENT TOKEN IS NUMBER/CHAR, PUSH NUMBER/CHAR. GOTO STEP 1
STEP 4: IF CURRENT TOKEN IS OPERATOR O:
4.1: POP TOS SYMBOL –NUM1
POP TOS SYMBOL – NUM2
PUSH (NUM1 OP NUM2)
GOTO STEP 1
STEP 5: IF CURRENT TOKEN IS EOS, PRINT TOS and EXIT
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Recursion:
Recursion is the process of function calling itself. Recursive functions are written using recurrence
relations. Recursion is ended by specifying base criteria. A stack frame is created for each call during
recursive function.

Eg: Finding factorial of a number using recursion:


Recurrence relation:
𝒏=𝟏 𝟏
𝒇𝒂𝒄𝒕(𝒏) = {
𝒏>𝟏 𝒏 ∗ 𝒇𝒂𝒄𝒕(𝒏 − 𝟏)
C code for factorial using recursion:
int fact(int n)
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

{
if(n==1) return 1;
else
return n*fact(n-1);
}
void main()
{
int n=5;
printf("%d\n",fact(n));
}

Eg: Finding n terms of Fibonacci series using recursion:

Recurrence relation:
𝒏 = 𝟎 𝒐𝒓 𝒏 = 𝟏 𝒏
𝒇𝒊𝒃(𝒏) = {
𝒏>𝟏 𝒇𝒊𝒃(𝒏 − 𝟏) + 𝒇𝒊𝒃(𝒏 − 𝟐)

C code for Fibonacci series using recursion:


int fib(int n)
{
if(n==0 || n==1)
return n;
else
return fib(n-1)+fib(n-2);
}
void main()
{
int n=5,i;
for(i=0;i<n;i++)
printf("%d,",fib(i));
}

Eg: Finding gcd of 2 numbers using recursion:


GCD of 2 numbers using following recurrence relation:

𝒏≠𝟎 𝒈𝒄𝒅(𝒏, 𝒎%𝒏)


𝒈𝒄𝒅(𝒎, 𝒏) = { 𝒆𝒍𝒔𝒆 𝒎)
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

C Program:
int gcd(int m, int n)
{
if(n!=0)
return gcd(n,m%n);
else
return m;

}
void main()
{
int m=81,n=27;
int ans=gcd(m,n);
printf("%d\n",ans);
}

Tower of Hanoi:
It is a mathematical game or puzzle consisting of three legs and a number of disks of
various diameters, which can slide onto any leg. The puzzle begins with the disks stacked on one leg
in order of decreasing size, the smallest at the top, thus approximating a conical shape. The objective
of the puzzle is to move the entire stack to the last leg, obeying the following rules:
1. Only one disk may be moved at a time.
2. Each move consists of taking the upper disk from one of the stacks and placing it on
top of another stack or on an empty leg.
3. No disk may be placed on top of a disk that is smaller than it.

Recursive Solution:
1. MOVE TOP N-1 DISKS FROM LEG A to LEG B
2. MOVE THE TOP DISK FROM LEG A TO LEG C
3. MOVE TOP N-1 DISKS FROM LEG B TO LEG C

C program:
void toh(int N,char A,char B, char C)
{
if(N>0) //termination condition (base condition)
{
toh(N-1,A, C, B);
printf("%c->%c\n",A,C);
toh(N-1,B,A,C);
}
}
void main()
{
int N=3;
toh(N,'A','B','C');
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Lab Component:
Design, Develop and Implement a menu driven Program in C for the following operations on
STACK of Integers (Array Implementation of Stack with maximum size MAX)
a. Push an Element on to Stack
b. Pop an Element from Stack
c. Demonstrate Overflow and Underflow situations on Stack
d. Display the status of Stack
e. Exit
Support the program with appropriate functions for each of the above operations

#define MAX 5
typedef struct
{
int data;
}stack;
int top=-1;
int isFull(stack arr[MAX])
{
if(top==MAX-1)
return 1; //Full
return 0; //Not full
}

int isEmpty(stack arr[MAX])


{
if(top==-1)
return 1; //Empty
return 0; //Not empty
}

void push(stack arr[MAX],int ele)


{
if(isFull(arr))
{
printf("Stack Overflow\n");
return;
}
arr[++top].data=ele; //pushing code
}
void pop(stack arr[MAX])
{
if(isEmpty(arr))
{
printf("Stack Underflow\n");
return;
}
printf("Element popped=%d\n",arr[top--].data);
}
void display(stack arr[MAX])
{
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

int i;
for(i=top;i>=0;i--)
{
printf("%d\n",arr[i].data);
}
}
void main()
{
stack arr[MAX];
int choice, ele;
while(1)
{
printf("****Stack Operations*****\n");
printf("1. PUSH\n");
printf("2. POP\n");
printf("3. DISPLAY\n");
printf("4. EXIT\n");
printf("Enter your choice\n");
scanf("%d",&choice);
switch(choice)
{
case 1:printf("Enter the element\n");
scanf("%d",&ele);
push(arr,ele);
break;
case 2:pop(arr);
break;
case 3:display(arr);
break;
case 4: exit(0);
default:printf("Enter 1/2/3/4\n");
}
}
}

Design, Develop and Implement a Program in C for the following Stack Application:
a. Evaluation of Suffix expression with single digit operands and operators: +, -, *, /, %, ^
#define MAX 20
typedef struct
{
int data;
}stack;
int top=-1;
void push(stack arr[MAX],int ele)
{
arr[++top].data=ele;
}
int pop(stack arr[MAX])
{
return arr[top--].data;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

}
void main()
{
char expr[MAX];
stack arr[MAX];
int num1,num2,i;
printf("Enter the valid postfix expression\n");
scanf("%s",expr);
for(i=0;i<strlen(expr);i++)
{
if(isdigit(expr[i])) //digit
{
push(arr,expr[i]-'0');
}
else
{
num2=pop(arr);
num1=pop(arr);
switch(expr[i])
{
case '+':push(arr,num1+num2);
break;
case '-':push(arr,num1-num2);
break;
case '*':push(arr,num1*num2);
break;
case '/':push(arr,num1/num2);
break;
}
}
}
printf("Ans=%d\n",arr[top].data);
}

Design, Develop and Implement a Program in C for the following Stack Application:
b. Solving Tower of Hanoi problem with n disks

void toh(int N,char A,char B, char C)


{
if(N>0) //termination condition (base condition)
{
toh(N-1,A, C, B);
printf("%c->%c\n",A,C);
toh(N-1,B,A,C);
}}
void main()
{
int N=3;
toh(N,'A','B','C');
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Module-3
Linked Lists:
A linked list or one way list is a linear collection of nodes. Each node contains data and a
pointer next that points to the next element in the list. Addition, deletion, updation, traversal,
searching, sorting, merging frequently needed on the linked list.

Operations on linked lists:


• Addition – an operation to add a new element to a list. Possible positions include
beginning, ending, specific and depending on sort requirement.
• Deletion – an operation to remove an existing element from the list. Deletion can be done
on any node in the list.
• Updation – an operation to update an existing element in the list. Updation can be done
on any node in the list.
• Traversal – an operation in which nodes are visited from beginning till end one by one.
• Searching – an operation to find an element of interest. Result can be successful or
unsuccessful.
• Sorting – an operation to order the linked list by ascending or descending order of the
information in the linked list.
• Merging – an operation to copy data from 2 lists into a single list.

Arrays vs Linked Lists:


Parameter Array Linked List
Memory allocation Arrays need contiguous Linked list provide or use
allocation. Hence as number of allocation which is not
elements are large, difficult to contiguous. As the number of
find contiguous allocation. elements increases, linked lists
are the better solution for the
memory allocation of
elements.
Memory allocation mechanism Arrays primarily use static Linked list depends primarily
allocation. However dynamic on dynamic allocation.
allocation is also possible. However, static allocation is
possible but sparingly used.
Accessing an element Direct access of any element is Indexing is not possible. To
possible through indexing. access any element traversal is
required till desired element is
found.
Adding a new element Needs lot of shifting of Only pointer adjustment of 2
elements towards right side nodes are required.
Deleting an existing element Needs lot of shifting of Only pointer adjustment of 2
elements towards left side. nodes are required.
Memory Issues Garbage and dangling pointer Garbage and dangling pointer
issues do not occur. issues do occur.
Overheads No overheads as elements are Each node has an overhead to
contiguously stored. maintain extra pointer.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Schematic of a Linked List:

Each node consists of information and a pointer called NEXT. NEXT points to the next element in
the list. If the node is the last node, NEXT is a null pointer. (NULL). The beginning node is referred
by a special pointer called START.
Example:
Linked list can be used to store patient list admitted to beds. The linked list is sorted in the ascending
order of patient names alphabetically.
Representation of Linked List in the memory:
Eg-1: Represent the word SCAM in memory:

Two arrays are maintained: INFO and LINK. String is scanned from left to right. For each character,
place is allotted in the INFO array wherever free. The next location of each letter is recorded in the
corresponding position in the LINK array.

Consider IA scores in subjects:


DS- 18,20,17,11,15
ADE- 20,19,14,12,18
Represent this as 2 linked lists in memory
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Discuss how an employee file containing 3 records with fields (EMPID, Name, Designation,
Rank) can be stored using linked lists and without linked lists. Compare and contrast both
approaches

An employee file with 3 records and 4 fields can be stored as 3 X 4 2D array. Each row will represent
an employee record and each column represent field of employee. This organization will help to
access any employee data directly with appropriate row and column indexing. However, when
number of employees increase, the contiguous allocation issue arises and fails. Further adding and
removing an element in the specific positions would incur lot of penalty with the amount of shifting
involved. Hence a linked list representation would solve issues of memory, complexity of addition
and deletion operations. For linked list representation, each node represents and employee with
information field divided into 4 separate fields for empid, name, designation and rank and a next field
to point to the next employee record.

C program to implement basic operations of a linked list:


#include<stdlib.h>
typedef struct
{
int data;
struct node *next;
}node;

/** Function to traverse a singly linked list (SLL)


Algorithm:
Step 1: Initialize temp node with START
Step 2: If temp==NULL, goto Step 6
Step 3: Print temp->data
Step 4: Move to next node with temp=temp->next
Step 5: Goto Step 2
Step 6: EXIT
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

*/
void traverse(node *start)
{
node*temp=start;
while(temp!=NULL)
{
printf("%d->",temp->data);
temp=temp->next;
}
printf("\b\b \n");
}

/** Function to count the number of nodes of a singly linked list (SLL)
Algorithm:
Step 1: Initialize temp node with START and COUNT to 0.
Step 2: If temp==NULL, goto Step 6
Step 3: COUNT=COUNT+1
Step 4: Move to next node with temp=temp->next
Step 5: Goto Step 2
Step 6: Print COUNT and EXIT
*/

void count_nodes(node *start)


{
int cnt=0;
node*temp=start;
while(temp!=NULL)
{
cnt++;
temp=temp->next;
}
printf("cnt=%d \n",cnt);
}

/** Function to search an element KEY in the unsorted singly linked list (SLL)
Algorithm:
Step 1: Initialize temp node with START
Step 2: If temp==NULL, goto Step 6
Step 3: If temp->data == KEY, PRINT SUCCESSFUL SEARCH and EXIT
Step 4: Move to next node with temp=temp->next
Step 5: Goto Step 2
Step 6: PRINT UNSUCCESSFULL SEARCH and EXIT
*/

void search_unsorted_list(node *start)


{
node *temp=start;
int key,pos=0;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

printf("Enter the key element\n");


scanf("%d",&key);
while(temp!=NULL)
{
pos++;
if(temp->data==key)
{
printf("Successful search and position=%d\n",pos);
return;
}

temp=temp->next;
}
printf("Unsuccessful search\n");

/** Function to search an element KEY in the sorted singly linked list (SLL)
Algorithm:
Step 1: Initialize temp node with START
Step 2: If temp==NULL, goto Step 7
Step 3: If temp->data == KEY, PRINT SUCCESSFUL SEARCH and EXIT
Step 4: If temp->data > KEY, PRINT UNSUCCESSFUL SEARCH and EXIT
Step 5: Move to next node with temp=temp->next
Step 6: Goto Step 2
Step 8: PRINT UNSUCCESSFULL SEARCH and EXIT
*/

void search_sorted_list(node *start)


{
node *temp=start;
int key,pos=0;
printf("Enter the key element\n");
scanf("%d",&key);
while(temp!=NULL)
{
pos++;
if(temp->data==key)
{
printf("Successful search and position=%d\n",pos);
return;
}
if(key<temp->data)
{
printf("Unsuccessful search\n");
return;
}

temp=temp->next;
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

printf("Unsuccessful search\n");

}
void main()
{
node *n1,*n2,*n3,*n4,*n5;
n1=malloc(sizeof(node)); //Dynamic memory allocation to create any node
n2=malloc(sizeof(node));
n3=malloc(sizeof(node));
n4=malloc(sizeof(node));
n5=malloc(sizeof(node));
n1->data=9;
n2->data=10;
n3->data=15;
n4->data=20;
n5->data=51;
n1->next=n2;
n2->next=n3;
n3->next=n4;
n4->next=n5;
n5->next=NULL;

traverse(n1);
count_nodes(n1);
// search_unsorted_list(n1);
search_sorted_list(n1);
}

Insertion of a new node to the linked list:


Insertion of a new node in the linked list, requires allocating memory to the new node and
adjusting pointers appropriately. Two pointers are maintained: START- start of the existing singly
linked list and AVAIL- start of free pool. Whenever a new node to be created, first node from free
pool is picked by accessing AVAIL and AVAIL is subsequently changed to point next free element.
The current node is a node after which a new node has to be inserted. New node is made to point to
the node which is pointed by current node. Current node then points to the new node. This mechanism
is pictorially represented in the following.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

C program to demonstrate different type of insertions:

#include<stdlib.h>
typedef struct
{
int data;
struct node *next;
}node;

node *start=NULL;

/**Function to insert a given node at the beginning


Algorithm:
STEP 1: Get the data for new node
STEP 2: Allocate memory for new node
STEP 3: Assign data to the new node
STEP 4: New node points to START
STEP 5: New START is set to new node
STEP 6: EXIT
*/
void insert_begining()
{
int ele;
node *newnode;
printf("Enter the element\n");
scanf("%d",&ele);
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->next=start;
start=newnode;

}
/**Function to insert a given node after a given location
Algorithm:
STEP 1: Get the data for new node
STEP 2; Get the required location LOC
STEP 3: Allocate memory for new node
STEP 4: Assign data to the new node
STEP 5: Set temp to START and CNT=1
STEP 6: IF temp==NULL goto STEP 10
STEP 7: IF CNT==LOC, Goto STEP 9
STEP 8: Move temp to next node: temp=temp->next and CNT=CNT+1. Goto STEP 6
STEP 9: Set: newnode->next to temp->next and temp->next to newnode.
STEP 10: EXIT
*/

void insert_after()
{
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

int ele,loc,cnt=1;
node *newnode,*temp;
printf("Enter the element\n");
scanf("%d",&ele);
printf("Enter the location\n");
scanf("%d",&loc);
newnode=malloc(sizeof(node));
newnode->data=ele;
temp=start;
while(temp!=NULL)
{
if(cnt==loc)
{
break;
}
else
{
temp=temp->next;
cnt++;
}

}
newnode->next=temp->next;
temp->next=newnode;

/**Function to insert a node in the sorted SLL (Singly Linked List)


Algorithm:
STEP 1: Get the data for new node
STEP 2: Allocate memory for new node
STEP 3: Assign data to the new node
STEP 4: Set temp to START and prev to temp
STEP 5: IF temp==NULL goto STEP 9
STEP 6: IF temp->data > data of new node, Goto STEP 8
STEP 7: Move temp to next node: temp=temp->next and prev=temp. Goto STEP 5
STEP 8: Set: prev>next to newnode and newnode>next to temp.
STEP 9: EXIT
*/

void insert_sorted_list()
{
int ele;
node *newnode;
node *prev,*temp;
printf("Enter the element\n");
scanf("%d",&ele);
newnode=malloc(sizeof(node));
newnode->data=ele;
prev=start;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

temp=start;
while(temp!=NULL)
{
if(temp->data>ele)
{
break;
}
else
{
prev=temp;
temp=temp->next;
}
}
prev->next=newnode;
newnode->next=temp;

void traverse()
{
node *temp=start;
while(temp!=NULL)
{
printf("%d->",temp->data);
temp=temp->next;
}
}

void main()
{

insert_begining();
insert_begining();
traverse();
insert_after();
traverse();
insert_sorted_list();
traverse();

Deletion of an existing node from the linked list:


Existing nodes from a singly linked list (SLL) can be deleted from any position. Specifically
following 2 cases are discussed:
(i) Deletion of node following a given node
(ii) Deletion of node matching item in the linked list
For first case, location is given after which node has to be deleted. For the second case, node matching
item is found and deleted. If such item does not exist, no nodes are deleted.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Case (i): C program for Deletion of a node following given node:

#include<stdio.h>
#include<stdlib.h>
typedef struct
{
int data;
struct node *next;
}node;
node *start=NULL;
void insert_node(int ele)
{
node* newnode;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->next=start;
start=newnode;
}

/**
Algorithm to delete a node after given location
Step 1: Initialize count to 1
Step 2: Initialize temp to start and declare cur as node pointer.
Step 3: If temp is not NULL
3.1.: Check count is same as user given node location (loc)
3.2: If same Goto Step 4
3.3: Move temp to temp->next
3.4: Increment count
3.5: Goto Step 3
Step 4: Assign cur as temp->next
Step 5: Assign temp->next to cur->next
Step 6: Free cur node
Step 7: Exit
**/

void delete_node_after(int loc)


{
int cnt=1;
node* temp=start,*cur;
while(temp!=NULL)
{
if(cnt==loc)
break;
temp=temp->next;
cnt++;
}
cur=temp->next;
temp->next=cur->next;
free(cur);
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

}
void display()
{
node*temp=start;
while(temp!=NULL)
{
printf("%d->",temp->data);
temp=temp->next;
}
}

void main()
{
insert_node(20);
insert_node(30);
insert_node(21);
display();

delete_node_after(1);
display();

Case (ii): C program for Deletion of a node with matching item:


#include<stdio.h>
#include<stdlib.h>
typedef struct
{

int data;
struct node *next;
}node;
node *start=NULL;
void insert_node(int ele)
{
node* newnode;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->next=start;
start=newnode;
}

/**
Algorithm to delete a node with matching item
Step 1: Initialize temp and prev node pointers to start.
Step 2: If temp is not NULL
2.1.: Check temp->data and item
2.2: If same Goto Step 3
2.3: Assign prev as temp
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

2.4: Assign temp as temp->next


2.5: Goto Step 2
Step 3: Assign prev->next as temp->next
Step 4: Free temp node
Step 5: Exit
**/

void delete_match(int item)


{
node*temp=start,*prev=start;
while(temp!=NULL)
{

if(temp->data==item)
break;
prev=temp;
temp=temp->next;
}
prev->next=temp->next;
free(temp);
}

void display()
{
node*temp=start;
while(temp!=NULL)
{
printf("%d->",temp->data);
temp=temp->next;
}
}

void main()
{
insert_node(20);
insert_node(30);
insert_node(21);
display();
delete_match(30);
display();
}

Sorting Linked Lists:


Linked lists sorting involves arranging items inside the linked list is an order. The order can be
ascending or descending. A variation of bubble sort algorithm is presented, in which there are nested
loops. In outer loop, each element is passed from linked list and in inner loop its compared with all
remaining elements and on out of order, swapping is done. It is an inplace sorting, as existing linked
list is sorted and no new memory is required.

Algorithm for sorting linked lists:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

STEP 1: REFER LIST BY A POINTER T


STEP 2: LET S=T->NEXT
STEP 3: IF S->DATA < T->DATA, SWAP S->DATA AND T->DATA
STEP 4 MOVE S to S->NEXT
STEP 5: IF S->NEXT==NULL,
MOVE T to T->NEXT AND GOTO STEP 2
STEP 6: ELSE GOTO STEP 3
STEP 7: EXIT

C program for sorting of a linked list:


#include<stdio.h>
#include<stdlib.h>
typedef struct
{

int data;
struct node *next;
}node;
node *start=NULL;
void insert_node(int ele)
{
node* newnode;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->next=start;
start=newnode;
}

void sort_list()
{
int temp;
node*t=start,*s;
while(t!=NULL)
{
s=t->next;
while(s!=NULL)
{
if(s->data<t->data)
{
temp=s->data;
s->data=t->data;
t->data=temp;
}
s=s->next;
}
t=t->next;
}
}

void main()
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

{
insert_node(20);
insert_node(30);
insert_node(21);
display();
sort_list();
display();

Merging Linked Lists:


Merging is an operation to copy the nodes of two linked lists into a single linked list. There are
2 variations of such merging:
(i) Concatenation – Copy data from list1 followed by data from list 2
(ii) Sorted Merge – During copy make sure the lowest is copied and resulting output list
is sorted.

Algorithm-SIMPLE MERGE
STEP 1: REFER LIST1 BY A POINTER TEMP1
STEP 2: REFER LIST2 BY A POINTER TEMP2
STEP 3: IF TEMP1!=NULL
3.1 ADD TEMP1 to END OF MERGEDLIST
3.2 MOVE TEMP1=TEMP1->NEXT
3.3 GOTO STEP3
STEP 4: IF TEMP2!=NULL
4.1 ADD TEMP2 to END OF MERGEDLIST
4.2 MOVE TEMP2=TEMP2->NEXT
4.3 GOTO STEP4
STEP 5 EXIT

Corresponding C program:
#include<stdlib.h>
typedef struct
{
int data;
struct node *next;
}node;
node *start1=NULL,*start2=NULL,*start3=NULL;
node* insert_front(node*s,int ele)
{
node* newnode;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->next=s;
s=newnode;
return s;
}
void display(node *s)
{
node*temp=s;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

while(temp!=NULL)
{
printf("%d->",temp->data);
temp=temp->next;
}
printf("\b\b ");
}
node* concat(node*start1, node*start2,
node *start3)
{
node* temp=start1,*temp3;
node *newnode;
//Append list1 to outputlist
while(temp!=NULL)
{
newnode=malloc(sizeof(node));
newnode->data=temp->data;
newnode->next=NULL;
if(start3==NULL)
start3=newnode;
else
{
temp3=start3;
while(temp3->next!=NULL)
temp3=temp3->next;
temp3->next=newnode;
}
temp=temp->next;
}
//Appending List 2 to output list
temp=start2;
while(temp!=NULL)
{
newnode=malloc(sizeof(node));
newnode->data=temp->data;
newnode->next=NULL;
if(start3==NULL)
start3=newnode;
else
{
temp3=start3;
while(temp3->next!=NULL)
temp3=temp3->next;
temp3->next=newnode;
}
temp=temp->next;
}
return start3;
}
void main()
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

{
start1=insert_front(start1,22);
start1=insert_front(start1,19);
start1=insert_front(start1,15);
display(start1);
printf("\n");
start2=insert_front(start2,23);
start2=insert_front(start2,17);
display(start2);
printf("\n");
start3=concat(start1,start2,start3);
display(start3);
}

Algorithm-SORTED MERGE
STEP 1: REFER LIST1 BY A POINTER TEMP1
STEP 2: REFER LIST2 BY A POINTER TEMP2
STEP 3: IF TEMP1!=NULL AND TEMP2!=NULL
3.1: IF TEMP1->DATA<TEMP2->DATA
3.1.1: ADD TEMP1 to MERGEDLIST,
TEMP1=TEMP1->NEXT, GOTO STEP 3
3.1.2: ELSE ADD TEMP2 to MERGEDLIST.
TEMP2=TEMP2->NEXT, GOTO STEP 3
STEP 4: IF TEMP1!=NULL, COPY RESIDUAL NODES TO MERGEDLIST and EXIT
STEP 5 IF TEMP2!=NULL, COPY RESIDUAL NODES TO MERGEDLIST and EXIT

Corresponding C program:
#include<stdlib.h>
typedef struct
{
int data;
struct node *next;
}node;

node* start1=NULL,*start2=NULL,*start3=NULL;
node* insert_front(int ele,node*start)
{
node* newnode;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->next=start;
start=newnode;
return start;
}

void display(node *st)


{
node* temp=st;
while(temp!=NULL)
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

{
printf("%d->",temp->data);
temp=temp->next;
}
}

void insert_end(int ele)


{
node*temp=start3;
node*newnode;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->next=NULL;
if(temp==NULL)
{
start3=newnode;
return;
}
while(temp->next!=NULL)
temp=temp->next;
temp->next=newnode;
}

void sorted_merge()
{
node*temp1=start1;
node* temp2=start2;
node* temp3=start3;
while(temp1!=NULL && temp2!=NULL)
{
if(temp1->data < temp2->data)
{
insert_end(temp1->data);
temp1=temp1->next;
}
else
{
insert_end(temp2->data);
temp2=temp2->next;
}
}
while(temp1!=NULL) //copy residual nodes of list1
{
insert_end(temp1->data);
temp1=temp1->next;
}
while(temp2!=NULL) //copy residual nodes of list2
{
insert_end(temp2->data);
temp2=temp2->next;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

}
}

void main()
{
start1=insert_front(22,start1);
start1=insert_front(11,start1);
start1=insert_front(10,start1);
display(start1);
printf("\n");
start2=insert_front(16,start2);
start2=insert_front(9,start2);

display(start2);
printf("\n");
sorted_merge();
display(start3);

Circular Linked List:


Circular Linked List is a variation of Singly Linked List where last NODE is connected back
to first NODE instead of NULL. Eg:

Circular linked lists have a number of advantages over traditional linked lists.
• As there is no defined beginning or end to the list, data can be added and removed from the
list at any time. This makes circular linked lists ideal for applications where data needs to be
constantly added or removed, such as in a real-time application.
• Since data is stored in a ring-like structure, it can be accessed in a continuous loop. This makes
circular linked lists ideal for applications where data needs to be processed in a continuous
loop, such as in a real-time application or simulation.
• As there is no defined beginning or end to the list, circular linked lists are typically more
efficient than traditional linked lists when it comes to memory usage. This is because
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

traditional linked lists often require additional memory for pointers that point to the beginning
and end of the list. Circular linked lists, on the other hand, only require a single pointer to be
stored in memory – the head pointer.
• Circular linked lists are often easier to implement than traditional linked lists. This is because
traditional linked lists often require the use of additional data structures, such as stacks and
queues, to keep track of the list's beginning and end. Circular linked lists, on the other hand,
only require a singly linked list data structure.

Implementation of various operations of circular linked list:


#include<stdlib.h>
typedef struct
{
int data;
struct node *next;
} node;

node *start=NULL;

//Insert a NODE to the beginning of Circular Linked List


void insert_begining(int ele)
{
node* newnode,*temp;
newnode=malloc(sizeof(node));
newnode->data=ele;
if(start==NULL) //Nothing is der
{
start=newnode;
newnode->next=start;
return;
}
else //Something is der
{
temp=start;
while(temp->next!=start)
{
temp=temp->next;
}
temp->next=newnode;
newnode->next=start;
start=newnode;

}
}

//Insert a NODE to the end of Circular Linked List


void insert_end(int ele)
{
node* temp=start;
node* newnode;
newnode=malloc(sizeof(node));
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

newnode->data=ele;

if(start==NULL)
{
start=newnode;
start->next=start;
return;
}
while(temp->next!=start)
{
temp=temp->next;
}
temp->next=newnode;
newnode->next=start;
}

//Insert a NODE to a specific position of the Circular Linked List


void insert_specific_position(int ele,int loc)
{
int cnt=1;
node* temp=start;
node* newnode;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->next=NULL;
while(temp->next!=NULL)
{
if(cnt==loc)
break;
cnt++;
temp=temp->next;

}
newnode->next=temp->next;
temp->next=newnode;
}

//Deleting a NODE at the beginning of Circular Linked List


void delete_front()
{
node*cur=start,*temp=start;
while(temp->next!=start)
temp=temp->next;
start=start->next;
temp->next=start;
free(cur);
}

//Deleting a NODE at the end of Circular Linked List


void delete_end()
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

{
node*prev=start,*temp=start;
while(temp->next!=start)
{
prev=temp;
temp=temp->next;
}
prev-> next=start;
free(temp);

//Deleting a NODE at the specific position of Circular Linked List


void delete_specific_pos(int loc)
{
node*temp=start,*prev=start;
int cnt=1;
while(temp->next!=start)
{
if(cnt==loc)
break;
cnt++;
prev=temp;
temp=temp->next;
}
prev->next=temp->next;
free(temp);
}

//Displaying (Traversing) a Circular Linked List


void display()
{
node*temp=start;
while(temp->next!=start)
{
printf("%d->",temp->data);
temp=temp->next;
}
printf("%d->",temp->data);
}

//Main driver program


void main()
{
insert_begining(20);
insert_begining(30);
insert_end(40);
insert_specific_position(19,2);
display();
printf("\n");
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

// delete_end();
// delete_front();
delete_specific_pos(2);
display();
}

Doubly Linked List (DLL):


A doubly linked list is a bi-directional linked list. Hence one can traverse it in both directions. Unlike
singly linked lists, its nodes contain one extra pointer called the previous pointer. This pointer points
to the previous node.
Eg:

It is advantageous over other data structures because it allows for quick insertion and deletion of
elements. Additionally, it is easy to implement and can be used in a variety of applications.

Implementation of various operations of DLL:


#include<stdlib.h>
typedef struct
{
int data;
struct node*prev;
struct node*next;
}node;

node*start=NULL;

//Inserting a node at front of DLL


void insert_front(int ele)
{
node*newnode;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->prev=NULL;
newnode->next=NULL;
if(start==NULL)
start=newnode;
else
{

newnode->next=start;
start->prev=newnode;
start=newnode;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

}
}

//Inserting a node at end of DLL


void insert_end(int ele)
{
node*newnode,*temp=start;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->prev=NULL;
newnode->next=NULL;
if(start==NULL)
start=newnode;
else
{
while(temp->next!=NULL)
temp=temp->next;
temp->next=newnode;
newnode->prev=temp;

}
}

//Inserting a node after the specified position in the DLL


void insert_specific_position(int pos,int ele)
{
node*newnode,*temp=start,*ntemp;
int cnt=1;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->prev=NULL;
newnode->next=NULL;

while(temp->next!=NULL)
{

if(cnt==pos)
break;
cnt++;
temp=temp->next;
}
ntemp=temp->next;
newnode->next=ntemp;
temp->next=newnode;
newnode->prev=ntemp;
ntemp->prev=newnode;

//Deleting a node at front of DLL


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

void delete_front()
{

node *temp=start;
start=start->next;
start->prev=NULL;
free(temp);
}

//Deleting a node at end of DLL


void delete_rear()
{
node* temp=start,*ntemp;
while(temp->next!=NULL)
temp=temp->next;
ntemp=temp->prev;
ntemp->next=NULL;
free(temp);
}

//Deleting a node in the specified position of DLL


void delete_specific_pos(int pos)
{
node*temp=start,*ntemp,*ftemp;
int cnt=1;
while(temp->next!=NULL)
{
if(cnt==pos)
break;
cnt++;
temp=temp->next;
}
ntemp=temp->prev;
ntemp->next=temp->next;
ftemp=temp->next;
ftemp->prev=ntemp;
free(temp);
}

//Displaying a DLL
void display()
{
node *temp=start;
while(temp!=NULL)
{
printf("%d->",temp->data);
temp=temp->next;
}
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

//Reversing a DLL
void reverse_list()
{

node *temp=start;
while(temp->next!=NULL)
temp=temp->next;
while(temp!=NULL)
{
printf("%d<-",temp->data);
temp=temp->prev;
}
}

//Main driver for various operations of DLL


void main()
{
insert_front(20);
insert_front(30);
insert_end(50);
insert_end(11);
insert_specific_position(2,33);
delete_specific_pos(2);
display();
printf("\n");
reverse_list();
}

Header Linked Lists (HLL)


Linked lists in which starting node is a special node called Header node. Header node does not have
any data. It is used to connect to the other nodes. Eg:

The header node does not represent an item in the linked list. This data part of this node is generally
used to hold any global information about the entire linked list. The next part of the header node
points to the first node in the list.

A header linked list can be divided into two types:


• Grounded header linked list that stores NULL in the last node’s next field.
• Circular header linked list that stores the address of the header node in the next part of the
last node of the list.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Advantages of Header Linked lists:


(i) Coding of insertion and deletion becomes easier as one need not worry about nothing or
something is there in the linked list.
(ii) Further header node data can be used to record number of nodes in the linked list. Hence
to know the number of nodes, one need not traverse linked list again and again.

Implementation of various operations of HLL:

#include<stdlib.h>
typedef struct
{
int data;
struct node*next;
}node;
node *head;

//Creating Header Node


void create_header_node()
{
head=malloc(sizeof(node));
head->next=NULL;
}

//Inserting a node to front of HLL


void insert_front(int ele)
{
node* newnode;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->next=head->next;
head->next=newnode;
}

//Inserting a node to end of HLL


void insert_end(int ele)
{
node* newnode,*temp=head;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->next=NULL;
while(temp->next!=NULL)
temp=temp->next;
temp->next=newnode;
}

//Displaying all the nodes of HLL (Traversal)


void display()
{
node*temp=head->next;
while(temp!=NULL)
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

{
printf("%d->",temp->data);
temp=temp->next;
}
}

//Deleting a node at the front of HLL


void delete_front()
{
node*temp=head->next;
head->next=temp->next;
free(temp);
}

//Deleting a node at the end of HLL


void delete_end()
{
node*temp=head,*prev=head;
while(temp->next!=NULL)
{
prev=temp;
temp=temp->next;
}
prev->next=NULL;
free(temp);
}

//Main program driver to demonstrate various operations of HLL


void main()
{
create_header_node();
insert_front(40);
insert_front(22);
insert_end(23);
insert_end(10);
delete_front();
delete_end();
display();
}

Lab Component:
Develop a C program to create Singly Linked List (SLL) of Integer Data (Linked Stack)
a. Create a SLL stack of N integer.
b. Display of SLL
c. Linear search.

#include<stdlib.h>
typedef struct
{
int data;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

struct node *next;


} node;
node *TOP=NULL;
void push(int ele) //Insertion at front
{
node *newnode;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->next=TOP;
TOP=newnode;
}
void pop() //Deletion from front
{
node *temp;
if(TOP==NULL)
{
printf("Stack Underflow\n");
return;
}
temp=TOP;
printf("Popped Element =%d\n",temp->data);
TOP=TOP->next;
free(temp);
}
void display()
{
node *temp=TOP;
while(temp!=NULL)
{
printf("%d\n",temp->data);
temp=temp->next;
}
}

void linear_search(int key)


{
node *temp=TOP;
while(temp!=NULL)
{
if(temp->data==key)
{
printf("Successful search\n");
return;
}
temp=temp->next;
}
printf("UnSuccessful search\n");
}
void main()
{
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

push(30);
push(23);
push(12);
display();
linear_search(22);
pop();
display();

Develop a C program that performs concatenation of 2 SLLs containing integer data:


#include<stdlib.h>
typedef struct
{
int data;
struct node *next;

} node;

node*start1=NULL,*start2=NULL,*start3=NULL;

node* insert_end(node* start,int ele)


{
node* newnode,*temp=start;
newnode=malloc(sizeof(node));
newnode->data=ele;
newnode->next=NULL;
if(start==NULL) //nothing
{
start=newnode;
}
else //something;
{
while(temp->next!=NULL)
temp=temp->next;
temp->next=newnode;
}
return start;
}
void display(node* start)
{
node*temp=start;
while(temp!=NULL)
{
printf("%d->",temp->data);
temp=temp->next;
}
printf("\n");
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

node* concat(node* start1,node*start2,node*start3)


{
node*temp=start1;
while(temp!=NULL)
{
start3=insert_end(start3,temp->data);
temp=temp->next;
}
temp=start2;
while(temp!=NULL)
{
start3=insert_end(start3,temp->data);
temp=temp->next;
}
return start3;
}

void main()
{
start1=insert_end(start1,20);
start1=insert_end(start1,30);
start1=insert_end(start1,10);
display(start1);
start2=insert_end(start2,15);
start2=insert_end(start2,11);
display(start2);
start3=concat(start1,start2,start3);
display(start3);

Design, Develop and Implement a menu driven Program in C for the following operations on
Doubly Linked List (DLL) of Professor Data with the fields: ID, Name, Branch, Area of
specialization.
a. Create a DLL stack of N Professor’s Data.

#include<stdlib.h>
typedef struct
{
int id;
char name[30];
char branch[30];
char area[30];
struct node *next;
struct node *prev;
}node;

node* top=NULL;
void push(int id, char*name, char*branch,char *area)
{
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

node*newnode;
newnode=malloc(sizeof(node));
newnode->id=id;
strcpy(newnode->name,name);
strcpy(newnode->branch,branch);
strcpy(newnode->area,area);
newnode->next=NULL;
newnode->prev=NULL;
if(top==NULL) //Nothing
{
top=newnode;
}
else
{
top->prev=newnode;
newnode->next=top;
top=newnode;
}
}
void pop()
{
node*temp;
if(top==NULL)
{
printf("Stack underflow\n");
return;
}
temp=top;
top=top->next;
if(top!=NULL)
top->prev=NULL;
printf("Popped Professor ID=%d\n",temp->id);
free(temp);
}

void display()
{
node*temp=top;
while(temp!=NULL)
{
printf("%d,%s,%s,%s->",temp->id,temp->name,
temp->branch,temp->area);
temp=temp->next;
}
}
void main()
{
int choice,id;
char name[30],branch[30],area[30];
while(1)
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

{
printf("******DLL Stack ************\n");
printf("1. PUSH\n");
printf("2. POP\n");
printf("3. DISPLAY\n");
printf("4. EXIT\n");
printf("Enter the choice\n");
scanf("%d",&choice);
switch(choice)
{
case 1: printf("Enter ID,Name,Branch,Area\n");
scanf("%d%s%s%s",&id,name,branch,area);
push(id,name,branch,area);
break;
case 2:pop();
break;
case 3: display();
break;
case 4:exit(0);
default: printf("Enter 1/2/3/4\n");
}

}
}
b. Create a DLL queue of N Professor’s Data Display the status of DLL and count the
number of nodes in it.
#include<stdlib.h>
typedef struct
{
int id;
char name[30];
char branch[30];
char area[30];
struct node *next;
struct node *prev;
}node;

node* rear=NULL,*front=NULL;
void addq(int id, char*name, char*branch,char *area)
{
node*newnode;
newnode=malloc(sizeof(node));
newnode->id=id;
strcpy(newnode->name,name);
strcpy(newnode->branch,branch);
strcpy(newnode->area,area);
newnode->next=NULL;
newnode->prev=NULL;
if(rear==NULL) //Nothing
{
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

front=newnode;
rear=newnode;
}
else //Something
{
rear->next=newnode;
newnode->prev=rear;
rear=newnode;
}
}
void deleteq()
{
node*temp;
if(front==NULL)
{
printf("Queue underflow\n");
return;
}
temp=front;
front=front->next;
if(front!=NULL)
front->prev=NULL;
printf("Popped Professor ID=%d\n",temp->id);
free(temp);
}

void display()
{
node*temp=front;
while(temp!=NULL)
{
printf("%d,%s,%s,%s->",temp->id,temp->name,
temp->branch,temp->area);
temp=temp->next;
}
}
int count_nodes()
{
int cnt=0;
node *temp=front;
while(temp!=NULL)
{
cnt++;
temp=temp->next;
}
return cnt;
}
void main()
{
int choice,id,cnt;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

char name[30],branch[30],area[30];
while(1)
{
printf("******DLL Queue ************\n");
printf("1. ADD Queue\n");
printf("2. Delete Queue\n");
printf("3. DISPLAY\n");
printf("4. COUNT\n");
printf("5. EXIT\n");
printf("Enter the choice\n");
scanf("%d",&choice);
switch(choice)
{
case 1: printf("Enter ID,Name,Branch,Area\n");
scanf("%d%s%s%s",&id,name,branch,area);
addq(id,name,branch,area);
break;
case 2:deleteq();
break;
case 3: display();
break;
case 4:cnt=count_nodes();
printf("Number of nodes=%d\n",cnt);
break;
case 5:exit(0);
default: printf("Enter 1/2/3/4\n");
}

}
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Module-4

Trees
Overview of a Tree:
A tree is a nonlinear hierarchical data structure that consists of nodes connected by edges. Other data
structures such as arrays, linked list, stack, and queue are linear data structures that store data
sequentially. In order to perform any operation in a linear data structure, the time complexity increases
with the increase in the data size. This behaviour is not acceptable in today's computational world.
Different tree data structures allow quicker and easier access to the data as it is a non-linear data
structure.
Eg: A Tree with 8 nodes having 4 levels. Different nodes connected with parent-child relationship.
These trees grow top down and special node at the top is called root.

Real time Trees:


Various applications of trees do exist in real time and are as follows:
(i) Folders-Files hierarchy in Operating system and cloud:

(ii) Every company/institution has an organization chart that shows the flow of authority in
the organization. Such an organization chart is depicted below:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

(iii) Computers/ computing devices are interconnected to form a computer network as


follows:

(iv) The website for any firm/organization/industry will have various webpages
organized as a tree fashion shown next:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

(v) Most trending network of the present era is the social network which is modelled as
a tree with subscribers as nodes and their relationship as edges.

Ancestor and Descendant Trees:


Ancestor Tree is a tree in which children of each node are its ancestors. Hence path from root to any
node gives the list of ancestors. One such ancestor tree is as follows. In this example, ancestors of
Kevin are: John, Terry (level1), Jack, Mary, Anthony, Karen (level2).

Descendant Tree is a tree in which children of each node are its descendants. Hence path from root
to any node gives the list of descendants. One such descendant tree is as follows. In this example,
descendants of Osco-Umbrian are: Osco and Umbrian.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Ancestor Tree

Descendant Tree

Definition of a tree:
A tree is a finite set of one or more nodes such that:
(1) Specially designated node called root
(2) Remaining nodes are partitioned into n disjoint sets, each of which are subtrees
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Tree Terminologies:
Consider an example tree for stating various terminologies:

Node of a tree: Any item which as information and branch to other node. In case of leaf node,
branch is NULL. Eg: in Node C, information is C and branch is to D.

Degree of a node: The number of subtrees of any node is its degree. Eg. B has degree 2 as it has 2
subtrees. If the degree of any node is 0, it is called Leaf Node. If degree of a node is non-zero, it is
called Non-terminal node.

Siblings: Children of the same parent are called siblings. E and F are siblings as they are children of
the same parent B.

Degree of a tree – max degree of any node is called its degree.

Ancestors: Ancestors of any node is the list of nodes in the path from root to that node.

Level: Level of a tree starts with 1 at root node. Subsequently number increases with other
descendants.

Height of a tree: Max level of a tree is the height of a tree.

Representation of Trees:
There are 3 ways of representing trees:
(i) List Representation
(ii) Leftchild, right sibling representation
(iii) Binary Tree (degree two) representation

(i) List Representation:


In the list representation, level by level traversal is performed. For each node a linked list is created
for its immediate children. For non-terminal nodes, data is left empty and pointer extended in next
level. For leaf nodes., pointer portion of node in the linked list is made 0 (NULL).
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Eg: For tree

:
Linked list representation proceeds as follows:

(ii) Left child -right sibling representation


In left child-right sibling representation, any node will be converted to have only left child. The right
child is reconnected as right sibling. The structure of any node in the tree is:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Eg: For tree

:
Left-child Right sibling representation proceeds as follows:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

(ii) Binary Tree representation:

In the binary tree representation, each node can contain max two children. To get such a
representation, tree is first converted to left-child, right sibling representation. Using such a
representation, each right sibling is converted to right subtree.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Eg: For tree

:
Binary Tree representation proceeds as follows:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Binary Trees:
A binary tree is a finite set of nodes that is either empty or consists of root node and two disjoint
binary trees called left subtree and right subtree. Each node of a binary tree consists of three items:
• data item
• address of left child
• address of right child

Types of Binary Tree


1. Full Binary Tree
A full Binary tree is a special type of binary tree in which all the nodes have two children except the
leaf nodes. Eg. full binary tree. This binary tree is a full binary tree as all the nodes except the leaf
nodes have two children.

2. Complete Binary Tree:


A binary tree is said to be a complete binary tree when all the levels are completely filled except the
last level, which is filled from the left. Eg. of complete binary tree – in this tree all levels are filled
making it complete binary tree.

The complete binary tree is similar to the full binary tree except for the two differences which are
given below:
o The filling of the leaf node must start from the leftmost side.
o It is not mandatory that the last leaf node must have the right sibling.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

3. Skewed Trees:
A binary tree can be called a skewed binary tree if all nodes have one child or no child at all. They
can be of two types:
• Left Skewed Binary Tree
• Right Skewed Binary Tree
Left Skewed Binary Tree
If all nodes are having a left child or no child at all then it can be called a left skewed binary tree. In
this tree all children at right side remain null.

Right Skewed Binary Tree


If all nodes are having a right child or no child at all then it can be called a right skewed binary tree.
In this tree all children at left side remain null.

Abstract Data Type of a binary tree:


ADT Binary_Tree:
objects: finite set of nodes either empty or consisting of root node, left subtree and right subtree
Functions:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Trees v/s Binary Trees:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Binary Tree Representations:


There are 2 ways of representing binary trees:
i. Using Arrays
ii. Using Linked List

(i) Array Representation:


In this representation, an array is declared with size being (n+1) for an n node tree. First
location of array (index 0) is empty. For remaining indices, elements will be filled such that following
relationship is maintained for an node with index ‘i' in the array.

For example tree:

Array Representation is done as follows:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

For example tree:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Array representation is done as follows:

Pros and cons of array representation:

(ii) Linked List representation:


In the Linked List representation, for each node in the tree, a node in the linked list is created. Each
node of linked list consists of following structure:

C programming language struct for the node is as follows:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

typedef struct
{
int data;
struct node *leftChild;
struct node *rightChild;
}node;

Hence for all nodes in the tree, nodes in the linked list is created. Later left and right child connectivity
through pointers are drawn.

For example tree:

LinkedList Representation is done as follows:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

For example tree:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

LinkedList representation is done as follows:

Binary Tree Traversal:


Traversal of a tree is a technique in which all nodes are visited. The order in which they are visited
gives different traversal techniques:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

(i) Inorder:
In the Inorder traversal, node comes in between left and right child. Hence technique is to go to
dead left and start printing nodes in LNR fashion for each subtree. The C recursive procedure for
inorder traversal is:

void inorder(treePointer ptr)


{
if(ptr)
{
inorder(ptr->leftChild);
printf(“%d”,ptr->data);
inorder(ptr->rightChild);
}
}
Example inorder traversal for the tree:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

(ii) Preorder:
In the preorder traversal, node is printed in the path it is traversed towards left and right subtrees.
Hence technique is NLR (Node Left Right). The C recursive procedure for preorder traversal is:
void preorder(treePointer ptr)
{
if(ptr)
{
printf(“%d”,ptr->data);
preorder(ptr->leftChild);
preorder(ptr->rightChild);
}
}

Example preorder traversal for the tree:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

(iii) Post order:


In the postorder traversal, left and right subtrees are completely traversed and then nodes are printed.
Hence technique is LRN (Left Right Node). The C recursive procedure for postorder traversal is:
void postorder(treePointer ptr)
{
if(ptr)
{
postorder(ptr->leftChild);
postorder(ptr->rightChild);
printf(“%d”,ptr->data);
}
}

Example postorder traversal for the tree:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Level-order traversal:
In the level order traversal of a tree, the nodes are visited level by level starting from level-1. In
each level, nodes are visited left to right. C procedure for level-order traversal is:
void levelorder(treePointer ptr)
{
treePointer queue[MAX_SIZE];
if(!ptr) return;
addq(ptr);
for(;;)
{
ptr=deleteq();
if(ptr)
{
printf(“%d”,ptr->data);
if(ptr->leftChild)
addq(ptr->leftChild);
if(ptr->rightChild)
addq(ptr->rightChild);
}
else
break;
}
}

Example level-order traversal for the tree:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Iterative Inorder traversal:


The iterative inorder traversal means that we have to traverse the binary tree in the inorder
fashion, i.e. (left, root, right) without using recursion. To do iterative inorder traversal we will use
the stack data structure. We create an empty stack and push the root node to it.
Algorithm for Iterative Inorder Traversal:
1. Create an empty stack treeStack.
2. Initialize currentNode as root.
3. Push the currentNode to treeStack and set currentNode = currentNode->left until current is
NULL
4. If currentNode is NULL and treeStack is not empty then
a) Pop the top element from treeStack.
b) Print the popped element, set currentNode = popped element->right
c) Go to step 3.
5. If currentNode is NULL and treeStack is empty then we are done.
Eg inorder traversal
Consider the tree:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

The stack processing along with inorder calls is shown in the following:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Traversal without Stack:


This mechanism can be accomplished by making leftChild and rightChild to maintain the path back
to root. Hence ancestry information can be obtained at any node. An example structure containing
such information about path to root is shown here:

Hence additional field called parent is maintained at each node.

Construction of a tree from given preorder and inorder traversals:

Algorithm:
Step 1: In Preorder, leftmost is the root
Step 2: Find position of root in Inorder
Step 3: Leftmost elements form left subtree and rightmost elements form right subtree.
Step 4: Recursively perform Step 2 and 3 until all nodes are traverses
Problems:

1. Construct a tree for:

1
Step 1: Root: leftmost element in the preorder =>
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Step 2: Check for position of root in Inorder. Leftsubtree of 1=>[4,2,7,5] Rightsubtree of 1=>[8,6,3]
Step 3: In left subtree, 2 appears before all elements in preorder. Hence 2 is the child of 1

Step 3: Now check for position of 2 in inorder. Leftsubtree of 2=[4] and Rightsubtree of 2=[7,5]
Step 4: Since 4 is the only node in LST of 2, make it as left child

Step 5: In RST of 2, 5 appears before 7 in preorder. Hence resulting tree is:

4 5

Step 6: In RST of 1, 3 appears first in preorder. Further in LST of 3=[8,6]

2 3

4 5

7
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Step 7: In LST of 3, 6 appears first in preorder and its position is left of 3. Similarly position of 8 is
to the left of 6 as shown in Inorder.
1

3
2

6
4 5

8
7

Construction of a tree from given postorder and inorder traversals:

Algorithm:
Step 1: In Postorder, rightmost is the root
Step 2: Find position of root in Inorder
Step 3: Leftmost elements form left subtree and rightmost elements form right subtree.
Step 4: Recursively perform Step 2 and 3 until all nodes are traverses

Construct a tree for:

Step 1: Root: rightmost element in the postorder => 1

Step 2: Check for position of root in Inorder. Leftsubtree of 1=>[4,2,7,5] Rightsubtree of 1=>[8,6,3]
Step 3: In left subtree, 2 appears after all elements in postorder. Hence 2 is the child of 1

Step 3: Now check for position of 2 in inorder. Leftsubtree of 2=[4] and Rightsubtree of 2=[7,5]
Step 4: Since 4 is the only node in LST of 2, make it as left child

4
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Step 5: In RST of 2, 5 appears after 7 in preorder. Hence resulting tree is:

4 5

Step 6: In RST of 1, 3 appears last in postorder. Further in LST of 3=[8,6]

2 3

4 5

Step 7: In LST of 3, 6 appears last in postorder and its position is left of 3. Similarly position of 8 is
to the left of 6 as shown in Inorder.
1

3
2

6
4 5

8
7

Threaded Binary Tree:


In the linked representation of binary trees, more than one half of the link fields contain NULL values
which results in wastage of storage space. If a binary tree consists of n nodes then n+1 link fields
contain NULL values. So in order to effectively manage the space, a method was devised by Perlis
and Thornton in which the NULL links are replaced with special links known as threads. Such binary
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

trees with threads are known as threaded binary trees. Each node in a threaded binary tree either
contains a link to its child node or thread to other nodes in the tree.

Types of Threaded Binary Tree


There are two types of threaded Binary Tree:
o One-way threaded Binary Tree
o Two-way threaded Binary Tree
One-way threaded Binary trees:

In one-way threaded binary trees, a thread will appear either in the right or left link field of a node. If
it appears in the right link field of a node then it will point to the next node that will appear on
performing in order traversal. Such trees are called Right threaded binary trees. If thread appears
in the left field of a node, then it will point to the nodes inorder predecessor. Such trees are called Left
threaded binary trees. Left threaded binary trees are used less often as they don't yield the last
advantages of right threaded binary trees. In one-way threaded binary trees, the right link field of last
node and left link field of first node contains a NULL. In order to distinguish threads from normal
links they are represented by dotted lines.

The above figure shows the inorder traversal of this binary tree yields D, B, E, A, C, F. When this
tree is represented as a right threaded binary tree, the right link field of leaf node D which contains a
NULL value is replaced with a thread that points to node B which is the inorder successor of a node
D. In the same way other nodes containing values in the right link field will contain NULL value.

Two-way threaded Binary Trees:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

In two-way threaded Binary trees, the right link field of a node containing NULL values is replaced
by a thread that points to nodes inorder successor and left field of a node containing NULL values is
replaced by a thread that points to nodes inorder predecessor.

The above figure shows the inorder traversal of this binary tree yields D, B, E, G, A, C, F. If we
consider the two-way threaded Binary tree, the node E whose left field contains NULL is replaced by
a thread pointing to its inorder predecessor i.e. node B. Similarly, for node G whose right and left
linked fields contain NULL values are replaced by threads such that right link field points to its
inorder successor and left link field points to its inorder predecessor. In the same way, other nodes
containing NULL values in their link fields are filled with threads.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

In the above figure of two-way threaded Binary tree, we noticed that no left thread is possible for the
first node and no right thread is possible for the last node. This is because they don't have any inorder
predecessor and successor respectively. This is indicated by threads pointing nowhere. So in order to
maintain the uniformity of threads, we maintain a special node called the header node. The header
node does not contain any data part and its left link field points to the root node and its right link field
points to itself. If this header node is included in the two-way threaded Binary tree then this node
becomes the inorder predecessor of the first node and inorder successor of the last node. Now threads
of left link fields of the first node and right link fields of the last node will point to the header node.

Threaded Binary Tree node structure:

typedef struct
{
char data;
struct node *leftChild;
struct node* rightChild;
int leftThread;
int rightThread;
}node;

Example threaded binary tree node structure:

C code:
node* insucc(node* ptr)
{
node* temp1;
temp1=ptr->leftChild;
if(!ptr->rightThread)
while(!temp1->leftThread)
temp1=temp1->leftChild;
return temp1;
}

void tinorder(node* ptr)


{
node* temp=ptr;
for(;;)
{
temp=insucc(temp);
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

if(temp==ptr)break;
printf(“%c”,temp->data);
}
}

Advantages of Threaded Binary Trees:


• In threaded binary tree, linear and fast traversal of nodes in the tree without stack.
• It is more general as one can efficiently determine the successor and predecessor of any
node by simply following the thread and links.

Disadvantages of Threaded Binary Trees:


• When implemented, the threaded binary tree needs to maintain the extra information for each
node to indicate whether the link field of each node points to an ordinary node or the node's
successor and predecessor.
• Insertion into and deletion from a threaded binary tree are more time consuming since both
threads and ordinary links need to be maintained.

Binary Search Tree


A binary search tree follows some order to arrange the elements. In a Binary search tree, the value of
left node must be smaller than the parent node, and the value of right node must be greater than the
parent node. This rule is applied recursively to the left and right subtrees of the root.
Eg:

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.
Suppose if we change the value of node 35 to 55 in the above tree, check whether the tree will be
binary search tree or not.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

In the above tree, the value of root node is 40, which is greater than its left child 30 but smaller than
right child of 30, i.e., 55. So, the above tree does not satisfy the property of Binary search tree.
Therefore, the above tree is not a binary search tree.

Advantages of Binary search tree


o Searching an element in the Binary search tree is easy as we always have a hint that which
subtree has the desired element.
o As compared to array and linked lists, insertion and deletion operations are faster in BST.

Abstract Data Type of a dictionary:


ADT Dictionary:
objects: collection of n>0 pairs, each pair has key and item
functions:

Properties of BST in terms of Dictionary:


(i) Each node has exactly one key and keys are distinct
(ii) The keys (if any) in Left SubTree are smaller than key in the root
(iii) The keys (if any) in Right SubTree are larger than key in the root
(iv) The Left and Right SubTrees are also Binary Search Trees
Procedure for creating BST
• First element given is root.
• Then, read the next element; if it is smaller than the root node, insert it as the root of the left
subtree, and move to the next element.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

• Otherwise, if the element is larger than the root node, then insert it as the root of the right
subtree.
--problems—

Procedure for searching BST


Step 1: If root=NULL, “Search unsuccessful” Exit
Step 2:Check key with root.
Step 3: If key<root,
Step 3.1: root=root->leftChild, goto Step 2
Step 4: If key>root
Step 4.1: root=root->rightChild, goto Step 2
Step 5: If key==root
“Search Successful”, Exit

--problems—

Deletion in BST
Case (i) Node to be deleted is a leaf node
Set its parent right/left child to NULL
Delete (free) the NODE
Eg: Deleting node 85 in tree shown left

Case (ii) Node to be deleted has only one child


Replace by setting its parent to point to its child
Delete (free) the child
Eg: Delete the node 12
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Case (iii) Node to be deleted has two children


Replace by its inorder predecessor or successor
Eg: Delete node 60 in the tree shown left

12,25,30,50,52,60,70,75,85

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.
Evaluation of the tree:
❖ Evaluate left subtree
❖ Evaluate right subtree
❖ Evaluate root
Eg: Evaluate the tree:

1.

Solution:

+ + 34

7 * 7 27

3
9
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

2.

Solution:

+
+

* /
* /

5 7
- 21 5 7
5 21

10 5

+
+ 28

* 3
25 3

5
5

Lab Component:
Given an array of elements, construct a complete binary tree from this array in level order
fashion. That is, elements from left in the array will be filled in the tree level wise starting from
level 0. Ex: Input : arr[] = {1, 2, 3, 4, 5, 6}

#include<stdlib.h>
typedef struct
{
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

int data;
struct node *leftChild;
struct node *rightChild;
}node;
node* create_node(int data)
{
node* newnode;
newnode=malloc(sizeof(node));
newnode->data=data;
newnode->leftChild=NULL;
newnode->rightChild=NULL;
return newnode;
}
void main()
{
int a[]={1,2,3,4,5,6,7};
int n=sizeof(a)/sizeof(a[0]),i,cnt;
node* arr[n+1];
for(i=1;i<=n;i++)
arr[i]=create_node(a[i-1]);
i=1;
cnt=1;
while(cnt<n)
{
arr[i]->leftChild=arr[2*i];
cnt++;
if(cnt>=n)
{
printf("%d->(%d)\n",arr[i]->data,
arr[2*i]->data);
break;
}
arr[i]->rightChild=arr[2*i+1];
printf("%d->(%d,%d)\n",arr[i]->data,
arr[2*i]->data,arr[2*i+1]->data);
i++;
cnt++;
}

Design, Develop and Implement a menu driven Program in C for the following operations on
Binary Search Tree (BST) of Integers a. Create a BST of N Integers b. Traverse the BST in
Inorder, Preorder and Post Order

#include<stdlib.h>
typedef struct
{
int data;
struct node *leftChild;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

struct node *rightChild;


} node;
node *tree=NULL;
void insert_BST(int data)
{
node* newnode,*temp,*prev;
newnode=malloc(sizeof(node));
newnode->data=data;
newnode->leftChild=NULL;
newnode->rightChild=NULL;
if(tree==NULL) //First time
{
tree=newnode;
return;
}
else
{
temp=tree;
prev=tree;
while(temp!=NULL)
{
prev=temp;
if(data>temp->data)
temp=temp->rightChild;
else if(data<temp->data)
temp=temp->leftChild;
}
if(data>prev->data)
prev->rightChild=newnode;
else if(data<prev->data)
prev->leftChild=newnode;

void inorder(node *ptr)


{
if(ptr)
{
inorder(ptr->leftChild);
printf("%d,",ptr->data);
inorder(ptr->rightChild);
}
}

void preorder(node *ptr)


{
if(ptr)
{
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

printf("%d,",ptr->data);
preorder(ptr->leftChild);
preorder(ptr->rightChild);
}
}

void postorder(node *ptr)


{
if(ptr)
{

postorder(ptr->leftChild);
postorder(ptr->rightChild);
printf("%d,",ptr->data);
}
}

void search_BST(int key)


{
node *temp=tree;
while(temp!=NULL)
{
if(temp->data==key)
{
printf("Successful\n");
return;
}
if(key>temp->data)
temp=temp->rightChild;
else if(key<temp->data)
temp=temp->leftChild;
}
printf("Not successful\n");
}
void main()
{
int choice,data,key;
while(1)
{
printf("***********BST Operations*********");
printf("1: Insert \n");
printf("2: Inorder Traversal\n");
printf("3: Preorder Traversal\n");
printf("4: Postorder Traversal\n");
printf("5: Search\n");
printf("6: Exit\n");
printf("Enter your choice\n");
scanf("%d",&choice);
switch(choice)
{
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

case 1: printf("enter the element\n");


scanf("%d",&data);
insert_BST(data);
break;
case 2: inorder(tree);
break;
case 3: preorder(tree);
break;
case 4: postorder(tree);
break;
case 5:printf("Enter the key element\n");
scanf("%d",&key);
search_BST(key);
break;
case 6:exit(0);
default: printf("Enter 1/2/3/4/5\n");
}
}
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Module-5
Graphs and Hashing
Need of Balanced Trees:
Consider a BST for the months of a year if input sequence is: JAN, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC ( in the order of occurrence of the months).

Computation:
Month No. of comparisons JUL 4
AUG 4
JAN 1
FEB 2 SEP 4
MAR 2
OCT 5
APR 3
MAY 3 NOV 6
JUN 3
DEC 5

Hence AVG=42/12=3.5
Max=6 for NOV

Now, Enter the nodes in the sequence: JULY, FEB, MAY, AUG, DEC,MAR,OCT,APR,JAN,JUNE,
SEP,NOV
Resultant BST is:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Average number of comparisons=3+2+3+4+2+4+1+3+4+3+4+4=37/12=3.1


Max comparisons=4 for APR, DEC,JUN, NOV and September

It can be observed that average number of comparisons and max comparisons are reduced due to
balancing of the BST. Balanced trees make searching faster and reduce the number of comparisons
required.

Now, Enter the months in the lexicographic order and resultant BST is:

Thus degenerate trees have worst case performance as they are completely imbalanced.

Observations:
- Average and maximum search time is reduced if binary tree is maintained as complete
binary trees
- However, such trees are difficult to grow dynamically
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

- These balanced trees have satisfactory search, insertion and deletion time properties

AVL Trees
AVL Tree is invented by GM Adelson - Velsky and EM Landis in 1962. The tree is named AVL in
honour of its inventors. AVL Tree can be defined as height balanced binary search tree in which each
node is associated with a balance factor which is calculated by subtracting the height of its right sub-
tree from that of its left sub-tree.
Tree is said to be balanced if balance factor of each node is in between -1 to 1, otherwise, the
tree will be unbalanced and need to be balanced.

Balance Factor (k) = height (left(k)) - height (right(k))


If balance factor of any node is 1, it means that the left sub-tree is one level higher than the right sub-
tree. If balance factor of any node is 0, it means that the left sub-tree and right sub-tree contain equal
height.
If balance factor of any node is -1, it means that the left sub-tree is one level lower than the right sub-
tree.
Eg. AVL Tree:

Trees based on balanced factor:


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

AVL Rotations
To balance itself, an AVL tree may perform the following four kinds of rotations:
• Left rotation
• Right rotation
• Left-Right rotation
• Right-Left rotation

Left Rotation:
Left rotation is performed to solve imbalance caused due to skewing of the tree on the right
side. Eg:

Right Rotation:
Right rotation is performed to solve imbalance caused due to skewing of the tree on the left
side. Eg:

Left-Right rotation
2 rotations i.e first Left and then right is performed on a subtree which is imbalanced due to first
growth of left child and subsequently right child of this left child. Eg:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Right-Left rotation
2 rotations i.e first Right and then Left is performed on a subtree which is imbalanced due to first
growth of right child and subsequently leftt child of this left child. Eg:

Construct AVL tree for the following sequence of elements:


MAR, MAY, NOV, AUG, APR, JAN, DEC, JUL, FEB,
Insert MAR

Insert MAY

Insert NOV

Insert APR

Insert AUG
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Insert JAN

Insert DEC

Insert JUL
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Insert FEB

C STRUCTURE FOR AVL TREES


typedef struct
{
int data;
struct node *leftChild;
struct node *rightChild;
short int balance_factor;
}node;

RED-BLACK Trees
The red-Black tree is a binary search tree. The prerequisite of the red-black tree is that we should
know about the binary search tree. Each node in the Red-black tree contains an extra bit that represents
a color to ensure that the tree is balanced during any operations performed on the tree like insertion,
deletion, etc.

Need of RED-BLACK Trees:


Consider the following right skewed BST:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

In this tree, Searching performance of worst case will be same as linear search. Hence need of
balanced trees arises. AVL is a balanced tree strict height, whereas Red-Black performs balancing
with colors.
Observations of Red-Black Trees:
❑ Red-Black tree is used because the AVL tree requires many rotations when the tree is large,
whereas the Red-Black tree requires a maximum of two rotations to balance the tree.
❑ The main difference between the AVL tree and the Red-Black tree is that the AVL tree is
strictly balanced, while the Red-Black tree is not completely height-balanced.
❑ Insertion is easier in the AVL tree as the AVL tree is strictly balanced, whereas deletion and
searching are easier in the Red-Black tree as the Red-Black tree requires fewer rotations
Properties of Red-Black Trees:
❖ Self balancing through rotation and recoloring
❖ Each node stores 1 extra bit for color
❖ Root node always black color
❖ NIL vs Internal nodes – different
❖ Node – Red, children should be black
❖ Never! Red-Red parent-child relationship exists
❖ Every path from a node to any of its descendant's NIL node should have same number of
black nodes.
Procedure for construction of Red-Black Tree:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Demonstrate the insertion into Red-Black Tree for the sequence:


10, 18, 7, 15, 16, 30 ,25

Insert 10

Insert 18

Insert 7

Insert 15

Insert 16
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Insert 30

Insert 25

Deletion from a Red-Black tree


Case 1: Leaf Node (Internal node) and color is red
Locate node using BST rules
Just delete
Eg:

Case 2: Node has one child


Locate node using BST rules
Replace with its child
Later just delete
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Eg:

Case 3: Node has two children


Locate node using BST rules
Replace with its inorder succesor
Later just delete

Eg:

Case 4: Leaf Node (Internal node) and color is black


Locate node using BST rules
Mark it NIL and double black
Mark parent black
Change double black to single black

Eg:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

C STRUCTURE FOR RED-BLACK TREES


typedef struct
{
int data;
struct node *leftChild;
struct node *rightChild;
short int color;
}node;

Splay Trees:
A splay tree is a self-balancing tree. AVL and Red-Black trees are also self-balancing trees then.
It has one extra property that makes it unique is splaying. A splay tree contains the same
operations as a Binary search tree, i.e., Insertion, deletion and searching, but it also contains one
more operation, i.e., splaying. So. all the operations in the splay tree are followed by splaying.
Splay trees are not strictly balanced trees, but they are roughly balanced trees. Let's understand
the search operation in the splay-tree.

Rotations
There are six types of rotations used for splaying:
1. Zig rotation (Right rotation)
2. Zag rotation (Left rotation)
3. Zig zag (Zig followed by zag)
4. Zag zig (Zag followed by zig)
5. Zig zig (two right rotations)
6. Zag zag (two left rotations)
Eg: Searching 7 in the given BST. Since parent on left, rotate right (Zig Rotation)

Since parent on right, rotate left (Zag Rotation).


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

SEARCH 1: Zig Zig (RR) rotation as LL is the problem

SEARCH 20: Zag Zag (LL) rotation as RR is the problem

SEARCH 13: Zig Zag (RL) rotation as RL is the problem


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

SEARCH 9: Zag Zig (LR) rotation as LR is the problem

Insertion on a Splay Tree:


Consider the sequence: 15, 10, 17, 7
Insert 15:

Insert 10

Insert 17

Insert 7
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

DELETION OPERATION in Splay Tree


Types of Deletions:
There are two types of deletions in the splay trees:
1. Bottom-up splaying
2. Top-down splaying
Bottom-up splaying
In bottom-up splaying, first we delete the element from the tree and then we perform the
splaying on the deleted node.
Eg:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Top-down splaying
In top-down splaying, we first perform the splaying on which the deletion is to be performed and then
delete the node from the tree. Once the element is deleted, we will perform the join operation.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

B-Trees:
B Tree is a specialized m-way tree that can be widely used for disk access. A B-Tree of order m can
have at most m-1 keys and m children. One of the main reason of using B tree is its capability to store
large number of keys in a single node and large key values by keeping the height of the tree relatively
small.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

A B tree of order m contains all the properties of an M way tree. In addition, it contains the following
properties.
❑ Root node has atleast 2 children
❑ All nodes other than root node have atleast ⌈𝒎/𝟐⌉ children
❑ All external nodes are at the same level.
It is not necessary that, all the nodes contain the same number of children but, each node must
have m/2 number of nodes.
When m=3, degree is (2,3) => 2-3 tree
When
Eg. of 2-3 m=4,
B-Tree degree is (2,4)=> 2-3-4 tree

Eg. of 2-3-4 B-Tree

Insertion into a B-Tree:


B-tree Insertion Algorithm:
Step 1: Location the position of node to be inserted
Step 2: If branch in which node is added is full, then take median of the node values and split nodes
as left and right of median.
Step 3: Step 2 is repeated for all ancestral nodes if they are full
Consider the sequence: 40,10,20,70,80,30,60
Insert 40:

Insert 10:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Insert 20

Insert 70

Insert 80

Insert 30

Insert 60

Deletion from B-Tree:


B-tree Deletion Algorithm:
Step 1: Location the position of node to be deleted
Step 2: If deleting the node, does not cause underflow, proceed with deletion
Step 3: If underflow happens and right sibling exists, rotate left. If left sibling exists, rotate right
Step 4: If rotation causes underflow, do “joining” and deletion of the node.
Eg:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Difference between B-tree and Binary tree


The following table highlights all the major differences between B-Tree and Binary Tree −

S.No. B-tree Binary tree

Here, a node can have a maximum of Here, a node can have maximum two
1. 'M'(where 'M' is the order of the tree) child child nodes (they are also known as sub-
nodes. trees).

2. It is also known as a sorted tree. It is not a sorted tree.

The nodes are present in 'inorder' traversal It can be sorted in inorder, preorder or
3. mode. postorder traversal.

It has a height of logM N (where 'M' is the It has a height of log2 N (base 2, log N,
4. order of tree and N is the number of nodes). where N is the number of nodes).

Operations are performed on a B-Tree when Binary tree operations are used when data
5. data is loaded to the disk. is loaded to the RAM (quicker).

It is used in database management system Its applications include usage in Huffman


6. to index code. coding.

It can also be used to insert the data or key It is also used in code optimization
7. in a B-tree. methods.

This is a big procedure in comparison to Data insertion is relatively easier in


8. operations on a binary tree. comparison to B-Tree.

Graphs
A graph G, consists of 2 sets V- vertices and E-edges. G=(V,E). In the Undirected graph, pair
representing edge is unordered and in the directed graph, it is ordered. Eg:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

In graph theory, Self edges and multi-graphs are not allowed. Eg:

Multi-graph with self edges

Definitions:
Maximum number of edges in a graph = n(n-1)/2
For an undirected graph of n vertices,
Each vertex can be maximum connected to (n-1) vertices
Hence number of edges for each vertex=(n-1)
Total Number of edges=(n-1)+(n-1)+..+(n-1)
=n(n-1)
But same edge is counted twice for an undirected graph
Hence total number of edges=n(n-1)/2
If (u,v) is an edge in G, then we say vertices u and v are adjacent and (u,v) is incident on vertices u
and v
Eg: For the graph shown below, for edge (1,3) 1 and 3 are adjacent and (1,3) is incident on vertices
1 and 3.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

A subgraph of G is a graph G’ such that V(G’) is a subset of V(G) and E(G’) is a subset of E(G)
Eg: for graph G shown below,

can be a subgraph obtained by deleting vertex 2 and all edges incident on vertex
2.

A path from vertex u to v is a set of vertices u,i1,i2..v such that (u,i1), (i1,i2)… (in,v) are edges. Length
of path=no of edges in it

Path from (0,6) is {0,2,6} and its length=3


A simple path is a path in which all vertices except first and last are distinct. A cycle is a simple path
in which first and last vertices are same.
In the above graph, (0,6) is path is simple. However for the graph below:

Path {0,1,2,0} is a cycle.


A tree is an acyclic graph

is an acyclic graph and hence tree.


DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

In an undirected graph G, two vertices u and v are connected iff there is a path from u to. An
undirected graph G is connected, iff for every distinct pair of vertices there exists a path.
Eg:

Hence for a disconnected graph, 2 components H1 and H2 are connected components.


A directed graph G is strongly connected iff for every pair of distinct vertices (u,v) there is a directed
path from u to v and v to u.

Degree of a vertex is number of edges incident to that vertex. For a directed graph, in-degree of a
vertex is the number of incoming edges. For a directed graph, out-degree of a vertex is the number of
outgoing edges.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Graph Representations:

Adjacency Matrix:
n graph theory, an adjacency matrix is a dense way of describing the finite graph structure. It is the
2D matrix that is used to map the association between the graph nodes.
If a graph has n number of vertices, then the adjacency matrix of that graph is n x n, and each entry
of the matrix represents the number of edges from one vertex to another.
An adjacency matrix is also called as connection matrix. Sometimes it is also called a Vertex
matrix.
If an Undirected Graph G consists of n vertices then the adjacency matrix of a graph is n x n matrix
A = [aij] and defined by -
aij = 1 {if there is an edge from Vi to Vj}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

aij = 0 {Otherwise}
Eg: Graph and its adjacency matrix

Directed graph and its adjacency matrx:

Hence it the adjacency matrix for undirected graph, edge from (1,2) creates an entry 1 for (1,2) and
(2,1) in the matrix and symmetry is preserved. However, for a directed graph, no symmetry is
considered while constructing the adjacency matrix.
For an undirected graph, degree of any vertex is its row sum. For a digraph, row-sum is outdegree
and column-sum is indegree. Drawback of Adjacency matrix is wastage of memory. If only few edges
are present in the graph, then most of entries becomes 0 and leads to a sparse matrix. Thus this
representation becomes memory inefficient.

What will be the adjacency matrix for the below directed weighted graph?
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Solution:

Adjacency List Representation:


An adjacency list is used in the linked representation to store the Graph in the computer's memory. It
is efficient in terms of storage as we only have to store the values for edges.

In the above figure, we can see that there is a linked list or adjacency list for every node of the graph.
From vertex A, there are paths to vertex B and vertex D. These nodes are linked to nodes A in the
given adjacency list.
An adjacency list is maintained for each node present in the graph, which stores the node value and
a pointer to the next adjacent node to the respective node. If all the adjacent nodes are traversed, then
store the NULL in the pointer field of the last node of the list.
The sum of the lengths of adjacency lists is equal to twice the number of edges present in an
undirected graph.
Now, consider the directed graph, and let's see the adjacency list representation of that graph.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

For a directed graph, the sum of the lengths of adjacency lists is equal to the number of edges present
in the graph.
Now, consider the weighted directed graph, and let's see the adjacency list representation of that
graph.

In the case of a weighted directed graph, each node contains an extra field that is called the weight of
the node.
In an adjacency list, it is easy to add a vertex. Because of using the linked list, it also saves space.

Create adjacency list for the following graphs:

Solution:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Solution:

Solution:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Create adjacency List and Inverse Adjacency List Representation

Adjacency List:

Inverse Adjacency List:

For an undirected graph, degree of any vertex is number of nodes in the chain of that vertex. For a
digraph, out-degree is the number of nodes in the chain of that vertex. For a digraph, in-degree is the
number of nodes in the chain of that vertex in Inverse Adjacency list.

Adjacency Multi-List Representation:


Adjacency Multi-lists are an edge, rather than vertex based, graph representation. In the Multilist
representation of graph structures; there are two parts, a directory of Node information (Vertex List)
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

and a set of linked list of edge information (Edge List). There is one entry in the node directory for
each node of the graph. The directory entry for node i points to a linked adjacency list for node i. each
record of the linked list area appears on two adjacency lists: one for the node at each end of the
represented edge.
Format of edge list:
m V1 V2 L1 L2
where,
m- Boolean field used to mark visited nodes during BFS or DFS
V1 and V2- source and destination vertices of the edge under consideration
L1- Link to next edge of V1
L2- Link to next edge of V2
Eg:
Consider the graph

Corresponding adjacency multi-list representation:

Graph Searching Techniques:


There are 2 popular Graph Searching Techniques:
(i) Breadth First Search (BFS)
(ii) Dept First Search (DFS)
BFS:
It is also known as level order traversal. The Queue data structure is used for the Breadth First
Search traversal. When we use the BFS algorithm for the traversal in a graph, we can consider any
node as a root node.
Consider the graph below:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Suppose we consider node 0 as a root node. Therefore, the traversing would be started from node 0.

Once node 0 is removed from the Queue, it gets printed and marked as a visited node.
Once node 0 gets removed from the Queue, then the adjacent nodes of node 0 would be inserted in a
Queue as shown below:

Now the node 1 will be removed from the Queue; it gets printed and marked as a visited node
Once node 1 gets removed from the Queue, then all the adjacent nodes of a node 1 will be added in a
Queue. The adjacent nodes of node 1 are 0, 3, 2, 6, and 5. But we have to insert only unvisited nodes
in a Queue. Since nodes 3, 2, 6, and 5 are unvisited; therefore, these nodes will be added in a Queue
as shown below:

The next node is 3 in a Queue. So, node 3 will be removed from the Queue, it gets printed and marked
as visited as shown below:

Once node 3 gets removed from the Queue, then all the adjacent nodes of node 3 except the visited
nodes will be added in a Queue. The adjacent nodes of node 3 are 0, 1, 2, and 4. Since nodes 0, 1 are
already visited, and node 2 is present in a Queue; therefore, we need to insert only node 4 in a Queue.

Now, the next node in the Queue is 2. So, 2 would be deleted from the Queue. It gets printed and
marked as visited as shown below:

Once node 2 gets removed from the Queue, then all the adjacent nodes of node 2 except the visited
nodes will be added in a Queue. The adjacent nodes of node 2 are 1, 3, 5, 6, and 4. Since the nodes 1
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

and 3 have already been visited, and 4, 5, 6 are already added in the Queue; therefore, we do not need
to insert any node in the Queue.
The next element is 5. So, 5 would be deleted from the Queue. It gets printed and marked as visited
as shown below:

Once node 5 gets removed from the Queue, then all the adjacent nodes of node 5 except the visited
nodes will be added in the Queue. The adjacent nodes of node 5 are 1 and 2. Since both the nodes
have already been visited; therefore, there is no vertex to be inserted in a Queue.
The next node is 6. So, 6 would be deleted from the Queue. It gets printed and marked as visited as
shown below:

Once the node 6 gets removed from the Queue, then all the adjacent nodes of node 6 except the visited
nodes will be added in the Queue. The adjacent nodes of node 6 are 1 and 4. Since the node 1 has
already been visited and node 4 is already added in the Queue; therefore, there is not vertex to be
inserted in the Queue.
The next element in the Queue is 4. So, 4 would be deleted from the Queue. It gets printed and marked
as visited. Once the node 4 gets removed from the Queue, then all the adjacent nodes of node 4 except
the visited nodes will be added in the Queue. The adjacent nodes of node 4 are 3, 2, and 6. Since all
the adjacent nodes have already been visited; so, there is no vertex to be inserted in the Queue.

DFS:
In DFS traversal, the stack data structure is used, which works on the LIFO (Last In First Out)
principle. In DFS, traversing can be started from any node, or we can say that any node can be
considered as a root node until the root node is not mentioned in the problem. In the case of BFS, the
element which is deleted from the Queue, the adjacent nodes of the deleted node are added to the
Queue. In contrast, in DFS, the element which is removed from the stack, then only one adjacent node
of a deleted node is added in the stack.
Consider the graph:

Consider node 0 as a root node.


First, we insert the element 0 in the stack as shown below:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

The node 0 has two adjacent nodes, i.e., 1 and 3. Now we can take only one adjacent node, either 1
or 3, for traversing. Suppose we consider node 1; therefore, 1 is inserted in a stack and gets printed
as shown below:

Now we will look at the adjacent vertices of node 1. The unvisited adjacent vertices of node 1 are 3,
2, 5 and 6. We can consider any of these four vertices. Suppose we take node 3 and insert it in the
stack as shown below:

Consider the unvisited adjacent vertices of node 3. The unvisited adjacent vertices of node 3 are 2
and 4. We can take either of the vertices, i.e., 2 or 4. Suppose we take vertex 2 and insert it in the
stack as shown below:

The unvisited adjacent vertices of node 2 are 5 and 4. We can choose either of the vertices, i.e., 5 or
4. Suppose we take vertex 4 and insert in the stack as shown below:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Now we will consider the unvisited adjacent vertices of node 4. The unvisited adjacent vertex of node
4 is node 6. Therefore, element 6 is inserted into the stack as shown below:

After inserting element 6 in the stack, we will look at the unvisited adjacent vertices of node 6. As
there is no unvisited adjacent vertices of node 6, so we cannot move beyond node 6. In this case, we
will perform backtracking. The topmost element, i.e., 6 would be popped out from the stack as
shown below:

The topmost element in the stack is 4. Since there are no unvisited adjacent vertices left of node 4;
therefore, node 4 is popped out from the stack as shown below:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

The next topmost element in the stack is 2. Now, we will look at the unvisited adjacent vertices of
node 2. Since only one unvisited node, i.e., 5 is left, so node 5 would be pushed into the stack above
2 and gets printed as shown below:

Now we will check the adjacent vertices of node 5, which are still unvisited. Since there is no vertex
left to be visited, so we pop the element 5 from the stack as shown below:

We cannot move further 5, so we need to perform backtracking. In backtracking, the topmost element
would be popped out from the stack. The topmost element is 5 that would be popped out from the
stack, and we move back to node 2 as shown below:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Now we will check the unvisited adjacent vertices of node 2. As there is no adjacent vertex left to be
visited, so we perform backtracking. In backtracking, the topmost element, i.e., 2 would be popped
out from the stack, and we move back to the node 3 as shown below:

Now we will check the unvisited adjacent vertices of node 3. As there is no adjacent vertex left to be
visited, so we perform backtracking. In backtracking, the topmost element, i.e., 3 would be popped
out from the stack and we move back to node 1 as shown below:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

After popping out element 3, we will check the unvisited adjacent vertices of node 1. Since there is
no vertex left to be visited; therefore, the backtracking will be performed. In backtracking, the
topmost element, i.e., 1 would be popped out from the stack, and we move back to node 0 as shown
below:

We will check the adjacent vertices of node 0, which are still unvisited. As there is no adjacent vertex
left to be visited, so we perform backtracking. In this, only one element, i.e., 0 left in the stack, would
be popped out from the stack as shown below:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

As we can observe in the above figure that the stack is empty. So, we have to stop the DFS traversal
here, and the elements which are printed is the result of the DFS traversal.

Differences between BFS and DFS


The following are the differences between the BFS and DFS:
BFS DFS

Full form BFS stands for Breadth First DFS stands for Depth First Search.
Search.

Technique It a vertex-based technique to find It is an edge-based technique because the


the shortest path in a graph. vertices along the edge are explored first from
the starting to the end node.

Definition BFS is a traversal technique in DFS is also a traversal technique in which


which all the nodes of the same traversal is started from the root node and
level are explored first, and then explore the nodes as far as possible until we
we move to the next level. reach the node that has no unvisited adjacent
nodes.

Data Structure Queue data structure is used for Stack data structure is used for the BFS
the BFS traversal. traversal.

Backtracking BFS does not use the backtracking DFS uses backtracking to traverse all the
concept. unvisited nodes.

Number of BFS finds the shortest path having In DFS, a greater number of edges are
edges a minimum number of edges to required to traverse from the source vertex to
traverse from the source to the the destination vertex.
destination vertex.

Optimality BFS traversal is optimal for those DFS traversal is optimal for those graphs in
vertices which are to be searched which solutions are away from the source
closer to the source vertex. vertex.

Speed BFS is slower than DFS. DFS is faster than BFS.

Suitability for It is not suitable for the decision It is suitable for the decision tree. Based on
decision tree tree because it requires exploring the decision, it explores all the paths. When
all the neighboring nodes first. the goal is found, it stops its traversal.

Memory It is not memory efficient as it It is memory efficient as it requires less


efficient requires more memory than DFS. memory than BFS.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Hashing
Hashing is a popular technique for quickly storing and retrieving data. The primary reason for using
hashing is that it produces optimal results by performing optimal searches. If we try to search, insert,
or delete any element in a balanced binary search tree, the time complexity for the same is O. (logn).
Now, there may be times when our applications need to perform the same operations in a faster, more
optimised manner, and this is where hashing comes into play. All of the above operations in hashing
can be completed in O(1), or constant time. It is critical to understand that hashing's worst-case time
complexity remains O(n), but its average time complexity is O. (1).

Static Hashing:
In Static hashing, dictionary pairs (key,value) are stored in a table called hash-table. Hash table is
static and changes very infrequently. Hash table should be created with larger size to accommodate
all possible insertions in then future. Hash table is Partitioned to buckets. Each bucket can have one
or more slots. Each slot is big enough to accommodate one dictionary pair.
Key density
Key density of a hash table = n/T
n – number of pairs
T- total possible number of keys
Compute key density for keys which are atmost 6 digits long and there are 1000 dictionary pairs
T= total number of possible keys= 9*10^5=900000
n=1000
Hence, key density=1000/900000=1/900=0.00111111111
Hence fraction of the usage of keys is very small.

Construct a hash table for C library functions, with first letter of the function goes to the
appropriate bucket. Assume 2 slots for each bucket

Solution:

Hence collision occurs while trying to insert library function clock.


❑ When no overflow occurs, time required to insert, delete or search using hashing depends only
on time required to compute hash function and time to search one bucket.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

❑ Hash table with 26 buckets and 2 slots is not useful due to large number of collisions
Desirable properties of hash functions:
❑ Easy to compute
❑ Minimizes the number of collisions
❑ Collisions are unavoidable, hence mechanisms to handle collisions is desired.
❑ Hash function maps a key to a bucket

Different Hash functions


Division Modulo Method - Hashing Technique
Division Modulo Method is the simplest method of hashing. In this method, divide the element with
the size of the hash table and use the remainder as the index of the element in the hash table.,
Example 1:
Size of Hash Table (m) = 1000 (0 - 999)
Suppose we want to calculate the index of element x, where x = 123789456
index =123789456 mod 1000
= 456
we store the element x at position 456 in the hash table.
Further examples:

Mid Square Method – Hashing


In this method, HashFunction will find the square of the given element then took the middle digits
and use those digits as the index of the element. Let's understand with an example.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Example:
Suppose the size of the Hash Table (m) = 10 (0 - 9) maximum digits required for the index is 1
Element (x) = 12 ⇒ x2 = 144
Mid 1 digit of 144 is 4, so the element x=12 will be stored at the index=4 in the hash table with the
size of 10 slots.
Another Example:
Suppose the size of the Hash Table (m) = 1000 (0 - 999) maximum digits required for the index is 3
Element (x) = 87431 ⇒ x2 = 7644179761
The possible 3 digit mids of 7644179761 are 417 or 179, we can pick any of those mids. If we pick
419 then the element x=87431 will be stored at the index=419 in the hash table with the size of
1000 slots.
There are very less chances of collision in this method.
Further examples:

Folding Method
In this method, the keys are divided into parts which are then combined (or “folded”) together
and often transformed into the address – Two types of folding are used, shift folding and boundary
folding
In shift folding, the parts are placed underneath each other and then processed (for
example, by adding) – Using a Social Security number, say 123-45-6789, we can divide
it into three parts - 123, 456, and 789 – and add them to get 1368 – This can then be
divided modulo hash_table size to get the address.
With boundary folding, the key is visualized as being written on a piece of paper and
folded on the boundaries between the parts. The result is that alternating parts of the key
are reversed, so the Social Security number part would be 123, 654, 789, totalling 1566 –
As can be seen, in both versions, the key is divided into even length parts of some fixed
size, plus any leftover digits – Then these are added together and the result is divided
modulo the table size – Consequently this is very fast and efficient, especially if bit strings
are used instead of numbers
Further examples:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Digit Analysis:

String to Integer conversions


Any string can be converted to number by (i) adding ASCII value of each character in the string (ii)
adding ASCII value of each character and left shifting every alternate character by 8 bits.
Code for adding ascii value of each character:
unsigned int stringToInt(char *key)
{
int number=0;
while(*key)
{
number+=*key++;

}
return number;
}
Code for adding ascii value of each character with left shifting every alternate character by 8
bits:
unsigned int stringToIntA(char *key)
{
int number=0;
while(*key)
{
number+=*key++;
if(*key) number+=(*key++)<<8;

}
return number;
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Collision Resolution Techniques:

Linear Probing
Linear probing is one of the forms of open addressing. As we know that each cell in the hash table
contains a key-value pair, so when the collision occurs by mapping a new key to the cell already
occupied by another key, then linear probing technique searches for the closest free locations and
adds a new key to that empty cell. In this case, searching is performed sequentially, starting from the
position where the collision occurs till the empty cell is not found.

Quadratic Probing
In case of linear probing, searching is performed linearly. In contrast, quadratic probing is an open
addressing technique that uses quadratic polynomial for searching until a empty slot is found.
It can also be defined as that it allows the insertion ki at first free location from (u+i2)%m where i=0
to m-1.
Let's understand the quadratic probing through an example.
Consider the same example which we discussed in the linear probing.
A = 3, 2, 9, 6, 11, 13, 7, 12 where m = 10, and h(k) = 2k+3
The key values 3, 2, 9, 6 are stored at the indexes 9, 7, 1, 5, respectively. We do not need to apply the
quadratic probing technique on these key values as there is no occurrence of the collision.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

The index value of 11 is 5, but this location is already occupied by the 6. So, we apply the quadratic
probing technique.
When i = 0
Index= (5+02)%10 = 5
When i=1
Index = (5+12)%10 = 6
Since location 6 is empty, so the value 11 will be added at the index 6.

Random probing
• Random probing avoids clustering by making the probe sequence depend on the key
• With random probing, the probe sequence is generated by the output of a pseudorandom
number generator seeded by the key (possibly together with another seed component that is
the same for every key, but is different for different tables)
• The insert algorithm for random hashing is then:
1. Create RNG seeded with K. Set indx = RNG.next() mod M.
2. If table location indx already contains the key, no need to insert it. Done!
3. Else if table location indx is empty, insert key there. Done!
4. Else collision. Set indx = RNG.next() mod M.
5. If all M locations have been probed, give up. Else, go to 2.
• Random probing is easy to analyze, but because of the "expense" of random number
generation, it is not often used; double hashing works about as well

Double Hashing
Double hashing is an open addressing technique which is used to avoid the collisions. When the
collision occurs then this technique uses the secondary hash of the key. It uses one hash value as an
index to move forward until the empty location is found.
In double hashing, two hash functions are used. Suppose h1(k) is one of the hash functions used to
calculate the locations whereas h2(k) is another hash function. It can be defined as "insert ki at first
free place from (u+v*i)%m where i=(0 to m-1)". In this case, u is the location computed using the
hash function and v is equal to (h2(k)%m).

Open hashing (Chaining)


In Open Hashing, one of the methods used to resolve the collision is known as a chaining method.
The chaining method maintains linked list for each possible locations as shown below:
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

Eg:

Static Hashing v/s Dynamic Hashing

Dynamic Hashing:
Dynamic hashing is used to overcome the problems of static hashing like bucket overflow.
Data buckets grow or shrink as the records increases or decreases. This method is also known
as Extendable hashing method. This method makes hashing dynamic, i.e., it allows insertion
or deletion without resulting in poor performance.
How to search a key
❑ Calculate the hash address of the key.
❑ Check how many bits are used in the directory, and these bits are called as i.
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

❑ Take the least significant i bits of the hash address. This gives an index of the directory.
❑ Now using the index, go to the directory and find bucket address where the record might be.
Eg:

Inserting a new record


❑ Follow the same procedure for retrieval, ending up in some bucket.
❑ If there is still space in that bucket, then place the record in it.
❑ If the bucket is full, then split the bucket and redistribute the records.
Insert key 9 with hash address 10001

Lab Component
Design, Develop and implement a program in C for the following operations on Graph (G) of
cities a. Create a Graph of N cities using Adjacency Matrix

#include<stdio.h>
void create_adjacent_matrix(int N,int cities[N][N])
{
int i,j,edges,src,dest;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
cities[i][j]=0;
}
}
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

printf("Enter the number of edges\n");


scanf("%d",&edges);
for(i=0;i<edges;i++)
{
printf("Enter the vertices of the edge\n");
scanf("%d%d",&src,&dest);
cities[src][dest]=1;
cities[dest][src]=1;
}

}
void print_adjacent_matrix(int N,int cities[N][N])
{
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
printf("%3d",cities[i][j]);
}
printf("\n");
}

void main()
{
int cities[6][6];
create_adjacent_matrix(6,cities);
print_adjacent_matrix(6,cities);

Print all the nodes reachable from a given starting node in a diagraph using DFS/BFS method.

void initialize_digraph(int N,int grp[N][N])


{
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
grp[i][j]=0;
}
}
}

void create_digraph(int N,int grp[N][N])


{
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

int edges,i,src,dest;
printf("Enter the number of edges\n");
scanf("%d",&edges);
for(i=0;i<edges;i++)
{
printf("Enter the vertices of the edge\n");
scanf("%d%d",&src,&dest);
grp[src][dest]=1;

}
}
void display_digraph(int N,int grp[N][N])
{
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
printf("%3d",grp[i][j]);
}
printf("\n");
}
}
void depth_first_search(int node,int N,int grp[N][N],
int visited[N])
{
int i;
visited[node]=1;
printf("Visited node=%d\n",node);
for(i=0;i<N;i++)
{
if(grp[node][i]==1 && visited[i]==0)
{
depth_first_search(i,N,grp,visited);
}
}

void breadth_first_search(int node,int N,


int grp[N][N],int visited[N])
{
int queue[N];
int front=0,rear=0,i,cnode;
queue[rear++]=node;
while(front<rear)
{
cnode=queue[front++];
printf("Visited node=%d\n",cnode);
for(i=0;i<N;i++)
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

{
if(visited[i]==0 && grp[cnode][i]==1)
{
queue[rear++]=i;
visited[i]=1;
}
}
}
}
void main()
{
int N=7,i;
int grp[N][N],visited[N];
initialize_digraph(N,grp);
create_digraph(N,grp);
display_digraph(N,grp);
printf("Depth First Search....\n");
for(i=0;i<N;i++)
visited[i]=0;
depth_first_search(0,N,grp,visited);
printf("Breadth First Search....\n");
for(i=0;i<N;i++)
visited[i]=0;
breadth_first_search(0,N,grp,visited);
}

int N=7;
int hash_table[7];
void initialize_hash_table()
{
int i;
for(i=0;i<N;i++)
hash_table[i]=-1;
}
void insert(int key)
{
int index;
index=key%N;
while(hash_table[index]!=-1)
{
index=(index+1)%N;
}
hash_table[index]=key;
}
void print_hash_table()
{
int i;
DATA STRUCTURES AND APPLICATIONS DEPT. OF AIML

for(i=0;i<N;i++)
{
printf("%d\n",hash_table[i]);
}
}
void main()
{
initialize_hash_table();
insert(76);
insert(93);
insert(40);
insert(47);
insert(10);
insert(55);
print_hash_table();
}

You might also like