[go: up one dir, main page]

0% found this document useful (0 votes)
9 views528 pages

Kamthane-Data Structures Using C-2012

The document is a textbook titled 'Data Structures Using C' by Ashok N. Kamthane, designed for students of Biju Patnaik University of Technology. It covers fundamental concepts of data structures and their applications in C programming, including various types of data structures, algorithms, and practical exercises. The book also includes a roadmap to the syllabus and solved university question papers to aid learning.

Uploaded by

janapriya campus
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)
9 views528 pages

Kamthane-Data Structures Using C-2012

The document is a textbook titled 'Data Structures Using C' by Ashok N. Kamthane, designed for students of Biju Patnaik University of Technology. It covers fundamental concepts of data structures and their applications in C programming, including various types of data structures, algorithms, and practical exercises. The book also includes a roadmap to the syllabus and solved university question papers to aid learning.

Uploaded by

janapriya campus
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/ 528

DATA STRUCTURES

USING C

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd i 3/2/2012 6:48:55 PM


This page is intentionally left blank.

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd ii 3/2/2012 6:48:55 PM


DATA STRUCTURES
USING C
Second Semester
Biju Patnaik University of Technology
Subject Code: BE-2106

Ashok N. Kamthane
Associate Professor
Department of Electronics and Telecommunication
Associate Dean (Academics)
SGGS Institute of Engineering and Technology
Nanded, Maharashtra

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd iii 3/2/2012 6:48:55 PM


The publishers would like to thank Muktikanta Sahu of International Institute of Information
Technology, Bhubaneswar, for his help in mapping the contents of this book to the requirements
of Biju Patnaik University of Technology.

Copyright © 2012 Dorling Kindersley (India) Pvt. Ltd.


Licensees of Pearson Education in South Asia

No part of this eBook may be used or reproduced in any manner whatsoever without the publisher’s
prior written consent.

This eBook may or may not include all assets that were part of the print version. The publisher
reserves the right to remove any material in this eBook at any time.

ISBN 9788131765067
eISBN 9788131776148

Head Office: A-8(A), Sector 62, Knowledge Boulevard, 7th Floor, NOIDA 201 309, India
Registered Office: 11 Local Shopping Centre, Panchsheel Park, New Delhi 110 017, India

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd iv 3/2/2012 6:48:56 PM


Contents
Preface ix 2.12 Column-major Arrays 2.34
2.13 Pointers and Arrays 2.35
About the Author xi 2.14 Pointers and Two-dimensional
Arrays 2.39
Roadmap to the Syllabus xiii 2.15 Array of Pointers 2.41
2.16 Pointers and Strings 2.43
Chapter 1 Introduction to Data Structures 1.1 Summary 2.46
1.1 Introduction 1.1 Exercises 2.46
1.2 Data and Information 1.4
1.3 Overview of Data Structures 1.4
Chapter 3 Recursion 3.1
1.4 Types of Data Structures 1.5
3.1 Introduction 3.1
1.5 Primitive and Non-primitive Data
3.2 Types of Recursions 3.4
Structures and Operations 1.7
3.3 Rules for Recursive Function 3.5
1.6 Binary and Decimal Integers 1.8
3.4 Direct Recursion 3.7
1.7 Logical Information 1.13
3.5 Indirect Recursion 3.10
1.8 Storage of Information 1.15
3.6 Recursion Versus Iteration 3.12
1.9 Hardware and Software 1.16
3.7 The Towers of Hanoi 3.15
1.10 Concept of Data Types 1.18
3.8 Advantages and Disadvantages
1.11 Data Types in C 1.18
of Recursion 3.18
1.12 Abstract Data Types 1.19
3.9 Tail Recursion 3.18
1.13 Pointers 1.20
3.10 Efficiency of Recursion 3.18
1.14 Structures in C 1.21
Summary 3.19
1.15 Unions 1.23
Exercises 3.19
1.16 Algorithms 1.25
Summary 1.27
Exercises 1.28 Chapter 4 Stacks 4.1
4.1 Introduction 4.1
Chapter 2 Data Structures: Arrays 2.1 4.2 Stack-related Terms 4.3
2.1 Introduction 2.1 4.3 Stack Implementation 4.4
2.2 Characterstics of Arrays 2.3 4.4 Operations on Stack 4.5
2.3 One-dimensional Arrays 2.6 4.5 Pointers and Stack 4.14
2.4 Operation with Arrays 2.7 4.6 Representation of Arithmetic
2.5 Two-dimensional Arrays 2.15 Expressions 4.17
2.6 Three- or Multi-dimensional Summary 4.23
Arrays 2.22 Exercises 4.24
2.7 Strings 2.23
2.8 Array of Structures 2.25 Chapter 5 Queues 5.1
2.9 Drawbacks of Linear Arrays 2.26 5.1 Introduction 5.1
2.10 Sparse Matrices and Dense 5.2 Various Positions of Queues 5.3
Matrices 2.26 5.3 Queue Implementation 5.4
2.11 Row-major Arrays 2.33 5.4 Operations on Queues 5.5

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd v 3/2/2012 6:48:56 PM


vi Contents

5.5 Disadvantages of Simple Queues 5.9 Chapter 7 Storage Management 7.1


5.6 Dynamic Implementation 7.1 Introduction 7.1
(Pointers) 5.15 7.2 Allocation Techniques 7.2
5.7 Insertion and Deletion 7.3 Memory Representation 7.2
Operation 5.17 7.4 Boundary Tag System 7.4
5.8 Types of Queues 5.19 7.5 Storage Allocations 7.5
5.9 Applications of Queues 5.39 7.6 Storage Release 7.6
5.10 Types of Systems 5.40 7.7 Buddy System 7.6
Summary 5.41 7.8 Binary Buddy System 7.11
Exercises 5.42 7.9 Compaction 7.11
7.10 Garbage Collection 7.16
Chapter 6 Linked List 6.1 Summary 7.17
6.1 Introduction 6.2 Exercises 7.17
6.2 Linked List 6.2
6.3 Illustration of Linked List Chapter 8 Applications of Stacks 8.1
for Storing a String 6.3 8.1 Introduction 8.1
6.4 Important Terms 6.4 8.2 Infix, Prefix and Postfix Notations 8.1
6.5 Memory Allocation 8.3 Evaluation of Postfix Expression 8.5
and De-allocation 6.9 8.4 Conversion of Expression
6.6 Operations on Linked Lists 6.10 from Infix to Postfix 8.7
6.7 Singly Linked List 6.11 8.5 Reverse String 8.12
6.8 Linked List with Header 6.11 8.6 Stack Frames 8.14
6.9 Linked List Without Header 6.14 8.7 Conversion of Number System 8.14
6.10 Insertion in the Linked List 6.19 8.8 Recursion 8.15
6.11 Insertion of Node at Start 6.19 8.9 Activation Record Organization 8.18
6.12 Insertion of Node at End 6.23 8.10 Scope Rules 8.19
6.13 Insertion of Node at a Given 8.11 Scope Rules Through Stack 8.20
Position 6.25 Summary 8.23
6.14 Representation of Stacks Exercises 8.24
Using Linked Lists 6.33
6.15 Representation of Queues Chapter 9 Trees 9.1
Using Linked Lists 6.39 9.1 Introduction 9.1
6.16 Reversing the Singly Linked 9.2 Basic Terms 9.2
List 6.41 9.3 General Tree 9.8
6.17 Concatenation of Two Lists 6.43 9.4 Binary Trees 9.8
6.18 Splitting of a Linked List 6.45 9.5 Complete Binary Tree 9.8
6.19 Circular Linked List 6.47 9.6 Strictly Binary Tree 9.9
6.20 Method for Detecting End 6.48 9.7 Extended Binary Tree 9.10
6.21 Doubly Linked List 6.62 9.8 Binary Tree Representation 9.11
6.22 Circular Doubly Linked List 6.69 9.9 Operations on Binary Trees 9.14
6.23 Applications of Linked 9.10 Traversal of a Binary Tree 9.15
List 6.71 9.11 Conversion of Expression
Summary 6.84 into Postfix 9.30
Exercises 6.86 9.12 Binary Search Tree 9.33

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd vi 3/2/2012 6:48:56 PM


Contents vii

9.13 Threaded Binary Tree 9.39 11.7 Tree Sort 11.13


9.14 B-Tree (Balanced Multi-way 11.8 Merge Sort 11.16
Tree) 9.42 11.9 Heap Sort 11.21
9.15 B-Tree of Order 5 9.44 11.10 Radix Sort 11.24
9.16 B+ Tree 9.46 11.11 Partition Exchange Sort 11.28
9.17 AVL Tree 9.47 Summary 11.31
Summary 9.52 Exercises 11.32
Exercises 9.52
Chapter 12 Searching 12.1
Chapter 10 Graphs 10.1 12.1 Introduction 12.1
10.1 Introduction 10.1 12.2 Searching 12.2
10.2 Graphs 10.2 12.3 Linear (Sequential) Search 12.2
10.3 Terminologies of Graph 10.3 12.4 Binary Search 12.7
10.4 Graph Representation 10.6 12.5 Hashing Method 12.12
10.5 Traversal in Graph 10.11 12.6 Hashing Function 12.12
10.6 Spanning Trees 10.11 12.7 Division Method 12.14
Summary 10.27 12.8 Mid-square Method 12.18
Exercises 10.27 12.9 Folding Method 12.20
12.10 Length-dependent Method 12.21
Chapter 11 Sorting 11.1 12.11 Multiplicative Hashing
11.1 Introduction 11.1 Function 12.24
11.2 Sorting 11.2 12.12 Digit Analysis Method 12.24
11.3 Insertion Sort 11.2 Summary 12.24
11.4 Selection Sort 11.6 Exercises 12.25
11.5 Bubble Sort 11.8
11.6 Quick Sort 11.10 Solved Question Papers Q.1

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd vii 3/2/2012 6:48:56 PM


This page is intentionally left blank.

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd viii 3/2/2012 6:48:56 PM


Preface
The world today is witnessing a new kind of revolution—the Information Revolution—ushered in by
technology. This revolution is in fact far more sweeping than any other revolution in history in its reach
and influence, bringing fundamental changes in all aspects of our life. Information technology (IT) is the
engine used to drive useful information systems. This includes computers, software, the Internet/Intranet,
and telecommunication systems. IT provides the means for collecting, storing, encoding, processing, ana-
lyzing, transmitting, receiving, and printing information. A thorough knowledge of the fundamentals of
IT and computer programming will prove to be highly beneficial for students of engineering.
The contents of this book have been designed to meet the requirements of the core course on Data
Structures Using C offered to students of the Biju Patnaik University of Technology, Rourkela, in their
first year. A roadmap to the syllabus has been included for the benefit of students. The utility of this book
has also been enhanced by the inclusion of three solved university question papers.
An indispensable text for teaching and learning, Data Structures Using C provides an introduction
to data structures and their applications in C programming. Theoretical concepts are supplemented by
numerous programs that enable a better understanding of the concepts. All suggestions to improve this
edition are welcome.

Acknowledgements
I express my sincere gratitude towards my beloved father, Late Shri Namdev Kamthane; my grandfather,
Late Shri Jagganath Kamthane; and my mother, Late Shrimati Sumanbai Namdev Kamthane. It is because
of their blessings that I could write this book in addition to several other technical books.
I am grateful to the members of the Board of Governors of our institute for encouraging and inspiring
me to write this book. I thank the chairman, Mr Baba N. Kalyani, the directors, Dr S. R. Kajale and
Shri Kamlesh Pande for their support.
I thank all the students, faculty, and non-teaching staff of this college who either directly or indirectly
helped me to complete this book. I also take this opportunity to thank the editorial team at Pearson
Education for their support.
Thanks are also due to my wife Surekha who supported me patiently during the preparation of this
book. Last, but not the least, my sons, Amol and Amit; daughter, Sangita; and daughter-in-law, Swaroopa,
were also of great help and supported me at all times. I thank them all.

Ashok N. Kamthane

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd ix 3/2/2012 6:48:56 PM


This page is intentionally left blank.

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd x 3/2/2012 6:48:56 PM


About the Author
Ashok Namdev Kamthane is a postgraduate in electronics from
Shri Guru Gobind Singhiji (SGGS) College of Engineering and Technology,
Nanded. An eminent academician, he has won a number of prizes for his
contribution to Information Technology including the Samaja Seva Bhushan
Award from Ramamurthy Subhram Trust, Bangalore.
The author has been associated with the development of hardware and
software using 8051 (8-bit microcontroller) on Acoustic Transceiver System
required in submarines. He has also worked at Meltron as an executive.
With a teaching career spanning 27 years, he is Associate Professor at
the Electronics and Telecommunications Engineering department, SGGS
college of Engineering and Technology, Nanded. Recently elevated as Associate Dean, Academics, he
teaches computer language subjects such as C, C++, Data Structures, Wireless Communication, and
Microprocessors and their applications. He has guided a number of undergraduate and postgraduate
students and published several technical papers of national and international repute.

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd xi 3/2/2012 6:48:56 PM


This page is intentionally left blank.

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd xii 3/2/2012 6:48:56 PM


Roadmap to the Syllabus
Module I Introduction to data structures: storage structure for arrays, sparse matrices; stacks and queues:
representation and application; linked lists: single linked lists, linked list representation of
stacks and queues; operations on polynomials; double linked list, circular list.

Refer Chapters 1–5

Module II Dynamic storage management: garbage collection and compaction; infix to postfix conver-
sion; postfix expression evaluation. Trees: tree terminology, binary tree, binary search tree,
general tree, B+ tree, AVL tree, complete binary tree representation, tree traversals, operation
on binary trees, expression manipulation.

Refer Chapters 6–8

Module III Graphs: graph terminology, representation of graphs, path matrix, breadth first search
(BFS), depth first search (DFS), topological sorting, Warshall’s algorithm (shortest path
algorithm); sorting and searching techniques: bubble sort, selection sort, insertion sort,
quick sort, merge sort, heap sort, radix sort; linear and binary search methods; hashing
techniques and hash functions.

Refer Chapters 9–12

Students will attend three hours of lecture classes per week. This course carries three credits.

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd xiii 3/2/2012 6:48:56 PM


This page is intentionally left blank.

A01_ASHOK NAMDEV KAMTHANE5067_01_SE_FM.indd xiv 3/2/2012 6:48:56 PM


Chapter 1

Introduction to Data
Structures
CHAP TER O U T LIN E
1.1 Introduction 1.9 Hardware and Software
1.2 Data and Information 1.10 Concept of Data Types
1.3 Overview of Data Structures 1.11 Data Types in C
1.4 Types of Data Structures 1.12 Abstract Data Types
1.5 Primitive and Non-primitive Data 1.13 Pointers
Structures and Operations
1.14 Structures in C
1.6 Binary and Decimal Integers
1.15 Unions
1.7 Logical Information
1.16 Algorithms
1.8 Storage of Information

1.1 INTRODUCTION

Humans use different languages to communicate data and information with each other. Besides, thoughts
and feelings can also be communicated to others using language. The newspaper, television and other
media use different languages for communication of data/information. In all occupations, language plays
a vital role. In fact, with the help of languages humans interact with each other.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 1 3/2/2012 6:49:28 PM


1.2 Data Structures Using C

Data is represented in the form of text or numbers or in the form of figures, tables, graphs, pictures,
etc. The data can be stored in physical devices such as note books and in memory as string, number,
characters, etc. A computer language is incomplete without data.
Information is derived from data. The following information can be drawn if data is provided:

• Per capita income


• Average population of the states
• Average temperature of the city
• Price index
• Performance of cricketers

Figure 1.1 illustrates how information can be drawn from data.

Method to
Data Information
Process Data

Figure 1.1 Relation Between Data and Information

1. Everyday newspapers are delivered to our houses by the service man. It may be The Times of India or
the Indian Express, and some other local language newspapers such as Lokmat and Janjagruti. The cost
of each newspaper is different. How many papers have been received can be recorded in a notebook.
This task is needed for calculating the total bill at the end of the month. The data here are the names
of the newspapers, the dates on which they have been received and the cost of each. This data is needed
to calculate the monthly or fortnightly bill. The total bill for the English newspapers as well as for
the other papers can be calculated and analysed. One can draw different kinds of inferences such as
whether the family is spending money on English newspapers or not and if so, how much. Does the
family have educated members? Is the amount incurred on newspapers more than that on food? Data
provided can be analysed for extracting different types of information.
2. Information about any human can be expressed with his/her name, age, gender, phone number, city,
etc., and can be stored in the form of a table, which is as shown in Table 1.1.

Table 1.1 Information About a Particular Human


Information Details Data
Name Satish
Gender Male
Age 23
Phone 23234507
City Pune

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 2 3/2/2012 6:49:28 PM


Introduction to Data Structures 1.3

3. Consider Fig. 1.2. A and B are two stations and distance between them is 100 km by train. The distance
between them is certainly more if travelled by road and shorter by plane. Here, the distance between the
two stations can be indicated by connecting two cities by train, road, or air. The distances, both relative
and absolute, between the cities are nothing but the data. This information helps a person to decide
the mode of travel from station A to B. One can decide to go by train or bus depending upon the need,
urgency and convenience. It should be clear now that data and information are not the same.

100 km
A B

Figure 1.2 Distance Representation

4. From the score of an individual cricket player we can draw information. Suppose, data consisting of
the runs scored by a player in one-day cricket matches are provided. From the given data, the following
information can be retrieved:
1. Total runs scored
2. Highest score
3. Lowest score
4. Average
5. Best performance
6. Strike rate
7. Number of sixes
8. Number of fours
9. Number of forward shots
10. Runs due to wide balls.
Information helps planners/analysts to make decisions. In this chapter, we are going to discuss applica-
tion of data and information related to the computer.
A computer is an electronic programmable device that manipulates information presented in the form
of data. Computer science is mainly related to the study of data structures and their applications. The
student of computer science should be aware of how data is manipulated in a system and the meth-
ods for utilization of data. It is, therefore, very essential to study the concepts of data organization and
manipulation.

Data “Data is nothing but a collection of numbers, alphabets and symbols combined to represent information.”
Data stands for value or group of values. Table 1.2 describes the common data types used in the computer.

Table 1.2 Data and its Description


Data Description
587 Numeric data
25/10/2011 Date (formatted data)
C PLUS PLUS Character data

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 3 3/2/2012 6:49:28 PM


1.4 Data Structures Using C

Entity An entity possesses some attributes and some values can be allocated to it. For example, a student
is an entity of a college. The probable properties and the corresponding values are indicated in Table 1.3:

Table 1.3 Information About Student


Entity: Student
Information Name Birth date Gender Course
Assigned Values Harsha 01.03.1982 M Data Structures

Every student in a college is an entity with different attributes. Sets of attributes are known as domain.
Domains refer to possible values of a particular property. For example, the gender property can be assigned
with values M or F.

1.2 DATA AND INFORMATION

The study of computer science deals with storage, retrieval, handling and organization of information.
Information is generated in every sphere of life. For example, information about business transactions, or a
student’s performance in an examination, can be stored in the computer memory. The same information can be
retrieved, modified, and restored. The total marks of a student can be obtained by adding the marks scored in
all subjects. Similarly, the average percentage of marks can be computed and student performance can be moni-
tored and evaluated using different factors such as total marks, average marks, highest score, and lowest score.
Information is symbolic representation. It has some useful meaning that helps us in making good judgments.

1.3 OVERVIEW OF DATA STRUCTURES

Data structures are a method of representing of logical relationships between individual data elements
related to the solution of a given problem. Data structures are the most convenient way to handle data
of different types including abstract data type for a known problem. For example, the characteristics of
a house can be represented by the house name, house number, location, number of floors, number of
rooms on each floor, kind of fencing to the house—either with brick walls or wire, electrification—either
underground or open, whether a balcony has been provided or not, etc. One can use a variety of data
types to represent these data elements while solving a problem with the help of computer language such
as char, int, boolean type, etc. Figure 1.3 shows the various fields of house. For example, with the help
of computer the characteristics of a house can be represented: the number of floors of a house can be given
with either int or char type. The house number, the number of rooms in it can be declared with the same
type, provided that the data is within the limits of the range of data type. In C language, the char data type

House

Name No. of Floors No. of Rooms Location

Figure 1.3 Information About a House

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 4 3/2/2012 6:49:29 PM


Introduction to Data Structures 1.5

works perfectly as integer data in the range from −128 to 127 and as unsigned char from 0 to 255. Some-
times, selection of data type is important. Just as, for example, if we are going to fence the house should
we use brick or wire. Here, the brick wall may be expensive. Likewise, if we are using signed int instead
of char to store a positive number (number of floors) we are wasting one byte of the system. Hence, here
char is appropriate, which occupies only one byte.
Electrification should be declared with char data type. Like the above example, in the practical appli-
cation of data structures, to create data structures some components are involved directly or indirectly
to build the system. In other words, data structures are a structured set of variables associated with one
another in different ways, co-operatively defining components of the system.
The components of data can be organized and records can be maintained. Further, the record forma-
tion leads to the development of abstract data type and database systems.
In data structures, we also have to decide on the storage, retrieval and operation that should be carried
out between logically related items. For example, the data must be stored in memory in computer-
understandable format, i.e. 0 and 1 and the data stored must be retrieved in human-understandable
format, i.e. ASCII. In order to transform data various operations have to be performed.

1.4 TYPES OF DATA STRUCTURES

A data structure is a structured set of variables associated with one another in different ways, co-opera-
tively defining components in the system and capable of being operated upon in the program. As stated
earlier, the following operations are done on data structures:
1. Data organisation or clubbing
2. Accessing technique
3. Manipulating selections for information
Data structures are the basis of programming tools and the choice of data structures should provide the
following:
1. The data structures should satisfactorily represent the relationship between data elements.
2. The data structures should be easy so that the programmer can easily process the data.
Data structures have been classified in several ways. Different authors classify it differently. Figure 1.4
(a) shows different types of data structures. Besides these data structures some other data structures such

Data Structures

Linear Non-linear

Arrays Linked Lists Stacks Queues

Trees Graphs Tables Sets

Figure 1.4 (a) Types of Data Structures

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 5 3/2/2012 6:49:29 PM


1.6 Data Structures Using C

as lattice, petri nets, neural nets, semantic nets, search graphs, etc. can also be used. The reader can see
Figs. 1.4 (a) and (b) for all data structures.

1 Rear
Front
2
4 Top

∗ 3
∗ Header Queue
2
n
1
Arrays
Stack 30 ∗ 40 ∗ 50 ∗

N1 N2 Linked List N 3 Nn

Figure 1.4 (b) Linear Data Structures

Tree Graph

Table Sets

Figure 1.4 (c) Non-linear Data Structures

Linear In linear data structures, values are arranged in linear fashion. Arrays, linked lists, stacks and
queues are examples of linear data structures in which values are stored in a sequence.

Non-Linear This type is opposite to linear. The data values in this structure are not arranged in order.
Tree, graph, table and sets are examples of non-linear data structures.

Homogenous In this type of data structures, values of the same types of data are stored, as in an array.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 6 3/2/2012 6:49:29 PM


Introduction to Data Structures 1.7

Non-homogenous In this type of data structures, data values of different types are grouped, as in
structures and classes.

Dynamic In dynamic data structures such as references and pointers, size and memory locations can be
changed during program execution.

Static Static keyword in C is used to initialize the variable to 0 (NULL). The value of a static variable
remains in the memory throughout the program. Value of static variable persists. In C++ member functions
are also declared as static and such functions are called as static functions and can be invoked directly.

1.5 PRIMITIVE AND NON-PRIMITIVE DATA STRUCTURES AND OPERATIONS

1.5.1 Primitive Data Structures


The integers, reals, logical data, character data, pointer and reference are primitive data structures. Data
structures that normally are directly operated upon by machine-level instructions are known as primitive
data structures.

1.5.2 Non-primitive Data Structures


These are more complex data structures. These data structures are derived from the primitive data
structures. They stress on formation of sets of homogeneous and heterogeneous data elements.
The different operations that are to be carried out on data are nothing but designing of data structures.
The various operations that can be performed on data structures are shown in Fig.1.5.
1. Create
2. Destroy
3. Select
4. Update
An operation typically used in combination with data structures and that creates a data structure is
known as creation. This operation reserves memory for the program elements. It can be carried out at
compile time and run-time.
For example,
int x;
Creation
Here, variable x is declared and memory is allocated
to it.
Another operation giving the balancing effect of a cre- Destroy
ation operation is destroying operation, which destroys
the data structures. The destroy operation is not an Operation
essential operation. When the program execution ends,
Selection
the data structure is automatically destroyed and the
memory allocated is eventually de-allocated. C++ allows
the destructor member function to destroy the object.
In C free ( ) function is used to free the memory. Languages Update
like Java have a built-in mechanism, called garbage col-
lection, to free the memory. Figure 1.5 Using Data Structures Operations

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 7 3/2/2012 6:49:29 PM


1.8 Data Structures Using C

The most commonly used operation linked with data structures is selection, which is used by programmers
to access the data within data structures. The selection relationship depends upon yes/no. This operation
updates or alters data. The other three operations associated with selections are:

1. Sorting
2. Searching
3. Merging

Searching operations are used to seek a particular element in the data structures. Sorting is used to
arrange all the elements of data structures in the given order: either ascending or descending. Chapter
11 discusses sorting and searching in detail. Merging is an operation that joins two sorted lists.
An iteration relationship is nothing but a repetitive execution of statements. For example, if we want
to perform any calculation several times then iteration, in which a block of statements is repetitively
executed, is useful.
One more operation used in combination with data structures is update operation. This operation
changes data of data structures. An assignment operation is a good example of update operation.
For example,
int X=2;

Here, 2 is assigned to x.
X=4;

Again, 4 is reassigned to x. The value of x now is 4 because 2 is automatically replaced by 4, i.e.


updated.

1.6 BINARY AND DECIMAL INTEGERS

Data is expressed in terms of 0 and 1 known as bits. Different number systems are used to represent
numbers. For example, decimal, octal and hexadecimal number systems, can be used. The decimal
system uses ten different symbols from 0 to 9, octal uses 0 to 7, hexadecimal from 0 to 9 and fur-
ther from A to F. We can convert from one number system to another. To convert a decimal number
to binary, the double dabble method is used. In this method, the decimal number is divided by 2
and remainders are listed in reverse direction. The binary number obtained from this method is the
equivalent of the decimal. For example, the binary 111 is nothing but decimal 7. In the binary number
system, every bit has its own weight. The least significant bit has 20 weight. Weight position is calcu-
lated to the power of 2. The right-most bit of a binary number has a value of 1, which is represented
as 20. The next bit position has value 21 and so on and the values for further bits can be calculated.
In other words, weights are assigned to each bit in binary. The weights from the least significant bits
are 1,2,4,8----.
For example, the equivalent binary representation of 5 is 101. This is explained as follows:

1 × 22 + 0 × 21 + 1 × 20
4 + 0 + 1 = 5

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 8 3/2/2012 6:49:29 PM


Introduction to Data Structures 1.9

The power of two (weights) and binary bits are multiplied and the sum of all multiplications is taken
to give the equivalent decimal number. There are two commonly used methods for representing negative
binary numbers; they are as described in the following sections.

1.6.1 One’s Complement


In this method, a positive integer is converted to negative by changing each bit to its opposite value. For
example, the binary number 0101 represents 5 and its complement is 1010.

1.6.2 Two’s Complement


In this method, 1 is added to the representation of one’s complement. For example, 7 is represented as
0111 with an unsigned number. With two’s complement, the number 7 becomes 1001 ( One’s comple-
ment of 0111 = 1000 and 1 is added at its least significant position giving a result of 1001).

1.6.3 Binary Coded Decimals


In addition to the binary number system, the programmer can also use decimal numbers. For example, a
string of bits can be used to represent integers in the decimal number system. The decimal number from
0 to 9 can be represented using only a four-bit combination. Table 1.4 shows the decimal number and
their equivalent binary digits.
A string of bits can be broken randomly into separate groups of four bits. Each group represents a digit.
For example, the bit string 01100010 can be separated into two strings 0110 and 0010. The first string
indicates six and the second two. The complete string represents 62. This method of representation is
called as binary coded decimal.

Table 1.4 Four Bits and Equivalent Decimal Number


Decimal Number Binary-coded Decimal Code (8421)
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 9 3/2/2012 6:49:29 PM


1.10 Data Structures Using C

1.6.4 Integers
We know what integers are and are aware of the arithmetic operations performed with them such
as addition, subtraction, multiplication, and division. Integer-type data plays an important role in
calculation. A counting of the number of objects can be shown by integers. The amount in a bank
account, the number of students in a class and number of keys on a keyboard-all this information can
be expressed in integers.
The traditional method of writing negative numbers is to put a sign symbol before the number. This
method is called as sign and magnitude method and is commonly used in several computers to represent
signed numbers. Normally, the sign is shown at the first or left-most bit of the binary number representa-
tion. In addition, the magnitude part appears followed by the sign.
The left-most bit is only for indicating the sign, but it does not have any weight as in an unsigned
number system. In other words, a bit string beginning with zero shows a positive number whereas a
bit string beginning with one indicates a negative number, if numbers are to be represented in a signed
format.
In Table 1.5, 0 and 1 are used to represent positive and negative numbers. An integer shown with
its sign is known as a signed integer. There are two types of signed integers: a) positive signed integer
b) negative signed integer. We studied that these signs are represented in memory by 0 and 1 as shown
in Table 1.5. The sign bit is always written as the leftmost bit. While storing signed numbers, the system
reserves the leftmost bit for representation of the sign.

Table 1.5 Sign Bit


Number Sign Bit Magnitude
+7 0 00...0111
−6 1 10...0110

Positive signed integers are shown in the form called the signed magnitude form. In this style, in the
leftmost bit, the sign is shown by 0 and magnitude is shown in the matching binary form.
For example, +7 is shown by 0111.
Negative signed numbers are shown in one of the following forms:

1. Signed − magnitude form


2. Signed − 1’s complement form
3. Signed − 2’s complement form

In the signed magnitude form method, 1 shows the sign of the number and magnitude is shown by the
corresponding binary form. For example:

−7 is shown as 1111 signed number.


−7 is shown as 1,000 in one’s complement format.
−7 is shown as 1001 in two’s complement format.

Table 1.6 shows the various ways of representing binary and negative numbers.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 10 3/2/2012 6:49:29 PM


Introduction to Data Structures 1.11

Table 1.6 Binary, Negative Numbers in Signed Format and 1’s Complement of
Negative Numbers
Decimal Binary Decimal Signed Numbers 1’s Complement
+0 0000 −0 1000 1111
+1 0001 −1 1001 1110
+2 0010 −2 1010 1101
+3 0011 −3 1011 1100
+4 0100 −4 1100 1011
+5 0101 −5 1101 1010
+6 0110 −6 1110 1001
+7 0111 −7 1111 1000

Positive and negative numbers are shown in Table 1.6. Signed numbers and signed −1’s complements
of negative numbers are also shown in the table. The sign is shown by 1 and the magnitude is shown in
the 1’s complement form. −7 is shown as 1,000.
In the signed −2’s complement form, the sign of the number is shown by 1 and the magnitude is shown
in the 2’s complement form. The 2’s complement of a number is the addition of 1’s complement of the
particular number and 1. Table 1.7 shows 2’s complement of the numbers. 2’s complement of −7 is shown
as 1,001.

Table 1.7 2’s Complement of Numbers


Decimal 2’s Complement Decimal 2’s Complement
+0 0000 0 1000
+1 0001 −1 1111
+2 0010 −2 1110
+3 0011 −3 1101
+4 0100 −4 1100
+5 0101 −5 1011
+6 0110 −6 1010
+7 0111 −7 1001

1.6.5 Real Numbers


A number having an integer part and a fractional part is called a real number. The real number 548.56 can
be written as 5.4856 × 102 or 0.54856 × 103. This type of representation is called scientific representation.
The floating-point notation is generally used by all computer systems to indicate real numbers. There

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 11 3/2/2012 6:49:29 PM


1.12 Data Structures Using C

are several notations or methods to represent real numbers. Each method is unique and has different
characteristics.
The real number has two parts: mantissa and base. It is represented by a number called mantissa. The
base portion is always raised to the number and it is called the exponent. The base is always fixed.
The mantissa and exponent vary. Different values of mantissa and exponent give different real numbers.
For example,
The base is 10; the number 221.98 would be 22198 × 10−2. The mantissa is 22198, exponent is −2. The
values can also be written as .22198 × 103, 221.98.
The benefit of floating-point notation is that it can be used to show numbers with small or large abso-
lute values. The biggest number that can be represented is 223−1 × 1027. In addition, the smallest positive
number may be 10−128, which is very small. The limit of precision on a computer is the number of signifi-
cant binary digits in the mantissa.

Example 1.1 Write a program to declare float and double type values and display them.

# include <stdio.h>
# include <conio.h>

void main()
{
float f=31343412.123;
double d=46481232.77;
clrscr();
printf("f=%lg",f);
printf("\nd=%lg",d);
}

OUTPUT
f = 3.13434e+07
d = 4.64812e+07

Explanation:
In this program the variables f of float and d of double type are declared and are initialized. The
values are displayed using base and mantissa format.

1.6.6 Character String


In the past, computers were in fact used as calculators and only numeric data could be manipulated
with them. In those days, computer programs were written in numeric form. Programming in numeric
form was difficult. To overcome this limitation symbolic codes were defined to represent information
as character data. The invention of character data led to the formation of mnemonics for use as address
and in operation. Using mnemonics, assembly languages and various procedure-oriented languages were
developed.
A character is stored in computer memory as a series of bits in succession. Unique bit patterns are
assigned to every character in the character set. Fixed length bits can be controlled more efficiently
than variable length bit sequences. For that reason, character sets are programmed in fixed length bit
sequences.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 12 3/2/2012 6:49:30 PM


Introduction to Data Structures 1.13

Information contains all types of data, viz., numbers, characters, symbols, etc. Hence, it is not possible
to represent information by only numeric data. Information such as names and book titles are required
to be represented with characters. Thus, all non-numeric information is represented by a sequence of
characters called strings.
For example, in some systems 00100110 is used to show the ‘$’ symbol and different types of such
bit patterns represent ‘A’, ‘C’, ‘D’ and so on. In different countries, the computer may have a few addi-
tional symbols. The character set can be created using fonts. The programmer can create different fonts
according to the language and culture of the country.
We know that 8 bits are used to represent a character and 256 different characters can be shown using
these unique bit combinations. Suppose, the string 1101001 is used to represent character ‘A’ and 0100001
is used to represent ‘B’, then the string “AB” can be shown by the bit string 11010010100001. We know
that a string is sequence of a characters and a character string is shown by concatenation as the bit strings,
which represent separate characters of the string. Examples of strings are illustrated in Chapter 2.

1.7 LOGICAL INFORMATION

Primitive data structures also include logical data, i.e. true or false. Only two logical constants, true and
false are present. In C /C++programming 0 is assumed as false and any non-zero value as true. In C++,
a new data type bool is introduced to handle logical conditions.
Expressions containing logical variables are used with relational operators such as <, >, ==, = etc.
The result of such expression is only true (1) or false (0). The result is returned by the expression.
The storage representation of logical values depends upon the compiler or interpreter used by the
language to convert the source program to a machine code. Normally, one bit is enough to store logical
information. In C/C++ it is possible to store information in bits. The following programs explain true and
false values returned by expressions and storing data using bits.

Example 1.2 Write a program to display logical values returned by logical expressions.

# include <stdio.h>
# include <conio.h>

void main()
{
clrscr();
printf("False : %d\n", 3>5);
printf("True : %d",5>1);
}

OUTPUT
False : 0
True : 1

Explanation:
The two expressions are put in the printf () statement. The first condition 3 > 5 is false;
hence, the return value is 0. The second expression 5 > 1 returns 1, i.e. the expression is true.
Consider the following program, which stores return values in bits using structure.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 13 3/2/2012 6:49:30 PM


1.14 Data Structures Using C

Example 1.3 Write a program to identify the entered IP address. Display its class, mask
and last address.

# include <stdio.h>
# include <conio.h>

void main()
{

int ip0,ip1,ip2,ip3;
clrscr();

printf("\nEnter the IP address:-");


scanf("%d.%d.%d.%d",&ip0,&ip1,&ip2,&ip3);

if(ip0 >= 1 && ip0<128)


{
printf("\nThe given IP address %d.%d.%d.%d is in class A",ip0,ip1,ip2,ip3);
printf("\nMask for class A address = 255.0.0.0");
printf("\nThe last address of class A = 127.255.255.255");
}

if(ip0>127 & ip0<192)


{
printf("\nThe given IP address %d.%d.%d.%d is in class B", ip0,ip1,ip2,ip3);
printf("\nMask for class B address = 255.255.0.0");
printf("\nThe last address of class B = 191.255.255.255");
}

if(ip0>191 & ip0<224)


{
printf("\nThe given IP address %d.%d.%d.%d is in class C",ip0,ip1,ip2,ip3);
printf("\nMask for class C address = 255.255.255.0");
printf("\nThe last address of class C = 223.255.255.255");
}

if(ip0>223 & ip0<240)


{
printf("\nThe given IP address %d.%d.%d.%d is in class D",ip0,ip1,ip2,ip3);
printf("\nThe last address of class D = 239.255.255.255");
}

if(ip0>239 & ip0<248)


{
printf("\nThe given IP address %d.%d.%d.%d is in class E",ip0,ip1,ip2,ip3);
printf("\nThe last address of class E = 247.255.255.255");
}

OUTPUT:

Enter the IP address:- 198.1.1.1


The given IP address 198.1.1.1 is in class C

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 14 3/2/2012 6:49:30 PM


Introduction to Data Structures 1.15

Mask for class C address = 255.255.255.0


The last address of class C = 223.255.255.255

Explanation:
In this program the IP address is stored in the ip0, ip1, ip2 and ip3 variables. For each class
a separate if condition is used and the relevant values are displayed on the screen.

Example 1.4 Write a program to store logical values in bit using structure.

# include <stdio.h>
# include <conio.h>

void main()
{

struct bits
{
int state :1;
};

struct bits a;
a.state=13>5;
clrscr();
if(a.state==0) printf("False");
else printf("True : %d",5>1);
}

OUTPUT
True: 1

Explanation:
In the structure bits, the number of bits given is to be used by the member of structure to store
values. The value returned by the expression 13 > 5 are stored in variable state that stores the
value in one bit. The if statement checks the value and the appropriate message is displayed.

1.8 STORAGE OF INFORMATION

The digital computers have two types of memory: operational memory and storage memory. The
operational memory refers to CPU registers. The CPU registers are temporarily used to store values.
The CPU contains registers called accumulators that contain the variables while arithmetic operations
are performed. For example, when numbers are added the result is stored in AX register of the CPU. The
following program explains this.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 15 3/2/2012 6:49:30 PM


1.16 Data Structures Using C

Example 1.5 Write a program to access value using CPU register.

# include <stdio.h>
# include <conio.h>

void main()
{
int x=10,y=2;
clrscr();
_AX=x*y;
printf("\n Multiplication of x and y is %d",_AX);
_AX=x+y;
printf("\n Addition of x and y is %d",_AX);
}

OUTPUT
Multiplication of x and y is 20
Addition of x and y is 12

Explanation:
In this program, integer variable, x and y are declared and initialised with 10 and 2. The statement
x * y calculates the product and x + y calculates the addition of the variables. The obtained
result is stored in register AX. We print the value using pseudo variable _AX.

In addition, CPU registers are also used to store ‘temporarily’ program instructions and program control
information, which is helpful in program execution. Therefore, registers are only used to hold data
temporarily.
The storage type memory is used for permanent storage of data that can be retrieved at any time.
Before performing an arithmetic operation, the value of a variable is stored in the memory unit and then
transferred to the register. If the obtained result is to be stored in another variable, it is necessary to again
transfer values from register to storage memory.
When a program execution is started, instructions and data are stored in storage units. The whole
storage unit of computer is called main memory. Information is an input to the storage unit.

1.9 HARDWARE AND SOFTWARE

The memory of the computer is nothing but a group of bits. The values 0 and 1 are called bits. The unit
formed by bits is called value, i.e. a group of bits represents a value. A group of 8 bits is called byte. Many
bytes when grouped together are called word. Every byte in a memory has a unique address. The address
is useful to identify the byte and its contents. In C it is possible to access the byte address. The address is
always numeric (unsigned integer) and a not-negative number. The address is also called memory location.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 16 3/2/2012 6:49:30 PM


Introduction to Data Structures 1.17

The computer system has a built-in mechanism that handles and manipulates different types of bit patterns
according to the object or variable that holds the value.
For example, the computer contains an instruction to multiply two binary numbers and place the
obtained value in another memory location. The mechanism to perform such an operation should have
the following steps:

1. Extract argument bit patterns from two given addresses.


2. Construct a third bit pattern showing an integer, which is a product of two binary integers.
3. The obtained result bit pattern is assigned to another memory location.

The computer hardware is bit oriented whereas software is byte oriented, i.e. the computer hardware
is capable of interpreting the bit patterns at a specified memory location. This is what we discussed con-
cerning an operation between two integers. In case two real values are given, the computer hardware will
apply another built-in mechanism to handle this data type. As discussed earlier, to handle native data type,
necessary routines are in-built into the hardware. The instruction identifies the data type by value or its
address. The values are assigned explicitly and addresses are allocated implicitly by the system.
Consider the following C/C++ statements.
int j=4, k=5,h;
float p=9.1, q=5.5, r;

In the above statements, variables are declared and memories in bytes are allocated to them. j, k, p, h, r
and q are called variables or identifiers. The variable name is useful to store values. A variable is nothing but
a name given to memory location. The values stored in j and k will be interpreted as integers whereas the
values of p and q will be interpreted as float. The C/C++ compiler translates the source program to machine
language (object code).
Consider the following statements:
h=j+k;
r=p+q;

The first statement performs addition of j and k integer variables and stores the result in h. In the
second statement addition of p and q are stored in variable r.
The operator ‘+’ is common. Operators such as +,*,-,/ are overloaded in such a way that they can be
used with any data type to perform an operation. All these operators are generic, i.e. they can be used with
all standard data types.

1. These operators perform operations with all data types.


2. These operators have different meaning depending on context. For example, the operator ‘*’ can be
used for multiplication as well as for pointer notation.

In high-level language, declaration of variable plays an important role. The declaration contains data
type name followed by variable list. The variables are allocated memory according to the data type.
For example, integer variable requires two bytes; float variable requires four bytes, etc.
Refer Table 1.8 for C data types. The first column contains the name of the data type. These names are
reserved words known as keywords. The second column has the number of bytes required by a variable of
data type. The number of bytes may vary in different systems. The third column contains a range of data
types, i.e. lowest and highest limits of numbers that can be stored in variables of respective data type.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 17 3/2/2012 6:49:30 PM


1.18 Data Structures Using C

1.10 CONCEPT OF DATA TYPES

A data type is a term that refers to the type of data values that may be used for processing and computing.
The information stored in memory is in the form of bits 0 and 1. We can view the memory in human-
understandable format with the help of data type. The type of computer hardware decides the data type
and the range it supports. Range means the largest and smallest possible values that can be represented.
Our goal is to study how a user can utilize the data type to represent information. We need not think
about what the computer does internally.
Suppose that data types are independent of computer hardware, then unlimited data types can be
built. A data type is nothing but an abstract concept designed using logical operators. After designing
such data type and its supporting operations we can use the data type. The instructions regarding the
operation related to data type can be given by hardware and software. The necessary instructions are
built into the computer hardware as hardware implementation. When a program gives such instructions
it is known as software implementation. The instructions given in the computer program interpret the
bit patterns.

1.11 DATA TYPES IN C

Various data types are used in the C language. Variables are used for assigning integers, long integers, or
characters, etc. We can differentiate between data types such as integer, real, logical, complex variables, etc.
C contains four standard data types. They are int, float, char and double. Almost in all computers, all the
above four data types are local to computer hardware. We have already discussed how integers, floats and
characters are stored in memory and their manipulation. A double variable is a double precision floating-
point number.
In addition, there are three qualifiers applicable to int. They are short, long and unsigned. When a vari-
able is declared unsigned, it can store only positive values. By default when a variable is declared as int, it
is short int. Its range is −32,768 to 32,767. To store values above this range, a long qualifier is used and
its range is −2147483648 to 2147483647. An unsigned integer is always an absolute value and follows
arithmetic laws of module 2n, where, n is the number of bits in an integer. The ranges of data types and
number of bytes needed to store them are shown in Table 1.8.

Table 1.8 C Data Types


Data Types No. of Bytes Range
char 1 −128 to 127
unsigned char 1 0 to 255
signed char 1 −128 to 127
int 2 −32768 to 32767
unsigned int 2 0 to 65535
signed int 2 −32768 to 32767
short int 2 −32768 to 32767

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 18 3/2/2012 6:49:30 PM


Introduction to Data Structures 1.19

unsigned short int 2 0 to 65535


signed short int 2 −32768 to 32767
long int 4 −2147483648 to 2147483647
signed long int 4 −2147483648 to 2147483647
unsigned long int 4 0 to 4294967295
float 4 3.4E−38 to 3.4E+38
double 8 1.7E−308 to 1.7E+308
long double 10 3.4E−4932 to 1.1E+4932
enum 2 −32768 to 32767

1.12 ABSTRACT DATA TYPES

In programming, a situation occurs when built-in data types are not enough to handle the complex data
structures. It is the programmer’s responsibility to create this special kind of data type. The programmer
needs to define everything related to the data type such as how the data values are stored, the possible
operations that can be carried out with the custom data type and that it must behave like a built-in type
and not create any confusion while coding the program. Such custom data types are called Abstract data
type. In C struct and in C++ struct/class keywords are used to create abstract data type.
For example, if the programmer wants to define date data type which is not available in C/C++, s/he
can create it using struct or class. Only a declaration is not enough; it is also necessary to check whether
the date is valid or invalid. This can be achieved by checking using different conditions. The following
program explains the creation of date data type:

Example 1.6 Write a program to create abstract data type date.

# include <stdio.h>
# include <conio.h>

struct date
{
int dd;
int mm;
int yy;
};

void main()
{
struct date d; /* date is abstract data type */
clrscr();
printf("Enter date(dd mm yy) :");
scanf("%d %d %d",&d.dd,&d.mm, &d.yy);

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 19 3/2/2012 6:49:30 PM


1.20 Data Structures Using C

printf("Date%d-%d-%d",d.dd,d.mm,d.yy);
}

OUTPUT
Enter date(dd/mm/yy): 25 10 2011
Date 25-10-2011

Explanation:
In this program, using struct keyword the date data type is declared. It contains three-integer
variables dd, mm and yy to store date, month and year. Through scanf statement date, month
and year is entered and it is displayed using printf statement.

1.13 POINTERS

A pointer is a link or reference to data structures. The most important characteristic of pointer is that it allows
identical method of referencing any data structures, no matter of what complexity and type. The pointer can
point to any data type character, float, int, etc., and the method of accessing elements are the same. A pointer
also allows quick insertion and deletion of an item in a list. The linked list is discussed later in this book.
There are two techniques of accessing data structures.

1.13.1 Computed Address


In this technique the data structures can directly be accessed using an address. The address is calculated by
the compiler or interpreter, which translates the source program to an object code.

1.13.2 Pointer Addressing


The C/C++ pointers are of this type, in which a memory address is assigned to a pointer variable. Depend-
ing upon the complexicity of data structures some operations are also required in this technique. However,
this technique is time consuming.
A pointer is a memory variable that stores a memory address of another variable. It can have any name that is
acceptable for other variables and it is declared in the same way as other variables. It is always denoted by ‘*’.
1. Pointers save memory space.
2. Execution time of a program is faster because address of variable can be accessed and read/write opera-
tion with addresses directly done.
3. Memory is used efficiently with pointers.
4. Pointers are used with data structures. They are very useful for representing arrays.
int *x;
float *y;
char *z;
1. In the first statement ‘x’ is an integer pointer and it tells the compiler that it holds the address of an
integer variable. The variable y is a float pointer and it holds the address of only the float variable. *z is
a character variable and holds the address of any character variable.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 20 3/2/2012 6:49:30 PM


Introduction to Data Structures 1.21

2. The indirection operator (*) is also called the dereferencing operator. When a pointer is dereferenced,
the pointer retrieves the value stored at that address.
3. The indirection operator (*) is used in two distinct ways with pointers, declaration and deference.
4. When the pointer is dereferenced, the indirection operator indicates that the value at that location
stored in the pointer is to be accessed rather than address.
5. The ‘&’ operator is an address operator and it gives the address of the variable. The ‘&’ immediately
preceding the variable returns the address of the variable.

Example 1.7 Write a program to demonstrate the use of a pointer.

# include <stdio.h>
# include <conio.h>

void main()
{
int x=2;
int *p;
clrscr();
p=&x;
printf("\n Address of x is = %u", &x);
printf("\n Value of x is = %d",*p);
}

OUTPUT
Address of x is = 65524
Value of x is = 2

Explanation:
In this program, an integer variable x is declared and assigned with value 2. Also, integer pointer
*p is declared and initialized with address of x. The first printf statement displays the address
of x. The second statement displays the value of x using pointer p.

Arithmetic operations on pointer variables are also possible. Increase, decrease, prefix and postfix
operations can be performed with the help of pointers.
The following operations are not possible with address:
1. Addition of two addresses (pointers).
2. Multiplication of two addresses or multiplication with a constant.
3. Division of address with a constant.

1.14 STRUCTURES IN C

In this topic, we will discuss C data structures called structures. A structures is a collection of one or
more variables of different data types, grouped together under a single name and new custom data type
formed. The individual variables are called member variables. By using structures, we can make a group

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 21 3/2/2012 6:49:30 PM


1.22 Data Structures Using C

of variables, arrays, pointers, etc. The new data type formed by the structures is independent of computer
hardware and we already studied that when data type is independent of computer hardware, unlimited
data types can be formed. Now, consider the following declaration of structure and program to understand
the concept.
struct student
{
char name[20];
int age;
float wt;
};

In this example, the structure student is declared by combining three standard data types. The structure
name is called as tag name. Here, three data types can be accessed separately and hence they are not mixed.
Consider the following example,

Example 1.8 Write a program to demonstrate how structures are used to store and display data.

# include <stdio.h>
# include <conio.h>

struct student
{
char *name;
int age;
float weight;
};

void main()
{
struct student s1;
s1.name="Nilesh";
s1.age=25;
s1.weight=55;
clrscr();
printf("\n Name = %s",s1.name);
printf("\n Age = %d",s1.age);
printf("\n Weight = %g",s1.weight);
}

OUTPUT
Name = Nilesh
Age = 25
Weight = 55

Explanation:
In this program, structure is defined and a custom data type is formed. Here, the program
contains information regarding data type; hence, it is called software implementation.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 22 3/2/2012 6:49:30 PM


Introduction to Data Structures 1.23

struct student s1; /* c style */


Using the above statement, variables (objects) of structures data type student can be declared. s1 is an object
of structure data type. The dot (.) operator with variable is used to access individual variables and initializa-
tion and display of value can be done. When a structure is declared separate, memory is allocated to each
variable according to its data type. The total size of the variable of struct type is the sum of bytes of all member
variables. Using the operator sizeof() we can demonstrate this. Consider the following program.

Example 1.9 Write a program to demonstrate that the size of structure variable is equal to the sum
of sizes of member variables.

# include <stdio.h>
# include <conio.h>
void main()
{
struct data
{
char ch;
int in;
float fl;
};
struct data d;
clrscr();
printf("\nSize of character ch = %d",sizeof(d.ch));
printf("\nSize of integer in = %d",sizeof(d.in));
printf("\nSize of float fl = %d",sizeof(d.fl));
printf("\nSize of object d = %d",sizeof(d));
}

OUTPUT
Size of character ch = 1
Size of integer in = 2
Size of float fl = 4
Size of object d = 7

Explanation:
In this program structure data is declared with three standard data types: char, int and
float. d is a variable of data type. Using sizeof () operator size of every member, variable
d is calculated and displayed. The size of variable d is the sum of the sizes of all members.
The output gives a clear idea.

1.15 UNIONS

Union is a user defined data type very similar to structure. It contains members like structure but no
separate memory is allocated to each member. The size of the largest element is detected and this much
amount is allocated. Members of a union share common memory locations. The union data structure is
useful to invoke BIOS and DOS services. An example follows:

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 23 3/2/2012 6:49:30 PM


1.24 Data Structures Using C

Example 1.10 Write a program to demonstrate use of unions.

# include <stdio.h>
# include <conio.h>
# include <dos.h>

void main()
{
union REGS in,out;
int86(18,&in,&out);
clrscr();
printf("\n Total memory = %d KB", out.x.ax);
}

OUTPUT
Total memory = 640 KB

Explanation:
In this program union is in use. int86() is a function. The value 18 is a service number. The
function calculates the total size of memory and it is displayed by printf () statement. While
discussing types of data structures, we discussed static data structures. Consider the following
example of a static variable.

Example 1.11 Write program for displaying the size of the data type in union and the size of the
object of the union.

# include <stdio.h>
# include <conio.h>

void main()
{
union set
{
char x;
int y;
float z;
long double a;
};
union set s1;
clrscr();
printf("\nSize of character x = %d",sizeof(s1.x));
printf("\nSize of integer y = %d",sizeof(s1.y));
printf("\nSize of float z = %d",sizeof(s1.z));
printf("\nSize of long double a = %d",sizeof(s1.a));

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 24 3/2/2012 6:49:30 PM


Introduction to Data Structures 1.25

printf("\nSize of object s1 = %d",sizeof(s1));


}

OUTPUT:
Size of character x = 1
Size of integer y = 2
Size of float z = 4
Size of long double a = 10
Size of object s1 = 10

Explanation:
In this program, union of the set is declared and s1 is the object of the union set. The union set
contains integer, character, float and long double data types. The program shows the size of all
the data types but it shows the size of the object 10 because the long double has the size 10.

Example1.12 Write a program to explain the use of a static variable.

# include <stdio.h>
# include <conio.h>

void main()
{
static int x;
clrscr();
x++;
printf(" x= %d",x);
}

OUTPUT
x=1

Explanation:
When variables are declared and not initialized, they contain garbage values. Hence, they cannot
be used without initializing. When such variables are declared as static, they are initialized to zero
and can directly be involved in an operation.

1.16 ALGORITHMS

An algorithm is a well-organized, pre-arranged and defined computational module that receives


some value or set of values as input and provides a single or a set of values as output. These well-
defined computational steps are arranged in sequence, which processes the given input into output.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 25 3/2/2012 6:49:30 PM


1.26 Data Structures Using C

Algorithms are used to solve applications that are complex. An algorithm is said to be accurate and
truthful only when it provides the exact wanted output, obviously, after implementation of algorithm
into program.

1.16.1 Analysing Algorithm


When one writes an algorithm, it is essential to know how to analyse it. Analyzing an algorithm refers
to calculating or guessing resources needful for the algorithm. Resources means computer memory, pro-
cessing time, logic gates, etc. In all these factors, time is most important because the program developed
should be fast in processing. The analysis can also be made by reading the algorithm for logical accuracy,
tracing the algorithm, implementing it and checking it with some data and with a mathematical technique
to confirm its accuracy.
Algorithms can also be expressed in a simple method that will help the user to put it into operation
easily. However, this approach has a few drawbacks. It requires more space and time. It is very essential to
consider the factors of time and space of an algorithm.

1.16.2 Rate of Growth


In practice, frequently it is not possible to act upon a simple analysis of an algorithm to conclude
the execution time of an algorithm. The execution time depends upon the machine and its way of
implementation.
Timing analysis depends upon the input required. To accurately carry the time analysis, it is also very
essential to know the exact directives executed by the hardware and the execution time passed for each
statement.

1.16.3 Space Requirement


The space or memory requirement of a program is the memory space required to execute the program.
From the total allocated memory, a fixed portion occupies code, variable and space for data, etc. The space
analysis is only made for the memory space to store data values. It does not include the space required for
the algorithm itself. The memory space requirement can be calculated as follows:
s(p) = c + sp
c is constant
s(p) is space requirement
sp refers to instance attribute

1.16.4 Time Requirement


It indicates the time required for execution of the program. The complete time T (p) is the total of time
required for compiling and executing of the program. The compile time is not dependent on instance
attribute.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 26 3/2/2012 6:49:30 PM


Introduction to Data Structures 1.27

SUMMARY
1. A computer is an electronic device that manipulates information presented in the form of
data.
2. The study of any characteristic in computer science means the study of storage, retrieval,
manipulation and organization of information.
3. Information is symbolic representation. It has some useful meaning for us and allows us
to make good judgements. Information is always expressed by data. Data is nothing but a
collection of numbers, alphabets, symbols, etc., combined to represent information.
4. The integers, real, logical data, character data, pointer and reference are primitive data
structures. Data structures that are normally directly operated upon by machine-level
instructions are known as primitive data structures.
5. Operations that create data structures are known as creation.
6. Destroy operations destroy data structures.
7. The most commonly used operation linked with data structures is selection, which is used
by programmers to access the data within data structures. Selection relationship depends
upon yes/no.
8. The iteration relationship depends upon repetition.
9. A number that has only the integer part is called an integer number.
10. A number that has the integer part and the fractional part is called a real number.
11. Primitive data structures also include logical data, i.e. true or false. Only two logical
constants—true and false—are present.
12. All non-numeric information is represented by a sequence of characters called strings.
13. The information stored in memory is in the form of bits 0 and 1. The information in the
memory can be viewed and understood by humans with the help of data types. The type
of computer hardware decides the data type and the range it supports. Range means the
largest and smallest possible values that can be represented.
14. A pointer is a link or reference to data structures.
15. A pointer is a memory variable that stores a memory address of another variable. It can
have any name that is valid for the other variable and it is declared in the same way as any
other variable. It is always denoted by ‘*’.
16. A structure is a collection of one or more variables of different data types grouped
together under a single name and new custom data type is formed.
17. An algorithm is a well-organized, pre-arranged, and defined computational module that receives
some value or set of values as input and provides a single or a set of values as output.
18. Analyzing an algorithm refers to calculating or estimating the resources needed for the
algorithm. Resources means computer memory, processing time, logic gates, etc.
19. The space or memory requirement of a program is the memory space required to
execute the program. The execution time is dependent upon the machine and the way of
implementation.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 27 3/2/2012 6:49:30 PM


1.28 Data Structures Using C

EXERCISES
A. Answer the following questions:

1. What is a computer?
2. What is information? Explain with a few examples.
3. What is data? Explain with a few examples.
4. Mention different types of data structures.
5. Distinguish between structure and class.
6. What are the functions of pointer and reference?
7. Explain logical information. List the operators related to it.
8. Explain the different operations related to data structures.
9. Explain the concept of data type.
10. Explain integers and real numbers.
11. Explain algorithm and its types. (a) Searching (b) sorting.
12. Explain algorithm with the factors time and space.
13. What are the different data types available in C language? Explain with examples.

B. Attempt the following programs:

1. Write a program to store logical values returned by an expression in individual bits.


2. Write a program to perform addition of two variables using pointers and reference.
3. Write a program to demonstrate the update of the operation of data structures with
variables.
4. Write a program to convert a decimal number to its binary equivalent.
5. Write a program to create abstract data types.
6. Write a program to get information about a student and display it on the screen by using
structure.
7. Write a program to add two numbers using structure.

C. Select the appropriate option for each of the following:

1. An array is a ——— type of data structure.


(a) linear (c) dynamic
(b) non-linear (d) (a) and (b)
2. Homogenous means ———.
(a) values of the same type (c) (a) and (b)
(b) having all equal values (d) dissimilar values
3. Information is represented by ———.
(a) data (c) numeral
(b) characters (d) bits

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 28 3/2/2012 6:49:30 PM


Introduction to Data Structures 1.29

4. In this method a positive integer is converted to negative by changing each bit to its opposite value.
(a) one’s complement (c) both (a) and (b)
(b) two’s complement (d) none of the above
5. The data type defined by the user is known as ———.
(a) abstract data type (c) classic data type
(b) built-in data type (d) none of the above

D. What will be the output of the following programs?

1. {
# include <stdio.h> union xyz
# include <conio.h> {
void main() float c;
{ int i;
static int a; double f;
clrscr(); };
printf(" %d",a++); union xyz w;
static int a; clrscr();
clrscr(); printf("\n%d",sizeof(w.c));
printf(" %d",a++); printf("\n%d",sizeof(w.i));
printf(" %d",a); printf("\%d",sizeof(w.f));
printf(" %d",a++); printf("\n%d",sizeof(w));
printf(" %d",a); }
}

4.
2. # include <stdio.h>
# include <stdio.h> # include <conio.h>
# include <conio.h> void main()
void main() {
{ int a=2;
struct abc float b=220.20;
{ clrscr();
char c; printf("\n %f %d",a,a);
int i; printf("\n %f %d",b,b);
float f; }
};
struct abc a;
clrscr(); 5.
printf("\n%d",sizeof(a.c)); # include <stdio.h>
printf("\n%d",sizeof(a.i)); # include <conio.h>
printf("\%d",sizeof(a.f)); void main()
printf("\n%d",sizeof(a)); {
} int a=2,b=10,c=100;
a=b;
3. b=c;
# include <stdio.h> clrscr();
# include <conio.h> printf("\n%d %d %d",a,b,c);
void main() }

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 29 3/2/2012 6:49:30 PM


This page is intentionally left blank.

M01_ASHOK NAMDEV KAMTHANE5067_01_SE_C01.indd 30 3/2/2012 6:49:30 PM


` Chapter 2

Data Structures: Arrays

CHAP TER O U T LIN E


2.1 Introduction 2.9 Drawbacks of Linear Arrays
2.2 Characteristics of Arrays 2.10 Sparse Matrices and Dense Matrices
2.3 One-dimensional Arrays 2.11 Row-major Arrays
2.4 Operation with Arrays 2.12 Column-major Arrays
2.5 Two-dimensional Arrays 2.13 Pointers and Arrays
2.6 Three- or Multi-dimensional Arrays 2.14 Pointers and Two-dimensional Arrays
2.7 Strings 2.15 Array of Pointers
2.8 Array of Structures 2.16 Pointers and Strings

2.1 INTRODUCTION

Array means collection. An array is used to store elements of the same type. It is a very popular and useful
data structure and stores data elements in contiguous locations. More than one element is arranged in
sequence so it is also called a composite data structure. Array is a linear and homogenous data structure.
Homogenous means that the same types of elements are stored in it. It can be combined with a non-
homogenous structure and a complex data structure can be created. We know that an array of structure
objects can also be useful. Array of any standard or custom data type can be declared. The array of charac-
ter (strings) type works somewhat differently from the array of int, float, etc.

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 1 3/2/2012 6:50:02 PM


2.2 Data Structures Using C

When we declare a variable for example,


x 4 6048
int X;
The variable x is declared and a memory location of
two bytes is allocated to it. Later, a single value can be
stored in it as shown in Fig. 2.1. Value
Variable Memory
X = 4; Name Location

The VITA concept is associated with all variables.


V stands for value of a variable Figure 2.1 Variable, Value and Address
I stands for identification of a variable
T stands for type of a variable
A stands for address of a variable
Every variable has a name, value and memory location. Hence, from the above, we can say that only
one value can be stored in a variable.

2.1.1 Array Declaration and Initialization


To store more than one value, programming languages have an in-built data structure called array.
a) int num[5];
In the above declaration, an integer array of five elements is declared. Memory for 5 integers, i.e. 10
successive bytes are reserved for num array. To initialize a num array, the following syntax can be used:
b) int num[5] = {1,2,4,2,5};

In the above statement, all elements are initialized. It is also possible to initialize individual elements
as follows:
num[0]=1;
num[1]=2;
num[2]=4;
num[3]=2;
num[4]=5;

The initialization can be done at compile time or dynamically at run time. The above is an example
of compile-time initialization. In the statement (b) declaration and initialization is done at once. In such
declaration, the number of elements (5) need not be mentioned in the []. The compiler automatically
counts the values initialized and assumes the number of elements initialized as the array size.
In the above array, the element, num [0], i.e. 1 is the lowest bound and num [4], i.e. 5 is the upper
element. In C, there is no bound checking. Hence, the programmer has to
check it while accessing or storing elements. Once the array is declared, its
lowest bound cannot be changed but the upper bound can be expanded. 1 num[0]
The array name itself is the constant pointer and, therefore, we cannot 2
modify it. Storing elements in successive memory locations can expand
the upper bound. 4
The array name itself is a pointer. The array num is pointer to the
2
first element, i.e. num contains the address of the memory location
where element 1 is stored as shown in Fig. 2.2. The address stored in 5 num[4]
the array name is called the base address. To access individual elements,
the following syntax is used: Figure 2.2 Arrays of Integers
num[0] refers to the 1
num[1] refers to the 2

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 2 3/2/2012 6:50:03 PM


Data Structures: Arrays 2.3

num[2] refers to the 4


num[3] refers to the 2
num[4] refers to the 5

An array is a collection of elements of the same data type, stored in unique and contiguous memory
locations.

2.1.2 Array Terminology


Size The number of elements or the array’s capacity to store elements denotes the size, which is always
mentioned in the bracket ([]).

Type Types refers to data type. It decides which type of element is stored in the array. It also instructs the
compiler to reserve memory according to data type.

Base The address of the first element (0th) element is a base address. The array name itself stores the
address of the first element.

Index The array name is used to refer to the array element. For example, in num [x], num is the array
name and x is the index. The value of x begins from 0 onwards depending on the size of the array. The
index value is always an integer value.

Range The index of an array, i.e. the value of x varies from the lower bound to the upper bound
while writing or reading elements from an array. For example, for num[100] the range of the index is
0 to 99.

Word This indicates the space required for an element. In each memory location, a computer can store
a data piece. The space occupied varies from machine to machine. If the size of the element is more than
word (one byte) then it occupies two successive memory locations. The various data types such as integer,
float, long, etc. needs more than one byte in memory.

2.2 CHARACTERSTICS OF ARRAYS

1. Array elements are stored in successive memory locations.

Example 2.1 Write a program to display array elements with their addresses.

# include <stdio.h>
# include <conio.h>

void main()
{
int Num[5]={1,2,3,2,5};
clrscr();

printf("\n Num[0] = %d Address: %u",Num[0],&Num[0]);


printf("\n Num[1] = %d Address: %u",Num[1],&Num[1]);
printf("\n Num[2] = %d Address: %u",Num[2],&Num[2]);

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 3 3/2/2012 6:50:03 PM


2.4 Data Structures Using C

printf("\n Num[3] = %d Address: %u",Num[3],&Num[3]);


printf("\n Num[4] = %d Address: %u",Num[4],&Num[4]);
}

OUTPUT
Num[0] = 1 Address: 65516
Num[1] = 2 Address: 65518
Num[2] = 3 Address: 65520
Num[3] = 2 Address: 65522
Num[4] = 5 Address: 65524

Explanation:
In the output of the program, elements and their addresses are displayed. Recall that integer
requires two bytes in memory. The memory locations displayed have a difference of two. From
the above program, it is clear that array elements are stored in successive memory locations.
Fig. 2.3 shows the memory location and the values stored.

Num[0] Num[1] Num[2] Num[3] Num[4]

1 2 3 2 5

65516 65518 65520 65522 65524

Figure 2.3 Storage of One-dimensional Array

2. Once the array is declared, its lowest bound cannot be changed, but the upper bound can be expanded
with the C++ compiler. The array name itself is a constant pointer and we cannot modify it. Therefore,
the lowest bound of an array cannot be expanded.

Example 2.2 Write a program to demonstrate that the upper bound of an array can be expanded.

# include <stdio.h>
# include <conio.h>

void main()
{
int Num[5]={1,2,3,2,5};
Num[5]=6;
clrscr();
printf("Num[5]=%d",Num[5]);
}

OUTPUT
Num[5]=6

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 4 3/2/2012 6:50:03 PM


Data Structures: Arrays 2.5

Explanation:
In this program array, Num [5] is declared with the array size 5 and it is initialized with five
elements. In the next statement, the 6th element is also initialized and displayed. Hence, we can
say that the upper bound of an array can be expanded. If you try this program with a C compiler,
a run time error message will be displayed.

3. We know that the array name itself is a pointer. Though it is a pointer, it does not need the ‘*’ operator.
The brackets [] automatically denote that the variable is a pointer.
4. All the elements of an array share the same name, and they are distinguished from one another with
the help of the element number.
5. The amount of memory required for an array depends upon the data type and the number of
elements.
Total bytes = size of (data type) * size of array
6. Operations such as insertion and deletion of element done with a list cannot be done with an array.
Once an array is created, we cannot remove or insert memory locations. An element can be deleted or
replaced but the memory location remains as it is.
7. When an array is declared and not initialized, it contains garbage values. If we declare an array as static,
all elements are initialized to zero. However, the values of static type data persist and remain in the
memory as long as the program executes. To overcome this problem, we initialize the first element of an
array with zero or any other number. All the remaining elements are automatically initialized to zero,
provided that the initialization is done in the declaration statement of array. The following program
illustrates this:

Example 2.3 Write a program to initialize an array.

# include <stdio.h>
# include <conio.h>

void main()
{
int Num[5]={0},j;
clrscr();
printf("The elements in array after initialization ");
for(j=0;j<5;j++)
printf("\nNum[%d]=%d",j,Num[j]);
}

OUTPUT
The elements in an array after initialization
Num[0]=0
Num[1]=0
Num[2]=0
Num[3]=0
Num[4]=0

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 5 3/2/2012 6:50:03 PM


2.6 Data Structures Using C

Explanation:
In this program an array, Num [5] is declared and the first element is initialized with zero. The
compiler automatically initializes all the elements with zero. Using the for loop the contents of an
array are displayed and we can see that all are zeros.

2.3 ONE-DIMENSIONAL ARRAYS

We have learnt how to declare, initialize and access the array elements. A one-dimensional array does not
have any corresponding elements; it has only one row of elements. So far, the example we have discussed
is of a one-dimensional array.
For example,
int Num[5]; /* one dimensional array */
In the following program we learn how to store and display values in the array during program
execution.

Traversing The operation of displaying or listing all elements of an array is called traversing. The
following program explains traversing with a one-dimensional array:

Example 2.4 Write a program to read and display the elements of an array.

# include <stdio.h>
# include <conio.h>

void main()
{
int num[5],j;
clrscr();
printf("\n Enter five elements: ");
for(j=0;j<5;j++)
scanf("%d",&num[j]);
printf("\n Elements Address ");
for(j=0;j<5;j++)
printf("\n%3d %10u ",num[j],&num[j]);
}

OUTPUT
Enter five elements: 4 6 4 2 1

Elements Address
4 65516
6 65518
4 65520
2 65522
1 65524

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 6 3/2/2012 6:50:03 PM


Data Structures: Arrays 2.7

Explanation:
In this program, an array num[] is declared. The first for loop, with the help of scanf()
statement, reads the elements and places in the array. The element position is indicated by
the loop variable j. The same procedure is applied for displaying elements. The printf()
statement displays the elements and addresses on the screen. The %3d and the %10u is used
to display the space.

From Figure 2.4 we can see that elements in a one-dimensional array are stored one after another in
sequence in memory. In the array we can insert, delete, or add any element but we cannot insert or delete
the memory location. We can change only the values.

4 6 4 2 1

65516 65518 65520 65522 65524

Base Address

Figure 2.4 Elements in Memory

2.4 OPERATION WITH ARRAYS

Figure 2.5 shows operations frequently carried out with arrays.

Deletion

Insertion

Searching
Array
Merging

Sorting

Figure 2.5 Operations with Arrays

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 7 3/2/2012 6:50:03 PM


2.8 Data Structures Using C

2.4.1 Deletion
This operation involves deleting specified elements from the array. Now, consider the following programs:

Example 2.5 Write a program to delete specified element from an array and rearrange the elements.

# include <stdio.h>
# include <conio.h>

void main()
{

int Num[20]={0},j,k,n,p,t;
clrscr();
printf("\n Enter Number of elements: ");
scanf("%d",&n);
printf("\n Enter elements: ");

for(j=0;j<n;j++)
scanf("%d",&Num[j]);
printf("\n Elements are: ");

for(j=0;j<n;j++)
printf("\n Num[j]=%d",Num[j]);
printf("\n Enter element number to delete: ");
scanf("%d",&p);
p–-;

for(j=0;j<n;j++)
{
if(j>=p)
Num[j]=Num[j+1];
}

for(j=0;j<n;j++)
if(Num[j]!=0)
printf("\nNum[j] = %d",Num[j]);
}

OUTPUT
Enter Number of elements: 5
Enter elements: 9 4 6 3 2
Elements are:
Num[j]=9
Num[j]=4
Num[j]=6
Num[j]=3
Num[j]=2
Enter element number to delete: 5

Num[j] = 9
Num[j] = 4
Num[j] = 6
Num[j] = 3

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 8 3/2/2012 6:50:03 PM


Data Structures: Arrays 2.9

Explanation:
In this program, an array Num [20] is declared. The program asks for number of elements to
be entered. The user has to enter the following input:
1. Number of integer elements to be entered.
2. Element number to be erased from an array.

In the first for loop the scanf statement reads the numbers from the keyboard and places it in the
array. In the second for loop the array elements are displayed. After this for loop the number to be
deleted is entered through the keyboard. In the third for loop the entered element is compared with
all array elements. When match is found, the element is deleted and successive elements are pushed in
their previous memory locations. The fourth for loop and printf statement display the elements
of the array. You can see in the output that the third memory location is the same; only its contents are
changed. See Fig. 2.6, where element ‘l’ is deleted and after deletion elements are shown in Fig. 2.6(c).

9 9 9

4 4 4

6 6 3

3 3

a. Original Array b. Shifting One Element Up c. After Deleting

Figure 2.6 Deletion in Steps

2.4.2 Insertion
This operation is used to insert an element at specified positions in an array. Consider the following program.

Example 2.6 Write a program to insert an element at a specified position in the array.

# include <stdio.h>
# include <conio.h>
void main()
{
int num[20]={0},j,k,n,p,t,s;
clrscr();
printf("\n Enter number of elements: ");
scanf("%d",&n);
printf("\n Enter elements: ");

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 9 3/2/2012 6:50:03 PM


2.10 Data Structures Using C

for(j=0;j<n;j++)
scanf("%d",&num[j]);
printf("\n Elements are: ");

for(j=0;j<n;j++)
printf("\n num[j]: %d",num[j]);

printf("\n Enter element and position to insert at: ");


scanf("%d %d",&s,&p);
p––;

for(j=n;j!=p;j––)
num[j]=num[j-1];
num[j]=s;

for(j=0;j<=n;j++)
printf("\n num[j] = %d",num[j]);
}

OUTPUT
Enter number of elements: 5

Enter elements: 1 2 3 4 5

Elements are:
num[j]: 1
num[j]: 2
num[j]: 3
num[j]: 4
num[j]: 5
Enter element and position to insert at: 2 5

num[j] = 1
num[j] = 2
num[j] = 3
num[j] = 4
num[j] = 2
num[j] = 5

Explanation:
This program is somewhat like the previous program. Here, an element is inserted. The
array elements are shifted to the next location, and at a specified position a space is created
and the new element is inserted (Figures 2.7 (b) and 2.7 (c)). Here also, you can see that
though we insert a new element, the memory location of the second element is the same
(65482). Once again, it is proved that in an array operation, only the contents of memory can
change but the actual address remains as it is. The address of the first element, i.e. num [0]
(65480), is called the base address. This address can also be stored in another pointer and array
elements can be accessed. The next program is illustrative in this regard.

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 10 3/2/2012 6:50:03 PM


Data Structures: Arrays 2.11

1 1 1

2 9

3 2 2

4 3 3

4 4

a. Original Array b. Insertion Element (Step 1) c. After Insertion

Figure 2.7 Insertion Steps

Example 2.7 Write a program to display a one-dimensional array using an integer pointer.

# include <stdio.h>
# include <conio.h>

void main()
{
int *p,num[5]={4,5,6,7,8},j;
clrscr();
p=num;
printf("Elements Address");
for(j=0;j<5;j++)
printf("\n %3d %7u", *(p+j),(p+j));
}

OUTPUT
Elements Address
4 65516
5 65518
6 65520
7 65522
8 65524

Explanation:
In this program, an integer array num [] is declared and initialized. In the same statement
pointer *p and integer variable j are declared. The base address is assigned to pointer p.
While assigning the base address it is enough to write the name of the array. It is optional to
write subscript number, i.e. num [0][0]. The for loop executes five times and the value
of j varies from 0 to 4. The first time 0 is added to the base address and there is no change
in the address. Hence, the 1st element is displayed. In the second iteration, one is added to
the base address. It takes the next successive address and the 2nd element is displayed. The
same procedure is continued and array elements are displayed. Fig. 2.8 shows what exactly
takes place.

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 11 3/2/2012 6:50:03 PM


2.12 Data Structures Using C

4 5 6 7 8

65516 65518 65520 65522 65524

0 1 2 3 4

65516 Base address

Figure 2.8 Accesses Through Base Address

In the above figure, the first line of boxes contains values, the second contains memory addresses and
the third contains loop variable values as used in the program. When the value of loop variable is added to
the base address we get the successive memory addresses and the values stored in them can be displayed.
For example,
65516 + 0 = 65516, i.e. 4
65516 + 1 = 65518, i.e. 5
¦ ¦
and so on values can be retrieved.

2.4.3 Searching
The process of seeking specified elements in an array is called searching.

Example 2.8 Write a program to search for a specified element in an array.

# include <stdio.h>
# include <conio.h>

void main()
{
int j=0,n;
int x[10];
clrscr();
printf("Enter ten elements of array:\n");
for(j=0;j<10;j++)
scanf("%d",&x[j]);
printf("\n Enter element to search:");
scanf("%d",&n);
for(j=0;j<10;j++)
{
if(x[j]==n)
break;
}
if(x[j]==n)

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 12 3/2/2012 6:50:04 PM


Data Structures: Arrays 2.13

printf("\n Element found");


else
printf("Element is not found");
}

OUTPUT
Enter ten elements of array:
1 2 3 4 5 6 7 8 9 12
Enter element to search: 3
Element found

Explanation:
In the above program, an integer array is declared and initialized with elements. The element
which is to be searched is entered through the keyboard. Using while loop, all the elements
are read. The if statement checks every element with the array elements. When the if
condition is satisfied the, message “element found” is displayed. Thus, the specified element
can be searched. When the element is not found the message displayed will be “Element is
not found”.

2.4.4 Merging
The merging of two arrays into a single one is an important operation. The easiest way of merging two
arrays is first, to copy all elements of one array into a third one and then copy all elements of the second
array also into the third one. We can also merge elements in an alternate order as shown in the follow-
ing program. Figure 2.9 indicates the merging of two arrays. The following points should be taken into
account.
1. Elements of one array can be appended to the end of the second array.
2. Elements of two arrays can be merged in an alternate order.
3. The size of the resulting array must be more than the size of two arrays.

Example 2.9 Write a program to merge two arrays into a third one. Display the contents of all the
three arrays.

# include <stdio.h>
# include <conio.h>

void main()
{
int j,h=0,k=0;
int x[4]={1,2,3,4};
int y[4]={5,6,7,8};
int z[8];
clrscr();

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 13 3/2/2012 6:50:04 PM


2.14 Data Structures Using C

printf("\n Array X: ");


for(j=0;j<4;j++)
printf(" %d ",x[j]);
printf("\n Array Y: ");

for(j=0;j<4;j++)
printf(" %d ",y[j]);
j=0;
while(j<8)
{
if(j%2==0)
z[j]=x[k++];
else
z[j]=y[h++];
j++;
}

printf("\n Array Z: ");


for(j=0;j<8;j++)
printf(" %d ",z[j]);
}

OUTPUT
Array X: 1 2 3 4
Array Y: 5 6 7 8
Array Z: 1 5 2 6 3 7 4 8

Explanation:
In the above program, three integer arrays are declared and initialized. The first two for loops
are used to view the elements of array x and z by a transverse process. The while loop is used
to execute until the condition is true. The ‘if’ statement checks the condition and accordingly
if and else blocks are executed. These statements also fetch elements from both arrays and
place them into array z. Fig. 2.9 illustrates the merging of two arrays.

1 1
2 5
3 2
4 6
3
5 7
6 4
7 8
8

Figure 2.9 Merging Two Arrays

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 14 3/2/2012 6:50:04 PM


Data Structures: Arrays 2.15

2.4.5 Sorting
Arranging elements in a specific order, either ascending or descending, is known as sorting. Sorting is a
very important operation and compulsorily used in database application programs. Let us study the fol-
lowing program, which sorts an array of integers and stores them in another array.

Example 2.10 Write a program to enter integer elements and sort them in ascending order.

# include <stdio.h>
# include <conio.h>
void main()
{
int num[5],j,k,s=0;
clrscr();
printf("\n Enter five Elements: ");

for(j=0;j<5;j++)
{
scanf("%d",&num[j]);
s=s+num[j];
}

for(k=0;k<s;k++)
{
for(j=0;j<5;j++)
{
if(num[j]==k)
printf(" %d ",num[j]);
}
}
}

OUTPUT
Enter five Elements: 5 8 9 7 2
2 5 7 8 9

Explanation:
In the above program, an integer array is declared and five numbers are entered. The sum of
all the numbers is taken. Using nested loops every number of the array is compared from one
to s (s = sum of all numbers). The if statement checks every array element with the
value of s and displays the numbers in ascending order. Sorting can be done in various ways.
The above sorting method is the simplest one.

2.5 TWO-DIMENSIONAL ARRAYS

Two-dimensional arrays can be thought of as rectangular display of elements with rows and columns.
Consider the following example:
int x[3][3];

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 15 3/2/2012 6:50:04 PM


2.16 Data Structures Using C

The two-dimensional array can be declared as above.

Column 0 Column 1 Column 2


Row0 x[0][0] x[0][1] x[0][2]
Row1 x[1][0] x[1][1] x[1][2]
Row2 x[2][0] x[2][1] x[2][2]

Row 0 [0][0] [0][1] [0][2]

Row 1 [1][0] [1][1] [1][2]

Row 2 [2][0] [2][1] [2][2]

Figure 2.10 Array: Element Arrangement

The arrangement of array elements shown in Fig. 2.10 is only for the sake of understanding. Actually,
the elements are stored in continuous memory locations.
A two-dimensional array is a collection of two one-dimensional arrays. The meaning of the first argument is in
x [3]. [3] means the number of rows, i.e. number of one-dimensional arrays and the second argument indicates
the number of elements. x [0][0] means the first element of the first row and column. Row number remains
the same but column number changes. The number of rows and columns is called as the range of the array. A
two-dimensional array clearly shows the difference between logical assumption and physical representation of
data. The computer memory is linear and whatever may be the type of array—one, two or multi dimensional—
it is stored in continuous memory locations. Fig. 2.11 explains storage of two-dimensional arrays.

x[0][0] Base Address


x[0][1]
x[0][2]
x[1][0]
x[1][1]
x[1][2]
x[2][0]
x[2][1]
x[2][2]

Figure 2.11 Storage of Two-dimensional Array

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 16 3/2/2012 6:50:04 PM


Data Structures: Arrays 2.17

Example 2.11 Write a program to demonstrate the use of a two-dimensional array.

# include <stdio.h>
# include <conio.h>
void main()
{
int i,j;
int a[3][3]={1,2,3,4,5,6,7,8,9};
clrscr();
printf("\n Array elements and address ");
printf("\n\t Col-0 Col-1 Col-2");
printf("\n\t ====== ====== ======");
printf("\nRow0");

for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
printf(" %d [%u]",a[i][j],&a[i][j]);
printf("\nRow%d",i+1);
}
printf("\r ");
}

OUTPUT
Array elements and address
Col-0 Col-1 Col-2
====== ====== ======
Row0 1 [65508] 2 [65510] 3 [65512]
Row1 4 [65514] 5 [65516] 6 [65518]
Row2 7 [65520] 8 [65522] 9 [65524]

Explanation:
From this program’s output, you can see that the memory addresses displayed are in sequence
and it is true that elements of two-dimensional arrays are stored in successive memory locations.
The one-dimensional array can be accessed using a single loop. However, for two-dimensional
arrays, two loops are required for the row and column. The inner loop helps to access the row-
wise elements and the outer loop changes the column number; just as a one-dimensional array
base address can be stored in a pointer. Consider the following program.

Example 2.12 Write a program to assign the base address of a two-dimensional array to a pointer
and display the elements.

# include <stdio.h>
# include <conio.h>

void main()

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 17 3/2/2012 6:50:04 PM


2.18 Data Structures Using C

{
int *p,num[2][2]={4,5,6,7},j;
clrscr();
p=&num[0][0];
printf("Elements Address");
for(j=0;j<4;j++)
printf("\n%3d %9u",*(p+j),(p+j));
}

OUTPUT
Elements Address
4 65490
5 65492
6 65494
7 65496

Explanation:
This program is the same as the last one. But the point to note here is that to store the base
address of a two-dimensional array, it is not enough to mention the array; in addition, subscript
number and address operation should also be mentioned. Only then will the compiler accept
the statement; other-wise, the compiler flags an error message. For a one-dimensional array, an
array name is sufficient, but onwards we have to mention the element number with the address
operator.

2.5.1 Insert Operation with Two-dimensional Array


We have studied the example of insertion of element with a one-dimensional array. We are also aware how
pointers can be used to access array elements. The following program gives you an idea of insert operations
with a two-dimensional array.

Example 2.13 Write a program to illustrate an insert operation with a two-dimensional array.

# include <stdio.h>
# include <conio.h>

void main()
{
int num[5][5]={0,0},j,*p,at,e,n;
clrscr();
printf("\n Enter how many elements (<=25): ");
scanf("%d",&n);
p=&num[0][0];

for(j=0;j<n;j++)
scanf("%d",p++);
p=&num[0][0]; printf("\n");

for(j=0;j<n;j++,p++)
printf(" %d ",*p);

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 18 3/2/2012 6:50:04 PM


Data Structures: Arrays 2.19

printf("\n Enter a number & position to insert: ");


scanf("%d %d",&e,&at);

for(j=n;j>=at;j––)
{
*p=*(p–1);
p––;
}
*p=e;
p=&num[0][0];

for(j=0;j<=n;j++,p++)
printf(" %d ",*p);
}

OUTPUT
Enter how many elements (<=25): 5
1 2 3 4 5
1 2 3 4 5
Enter a number & position to insert: 8 3
1 2 8 3 4 5

Explanation:
In all types of array, one, two and three-dimensional elements are stored in the successive
memory locations. A pointer can dereference to get successive memory location of memory. In
this way, elements of the array can be accessed, changed or replaced. For all this, we require only
the base address of the array that is to be assigned to a pointer.

Consider the statement p=&num [0][0]; used to store base address (address of 0th element of the array)
of an array. Later in this program the array is not accessed by its name and corresponding row column
numbers. The total capacity of the array of storing elements is 25 as per the declaration. The user is asked
to enter the number of elements he wants to enter. The entered value is stored in the variable n through
the scanf() statement. Thus, by using loops, values are repetitively entered and displayed.
The user is again asked to enter a number and position in the array where the element is to be inserted.
These values are stored in the variables (scanf( “%d %d ”,&e,&at);), e & at.

for(j=n;j>=at;j––)
{
*p=*(p−1);
p––;
}

Using the for loop the elements are shifted to next position up to the value of the variable “at”.
When the loop ends, the entered element is assigned to * (*p=e;). The ex- element is already shifted to
the next position. Thus, finally the list of latest elements is displayed. Figure 2.12 (a) and (b) shows the
insertion of element.

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 19 3/2/2012 6:50:04 PM


2.20 Data Structures Using C

8 is to be inserted after 3

1 2 3 4 5 25

Shifting
a. Before Insertion

1 2 8 3 4 5

b. After Insertion

Figure 2.12 Insertion of Element

2.5.2 Delete Operation with Two-dimensional Array


Like insert operation delete operation can also be performed on an array. Consider the following program.

Example 2.14 Write a program to demonstrate delete operation of element with


two-dimensional array.

# include <stdio.h>
# include <conio.h>

void main()
{
int num[5][5]={0,0},j,*p,at,e,n;
clrscr();

printf("\n Enter how many elements (<=25): ");


scanf("%d",&n);
p=&num[0][0];

for(j=0;j<n;j++)
scanf("%d",p++);
p=&num[0][0]; printf("\n");

for(j=0;j<n;j++,p++)
printf(" %d",*p);

printf("\n Enter Element position to delete: ");


scanf("%d",&at);
at––;
p=&num[0][0];
p+=at;

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 20 3/2/2012 6:50:04 PM


Data Structures: Arrays 2.21

for(j=at;j<n;j++)
{
*p=*(p+1);
p++;
}

*p=0;

p=&num[0][0];

while(*p!=0)
{
printf(" %d ",*p);
p++;
}
}

OUTPUT
Enter how many elements (<=25): 7
1 2 3 4 5 6 7
1 2 3 4 5 6 7
Enter Element position to delete: 5
1 2 3 4 6 7

Explanation:
The method for obtaining base address and pointer arithmetic involved in the program is same
as the last program. The element to be deleted is replaced with the next element. Thus, the
entire elements are shifted to the previous location. Figs. 2.13 (a) and (b) describe the deletion
of element.

Element to be
deleted

1 2 3 4 5 6 7

a. Before Deletion

1 2 3 4 5 6 7

b. After Deletion

Figure 2.13 Deletion of Element

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 21 3/2/2012 6:50:04 PM


2.22 Data Structures Using C

2.6 THREE- OR MULTI-DIMENSIONAL ARRAYS

A three-dimensional array can be thought of as array of arrays. Consider the following program:

int mat[3][3][3] =
{1,2,3,
4,5,6,
7,8,9,

1,4,7,
2,5,8,
3,6,9,

1,4,4,
2,4,7,
8,8,5};

Example 2.15 Write a program to demonstrate the use of three-dimensional array.

# include <stdio.h>
# include <conio.h>

void main()
{
int a,b,c;
int mat[3][3][3] ={1,2,3,
4,5,6,
7,8,9,
1,4,7,
2,5,8,
3,6,9,
1,4,4,
2,4,7,
8,8,5};
clrscr();

for(a=0;a<3;a++)
{
printf("\n");
for(b=0;b<3;b++)
{
for(c=0;c<3;c++)
printf("%3d [%u] ",mat[a][b][c],&mat[a][b][c]);
printf("\n");
}
}
}

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 22 3/2/2012 6:50:04 PM


Data Structures: Arrays 2.23

OUTPUT
1 [65470] 2 [65472] 3 [65474]
4 [65476] 5 [65478] 6 [65480]
7 [65482] 8 [65484] 9 [65486]

1 [65488] 4 [65490] 7 [65492]


2 [65494] 5 [65496] 8 [65498]
3 [65500] 6 [65502] 9 [65504]

1 [65506] 4 [65508] 4 [65510]


2 [65512] 4 [65514] 7 [65516]
8 [65518] 8 [65520] 5 [65522]

Explanation:
In this example, a three-dimensional array is initialized. The three loops are used to access the
elements. The logic of accessing the elements is same as in the case of two-dimensional array.
From the output obtained, we can say that elements of multi-dimensional array are stored in
continuous memory locations.

2.7 STRINGS

The collection of characters, digits and symbols enclosed within quotation marks are called as strings.
Strings are always declared as character array. Like other type of arrays, the elements of character array are
also stored in continuous memory location. Each character occupies one byte in memory. One different
thing about strings is that, the compiler automatically adds NULL (‘\0’) character at the end of the string.
This character is used to detect the end of the string. The declaration of string can be done as follows. The
Fig. 2.14 shows how the name is stored in the array.
char name[6]= "KAMAL";

K A M A L ‘\0’

Figure 2.14 Storing Name in Array

While declaring character array the declaration of NULL character should be taken into account.
Therefore, the above array is declared of 6 sizes out of which five characters are stored first, then NULL
character is stored at the end.

Example 2.16 Write a program to declare, initialize character array and display the string.

# include <stdio.h>
# include <conio.h>

void main()
{
char name[6]="kamal";

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 23 3/2/2012 6:50:05 PM


2.24 Data Structures Using C

clrscr();
printf("%s",name);
}

OUTPUT
kamal

Explanation:
In this program a character array is declared and initialized with string “kamal”. Here, the array
limit is declared for 6 characters and total six characters are stored including NULL character.
Using printf() statement, string is displayed. Instead of 6 if limit is declared of 5, there is no
place to insert NULL character and therefore the string will not be displayed properly.

Example 2.17 Write a program to encrypt a name and decrypt it.

# include <stdio.h>
# include <conio.h>
void main()
{
char name[10],iname[10],dname[10];
int i=0,y;
clrscr();
printf("\nEnter the name:-");
scanf("%s",name);
while(name[i]!='\0')
{
iname[i]=name[i]+3;
i++;
}
iname[i++]='\0';
printf("\nThe encrypted name is:- %s",iname);
i=0;
while(iname[i]!='\0')
{
dname[i]=iname[i]-3;
i++;
}
dname[i++]='\0';
printf("\nThe decrypted name is:- %s",dname);
}

OUTPUT:
Enter the name:-amit
The encrypted name is:- dplw
The decrypted name is:- amit

Explanation:
In this program, name is entered through the keyboard. In the encryption process, each letter is
shifted by 3 and during decryption each letter is shifted downward by 3.

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 24 3/2/2012 6:50:05 PM


Data Structures: Arrays 2.25

Example 2.18 Write a program to display the string and determine end of the string by NULL character.

# include <stdio.h>
# include <conio.h>

void main()
{
char arr[]={'A','B','C','D','E','\0'};
int j=0;
clrscr();
printf("Characters Address");
while(arr[j]!='\0')
{
printf("\n %3c %9u",arr[j],&arr[j]);
j++;
}

OUTPUT
Characters Address
A 65492
B 65493
C 65494
D 65495
E 65496

Explanation:
In this program a character array is declared and initialized. In the initialization, a NULL character
is also initialized. The condition given in the while loop tests for NULL character. If it finds,
the while loop is terminated, otherwise a character is displayed. We can also find that the
characters are stored in successive memory locations.

2.8 ARRAY OF STRUCTURES

We have already studied structure in the first chapter. We also know that array is a homogeneous data
structure and structure is a non-homogenous data structure. By declaring an array of structure objects,
we can make combination of data structure of different types. However, we cannot create an array of non-
homogenous type as such an array will also be homogenous type. Because all the elements are of the same
type, i.e. structure type. The following program explains array of structure.

Example 2.19 Write a program to read display data using array of structure.

# include <stdio.h>
# include <conio.h>

void main()
{
struct item

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 25 3/2/2012 6:50:05 PM


2.26 Data Structures Using C

{
int codeno;
int price;
};

int j;
struct item a[2];

clrscr();

printf("\n Enter Codeno, Price\n ");

for(j=0;j<2;j++)
scanf("%d %d",&a[j].codeno,&a[j].price);

printf("\n Codeno Price ");

for(j=0;j<2;j++)
printf("\n %d %d",a[j].codeno,a[j].price);
}

OUTPUT
Enter Codeno, Price
002 541
003 125
Codeno Price
2 541
3 125

Explanation:
In this program, structure item is defined with two numeric fields, i.e. codeno and price.
An array of structure item type a[2] is declared. Using for loop data read and displayed.

2.9 DRAWBACKS OF LINEAR ARRAYS

1. The number of elements, which is to be stored in an array, must be known first.


2. When an array is declared, memory is allocated to it. If array is not filled completely, the vacant place
occupies memory.
3. Once the array is declared, its dimension can be changed.

2.10 SPARSE MATRICES AND DENSE MATRICES

A sparse matrix is a two-dimensional array in which most of the elements are null. Figs. 2.15 (a) and 2.15 (b)
indicate sparse and dense matrices. The matrix, which is not a sparse matrix, is called dense matrix. One
cannot exactly determine the boundary between sparse and dense matrix. The sparse matrices are very
useful in various applications. In sparse matrices, memory is wasted because the NULL values are stored
and hence to overcome wastage of memory a mechanism must be followed. One of the mechanism is
linked list, which will be discussed in detail in Chapter 6.
The classification of sparse matrices is shown in Fig. 2.16.

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 26 3/2/2012 6:50:05 PM


Data Structures: Arrays 2.27

3 0 78 0 12 3 0 0 0 1
1 6 7 8 11 2 0 0 0 0
0 5 0 1 0 0 0 0 1 0
1 0 1 0 5 1 0 1 0 0
a. Dense Matrix b. Sparse Matrix

Figure 2.15 Sparse Matrices and Dense Matrices

Sparse Matrices (Symmetric)

Triangular Matrices Band Matrices

Diagonal

Upper Lower
Tridiagonal

Left Left αβ-band

Right Right

Figure 2.16 Types of Sparse Matrices

2.10.1 Upper Triangular Matrices


The upper matrix is a type of triangular matrix, which is also a type of sparse matrix. A sparse matrix is a
matrix in which maximum of the elements are zero. The upper matrix is also of two kinds: upper left and
upper-right as shown in Fig. 2.17 and Fig. 2.18, respectively.
In Fig. 2.17, a triangle of null elements and non-element is present. The triangle of NULL elements is
present the left side and the triangle of non-element is present on the right side.

0 0
0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

Figure 2.17 Upper Right Triangular Figure 2.18 Upper Left Triangular

Example 2.20 Write a program to initialize and display an upper right triangular matrix.

# include <stdio.h>
# include <conio.h>
void main()

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 27 3/2/2012 6:50:05 PM


2.28 Data Structures Using C

{
int j,k,urt[5][5]={ 0,4,3,2,1,
0,0,3,2,1,
0,0,0,2,1,
0,0,0,0,1,
0,0,0,0,0,
};
clrscr();
printf("\n UPPER RIGHT TRIANGULAR\n");
for(j=0;j<5;j++)
{
for(k=0;k<5;k++)
printf(" %d ",urt[j][k]);
printf("\n");
}
}

OUTPUT
UPPER RIGHT TRIANGULAR
0 4 3 2 1
0 0 3 2 1
0 0 0 2 1
0 0 0 0 1
0 0 0 0 0

Explanation:
In this program an array is initialized and the NULL elements form an upper right triangular
matrix and it is displayed. Fig. 2.18 shows the upper left triangular matrix.

Example 2.21 Write a program to initialize and display an upper left triangular matrix.

# include <stdio.h>
# include <conio.h>
void main()
{
int j,k,ult[5][5]={ 1,2,3,4,0,
1,2,3,0,0,
1,2,0,0,0,
1,0,0,0,0,
0,0,0,0,0,
};
clrscr();
printf("\n UPPER LEFT TRIANGULAR\n");
for(j=0;j<5;j++)
{
for(k=0;k<5;k++)
printf(" %d ",ult[j][k]);
printf("\n");
}
}

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 28 3/2/2012 6:50:05 PM


Data Structures: Arrays 2.29

OUTPUT
UPPER LEFT TRIANGULAR
1 2 3 4 0
1 2 3 0 0
1 2 0 0 0
1 0 0 0 0
0 0 0 0 0

Explanation:
The two-dimensional matrix ult[5][5] is declared and initialized. The elements of the matrix
are displayed.

2.10.2 Lower Triangular Matrices


Example 2.22 Write a program to display lower left triangular matrix.

# include <stdio.h>
# include <conio.h>

void main()
{
int j,k,llt[5][5]={ 0,0,0,0,0,
1,0,0,0,0,
1,2,0,0,0,
1,2,3,0,0,
1,2,3,4,0,
};
clrscr();
printf("\n LOWER LEFT TRIANGULAR\n");
for(j=0;j<5;j++)
{
for(k=0;k<5;k++)
printf(" %d ",llt[j][k]);
printf("\n");
}
}

OUTPUT 0 0 0 0 0
LOWER LEFT TRIANGULAR
0 0 0 0
0 0 0 0 0
1 0 0 0 0 0 0 0
1 2 0 0 0 0 0
1 2 3 0 0
0
1 2 3 4 0
Figure 2.19 Lower-left Triangular
Explanation:
In this program an array llt [][] is initialized. The array is initialized in such a way that
maximum elements are NULL and hence, it is sparse matrix. The NULL elements form a triangular
at lower left side. Hence, this matrix is called lower left triangular matrix. The Fig. 2.19 shows the
lower left triangular matrix.

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 29 3/2/2012 6:50:05 PM


2.30 Data Structures Using C

Example 2.23 Write a program to initialize and display a lower right triangular matrix.

# include <stdio.h>
# include <conio.h>

void main()
{
int j,k,lrt[5][5]={ 0,0,0,0,0,
0,0,0,0,1,
0,0,0,2,1,
0,0,3,2,1,
0,4,3,2,1,
};
clrscr();
printf("\n LOWER RIGHT TRIANGULAR\n");
for(j=0;j<5;j++)
{
for(k=0;k<5;k++)
printf(" %d ",lrt[j][k]);
printf("\n");
}
}

OUTPUT
0 0 0 0 0
LOWER RIGHT TRIANGULAR
0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 0 0 2 1
0 0
0 0 3 2 1
0 4 3 2 1
Figure 2.20 Lower Right Triangular

Explanation:
This program is the same as the last one and displays lower right triangular matrix. Fig. 2.20 is an
example of lower right triangular matrix.

Example 2.24 Write a program to find whether the given matrix is lower right triangular matrix or not.

# include <stdio.h>
# include <conio.h>
int matrix[3][3];

void main()
{
clrscr();
input();
display();
lowe_r();
}

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 30 3/2/2012 6:50:05 PM


Data Structures: Arrays 2.31

input()
{

int n,j,k;
printf("\n Enter elements for matrix ");
for(j=0;j<3;j++)
{
for(k=0;k<3;k++)
scanf("%d",&matrix[j][k]);
}
return 0;}display()
{

int n,j,k;
printf("\n Elements of matrix\n");
for(j=0;j<3;j++)
{
for(k=0;k<3;k++)
printf("%4d",matrix[j][k]);
printf("\n"); }
return 0;}
lowe_r()
{

int n,j,k,u=3; char b=' ';


printf("\n Elements of matrix\n");
for(j=0;j<3;j++)
{
for(k=0;k<u;k++)
{
printf("%4d",matrix[j][k]);
if(matrix[j][k]==0)
b='Y'; else b='N';
}
u––;
printf("\n");

}
if(b=='Y')
puts("\n The given matrix is lower right triangular matrix");
else
puts("\n Not a sparse matrix");
return 0;
}

OUTPUT
Enter elements for matrix 0 0 0 0 0 0 0 1 5

Elements of matrix
0 0 0
0 0 0
0 1 5

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 31 3/2/2012 6:50:05 PM


2.32 Data Structures Using C

Elements of matrix
0 0 0
0 0
0

The given matrix is lower right triangular matrix.

Explanation:
In this program matrix [3][3] is declared. Through input() function, elements are entered.
The display() function displays the elements of the matrices. Through use of lowe_r()
function, elements of rows 1st, 2nd and 3rd are checked. The numbers of elements are 3,2 and 1,
respectively. If these elements are NULL, the matrix is lower right triangular matrix.

In some of the earlier programs, arrays, i.e. matrix, are initialized and displayed. This can be imple-
mented easily. However, in the above program, elements are entered during program execution. Hence,
few additional statements are required.
In case of diagonal matrices, only diagonal elements are non-zero and other values are NULL as shown
in the Fig. 2.21.
1 0 0 0 0 0 0 0 0 5
0 2 0 0 0 0 0 0 4 0
0 0 3 0 0 0 0 3 0 0
0 0 0 4 0 0 2 0 0 0
0 0 0 0 5 1 0 0 0 0

Figure 2.21 Diagonal Matrices

Example 2.25 Write a program to initialize and display diagonal matrix.

# include <stdio.h>
# include <conio.h>

void main()
{
int j,k,dgl[5][5]={ 1,0,0,0,0,
0,2,0,0,0,
0,0,3,0,0,
0,0,0,4,0,
0,0,0,0,5,
};
clrscr();
printf("\n DIAGONAL MATRIX\n");
for(j=0;j<5;j++)
{
for(k=0;k<5;k++)
printf(" %d ",dgl[j][k]);
printf("\n");
}
}

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 32 3/2/2012 6:50:05 PM


Data Structures: Arrays 2.33

OUTPUT
DIAGONAL MATRIX
1 0 0 0 0
0 2 0 0 0
0 0 3 0 0
0 0 0 4 0
0 0 0 0 5

Explanation:
In this program an array is initialized in which diagonal elements are non-zero.

Figure 2.22 shows diagonal matrices. Readers can write programs to show elements as seen in these tables.

1 1 0 0 0 0 0 0 2 5
1 2 8 0 0 0 0 4 4 1
0 4 3 3 0 0 7 3 9 0
0 0 5 4 5 8 2 7 0 0
0 0 0 8 5 1 4 0 0 0

Figure 2.22 Tri-diagonal Matrices

2.11 ROW-MAJOR ARRAYS


Row-major implementation is a liberalization technique in which elements in an array are arranged row-
wise. Elements are stored row by row as shown in Fig. 2.23.
Consider an array
int X[3][3];

COLUMN-0 COLUMN-1 COLUMN-2


X[0][0] X[0][1] X[0][2] Row-0
X[1][0] X[1][1] X[1][2] Row-1
X[2][0] X[2][1] X[2][2] Row-2

X[0][0] X[0][1] X[0][2] X[1][0] X[1][1] X[1][2] X[2][0] X[2][1] X[2][2]


ROW-0 ROW-1 ROW-2

X[0][0] X[0][1] X[0][2]

X[1][0] X[1][1] X[1][2]

X[2][0] X[2][1] X[2][2]

Figure 2.23 Row-major Array

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 33 3/2/2012 6:50:06 PM


2.34 Data Structures Using C

Consider the following program.

Example 2.26 Write a program to implement an array by row-major method.

# include <stdio.h>
# include <conio.h>
void main()
{
int j,k,x[3][3];
clrscr();
printf("\n Enter nine elements: ");
for(j=0;j<=2;j++)
for(k=0;k<=2;k++)
scanf("%d",&x[j][k]);

printf("\n Row major array\n");


for(j=0;j<=2;j++)
{
for(k=0;k<=2;k++)
printf(" %d ",x[j][k]);
printf("row- [ %d ]\n",j+1);
}
}
OUTPUT
Enter nine elements: 7 8 9 4 5 2 1 5 9
Row major array
7 8 9 row- [ 1 ]
4 5 2 row- [ 2 ]
1 5 9 row- [ 3 ]

Explanation:
In this program two for loops are used. The elements are entered through the keyboard. The
outer loop indicates row and inner loop indicates column. After finishing the execution of inner
loop, outer loop is executed once. Thus, when one complete row is filled with elements, the
outer loop is executed and it indicates next row, which is to be filled. Again, the inner loop is
used to fill the elements. Thus, elements are stored row-by-row.

2.12 COLUMN-MAJOR ARRAYS

In column major array elements are stored column-by-column as shown in Fig. 2.24.

COLUMN-0 COLUMN-1 COLUMN-2


X[0][0] X[0][1] X[0][2] Row-0
X[1][0] X[1][1] X[1][2] Row-1
X[2][0] X[2][1] X[2][2] Row-2

Figure 2.24 (continued)

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 34 3/2/2012 6:50:06 PM


Data Structures: Arrays 2.35

X[0][0] X[1][0] X[2][0] X[0][1] X[1][1] X[2][1] X[0][2] X[1][2] X[2][2]


COLUMN-0 COLUMN-1 COLUMN-2

Figure 2.24 Column Major Array

Example 2.27 Write a program to implement an array by column major method.

# include <stdio.h>
# include <conio.h>

void main()
{
int j,k,x[3][3];
clrscr();
printf("\n Enter nine elements: ");
for(j=0;j<=2;j++)
for(k=0;k<=2;k++)
scanf("%d",&x[k][j]);
printf("\n Column major array\n");
for(j=0;j<=2;j++)
{
for(k=0;k<=2;k++)
printf(" %d ",x[j][k]);
printf("\n");
}
}

OUTPUT
Enter nine elements: 1 2 3 4 5 6 7 8 9

Column major array


1 4 7
2 5 8
3 6 9

Explanation:
In column major method the elements entered are stored column by column. The outer loop indicates
column number and inner loop indicates row. When one complete column is filled, next column is
considered for filling.

2.13 POINTERS AND ARRAYS

Array name by itself is an address or pointer. It points to the address of the first element (0th element of
an array). The elements of the array together with their addresses can be displayed by using array name
itself. Array elements are always stored in contiguous memory locations.
Programs in this regard are explained below.

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 35 3/2/2012 6:50:06 PM


2.36 Data Structures Using C

Example 2.28 Write a program to display elements of an array. Start element counting
from 1 instead of 0.

# include <stdio.h>
# include <conio.h>

void main()
{

int x[]={2,4,6,8,10},k=1;
clrscr();
while(k<=5)
{
printf("%3d",k[x-1]);
k++;
}
}

OUTPUT:
2 4 6 8 10

Explanation:
Array element counting always starts from ‘0’. The element number is added in the base
address and each element of an array is accessed. If one is subtracted from base address of an
array, it points to the prior address of 0th element. By adding one to its reduced base address it
is possible to start element counting from ‘1’.

Example 2.29 Write a program to display array element with their addresses using array name as a pointer.

# include <stdio.h>
# include <conio.h>

void main()
{
int x[5]={2,4,6,8,10},k=0;
clrscr();
printf("\nElement No. Element Address");

while(k<5)
{
printf("\nx[%d] = \t%8d %9u",k,*(x+k),x+k);
k++;
}
}

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 36 3/2/2012 6:50:06 PM


Data Structures: Arrays 2.37

OUTPUT:
Element No. Element Address
x[0] 2 4056
x[1] 4 4058
x[2] 6 4060
x[3] 8 4062
x[4] 10 4064

Explanation:
In this program variable ‘k’. acts as element number and its value varies from 0 to 4.
When it is added with array name ‘x’, i.e. with address of the first element, it points
to the consecutive memory location. Thus, element no., element, and their addresses are
displayed.

Example 2.30 Write a program to display array elements with their addresses using array
name as a pointer.

# include <stdio.h>
# include <conio.h>

void main()
{
int num[4]={10,25,35,45},i;
clrscr();
printf("Element Address\n");
for(i=0;i<4;i++)
{
printf("num[%d]=%d",i,*(num+i));
printf("%8u\n",num+i);
}
}

OUTPUT:
Element Address
num[0] = 10 4062
num[1] = 25 4064
num[2] = 35 4066
num[3] = 45 4068

Explanation:
Here, the array name ‘num’. itself acts as a pointer to the array num []. The pointer ‘num’
provides address of first element and ‘*num’ gives value stored at that address. When ‘i’ is
added with ‘num’, the equations *(num+i) and num+i show ‘i’ the element and its location,
respectively.

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 37 3/2/2012 6:50:06 PM


2.38 Data Structures Using C

Example 2.31 Write a program to access elements of array through different ways using pointer.

# include <stdio.h>
# include <conio.h>

void main()
{
int arr[5]={10,20,30,40,50},p=0;
clrscr();

for(p=0;p<5;p++)
{
printf("Value of arr[%d]=",p);
printf("%d ¦ ",arr[p]);
printf("%d ¦ ",*(arr+p));
printf("%d ¦ ",*(p+arr));
printf("%d ¦",p[arr]);
printf(" address of arr[%d] =%u\n",p,&arr[p] );
}
}

OUTPUT:
Value of arr[0]=10 ¦ 10 ¦ 10 ¦ 10 ¦ address of arr[0]=4056
Value of arr[1]=20 ¦ 20 ¦ 20 ¦ 20 ¦ address of arr[1]=4058
Value of arr[2]=30 ¦ 30 ¦ 30 ¦ 30 ¦ address of arr[2]=4060
Value of arr[3]=40 ¦ 40 ¦ 40 ¦ 40 ¦ address of arr[3]=4062
Value of arr[4]=50 ¦ 50 ¦ 50 ¦ 50 ¦ address of arr[4]=4064

Explanation:
In this program elements are displayed using different syntax, a. arr[p] b. *(arr+p))
c) *(p+arr)) d) p[arr]). The results of all of them would be the same.
a. arr[p]: This statement displays various array elements. Here, ‘arr’ refers to the address and
‘p’ refers to the element number.
b. *(arr+p): The arr+p is addition of constant with base address of the array. It shows address
of pth element. The *(arr+p) points to the pth element of the array.
c. *(p+arr): This statement is same as (b).
d. p[arr]: This statement is same as (a). Here, ‘p’ refers to the element number and ‘arr’ refers
to the base address. By varying ‘p’ and ‘arr’ the various elements of the array are displayed.

Example 2.32 Write a program to find sum of all the elements of an array. Use array name
itself as a pointer.

# include <stdio.h>
# include <conio.h>

void main()

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 38 3/2/2012 6:50:06 PM


Data Structures: Arrays 2.39

{
int sum=0,i=0,a[]={1,2,3,4,5};
clrscr();
printf("Elements Values Address\n\n");
while(i<5)
{
printf("a[%d]\t%5d\t%8u\n",i,*(a+i),(a+i)); sum=sum+*(a+i++);
}

printf("\nSum of Array Elements = %d",sum);


}

OUTPUT:
Elements Values Address
a[0] 1 4056
a[1] 2 4058
a[2] 3 4060
a[3] 4 4062
a[4] 5 4064

Sum of Array Elements = 15

Explanation:
In this program array name ‘a’ acts as pointer and variable ‘i’ is used for referring element
numbers. Using the for loop and expressions *(a+i) and (a+i) various elements and their
addresses are displayed respectively. In the ‘sum’ variable sum of all elements is obtained.

2.14 POINTERS AND TWO-DIMENSIONAL ARRAYS

A matrix can represent two-dimensional elements of an array. Here, the first argument is row number
and second is column number. To display the elements of two-dimensional array using pointer it is
essential to have ‘&’ operator as pre-fix with array name followed by element numbers, otherwise
compiler shows an error.

Example 2.33 Write a program to display array elements and their address using pointers.

# include <stdio.h>
# include <conio.h>

void main()
{

int i,j=1,*p;
int a[3][3]={{1,2,3},{4,5,6},{7,8,9}};
clrscr();
printf("\tElements of An Array with their addresses\n\n");

p=&a[0][0];

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 39 3/2/2012 6:50:06 PM


2.40 Data Structures Using C

for(i=0;i<9;i++,j++)
{
printf("%5d [%5u ]",*(p),p);
p++;

if(j==3)
{
printf("\n");
j=0;
}
}
}

OUTPUT:
Elements of an Array with their addresses.
1 [4052] 2 [4054] 3 [4056]
4 [4058] 5 [4060] 6 [4062]
7 [4064] 8 [4066] 9 [4068]

Explanation:
In this program two-dimensional array is declared and initialized. The base address of array
is assigned to integer pointer ‘p’. While assigning base address of two-dimensional array,
‘&’ operator is to be pre-fixed with array name followed by element numbers are necessary
otherwise compiler shows an error. The statement p = &a[0][0] is used in this context.
The pointer ‘p’ is printed and incremented in for loop till it prints entire array elements.
The if statement splits a line when three elements in each row are printed.

Example 2.34 Write a program to display array elements and their address. Use array name itself
as a pointer.

# include <stdio.h>
# include <conio.h>

void main()

int i;
int a[][3]={{1,2,3},{4,5,6},{7,8,9}};
clrscr();
printf("\tElements of An Array with their addresses. \n\n");

for(i=0;i<9;i++)
{
printf("%8u",&a[0][0]+i);
printf(" [%d]",*(&a[0][0]+i));

if(i==2 || i==5)

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 40 3/2/2012 6:50:06 PM


Data Structures: Arrays 2.41

printf("\n");

}
}

OUTPUT:
Elements of an Array with their addresses.
1 [4052] 2 [4054] 3 [4056]
4 [4058] 5 [4060] 6 [4062]
7 [4064] 8 [4066] 9 [4068]

Explanation:
The logic of the program is the same as the previous one. The only difference is that the array
name itself is used as pointer. The if statement inserts a line after displaying every three
elements.

2.15 ARRAY OF POINTERS

So far, we have studied array of different standard data types such as array of int, float, characters, etc. In
the same way the ‘C ’ language also supports array of pointers. It is nothing but a collection of addresses.
Here, we store address of variables for which we have to declare array as pointer.

Example 2.35 Write a program to store addresses of different elements of an array—using


array of pointers.

# include <stdio.h>
# include <conio.h>

void main()
{

int *arrp[3];
int arrl[3]={5,10,15},k;

for(k=0;k<3;k++)
arrp[k]=arrl+k;

clrscr();
printf("\n\tAddress Element\n");

for(k=0;k<3;k++)
{
printf("\t%u",arrp[k]);
printf("\t%7d \n",*(arrp[k]));
}
}

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 41 3/2/2012 6:50:06 PM


2.42 Data Structures Using C

OUTPUT:
Address Element
4060 5
4062 10
4064 15

Explanation:
In this program *arrp[3] is declared as array of pointer. Using first for loop addresses of
various elements of array ‘arr1[]’ are assigned to ‘*arrp[]’. The second for loop
picks up addresses from ‘*arrp[]’ and displays the value present at those locations. Here,
each element of ‘*arrp[]’ points to respective element of array ‘arr[]’. Table 2.1 shows
elements of array and their addresses using array of pointers.

Table 2.1 Array of Pointers in Memory


Element No. Array of Elements Element No. Array of Addresses
arr[0] 5 arrp[0] 4060
arr[1] 10 arrp[1] 4062
arr[2] 15 arrp[2] 4064

Example 2.36 Write a program to display address of elements and pointers.

# include <stdio.h>
# include <conio.h>

void main()
{
int a[5]={0,1,2,3,4};
int *p[5],i;

for(i=0;i<5;i++)
p[i]=a+i;

clrscr();

for(i=0;i<5;i++)
{
printf("\n\t%d at location",*(*p+i));
printf("\t%u at location ",*(p+i));
printf("%u",p+i);
}

printf("\n\n Integer requires 2 bytes, address require 4 bytes");


}
OUTPUT:

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 42 3/2/2012 6:50:06 PM


Data Structures: Arrays 2.43

0 at location 4036 at location 4046


1 at location 4038 at location 4050
2 at location 4040 at location 4054
3 at location 4042 at location 4058
4 at location 4044 at location 4062
Integer requires 2 bytes, address requires 4 bytes

Explanation:
In this program the first for loop assigns addresses of elements of integer array to pointer
array. The first printf() statement prints element, the second displays address of element
and the third displays address of the address, i.e. address of the pointer. Thus, it is clear from
the above example that integer requires two bytes and pointer requires four bytes.

2.16 POINTERS AND STRINGS

Example 2.37 Write a program to read string from keyboard and display it using character pointer.

#include <stdio.h>
#include <conio.h>
void main()
{
char name[15],*ch;
printf("Enter Your Name:");
gets(name);
ch=name;
/* store base address of string name */
while(*ch!='\0')
{
printf("%c",*ch);
ch++;
}
}

OUTPUT:
Enter Your Name: KUMAR
KUMAR

Explanation:
Here, the address of 0th element is assigned to character pointer ‘ch’. In other words, base
address of string is assigned to ‘ch’. The pointer ‘*ch’ points to the value stored at that
memory location and it is printed through printf() statement. After every increment of
‘ch’ the pointer goes to the next character of the string. When it encounters NULL character
the while loop terminates the program.

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 43 3/2/2012 6:50:06 PM


2.44 Data Structures Using C

Example 2.38 Write a program to find length of a given string including and excluding
spaces using pointers.

# include <stdio.h>
# include <conio.h>
void main()
{
char str[20],*s;
int p=0,q=0;
clrscr();
printf("Enter String:");
gets(str);
s=str;
while(*s!='\0')
{
printf("%c",*s);
p++;
s++;
if(*s==32) /* ASCII equivalnet of ' ' (space)is 32*/
q++;
}
printf("\nLength of String including spaces: %d",p);
printf("\nLength of String excluding spaces: %d",p-q);
}

OUTPUT:
Enter String: POINTERS ARE EASY
POINTERS ARE EASY
Length of String including spaces: 17
Length of String excluding spaces: 15

Explanation:
Here, the address of 0th element is assigned to character pointer ‘ch’. In other words, base
address of string is assigned to ‘ch’. The pointer ‘*ch’ points to the value stored at that
memory location and it is printed through printf() statement. After every increment of
‘ch’ the pointer goes to the next character of the string. When it encounters NULL character
the while loop terminates the program.

Example 2.39 Write a program to find length of a given string including and excluding
spaces using pointers.

# include <stdio.h>
# include <conio.h>
void main()
{
char str[20],*s;
int p=0,q=0;
clrscr();

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 44 3/2/2012 6:50:06 PM


Data Structures: Arrays 2.45

printf("Enter String:");
gets(str);
s=str;
while(*s!='\0')
{
printf("%c",*s);
p++;
s++;
if(*s==32) /* ASCII equivalent of ' ' (space)is 32*/
q++;
}
printf("\nLength of String including spaces: %d",p);
printf("\nLength of String excluding spaces: %d",p-q);
}

OUTPUT:
Enter String: POINTERS ARE EASY

POINTERS ARE EASY

Length of String including spaces: 17


Length of String excluding spaces: 15

Explanation:
This program is the same as the previous one. Here, the counter variables ‘p’ and ‘q’ are
incremented to count number of characters and spaces found in the string. The ASCII value of
space is 32. Thus, at the end of the program both the variables are printed.

Example 2.40 Write a program to interchange elements of character array using pointer.

# include <stdio.h>
# include <conio.h>
void main()
{
char *names[]={
"kapil",
"manoj",
"amit",
"amol",
"pavan",
"mahesh"
};
char *tmp;
clrscr();
printf("Original: %s %s",names[3],names[4]);
tmp=names[3];
names[3]=names[4];
names[4]=tmp;
printf("\nNew: %s %s",names[3],names[4]);
}

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 45 3/2/2012 6:50:06 PM


2.46 Data Structures Using C

OUTPUT:
Original: amol pavan
New: pavan amol

Explanation:
In this program character array *names [] is declared and initialized. Another character pointer
*tmp is declared. The destination name that is to be replaced is assigned to variable ‘*tmp’.
The destination name is replaced with source name and the source name is replaced with *tmp
variable. Thus, using simple assignment statements two names are interchanged.

SUMMARY
1. Array is a very popular and useful data structure used to store data elements in successive
manner. Array is a linear and homogenous data structure. Homogenous means same types
of elements are stored in it. It may be non-homogenous if structure is associated with it.
2. One-dimensional arrays having only one row of elements and elements are stored in suc-
cessive memory locations.
3. The various operations carried out with arrays are insertion, deletion, searching, sorting, etc.
4. Two-dimensional arrays can be thought of as rectangular display of elements with rows
and columns.
5. A three-dimensional arrays can be thought of as array of arrays.
6. The collection of characters, digits, and symbols enclosed within quotation marks are
called strings. Strings are always declared as character array. Like other type of arrays,
elements of character array are also stored in continuous memory location. Each
character array occupies one byte in memory. One different thing about strings is that,
the compiler automatically adds NULL (‘\0’) character at the end of string.

EXERCISES
A. Answer the following questions:

1. What are arrays?


2. How are elements of array stored?
3. What are one-dimensional arrays?
4. What are two-dimensional arrays?
5. Explain multi-dimensional array.
6. What are strings? How are they declared?
7. What is NULL character?

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 46 3/2/2012 6:50:06 PM


Data Structures: Arrays 2.47

8. Explain various operations with arrays.


9. What are sparse matrices?
10. Distinguish between character and integers arrays.

B. Attempt the following programs:

1. Write a program to declare and initialize a one-dimensional float type array. Display its
elements with memory addresses.
2. Write a program to read ten integers in an array and find the number of even and odd integers
in it.
3. Write a program to input a number containing five digits. Obtain cube of each digit and dis-
play the cubes of all digits on the screen.
4. Read the marks in physics, chemistry and mathematics obtained by ten students. Display the
top three students with their total marks.
5. Write a program to enter a four-digit number using array and arrange it in the reverse order.
6. Write a program to demonstrate use of two-dimensional array.
7. Write a program to access elements of an array using another pointer.
8. Write a program to declare a character array. Initialize it with the string and display the contents.
9. Write a program to demonstrate the use of multi-dimensional array.
10. Write a program to create array of structure objects. Read and display the data.

C. Select the appropriate option for each of the following questions:

1. Array elements are stored in


(a) successive memory locations (c) both (a) and (b)
(b) random memory locations (d) none of the above.
2. Accessing all elements of the array is known as
(a) transverse (c) deletion
(b) insertion (d) listing.
3. Merging of array elements means
(a) combining two or more arrays (c) interchanging elements of two arrays
(b) addition of elements of two arrays (d) none of the above.
4. Following one operation cannot be performed on arrays
(a) merging (c) deletion
(b) insertion (d) memory re-allocation.
5. Base address means
(a) address of 0th element (c) address of last element
(b) address of array name (d) none of the above.
6. Array elements are stored in
(a) random memory locations (c) both of the above.
(b) sequential memory locations

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 47 3/2/2012 6:50:06 PM


2.48 Data Structures Using C

7. A character array always ends with


(a) comma(,) (c) null character (\0)
(b) question mark(?) (d) Full stop (.).
8. Arrays can not be initialized if they are
(a) automatic (c) external
(b) static (d) none of the above
9. All the elements in the array must be
(a) initialized (c) none of the above.
(b) defined

D. What will be the output of the following programs?

1. 3.
#include <stdio.h> # include <stdio.h>
#include <conio.h> # include <conio.h>
void main() void main()
{ {
char nam[10],*h; int i;
printf("Enter Your Name:"); char name[10];
scanf("%s",&nam); clrscr();
h=nam; scanf("%s",name);
while(*h!='\0') for(i=0;i<10;i++)
{ {
printf("%c",*h); if(name[i]=='\0')
h++; exit(1);
} printf("%c",
} name[i]+3);
}
2.
}
# include <stdio.h>
# include <conio.h>

void main()
4.
# include <stdio.h>
{
# include <conio.h>
int x[5]={12,42,
26,18,80},a=0;
void main()
clrscr();
{
while(a<5)
char name[6]="DATA";
{
clrscr();
printf("\n%d",x[a]);
printf("%c",name);
a++;
printf("%s",name);
}
} }

M02_ASHOK NAMDEV KAMTHANE5067_01_SE_C02.indd 48 3/2/2012 6:50:06 PM


Chapter 3

Recursion

CHAP TER O U T LIN E


3.1 Introduction 3.7 The Towers of Hanoi
3.2 Types of Recursions 3.8 Advantages and Disadvantages
of Recursion
3.3 Rules for Recursive Function
3.9 Tail Recursion
3.4 Direct Recursion
3.10 Efficiency of Recursion
3.5 Indirect Recursion
3.6 Recursion Versus Iteration

3.1 INTRODUCTION

A function is a block of statement that can be used to perform a specific task. Figure 3.1 describes the various
parts of the function. A function has the following parts:
a. Function prototype declaration
b. Definition of a function (function declarator)
c. Actual and formal arguments
d. Return statement
e. Invoking function.

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 1 3/2/2012 6:50:35 PM


3.2 Data Structures Using C

void main ()
{
float sum (float, int); Function Prototype

float x,y=2.4;
int z=5; Actual Arguments

}
x=sum( y, z ); Function Call

} Formal Arguments

float sum (float j, int k) Function Declarator


{
return (j+k); Function Body
}

Return Statement

Figure 3.1 Parts of Function

3.1.1 Function Prototypes


We use many built-in functions. The prototypes of these functions are given in the respective header files.
We include them using # include directive. In C++, while defining user-defined functions, it is unavoid-
able to declare its prototype. A prototype statement helps the compiler to check the return and argument
types of the function.
A function prototype declaration consists of function’s return type, name, and arguments list. It tells
the compiler:
a. Name of the function
b. Type of value returned
c. The type and number of arguments.
When the programmer defines the function, the definition of function must be similar to its proto-
type declaration. If the programmer makes a mistake, the compiler flags an error message. The function
prototype declaration statement is always terminated with a semi-colon. The statements given below are
examples of function prototypes.

A. void show (void);


B. f loat sum ( float, int);
C. float sum ( float x, int y);

In example (A) the return type is void, i.e. the function will not return any value. The void functions are
always without return statement. The argument void indicates the function will not require any argument.
By default, every function returns an integer value. To return a non-integer value, the data type should
be mentioned in function prototype and definition. While writing definition of function, the return type
must be preceded by the function name and it is optional if return type is default (int).
In example (B) the prototype of function sum() is declared. Its return type is float and arguments are
float and integer type, respectively. It is shown in the Fig. 3.1.

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 2 3/2/2012 6:50:36 PM


Recursion 3.3

In example (C) with argument type, argument names are also declared. It is optional and not compulsory
to use the same variable name in the program.

3.1.2 Function Definition


The first line is called as function declarator and then function body follows it. The block of statements
followed by function declarator is called as function definition. The declarator and function proto-
type declaration should match with each other. The function body is enclosed within curly braces. The
function can be defined anywhere. If the function is defined before its caller, then its prototype declaration
is optional.

3.1.3 Function Call


A function is a latent body. It is activated only when a call to function is invoked. A function must be
called by its name followed by argument list enclosed in parenthesis and terminated by semi-colon.

3.1.4 Actual and Formal Argument


The arguments declared in caller function and given in the function call are called as actual arguments.
The arguments declared in the function declarator are known as formal arguments. For example,

void main()
{
x=sum( y, z );
}
Actual Arguments

float sum (float j, float k)


{ Formal Arguments
return (j+k)
}

Figure 3.2 Actual and Formal Arguments

As shown in Fig. 3.2, variable y and z are actual arguments and j and k are formal arguments. The
values of y and z are stored in j and k, respectively. The values of actual arguments are assigned to formal
arguments. The function uses formal arguments for computing.

3.1.5 The Return Statement


The return statement is used to return value to the caller function. The return statement returns only one
value at a time. When a return statement is encountered, the compiler transfers the control of the program
to caller function. The syntax of return statement is as follows:
return(variable name); or return variable name;

The parenthesis is optional.

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 3 3/2/2012 6:50:36 PM


3.4 Data Structures Using C

3.2 TYPES OF RECURSIONS

Recursion a little bit tough, but if we keep track of the program, in which sequence it is executing, it is easy
to understand. Recursion is one of the most dominant tools used in the programming technique. There
are various situations when we need to execute a block of statements for a number of times depending
on condition at that time recursion is useful. Recursion is used to solve a problem, which has iterations
in reverse order. Data structures also support recursion, for example, tree supports recursion. Various
programs are solved with the use of recursion. The major application of recursion is game programming
where series of steps can be solved with recursion.
When a function calls itself recursively it is known as recursion. Recursion is of two types:
1. Direct recursion
2. Indirect recursion.
The recursion in which the function calls itself is called direct recursion. In this type, only one function is
involved. In indirect recursion two functions call each other. Fig. 3.3 describes direct and indirect recursion.

int num ()
{

−−−
int sum ();
}
int num ()
{ int sum ()
{
−−−
−−−
int num (); num();
} }

a. Direct Recursion b. Indirect Recursion

Figure 3.3 Types of Recursions

Recursion is one of the applications of stack. Stacks are explained in the next chapter. There are several
problems in which without recursion their solution is lengthy.
The programming languages like C, C++ allow us to define user defined functions. Functions in the
programming languages are very useful, because by using function a separate block of statements can be
defined. This block can be invoked a number of times anywhere in the program. A function which can call
itself or another function and which eventually calls another function is known as recursive function.
Two essential conditions should be satisfied by a recursive function. First, every time a function should
call itself directly or indirectly. Second, the function should have a condition to stop the recursion. Other-
wise, an infinite loop is generated and the loop will not lose control.
Some people think that recursion is a very needless luxury in the programming language. Using itera-
tion one can solve the problems. However, in programming in some situation there is no substitute for
recursion.

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 4 3/2/2012 6:50:36 PM


Recursion 3.5

There are some problems associated with recursive function which are not present in the non-recursive
function. The recursive function can be invoked by itself or any other function. To make sure execution it
is very essential for the function to save the return address in order to return to proper location. Also, the
function has to save the formal and local variables.

Example 3.1 Write a program to calculate factorial of given number using recursion using
C statements.

# include <stdio.h>
# include <conio.h>

int fact(int);

void main()
{
int num,f;
clrscr();
printf("\n Enter a number:");
scanf("%d",&num);
f=fact(num);
printf("\n Factorial of %d is %d",num,f);
}

int fact(int f)
{
if(f==1) return f;
else return f*fact(f-1);
}

OUTPUT
Enter a number: 4
Factorial of 4 is 24

Explanation:
In this program fact()is a recursive function. The entered number is passed to function
fact(). When function fact()is executed, it is repeatedly invoked by itself. Every time a
function is invoked, the value of f is reduced by one and multiplication is carried. The recursive
function produces the numbers 4,3,2 and 1. The multiplication value of these numbers is taken
and returned to main()function.

3.3 RULES FOR RECURSIVE FUNCTION

1. In recursion, it is essential for a function to call itself, otherwise recursion will not take place, as shown
in Fig. 3.3.
2. Only user defined function can be involved in the recursion. Library function cannot be involved in
recursion because their source code cannot be viewed.

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 5 3/2/2012 6:50:36 PM


3.6 Data Structures Using C

3. A recursive function can be invoked by itself or by other function.


It saves return address in order with the intention that to return at
int num()
proper location when return to a calling statement is made. The
{
last-in-first-out nature of recursion indicates that stack data struc-
ture can be used to implement it. −−−
if (condition)
4. Recursion is turning out to be increasingly important in non-
numeric applications and symbolic manipulations. −−−
num();
5. To stop the recursive function it is necessary to base the recursion on
}
test condition and proper terminating statement such as exit() or
return must be written using if() statement as shown in the Fig. 3.4.
6. The user defined function main() can be invoked recursively.
To implement such recursion it is necessary to mention prototype of
Figure 3.4 Terminating Statement
function main(). An example in this regard is explained as follows:
in Recursion

Example 3.2 Write a program to call main () recursively.

# include <stdio.h>
# include <conio.h>
# include <process.h>

char str[]="Have a Good Day";


int x=0;

main();

void main()
{
switch(str[x])
{
case 'H':
clrscr();
default:
printf("%c",str[x]);
break;
case '\0':
exit(0);
break;
}
x++;
main();
}

OUTPUT
Have a Good Day

Explanation:
In this program main()function is invoked recursively. A prototype of function main()is given
before function definition. However, in normal practice it is not necessary to give prototype.
A recursive function must know its return type and number and type of the arguments passed.

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 6 3/2/2012 6:50:36 PM


Recursion 3.7

7. Any function can be called recursively. An example is illustrated as above.


8. When a recursive function is executed, the recursion calls are not implemented instantly. All the
recursive calls are pushed onto the stack until the terminating condition is not detected. As soon as
the terminating condition is detected, the recursive calls stored in the stack are popped and executed.
The last call is executed first then second, then third and so on.
9. During recursion, at each recursive call new memory is allocated to all the local variables of the recur-
sive functions with the same name.
10. At each call the new memory is allocated to all the local variables, their previous values are pushed
onto the stack and with its call. All these values can be available to corresponding function call when
it is popped from the stack.

3.4 DIRECT RECURSION

In this type, only one function is involved which calls itself until the given condition is true. Consider the
following program:

Example 3.3 Write a program call function main () and perform sum of first five numbers.

# include <stdio.h>
# include <process.h>
void main(int);
int x,s;
void main(x)

{
s=s+x;
printf("\n x=%d s=%d",x,s);
if(x==5) exit(0);
main(++x);
}

OUTPUT
x=1 s=1
x=2 s=3
x=3 s=6
x=4 s=10
x=5 s=15

Explanation:
In this program variable x and s are declared outside main(). Initially their values are zero.
The prototype of function main() is declared. This is essential because while calling, the
compiler checks the function with its prototype. It is advance information regarding the function.
The variable x is passed to the function main(). The variable x is added to variable s until
the value of x reaches to five. When x reaches to five, the program terminates. The steps of
recursive function main(++x) are shown in Table 3.1.

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 7 3/2/2012 6:50:36 PM


3.8 Data Structures Using C

Table 3.1 Steps of Recursive Function


Function Call Value of x Value of s (sum)
main(1) x =1 s = 1 (0 + 1)
main(2) x =2 s = 3 (2 + 1 + 0)
main(3) x =3 s = 6 (3 + 2 + 1 + 0)
main(4) x =4 s = 10 (4 + 3 + 2 + 1 + 0)
main(5) x =5 s = 15 (5 + 4 + 3 + 2 + 1 + 0)

Example 3.4 Write a program to calculate triangular number using recursion.

# include <stdio.h>
# include <conio.h>
# include <process.h>

void main()
{
int trinum(int);
int t,x;
clrscr();
printf("\n Enter a Number: ");
scanf("%d",&x);
t=trinum(x);
printf("\n Triangular Number of %d is %d",x,t);
}

int trinum(int x)
{
int f=0;
if(x==0) return f;
else f=f+x+trinum(x-1);
return f;
}

OUTPUT
Enter a Number: 4
Triangular Number of 4 is 10

Explanation:
In this program a function trinum() is defined which calls itself. An integer is entered through
the keyboard and it is stored in the variable x. The function trinum() calls itself and the
argument passed to this called function is one less than the value of x. The return values are
added to variable f. When value of x becomes zero, the recursion ends and the total is returned
to variable t in function main(). The value of t is triangular number of the entered number,
which is nothing but the sum of all the integers between 1 to the entered number. The recursive
function is called repetitively by itself without completing the execution of previous call. When

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 8 3/2/2012 6:50:36 PM


Recursion 3.9

program ends and the control is about to return to caller function the number of times the
return statement executed is equal to the number of times the function is called recursively.
The compiler keeps track of how many times a function is executed. To see, these points
execute the program in single step by pressing F7 key.

When a function returns three actions are done. The return address is placed in the safe location. The
data stored in local variables of function are freed. The previously saved address is retrieved. The return
value of function is returned and put in the safe location and calling program receives it. Normally, the
location is a hardware register, which is placed in CPU for the same purpose.
As shown in Fig. 3.5 the main function call invokes the function B. The function B invokes the
function C and again C invokes D. The figure shows the control is present in the function D. In every
function, a location is reserved for storage of return address. The return address location of function D
contains the address of statement in C immediately after the function invocation statement.

Function B Function C Function D

main () Return Return Return


Address Address Address

Call on B
Call on C Call on D

Figure 3.5 Functions Calling One Another

Whenever a recursive function invokes itself, new data variables are created and memory is allocated
for data. The data area contains all local variables and return address. In the recursion function, the data
area is not connected only with the function but closely associated with the particular function call.
In every call new data area is allocated and the particular function’s data area contains information about
recent call. Every time control returns, the data area is de-allocated or freed and the former data area turn
into current.
The recursion in C and C++ language is more expensive as compared to non-recursive function. It takes
not only more space but it is also time consuming. In some system program such as compiler or operating
system, if program contains recursive function it will be executed many a time. In such a case, an alternate
non-recursive function may be defined.

Example 3.5 Write a program to define to a recursive function to calculate factorial of a number.

# include <stdio.h>
# include <conio.h>

void main()
{
int fact(int);
int f,n;
clrscr();

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 9 3/2/2012 6:50:37 PM


3.10 Data Structures Using C

printf("\n Enter a Number:");


scanf("%d",&n);
f=fact(n);
printf("Factorial of Number %d: %d",n,f);
}

int fact(int j)

{
int f=1;
if(j==1)
return 1;
else
f=j*fact(j-1);
return f;
}

OUTPUT

Enter a Number: 5
Factorial of Number 5: 120

Explanation:
In this program function fact() is defined and the number entered by the user is passed to
the function fact(). In the function fact() the if statement checks the value of variable j
(formal argument of n). If the value is 1 the return statement returns 1 otherwise the fact()
function is called. At this point, the recursion actually begins. When the function fact() is
recursively invoked the value of j is decreased by one and then passed.

3.5 INDIRECT RECURSION

In this type of recursion two or more functions are involved in the recursion. The indirect recursion
does not make any overhead as direct recursion. When control exits from one function and enters into
another function, the local variables of former function are destroyed. Hence, memory is not engaged.
The following program explains the indirect recursion.

Example 3.6 Write a program to demonstrate recursion between two functions.

# include <stdio.h>
# include <conio.h>
# include <process.h>

int s;
void show(void);

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 10 3/2/2012 6:50:37 PM


Recursion 3.11

void main()
{
if(s==5) exit(0);
show();
}
void show()
{
printf("%d",s);
s++;
main();
}

OUTPUT
0 1 2 3 4

Explanation:
In this program two user defined functions are defined main() and show(). The s is global
variable. The main() function invokes show() function and the show() function invokes
main() function. The value of s is increased and displayed. When value of s reaches to 5 the
program is terminated.

Example 3.7 Write a program to display numbers in several rows.

# include <stdio.h>
# include <conio.h>
# include <process.h>

int s;
void show(void);

void main()
{
if(s==0)
clrscr();
if(s==10)
exit(0);
show();
}

void show()
{
int j;
for(j=0;j<=s;j++)
printf("%d",j);
printf("\n");
s++;
main();
}

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 11 3/2/2012 6:50:37 PM


3.12 Data Structures Using C

OUTPUT
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
0 1 2 3 4 5
0 1 2 3 4 5 6
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7 8 9

Explanation:
This program is same as the last one. Here, depending on the value of variable s, the iteration of
for loop is performed.

3.6 RECURSION VERSUS ITERATION

We have studied both recursion and iteration. They can be applied to a program depending upon the
situation. Table 3.2 explains the differences between recursion and iteration.

Table 3.2 Recursion Versus Iteration


Recursion Iteration
Recursion is the term given to the mechanism of The block of statement executed repeatedly using loops.
defining a set or procedure in terms of itself.
A conditional statement is required in the body of The iteration control statement itself contains statement for
the function for stopping the function execution. stopping the iteration. At every execution, the condition is
checked.
At some places, use of recursion generates extra All problems can be solved with iteration.
overhead. Hence, better to skip when easy solution
is available with iteration.
Recursion is expensive in terms of speed and Iteration does not create any overhead. All the
memory. programming languages support iteration.

Figure 3.6 illustrates the iterative process.

Initialization The variables involved in the iteration process are initialized. These variables are used to
decide when to end the loop.

Loop continuation condition The loop variable is used to decide whether to continue or discontinue the
loop. When the condition is true, control goes to computation blocked or else it exits.

Computation The required processing or computation is carried out in this block.

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 12 3/2/2012 6:50:37 PM


Recursion 3.13

Entry

Initialization

False
Condition Exit
?

True

Update Computation

Figure 3.6 Iterative Processes

Update The decision argument is changed and shifted to next iteration.


The common algorithm for any kind of recursive function is shown in Fig. 3.7.

Preliminary part The use of this block is to store the local variables, formal arguments and return
address. The end-part will restore these data. Only recently saved arguments, local variables and return
address are restored. The variables last saved are restored first.

Body If the test condition is satisfied, it performs the complete processing and control passes to end-
block. If not, partial processing is performed and a recursive call is made. The body also contains call
to itself and one or more calls can be made. Every time a recursive call is made, the preliminary part of
the function saves all the data. The body also contains two processing boxes i.e. partial processing and
complete processing. In some programs, the result can be calculated after complete processing. For this,
the recursive call may not be required. For example, we want to calculate factorial of one. The factorial
of one is one. For this, it is needless to call function recursively. It can be solved by transferring control to
complete processing box.
In other case, if five is given for factorial calculation, the factorial of five can be calculated in step 8.
Hence, the function will be called recursively. Every time one step is solved, i.e. 5*4*3 and so on. Hence,
it is called partial processing.

Depth of Recursion The recursion function calls itself infinite times. If we want to calculate factorial
of five then we can easily estimate the number of times the function would be called. In this case, we can
determine the depth of the recursive function. In complex program, it is difficult to determine the number
of calls of recursive function.

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 13 3/2/2012 6:50:37 PM


3.14 Data Structures Using C

Entry

Preliminary part

Store local variables,


formal arguments,
return address

Condition
Check Partial
? Processing Body

Function
Complete call to
Processing itself

Restore previously
stored local variables,
formal parameters and
return address.
End-part

Exit

Figure 3.7 Recursive Process

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 14 3/2/2012 6:50:37 PM


Recursion 3.15

3.7 THE TOWERS OF HANOI

The Tower of Hanoi has historical roots in the ceremony of the ancient tower of Brahma. There are n disks
of decreasing sizes mounted on one needle as shown in the Fig. 3.8(a). Two more needles are also required
to stack the entire disk in the decreasing order. The use of third needle is for impermanent storage. While
mounding the disk, following rules should be followed.
1. At a time only one disk may be moved.
2. The disk may be moved from any needle to another needle.
3. No larger disk may be placed on the smaller one.
Our aim is to move the disks from A to C using the needle B as an intermediate by obeying the
above three conditions. Only top-most disks can be moved to another needle. The following figures and
explanation clear the process of Tower of Hanoi stepwise.
In Fig. 3.8 (a), the three needles are displayed in the initial state. The needle X contains three disks and
there are no disks on needle Y and Z.
In Fig. 3.8 (b), the top-most disk is moved from needle X to Z. The arrow indicates the movement of
disk from one needle to another needle.
In Fig. 3.8 (c), the disk from the X needle moves to the Y needle.
In Fig. 3.8 (d), the disk from Z needle moves to Y needle. Needle Y has two disks.
In Fig. 3.8 (e), the disk from the X needle moves to the Z needle. Now there is no disk in the X needle.
In Fig. 3.8 (f ), the disk from the Y needle moves to the X needle.
In Fig. 3.8 (g ), the disk from the Y needle moves to the Z needle. The Y needle contains no disk.
In Fig. 3.8 (h ), the disk from the X needle moves to the Z needle. Thus, the Z needle contains all the
three disks of the X needle shown in Fig. 3.8 (a). Thus, the problem is solved.

X Y Z X Z

Figure 3.8 (a) Towers of Hanoi Figure 3.8 (b) Towers of Hanoi

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 15 3/2/2012 6:50:37 PM


3.16 Data Structures Using C

X Y Z X Y Z

Figure 3.8 (c) Towers of Hanoi Figure 3.8 (d) Towers of Hanoi

X Y Z X Y Z

Figure 3.8 (e) Towers of Hanoi Figure 3.8 (f) Towers of Hanoi

X Y Z X Y Z

Figure 3.8 (g) Towers of Hanoi Figure 3.8 (h) Towers of Hanoi

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 16 3/2/2012 6:50:37 PM


Recursion 3.17

The above process is summarized as follows:


1. The three needles are displayed in the initial state.
2. The needle X contains three disks and there are no disks on needle Y and Z.
3. The top-most disk is moved from the needle X to Z
4. The disk from the X needle moves to the Y needle.
5. The disk from the Z needle moves to the Y needle.
6. The disk from the X needle moves to the Z needle.
7. The disk from the Y needle moves to the X needle.
8. The disk from the Y needle moves to the Z needle.
9. The disk from the X needle moves to the Z needle.

Example 3.8 Write a program to illustrate Towers of Hanoi.

# include <conio.h>
# include <stdio.h>
void hanoi(int,char,char,char);
main()
{
int num;
clrscr();
printf("\n Enter a Number:");
scanf("%d",&num);
clrscr();
hanoi(num,'A','C','B');
}
void hanoi( int num, char f_peg,char t_peg, char a_peg)
{
if(num==1)
{
printf("\nMove disk 1 from Needle %c to Needle %c",
f_peg,t_peg);
return;
}
hanoi(num-1,f_peg,a_peg,t_peg);
printf("\nMove disk %d from Needle %c to Needle %c",num,
f_peg,t_peg);
hanoi(num-1,a_peg,t_peg,f_peg);
}

Output
Enter a number:3
Move disk 1 from Needle A to Needle C
Move disk 2 from Needle A to Needle B
Move disk 1 from Needle C to Needle B
Move disk 3 from Needle A to Needle C
Move disk 1 from Needle B to Needle A
Move disk 2 from Needle B to Needle C
Move disk 1 from Needle A to Needle C

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 17 3/2/2012 6:50:38 PM


3.18 Data Structures Using C

Explanation:
In the above program numbers of disks are entered. The function Hanoi() is invoked from main().
The A, B and C are needles. If value of num is one, the disk is transferred from A to C and program
ends. If the value of num is greater than one, then the Hanoi() function invokes itself recursively,
every time value of num is decreased by one. The output of the program is shown as above.

3.8 ADVANTAGES AND DISADVANTAGES OF RECURSION

Advantages of recursion,
1. Sometimes, in programming a problem can be solved without recursion, but at some situations in
programming it is must to use recursion. For example, a program to display the list of all files of the
system cannot be solved without recursion.
2. The recursion is very flexible in data structure like stacks, queues, linked list and quick sort.
3. Using recursion, the length of the program can be reduced.
Disadvantages of recursion,
1. It requires extra storage space. The recursive calls and automatic variables are stored on the stack.
For every recursive call separate memory is allocated to automatic variables with the same name.
2. If the programmer forgot to specify the exit condition in the recursive function, the program
will execute out of memory. In such a situation user has to press ctrl + break to pause or stop the
function.
3. The recursion function is not efficient in execution speed and time.
4. If possible, try to solve problem with iteration instead of recursion.

3.9 TAIL RECURSION

In this chapter we have studied the recursion and we can say that recursion is a method in which set of
process is given in terms of itself. Recursive function is invoked by itself and this function call is given
in the same function body. If the function call statement is the last statement in the function body, this
recursion is called tail recursion. In tail recursion, we can use return value as a parameter for the function.
All the functions are maintained using stack, however, in this type, it will not push new function call to
stack but it will replace the value of previous call with new call. This approach provides decreased stack
implementation time and gives faster execution. The program 3.7 is an example of tail recursion.

3.10 EFFICIENCY OF RECURSION

We have studied both advantages and disadvantages of recursion. We have also studied the iteration which
is an alternative to recursion. The major overhead of recursion is the memory it occupies and execution
time. A non-recursive function will require minimum memory and less time for execution as compared
with recursive function. The recursive function uses stack to push and pop the local variables. In non-
recursive function the above push and pop operations with stack can be skipped. However, at some
situation in programming use of recursion is must. If the part of program is to be invoked frequently,
in such a case it is better to develop non-recursive function.

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 18 3/2/2012 6:50:38 PM


Recursion 3.19

SUMMARY
1. A function is a block of statement that can be used to define to perform a special task.
2. A function prototype declaration consists of function’s return type, name, and arguments list.
It tells the compiler, a) name of the function, b) type of value returned, c) the type and number
of arguments.
3. When a function calls itself is called direct recursion.
4. When a function calls another function it is called indirect recursion.
5. The user defined function main() can be invoked recursively. The library functions cannot be
invoked recursively.
6. Constructor is a special member function used to initialize the data members. The con-struc-
tor can also be invoked recursively.
7. Whenever a recursive function invokes itself, every time new data variables are created and
data area and memory is allocated. The data area contains all local variables and return address.
In the recursion of function, the data area is not connected only with the function but closely
associated with the particular function call.

EXERCISES
A. Answer the following questions:
1. Explain recursion process in detail.
2. Differentiate between direct and indirect recursions.
3. Differentiate between recursion and iteration.
4. Mention the advantages and disadvantages of recursions.
5. List the three rules of tower of Hanoi problem.
6. What is depth of recursion?
7. Explain tail recursion.
B. Attempt following program with recursion:
1. Write a program to compute the nth number of fibonacci series.
2. Write a program to reverse a number.
3. Write a program to display list of prime numbers up to 15.
4. Write a program to display a message “Hello” for 10 times.
5. Write a program to call function main() recursively.
6. Write a program to demonstrate tail recursion.
7. Consider the following list
58, 69, 59, 12, 34, 78, 25, 98, 20
a. Find elements 34, 25 and 20 using recursion

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 19 3/2/2012 6:50:38 PM


3.20 Data Structures Using C

b. Caculate product of all elements of array


c. Sum of all the elements.
C. Select the appropriate option for each of the following questions:
1. When a function calls itself is called
(a) Recursion (c) function
(b) iteration (d) none of the above.
2. In indirect recursion a function calls
(a) another function (c) only main () function
(b) itself (d) none of the above.
3. In tower of Hanoi the following one condition is not applicable:
(a) at a time only one disk may be moved
(b) the disc may be moved from any needle to another needle
(c) No larger disk may be placed on the smaller one
(d) The disks can be placed in any order.
4. The function declarator is used to
(a) declare formal arguments
(b) declare function prototype
(c) function call
(d) all of the above.

D. What will be the output of the following programs:


1. else
# include <stdio.h> return main();
# include <conio.h> }
main()
3.
{
# include <stdio.h>
int main(void);
# include <conio.h>
printf("\n Hello");
int main()
return(main());
{
}
int num(void);
2. clrscr();
# include <stdio.h> int n[]={num()};
# include <conio.h> for(int i=0;i<3;i++)
int x; printf("%d",n[i]);
int main() return 0;
{ }
clrscr(); int num()
int num(void); {
printf("%d",num()); int x;
return 0; printf("\n Enter
} a number:");
int num() scanf("%d",&x);
{ if(x==0)
x++; return x;
if(x>8) return x; num();

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 20 3/2/2012 6:50:38 PM


Recursion 3.21

return x; void show()


} {
int i,j;
4.
for(i=0;i<=5;i++)
# include <stdio.h>
for(j=0;j<=i;j++)
# include <conio.h>
printf("%d",j);
void show(void); printf("\n");

void main() }
{
clrscr();
show();
}

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 21 3/2/2012 6:50:38 PM


This page is intentionally left blank.

M03_ASHOK NAMDEV KAMTHANE5067_01_SE_C03.indd 22 3/2/2012 6:50:38 PM


Chapter 4

Stacks

CHAP TER O U T LIN E


4.1 Introduction 4.4 Operations on Stack
4.2 Stack-related Terms 4.5 Pointers and Stack
4.3 Stack Implementation 4.6 Representation of Arithmetic Expressions

4.1 INTRODUCTION

In this chapter, we will study one of the most important simple data structures ‘stack’. Stack is an important
tool in programming languages. Stack is one of the most essential linear data structures. Implementation
of most of the system programs is based on stack data structure. We can insert or delete an element from a
list, which takes place from one end. The insertion of element onto the stack is called as “push” and deletion
operation is called “pop”, i.e. when an item is added to the stack the operation is called “push” and when it
is removed the operation is called “pop”. Due to the push operation from one end, elements are added to
the stack, the stack is also known as pushdown list. The most and least reachable elements in the stack are
respectively known as the “top” and “bottom” of the stack. A stack is an arranged collection of elements into
which new elements can be inserted or from which existing new elements can be deleted at one end. Stack is
a set of elements in a last-in-first-out technique. As per Fig. 4.1 the last item pushed onto the stack is always
the first to be removed from the stack. The end of the stack from where the insertion or deletion operation
is carried out is called top. In Fig. 4.1(a) a stack of numbers is shown.
As shown in Fig. 4.1(a) the stack is based on the rule last-in-first-out. The element appended lastly is
deleted first. If we want to delete element 3 it is necessary to delete the top elements 5 and 4 first.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 1 3/2/2012 6:51:05 PM


4.2 Data Structures Using C

Top of
5 the stack

Figure 4.1 (a) Stack Figure 4.1 (b) A Pot with Plates

In Fig. 4.1 (b), you can see a pot containing plates kept one above the other. Plates can be inserted or
removed from the top. The top plate can be removed first in case pop operation is carried out, otherwise
plates are to be added on the top. In other words, the removal operation has to be carried out from the
top. Thus, placing or removing takes place from top, i.e. from the same end.

4 4 4

3 3 3 3 3

2 2 2 2 2 2 2

1 1 1 1 1 1 1 1 1

push pop

Figure 4.2 Working of Stack

As shown in the first half portion of Fig. 4.2, first integer 1 is inserted and then 2,3,4 and 5 are pushed
on to the stack. In the second half portion of the same figure, the elements are deleted ( pop) one by one
from the top. The elements are deleted in the order from 5 to 1. The insertion and deletion operation is
carried out at one end (top). Hence, the recently inserted element is deleted first. If we want to delete a
particular element of the stack, it is necessary to delete all the elements present above that element. It is
not possible to delete element 2 without deleting elements 5,4 and 3. The stack expands or shrinks with
the passage of time. In the above example, the stack initially expands until element 5 is inserted and then
shrinks after removal of elements. There is no higher limit on the number of
elements to be inserted in the stack. The total capacity of stack depends on
memory of the computer.
In practical life, we come across many examples based on the principle
of stack.
Fig. 4.3 illustrates the stack of books that we keep in the order. Whenever
we want to remove a book the removal operation is made from the top or
new books can be added at the top. Figure 4.3 Stack of Books

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 2 3/2/2012 6:51:06 PM


Stacks 4.3

Another example of stack that can be cited is a railway system for shunting the trains. Figure 4.4 shows
a picture of a railway system. The incoming trains arrive in a sequence in the stack. The last entered train
in the stack leaves first and it will be placed at first on the outgoing track.

Incoming Trains Outgoing Trains

STACK

Figure 4.4 A Railway Track

4.2 STACK-RELATED TERMS

Stack: Stack is a memory portion, which is used for storing the elements. The elements are stored based
on the principle of last-in-first-out. In the stack the elements are kept one above the other and its size is
based on the memory.
Top: The top of the pointer points to the top element in the stack. The top of the stack indicates its
door from where elements are entered or deleted. The stack top is used to verify stack’s current position,
i.e. underflow, overflow, etc. The top has value 0 when the stack is empty. Some programmers assign
−1 to the top as initial value. This is because when the element is added, the top is incremented and it
would become zero. The stack is generally implemented with the help of an array. In an array, counting
of elements begins from 0 onwards. Hence, on the similar grounds stack top also begins from 0 and it
is convenient to assign −1 to top as initial value.

Stack Underflow: When there is no element in the stack or stack holds elements less than its capacity, the
status of stack is known as stack underflow. In this situation, the top is present at the bottom of the stack.
When an element is pushed, it will be the first element of the stack and top will be moved one step up.

Stack Overflow: When the stack contains equal number of elements as per its capacity and no more
elements can be added, the status of stack is known as stack overflow. In such a position, the top rests at
the highest position.

Storage: A function containing local variables and constants are stored in stack. Only global variables
are stored in a stack frame.

Stack Frames: This data structure holds all formal arguments; return address and local variables on the
stack at the time when function is invoked.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 3 3/2/2012 6:51:06 PM


4.4 Data Structures Using C

4.2.1 Representation of Stack


The stack is represented in various ways. The stack can be shown as completely empty or fully filled or filled
with few elements. When stack has no element, it is called empty stack which is shown in Fig. 4.5 (a). The
stack with completely filled elements is shown in the Fig. 4.5 (b) and no further elements can be inserted.
A top pointer maintains track of the top elements as shown in Fig. 4.5 (c). For empty stack, the top
value is zero. When stack has one element the value of top is one. Whenever an element is inserted ( push
operation) in the stack the value of pointer top is incremented by one. In the same manner, the value of
pointer is reduced when an element is deleted from the stack ( pop operation). The push operation can be
applied to any stack, but before applying pop operation on the stack, it is necessary to make sure that the
stack is not empty. If a pop operation is performed on empty stack, it results in underflow.

2 2 Top

3 3

4 4 Bottom

a. Empty Stack b. Filled Stack c. Stack

Figure 4.5 Representation of Stack

Stack is very helpful in every ordered and chronological processing of functions. The most useful appli-
cation of stack is in recursion (explained in previous chapter). It saves memory space. The mechanism of
stack last-in-first-out (LIFO) is commonly useful in applications such as manufacturing and accounting
calculations. It is a well-known accounting concept.

4.3 STACK IMPLEMENTATION

The stack implementation can be done in the following two ways:

4.3.1 Static Implementation


Static implementation can be achieved using arrays. Though, it is a very simple method, it has few limita-
tions. Once a size of an array is declared, its size cannot be modified during program execution. It is also
inefficient for utilization of memory. While declaration of an array, memory is allocated which is equal
to array size. The vacant space of stack (array) also occupies memory space. In both cases, if we store less
argument than declared, memory is wasted and if we want to store more elements than declared, array
cannot be expanded. It is suitable only when we exactly know the number of elements to be stored.

4.3.2 Dynamic Implementation


Pointers are used for implementation of stack. The linked list is an example of this implementation.
The limitations noticed in static implementation can be removed using dynamic implementation. The

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 4 3/2/2012 6:51:06 PM


Stacks 4.5

dynamic implementation is achieved using pointers. Using pointer implementation at run time there is no
restriction on the number of elements. The stack may be expandable. The memory is efficiently utilized
with pointers. Memory is allocated only after element is pushed to the stack. Both the above implementa-
tions are illustrated with suitable examples in the next section.

4.4 OPERATIONS ON STACK

The following fundamental operations on stack can be carried out through static implementation called
array implementation. Operation on stack is also possible with the pointers, which is called dynamic
implementation. We will perform the following operations on the stack:
1. Creating a stack
2. Checking stack—either empty or full
3. Initializing a stack
4. Insert (push) an element in the stack
5. Delete (pop) an element from the stack
6. Access the top element
7. Display elements of stack
8. Status: to identify present position of stack.
Some terms relevant to the stack operations are narrated below.

Push The procedure of inserting a new element to the top of the stack is known as push operation. After
every push operation, the top is incremented by one. When the array is full (if static implementation is
applied) the status of stack is full and this condition is called as stack overflow. In such a case, no further
element can be inserted. After every push operation, the new element rests at the top. Fig. 4.6 (a) shows
the push operation.

8 TOP
5 TOP
5
2 TOP 2
2

Empty push (2) push (5) push (8)


stack

Figure 4.6 (a) Push Operation with Stack

Pop The procedure of removing element from the top of the stack is called as pop operation. After
every pop operation, the top is decremented by one. If there is no element in the stack, it is called as
empty stack or stack underflow. In such a case, pop operation cannot be applied. Fig. 4.6 (b) illustrates
the pop operation.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 5 3/2/2012 6:51:06 PM


4.6 Data Structures Using C

8 TOP
5 5 TOP
2 2 2 TOP
Stack Initially pop(8) pop(2)

EMPTY
STACK

Figure 4.6 (b) Pop Operation with Stack

The stack can be supposed as a one-dimensional array. The various operations listed above can be car-
ried out with one-dimensional array. The following programs explain the operations listed above.
As mentioned earlier, one-dimensional array can be used as stack. We can add elements in the one-
dimensional array. Using if statement we can check whether the stack is empty or full. Consider the
following programs.

Example 4.1 Write a program to explain working of stack using array implementation.

# include <stdio.h>
# include <conio.h>
# include <process.h>

void main()
{
int j,stack[5]={0};
int p=0;
clrscr();
printf("Enter Elements, put zero to exit: \n");

while(1)
{
scanf("%d",&stack[p]);
if(stack[p]==0)

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 6 3/2/2012 6:51:06 PM


Stacks 4.7

{
printf("\n By choice terminated: ");
exit(0);
}
p++;

if(p>4)
{
printf("Stack is full \n");
break;

}
else
printf("Stack is empty\n");
}

printf("\n Elements of stack are: ");


for(j=0;j<5;j++)
printf(" %d ",stack[j]);
}

OUTPUT
Enter Elements, put zero to exit:
4
Stack is empty
2
Stack is empty
6
Stack is empty
8
Stack is empty
3
Stack is full
Elements of stack are: 4 2 6 8 3

Explanation:
In this program, an array stack [5] is declared. Using while loop, elements are entered
through the keyboard and placed in an array. The value of variable p is initially zero. The
variable p increases in every iteration. The variable p acts as a top of stack. The if statement
checks the value of p. If the value of p is greater than four it means that, the stack is full and no
more elements can be added. When value of p is less than four it means more elements can
be inserted in the stack. The for loop and printf statements display the array elements. In
stack random insertion or deletion of element is not possible (Though in array it is possible,
but here keep in mind that we are treating an array as a stack. Hence, we have to follow the
restrictions that exist in stack implementation). If we want to delete any particular element,
we have to delete every element present before that element. Example 4.2 explains deletion
of elements.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 7 3/2/2012 6:51:06 PM


4.8 Data Structures Using C

Example 4.2 Write a program to store elements in the stack. Delete the specified element.

# include <stdio.h>
# include <conio.h>

void main()
{
int j,stack[5];
int p=0;
clrscr();
printf("Enter Elements
put zero to exit: \n");

while(1)
{
scanf("%d",&stack[p]);
if(stack[p]==0)
break;
p++;

if(p>4)
{
printf("Stack is full \n"); break;
}
}

printf("\nStack elements are: ");

for(j=0;j<5;j++)
printf(" %d ",stack[j]);
printf("\n Enter element position to delete: ");
scanf("%d",&p);
p−−;
for(j=4;j>=p;j−−)
stack[j]=NULL;
printf("Stack elements are:");

for(j=0;j<5;j++)
printf(" %d ",stack[j]);
getch();
}
OUTPUT
Enter Elements put zero to exit:
8
9
4
5
3
Stack is full
Stack elements are: 8 9 4 5 3
Enter element position to delete: 3
Stack elements are: 8 9 0 0 0

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 8 3/2/2012 6:51:06 PM


Stacks 4.9

Explanation:
In this program, as usual, elements are entered and stored in the stack. The element number
that is to be deleted from the stack will be entered from the keyboard. Recall that in a stack,
before deleting any element, it is compulsory to delete all elements before that element. In this
program, the elements before a target element are replaced with value NULL (0). The elements
after target element are kept as it is. Recall that when an element is inserted in the stack the
operation is called “push.” When an element is deleted from the stack the operation is “pop”.
Example 4.3 explains the push and pop operations.

Example 4.3 Write a simple program to demonstrate push () and pop () operations.

# include <stdio.h>
# include <conio.h>

static int stack[10], top=−1;

void main()
{
void push(int);
void pop(void);
void show(void);
clrscr();
printf("\n\n push operation: ");

push(5);
show();
push(8);
show();
push(9);
show();
printf("\n\n pop operation: ");
show();
pop();
show();
pop();
show();
}
void push(int j)
{
top++;
stack[top]=j;
}

void pop()
{
stack[top]=0;
top−−;
}

void show()

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 9 3/2/2012 6:51:06 PM


4.10 Data Structures Using C

{
int j;
printf("\n stack elements are: ");
for(j=0;j<10;j++)
stack[j]!=0 ? printf(" %d ",stack[j]): printf("");
}

OUTPUT
push operation:
stack elements are: 5
stack elements are: 5 8
stack elements are: 5 8 9

pop operation:
stack elements are: 5 8 9
stack elements are: 5 8
Stack elements are: 5

Explanation:
In this program stack[ ] and top variables are declared as static. The variable top is
initialized with −1. It is not necessary to declare top as static. The push() operation inserts
an element into the stack. The next element pushed is displayed after the first element and so
on. The pop() operation removes the element from the stack. The last element inserted is
firstly deleted. In the output the element 9 is deleted first as it is entered at last. Then, element
8 is removed. At last, the stack holds only one element having number 5.

Example 4.4 Write a program to perform pop and push operation on the stack.

# include <stdio.h>
# include <conio.h>
# include <process.h>

int ch,p,z=6,top=0,stack[7],c;

void main()
{
void make();
void push();
void pop();
void show();
clrscr();
while(ch<5)
{
printf("\n1] Stack creation");
printf("\n2] Insert element");
printf("\n3] Delete Element");

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 10 3/2/2012 6:51:07 PM


Stacks 4.11

printf("\n4] Display Element");


printf("\n5] Exit\n");
printf("Enter the choice:- ");
scanf("%d",&ch);

switch(ch)

{
case 1: make();
continue;
case 2: push();
continue;
case 3: pop();
continue;
case 4: show();
continue;
default: exit(0);
}
}
}

void make()
{
printf("\n Enter number of elements in the stack(<7): ");
scanf("%d",&c);
for(top=0;top<c;++top)
{
printf("Enter Element[%d]:- ",top);
scanf("%d",&stack[top]);
}
}
void push()
{
if(top>=z)
{
printf("\n Stack is full");
getch();
}
else
{
printf("\n Enter number to be pushed:-");
scanf("%d",&stack[top]);
top++;
}
}

void pop()
{
if(top<=0)
{
printf("\nThe stack is empty ");

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 11 3/2/2012 6:51:07 PM


4.12 Data Structures Using C

getch();
}
else
top−−;
}

void show()
{
for(p=top-1;p>=0;−−p)
printf(" %d ",stack[p]);
}

OUTPUT

1] Stack creation
2] Insert element
3] Delete Element
4] Display Element
5] Exit
1

Enter number of elements in the stack(<7): 4


Enter Elements: 1 2 3 4
1] Stack creation
2] Insert element
3] Delete Element
4] Display Element
5] Exit
4
0 4 3 2 1

1] Stack creation
2] Insert element
3] Delete Element
4] Display Element
5] Exit

Explanation:
In this program, few variables and array stack[] are declared globally so that every program
can access them. Functions make(), push(), void pop() and void show() are defined.
When the user selects first option, the user is prompted to enter the number of elements.
Immediately followed by this, the user has to enter choice by entering the integer number. These
integers are stored in the array stack[]. The user can see the stack elements by selecting
fourth choice on the screen. When delete operation is performed, the top element of the stack is
deleted. The user can confirm this operation by selecting display element operation. When insert
operation is selected, the entered element is inserted at the top of the stack. The global variable
top keeps track of the total number of elements present in the stack.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 12 3/2/2012 6:51:07 PM


Stacks 4.13

Example 4.5 Write a program to create a class stack and define member function push () and pop ().

# include <stdio.h>
# include <conio.h>

int stacks[10];
int top;

void main()
{
void show(void);
void push(int j);
void pop();
int n,j;
top=-1;
stacks[10]=NULL;
clrscr();
printf("\nInsert four element in stack");
printf("\npush operation: ");
push(2);
push(5);
push(8);
push(3);
show();
printf("\n\nDeleting two elements from the stack");
printf("\npop operation: ");
pop();
pop();
show();
}
void push(int j)
{
top++;
stacks[top]=j;

void pop()
{
stacks[top]=0;
top−−;
}

void show()
{
int j;
for(j=0;j<=top;j++)
printf(" %d",stacks[j]);
}

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 13 3/2/2012 6:51:07 PM


4.14 Data Structures Using C

OUTPUT
Insert four element in stack
push operation: 2 5 8 3
Deleting two elements from the stack
pop operation: 2 5

Explanation:
In this program an array stack is declared. Both two array variables, stacks[10] and
top, are static and they are initialized. Three-functions push(), pop() and show() are
defined. Invoking push() function elements are pushed. The pop() operation removes the
elements. The show() function displays the elements of stack.

4.5 POINTERS AND STACK

We are already aware that array name itself is a pointer. Pointer implementation of a stack carried out is simi-
lar to array implementation. Stack is particularly straightforward version of linked lists. The implementation
of array-like elements can be done using pointer. Like array, elements can be stored in successive memory
location using pointer. First, we learn a simple program to create stack using pointer instead of array.

Example 4.6 Write a program to create an array-like list of integers using pointer.

# include <stdio.h>
# include <conio.h>

void main()
{
int *p,j,e;
clrscr();
printf("\n Enter five Integers: ");
for(e=4;e>=0;e−−)
scanf("%d",(p+e));
for(e=0;e<5;e++)
printf("%d ",*(p+e));

OUTPUT
Enter five Integers: 4 5 8 7 5
5 7 8 5 4

Explanation:
In this program a pointer *p is declared. The first for loop is used to read numbers in association
with scanf() statement. The value of variable e is added to the address of pointer p, so
that successive locations are accessed and the number is placed in the location. For displaying
elements, same logic is applied.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 14 3/2/2012 6:51:07 PM


Stacks 4.15

Example 4.7 Write a program to implement stack operation push and pop with pointer.

# include <stdio.h>
# include <conio.h>
# include <stdlib.h>

struct stack
{
int num;
struct stack *next;
} *T=0;

typedef struct stack it;

void push();
int pop();
void show();

void main()
{
char chr;
int opt,no;
do
{
clrscr();
printf("\n 1: push ");
printf("\n 2: pop ");
printf("\n 3: show ");
printf("\n >3: exit");
printf("\n Enter your option: ");
scanf("%d",&opt);

switch(opt)
{
case 1: push(); break;
case 2: no = pop();
printf("\n The delete number was %d ", no);
break;
case 3: show(); break;
default: printf("\n Good Bye ");
exit(0);
}

printf("\n Continue(y/n )" );


fflush(stdin);
chr=getche();

} while(chr=='Y' || chr=='y');
}

void push()
{
it *node;
node=(it*) malloc(sizeof(it));
printf("\n Enter the number ");

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 15 3/2/2012 6:51:07 PM


4.16 Data Structures Using C

scanf("%d",&node->num);
node->next=T;
T=node;
}

int pop()
{
it *temp;
temp=T;

if(T==NULL)
{
puts("\n Stack underflow ");
getch();
exit(0);
}

else
{
T=T->next;
free(temp);
}
return(temp->num);
}

void show()
{
it *tmp;
tmp=T;

while(tmp->next !=NULL)
{
printf(" %d ", tmp->num);
tmp=tmp->next;
}
printf(" %d ", tmp->num);
}

OUTPUT
1: push
2: pop
3: show
>3: exit
Enter your option: 3
7 2
Continue(y/n)

Explanation:
In this program the structure stack is defined with variables num and a pointer variable *next of
stack (itself) type. Later *T a pointer is declared. The prototype declaration of pop (), push ()
and show () is done. The user is asked to entered option and the entered option number is
passed to switch () case structure to execute the anticipated option. The user has to press ‘y’
to continue the program, else if other alphabet is entered, the program will terminate.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 16 3/2/2012 6:51:07 PM


Stacks 4.17

In the push() function, it is a custom data type created with typedef statement. The variable
*node is variable of type structure stack. The malloc() function is used to allocate memory to *node
pointer equal to the size of structure variable. The element entered immediately by the user is stored in
allocated memory. The number is stored in the num variable and the T is assigned to node->next.
In pop() function, another variable tmp is declared. If the T is NULL, i.e. the stack is still underflow
and we can continue the push operation. Otherwise, the free function de-allocates the memory of last
element pointed by next. When the memory is de-allocated the element also is destroyed. The show()
function is used to print the elements. This is achieved using while loop.

4.6 REPRESENTATION OF ARITHMETIC EXPRESSIONS

An arithmetic expression contains operators and operands. Variables and constants are operands. The
operators are of various kinds such as arithmetic binary, unary for example, + (addition), − (subtraction),
*(multiplication), / (division) and % (modular division). The following Table 4.1 describes types of
operators and the Fig. 4.7 shows the numbers of operators.

Table 4.1 Operators and its Symbolic Representation


Types of Operators Symbolic Representation
Arithmetic operators +,−, *, / and %
Relational operators >, <, =, ==, >=, <= and !=
Logical operators &&, | |, !
Increment/decrement operators ++, —
Assignment operators =, *=, /=, %=, +=; −=; <<=; >>=; &=; ^=p^ |=;
Bitwise operators &, |, ^, >>, <<, ~
Special operators , (comma)
Conditional operators ?:

Arithmetic Operators

Relational Operators

Logical Operators

Assignment Operators

Operators Increment/Decrement Operators

Conditional Operators

Bitwise Operators

Special Operators

Figure 4.7 Types of Operators

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 17 3/2/2012 6:51:07 PM


4.18 Data Structures Using C

The precedence of operator also plays an important role in expression solving. The precedence of
operators is given in Table 4.2.

Table 4.2 Precedence of Operators


Operators Precedence Associativity
+ (unary), − (unary), NOT 6 ––
^ (Exponentiation) 6 Right to left
* (multiplication), / (division) 5 Left to right
+ (addition), − (subtraction) 4 Left to right
<,<=,+,<,>= 3 Left to right

We have already studied the different stack operations. Now, we will study how stack can be useful in
problem solving. Consider a mathematical expression.
5 - ((A * (( B + K)/ (U-4))+K) / 8 (8-4.3))

The common mistake, which can be made frequently by the programmer, is unbalance of parenthesis.
For correct representation of mathematical expression, the following precautions must be taken:
1. There must be equal number of left and right parenthesis.
2. Each left parenthesis must be balanced by right parenthesis.
The expressions ((x+y) and ) x+y (-u are wrong.
Thus, by using stack such a problem can be solved. Assume the left parenthesis as opening scope
and right parenthesis as end of scope. Some time the expression contains nested parenthesis, hence
various scopes are opened but not closed. Count the number of opening parenthesis from beginning
of expression to end. If the number of opening parenthesis is equal to closing parenthesis it means no
scope is left open. The number of opening and closing parenthesis is found same. If the parenthesis
count in the expression is negative, it means a right parenthesis is found, but no left parenthesis of its
pair is defined.
( (x + y )
1 2 1

In the above example, when opening parenthesis is encountered, counter is incremented and when
closing parenthesis is encountered, counter is decremented.
) x + y ( -z
-1 0

In the above example, when the first closing parenthesis is encountered, the counter is decremented.
5 - ( ( A * ( ( B + K ) / ( U-4 ) ) + K ) / 8 ( 8-4.3 ) )
0 1 2 3 4 3 4 3 2 1 2 1 0
In the above example the opening and closing parenthesis are balanced.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 18 3/2/2012 6:51:07 PM


Stacks 4.19

Example 4.8 Write a program to count opening and closing parenthesis and test the expression
having balanced parenthesis or not.

# include <stdio.h>
# include <conio.h>

int stack[10];
int top=9;
void main()
{
int c=0,p=0;
char exp[]="(p+(q-(m+n))*j-((x+y))) / (j-(k-(-k(l-n))))";
clrscr();
printf("\n%s\n",exp);
while(exp[c]!='\0')
{
switch(exp[c])
{
case '{':
case '(':
case '[':
p++;
printf("%d",p);
break;
case '}':
case ')':
case ']':
p−−;
printf("%d",p);
break;
default:
printf("%d",p);
}
c++;
}
}

OUTPUT
(p +(q-(m +n))*j-((x + y))) / (j-(k-(-k(l - n))))
111 222333321111 23333 21000011122233344443210

Explanation:
In this program whatever we discussed in last paragraph are applied practically. When an
opening parenthesis is found counter p is incremented and when closing parenthesis is found
counter is decremented. The counter value is displayed in the output. In the above program if
expressions“)p + (p + q)” are entered the output will be -1-1-10000-1. So far, we used only
one type of parenthesis, i.e. (). In expression other type of parenthesis like {}, [] can be used. In
such case, it is necessary to keep record of not only number of opening and closing braces but
also their type. The stack can be used in such application.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 19 3/2/2012 6:51:07 PM


4.20 Data Structures Using C

When an opening parenthesis is found it is pushed into the stack. When a closing parenthesis is found
the pop operation is carried and it is tested, the deleted parenthesis corresponds to the opening parenthesis.
If the opening and closing parentheses match, the program will continue otherwise the entered string is
invalid. When the end of string is found, the stack must be empty. If the stack contains elements, it means
there is opening parenthesis that had not been closed.
Consider the following expression.
{p+(q-[m+n])*j-[(x+y)]} / (j-(k-(k-[l-n])))

( ( (

{ { { { {

(a) (b) (c) (d) (e)

( (

[ (
(
{ (

(f) (g) (h) (i) (j)

Figure 4.8 Different Views of Stack

As soon as the opening parenthesis of types (, {or [is encountered it is pushed on to the stack. We
can see this in Fig. 4.8 (a), (b) and (c). When a closing parenthesis is found the top element of the
stack is popped. Only when the encountered closing bracket and the top element of the stack matching,
i.e. {}, () and []. We can observe this in Fig. 4.8 (d) and (e). In Fig. 4.8 (g) the stack is empty because there
expression up to {p+(q-[m+n])*j-[(x+y)]} is read. The number of opening and closing brackets are same.
Hence, the expression is correct. When an element remains in the stack, it means the expression is wrong
and parentheses are not properly closed. Again, the expression is read and same push and pop procedure
is applied. The remaining expression (j- (k-(k-[l-n]))) is read.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 20 3/2/2012 6:51:07 PM


Stacks 4.21

Example 4.9 Write a program to compare opening and closing brackets.

# include <stdio.h>
# include <conio.h>

char stack[15];
int t=14;

void main()
{
void pop(void);
void show(void);
void push(char);

char exp[20];
int j=0,b=0;
clrscr();

printf("\n Enter an Expression: ");


scanf("%s",exp);

while(exp[j]!='\0')
{
switch(exp[j])
{
case '{':
case '(':
case '[':
push(exp[j]);
show();
b++;
break;

case '}':

if(stack[t+1]=='{')
{
pop();
b−−;
}
else
printf("\n Error in expression");
break;
case ')':

if(stack[t+1]=='(')
{
pop();
b−−;
}
else
printf("\n No matching opening and closing brackets");
break;

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 21 3/2/2012 6:51:07 PM


4.22 Data Structures Using C

case ']':

if(stack[t+1]=='[')
{
pop();
b−−;
}
else
printf("\n No matching opening and closing brackets");
break;
}

j++;
}

if(b==0)
printf("\n Expression is correct");
else
printf("\n %d closing brackets are not closed",b);
show();
}

void push(char c)
{
stack[t]=c;
t−−;
}

void pop()
{
t++;
stack[t]=NULL;
}

void show()
{
int k;
printf("\n");
for(k=0;k<=14;k++)
printf("%c",stack[k]);
}
OUTPUT

1)

Enter an Expression: {(a+b)}

{
(({

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 22 3/2/2012 6:51:07 PM


Stacks 4.23

Expression is correct

2)

Enter an Expression: {(a+b}

{
({
Error in expression
2 closing brackets are not closed
({

Explanation:
An entered expression by the user is stored in the array exp []. Using while loop the entire
string (expression) is scanned. The switch () case structure within while loop is used to
check different conditions. If any opening bracket comes across, it is pushed on to the stack
by invoking push () function, i.e. the meet opening bracket is stored in the array stack using
push () function.

We know that in any valid expression, the first opened parenthesis is closed lastly and the lastly opened
parenthesis is closed first, i.e. the parenthesis arrangement is like stack mechanism first-in-last-out. The
encountered opening parenthesis are pushed onto the stack. When closing parenthesis of same type is
found the item is popped from the stack. Thus, matching pairs of parenthesis are checked. If no match is
found, the error will be displayed. In case an opening parenthesis does not have closing parenthesis, the
message displayed will be “Error in expression”.

SUMMARY
1. Stack is an important tool in programming languages. Most of the programming languages
support stack operations. The main operations are push and pop. The insertion of element
onto the stack is called “push”. and deletion operation is called “pop”. Due to the push
operation that adds elements in the stack, the stack is also known as pushdown list. The most
and least reachable elements in the stack are known as the “top” and “bottom” of the stack.
Stack is a set of elements in a last-in-first-out technique.
2. The insertion and deletion operations are carried out at one end. Hence, the recent ele-
ment inserted is deleted first. If we want to delete the particular element of the stack, it is
necessary to delete all the elements appearing before that element.
3. A top pointer maintains track of the top elements.
4. When stack has no element, it is called empty stack.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 23 3/2/2012 6:51:07 PM


4.24 Data Structures Using C

5. Whenever an element is inserted (push operation) in the stack the value of pointer top is
increased by one. In the same manner, the value of pointer is decremented when an ele-
ment is deleted from the stack (pop operation).
6. If a pop operation is performed on an empty stack it is called as underflow stack. An opera-
tion to insert an element more than the capacity of stack is known as overflow stack.
7. Static implementation can be implemented using arrays. However, it is a very simple method
but it has few limitations.
8. Pointers can also be used for implementation of stack. The linked list is an example of this
type of implementation. The limitations noticed in static implementation can be removed
by using dynamic implementation.
9. Recall that array name itself is a pointer. Pointer implementation of a stack is carried out
similar to array implementation.
10. An arithmetic expression contains operators and operands. Variable and constant are
operands. The operators are of various kinds such as arithmetic binary, unary, for example, +
(Addition), − (subtraction), *(multiplication), / (division) and % (modular division).

EXERCISES
A. Answer the following question:

1. What do you mean by stack?


2. Define various terms related to stack.
3. Explain implementation procedure of stack.
4. What is the top of the stack?
5. What do you mean by stack overflow and stack underflow?
6. Explain the push and pop operations.
7. Explain stack mechanism.

B. Attempt following programs:

1. Write a program to demonstrate push () and pop () operation using class and member function.
2. Write a program to enter an integer. Reverse the digits of the integer. Use stack mechanism.
3. Write a program to implement stack operation push and pop with pointer.
4. Write a program to perform following operations:
a. push
b. pop
c. stack underflow
d. stack overflow
e. display all elements.
5. Write a program to implement stack with two-dimensional array. Perform push () and pop ()
operation.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 24 3/2/2012 6:51:08 PM


Stacks 4.25

6. Write a program to perform following stack operations:


a. Create a stack with item code and quantity

Item code Quantity


001 450
002 0
003 487
004 101
005 500
006 0
007 359
008 0
009 458

b. Delete the items having quantity zero and update the stack.

C. Select the appropriate option for each of the following questions:

1. The stack is based on the rule


(a) first-in-last-out (c) both (a) and (b)
(b) last-in-first-out (d) first-in-first-out
2. The push () operation is used
(a) to insert an element (c) to move an element
(b) to remove an element (d) all of the above.
3. The pop operation removes
(a) the element lastly inserted (c) any element randomly
(b) first element of the stack (d) none of the above.
4. The top pointer is increased
(a) when push () operation is done (c) both (a) and (b)
(b) when pop () operation is done (d) none of the above.
5. A stack holding elements equal to its capacity and if push is performed then such situation is
called
(a) stack overflow (c) illegal operation
(b) stack underflow (d) none of the above.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 25 3/2/2012 6:51:08 PM


4.26 Data Structures Using C

D. Find the output. if(j>5)


{
for(j=0;j<6;j++)
1.
printf(" %c ", stack[j]);
# include <stdio.h>
printf("\nStack is full \n");
# include <conio.h>
}
void main() else
{ {
static int stack[6],j; for(j=0;j<p;j++)
clrscr(); printf(" %c ",
printf("Enter stack[j]);
Elements, put zero to exit: }
\n"); }
for(j=0;j<6;j++)
{ 3.
printf("\n Elements of stack # include <stdio.h>
are: "); # include <conio.h>
scanf("%d",&stack[j]); int p,top=0,stack[3],c;
if(stack[j]==0)
void main()
{
{
printf("\nBy choice termi-
void push();
nated:- ");
void show();
break;
clrscr();
}
push();
}
show();
if(j>5)
push();
printf("Stack is full \n");
show();
printf("\nStack elements are:-");
}
for(j=0;j<6;j++)
printf(" %d ",stack[j]); void push()
{
} printf("\n Enter number to be
pushed:- ");
scanf("%d",&stack
2. [top]);
# include <stdio.h> top++;
# include <conio.h> }
void main()
void show()
{
{
char stack[5];
printf("\nContents of stack
int j,p=0;
are:-");
clrscr();
for(p=top-1;p>=0;−−p)
printf("Enter less than seven
printf("\n%d ",stack[p]);
Characters: \n");
}
scanf("%s",&stack);
printf("\nStack
characters are:-"); 4.
for(j=0;j<6;j++) # include <stdio.h>
{ # include <conio.h>
p=j; # include <process.h>
if(stack[j]=='\0') int p,z=6,top=0,
break; stack[7],c;
}
main()

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 26 3/2/2012 6:51:08 PM


Stacks 4.27

{ printf("\nStack elements are:");


void push(); for(p=top-1;p>=0;—–p)
void pop(); printf(" \n%d ",stack[p]);
void show(); }
clrscr();
push(); 5.
show(); # include <stdio.h>
push(); # include <conio.h>
show(); void main()
pop(); {
printf("\n\t After pop opera-
tion:"); char text[40];
show(); int k=0,j;
} clrscr();
puts("\n Enter a
void push() string:- ");
{ scanf("%s",&text);
printf("\nEnter number to be while(text[k]!='\0')
pushed:- "); k++;
scanf("%d",&stack[top]); printf("\nValue of top is:-
top++; %d",k);
} printf("\nReverse string is: ");
void pop() for(j=k;j>=0;j—)
{ {
top−−; printf("%c",text[k]);
} k−−;
void show() }
{ }

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 27 3/2/2012 6:51:08 PM


This page is intentionally left blank.

M04_ASHOK NAMDEV KAMTHANE5067_01_SE_C04.indd 28 3/2/2012 6:51:08 PM


Chapter 5

Queues

CHAP TER O U T LIN E


5.1 Introduction 5.6 Dynamic Implementation (Pointers)
5.2 Various Positions of Queues 5.7 Insertion and Deletion Operation
5.3 Queue Implementation 5.8 Types of Queues
5.4 Operations on Queues 5.9 Applications of Queues
5.5 Disadvantages of Simple Queues 5.10 Types of Systems

5.1 INTRODUCTION

A queue is one of the simplest data structures and can be implemented with different methods on a
computer. Queue of tasks to be executed in a computer is analogous to the queue that we see in our daily
life at various places. The theory of a queue is common to all. Queue of people in a bank, students queue
in school, a travellers’ queue for tickets at railway station are few examples of queue. It is necessary to wait
in a queue for obtaining the service. In the same fashion, in a computer there may be a queue of tasks wait-
ing for execution, few others for printing, and some are for inputting the data and instructions through
the keyboard. Unless the task turns and comes on front, it will not be executed. This data structure is very
useful in solving various real life problems. One can simulate the real life situations with this data struc-
ture. This chapter describes the queue and its types.
A queue is a non-primitive, linear data structure, and a sub-class of list data structure. It is an ordered,
homogenous collection of elements in which elements are appended at one end called rear end and
elements are deleted at other end called front end. The meaning of front is face side and rear means

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 1 3/2/2012 6:51:35 PM


5.2 Data Structures Using C

back side. The first entry in a queue to which the service is offered is to the element that is on front. After
servicing, it is removed from the queue. The information is manipulated in the same sequence as it was
collected. Queue follows the rule first-in-first-out (FIFO). Fig. 5.1 illustrates a queue.

Deletion Insertion

Front Rear

Figure 5.1 Queue

Figure 5.1 shows that insertion of elements is done at the rear end and deletion at the front end.

A P Q R S

B Front Q R S Rear

C Q R S T

Figure 5.2 Queues

Fig. 5.2 illustrates the queue containing elements. The queue (Fig. 5.2 (a)) contains four elements P, Q,
R and S. The element P is at the front end and element S is at the rear end. In Fig. 5.2 (b), an element P has
been deleted from the queue. Now, the element Q is the first element and it is on the front. In Fig. 5.2 (c),
element T is inserted from the rear end. Thus, the elements are inserted from the rear end of queue. The
element T is inserted after S. As far as removal operation is concerned, the S is to be removed before T.
In other words, the service is provided to the element, which is at front and this element is to be
removed first. We call this entry front of the queue. The entry of element that is recently added is done
from rear of the queue or it can be called as tail end of the queue.
Two operations are frequently carried on queue. They are insertion and deletion of elements. These two
operations depend upon the status of the queue. The insertion operation is possible, only when the queue
contains elements less than the capacity it can hold. The deletion operation is only possible when the queue
contains at least one element. The queue containing no elements is called underflow as shown in Fig. 5.3.

Figure 5.3 Empty Queue (underflow)

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 2 3/2/2012 6:51:36 PM


Queues 5.3

5.2 VARIOUS POSITIONS OF QUEUES

Consider the following figures:

0 1 2 3 4 5

Figure 5.4 (a) Empty Queue

In Fig. 5.4 (a) the queue is empty, hence value of rear = –1 and front = –1. The above queue is called as
empty queue. Initially, the status of queue is always empty.

5
0 1 2 3 4 5

Figure 5.4 (b) One Element in the Queue

In Fig. 5.4 (b), the queue holds one element. The value of rear = 0 and front = 0. Both front and rear
end are on same element because the queue contains only one element. The next element appended will
be stored followed by 5. Then, the front will remain at 5 but rear will be shifted on to the new element.
The value of front is changed only once when the first element is inserted in the queue. Later, for every
insertion of element, the front remains same but the value of rear changes.

5 3
0 1 2 3 4 5

Figure 5.4 (c) Two Elements in the Queue

In Fig. 5.4 (c), another element is inserted from the rear side and it is stored behind 5. Whenever we
insert an element in the queue the value of rear is incremented, i.e. the rear end is shifted towards the right.
At this step the value of front = 0 and rear = 1.

5 3 2
0 1 2 3 4 5

Figure 5.4 (d) Three Elements in the Queue

In Fig. 5.4 (d), the value of rear is 2.

3 2
0 1 2 3 4 5

Figure 5.4 (e) Deletion of the Element and Shifting to the Front

In Fig. 5.4 (e), one element is deleted from the queue. Now, the front is shifted towards bottom.
Thus, the front will be on element 3 now. The value of the front will be increased when an element is
removed. The value of front = 1 and rear = 2. The programs on above discussion are explained in queue
implementation.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 3 3/2/2012 6:51:36 PM


5.4 Data Structures Using C

5.3 QUEUE IMPLEMENTATION

Queue can be put into operation in two ways:


a. Static implementation (array)
b. Dynamic implementation (pointers).

5.3.1 Static Implementation


The static implementation is done with an array. In this implementation, we should know the exact
number of elements to be stored in the queue. The size of array is decided before execution at compile
time. Once the array is declared, its size cannot be altered during the run time of the program. The begin-
ning of the array, i.e. 0th element is the front and the last memory location will be rear of the queue.
A queue can be created by declaring an array that hold the entries. Here, we should keep the track of both
front as well as rear of the queue. Assume an array of integer data types as declared below.
int queue[8];

In the above statement, an array queue [] of integer type is declared.


From the Fig. 5.5 we can say that first six locations of a queue are filled and the remaining two are
vacant. The element 5 is at front and 8 is at rear.
1. If the value of front element is zero, then queue is empty.
2. If the value of queue [7] is non-zero then the queue is full.
3. When an element is inserted, the position of rear increases.
4. When an element is deleted from the queue the value of front increases by one.

5 4 8 7 3 8

Front Rear

Figure 5.5 Queues

The above operation can be shown with few programs as described below. Consider the following
program,

Example 5.1 Write a program to implement a queue using an array.

# include <stdio.h>
# include <conio.h>
# include <process.h>

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 4 3/2/2012 6:51:37 PM


Queues 5.5

void main()
{
int queue[8];
int rear=0;
clrscr();
while(1)
{
printf("Enter element: ");
scanf("%d",&queue[rear]);
rear++;
if(rear==7)
{
printf("\n Queue is full ");
break;
}
}
printf("\n Elements of Queue are: ");
rear=0;

while(1)
{

printf(" %d ", queue[rear]);


rear++;
if(rear==7) break;
}
}

OUTPUT
Enter element: 1
Enter element: 2
Enter element: 3
Enter element: 4
Enter element: 5
Enter element: 6
Enter element: 7
Queue is full
Elements of Queue are: 1 2 3 4 5 6 7

Explanation:
This a simple example of queue. All the elements are entered and stored in the queue. Of course,
the queue is implemented by declaring an array. The while loop and scanf() statement read
elements through the keyboard. The variable rear is incremented to get successive position in
the queue. In the same way, the second while loop displays the elements.

5.4 OPERATIONS ON QUEUES

Two operations can be carried out on queue.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 5 3/2/2012 6:51:37 PM


5.6 Data Structures Using C

5.4.1 Insertion of Element


Table 5.1 Algorithm for Insertion in Queue
Algorithm for Insertion of Element in a Queue

1. Initialize front = 0 rear = −1, queue[SIZE] Initialization of queue


2. If rear ≥ size Test for overflow condition
(Display queue overflow message and exit)
Else
<enter element>
3. Queue[rear] = element Element is stored in an array
Rear++ Rear is incremented
4. Go to step 2 Control goes to step 2

A program based on algorithm, which is shown in Table 5.1, is described below.

Example 5.2 Write a program to insert elements in a queue.

# include <stdio.h>
# include <conio.h>
# include <process.h>
# define S 5

void main()
{
int queue[S];
int r=0,n;

clrscr();

while(1)
{
if(r>=S)
{
printf("\n Queue overflow");
break;
}
else
printf("Enter a number: ");
scanf("%d",&n);
queue[r]=n;
r++;
}

printf("\n Queue elements are: ");


for(n=0;n<S;n++)
printf(" %d ",queue[n]);

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 6 3/2/2012 6:51:37 PM


Queues 5.7

OUTPUT
Enter a number: 3
Enter a number: 4
Enter a number: 5
Enter a number: 6
Enter a number: 7
Queue overflow
Queue elements are: 3 4 5 6 7

Explanation:
This a simple example of queue that contains maximum 5 elements. All the elements are entered
and stored in the queue. The queue is implemented by declaring array[s]. The while loop
and scanf() statement read elements through the keyboard. The rear is incremented to get
successive position in the queue. The for loop displays the elements.

Example 5.3 Write a program to perform insertion operation and show value of front and rear.

# include<stdio.h>
# include <conio.h>

void main()
{
int queue[7];
int r=-1,f=-1,j;
clrscr();

while(r<6)
{
r++;
printf("rear=%d front=%d Enter element:",r,f);
scanf("%d",&queue[r]);

if(r==0) f=0;

}
printf("\n Queue elements are: ");
for(j=0;j<7;j++)
printf(" %d ",queue[j]);

OUTPUT
rear=-1 front=-1 Enter element:8
rear=0 front=0 Enter element:9
rear=1 front=0 Enter element:4
rear=2 front=0 Enter element:5

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 7 3/2/2012 6:51:37 PM


5.8 Data Structures Using C

rear=3 front=0 Enter element:1


rear=4 front=0 Enter element:2
rear=5 front=0 Enter element:3
Queue elements are: 8 9 4 5 1 2 3

Explanation:
In this program our aim is to concentrate only at element insertion operation and the
values of front and rear ends displayed after insertion of every element. Initially, rear and
front are initialized to –1. Conceptually, it is not necessary to initialize these variables
to –1. The user can also initialize them to zero. The values of rear start from –1 to 6. Here, –1 is
the value before insertion operation. When one element is added the value of rear is increased
to 1 and later the value reaches up to 6. On the other hand the value of front changes only once
from –1 to 0 and then its value remains same.

5.4.2 Deletion of Element


The following program explains insertion and deletion operations.

Example 5.4 Write a program to perform deletion operation on queue and show value of front and rear.

# include<stdio.h>
# include <conio.h>

void main()
{
int queue[7]={11,12,13,14,15,16,17};
int i,r=6,f=0,n;
clrscr();

printf("\nThe Elements of queue are as follows:-\n");


for(i=0;i<7;i++)
printf("%2d ",queue[i]);

printf("\nInitial values rear=%d front=%d",r,f);


printf("\n\nHow many elements u want to delete: ");
scanf("%d",&n);
while(f<n)
{
queue[f]=NULL;
f++;
printf("\nrear=%d front=%d",r,f);
}
printf("\n Queue elements are: ");
for(n=0;n<7;n++)
printf(" %d ",queue[n]);
}

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 8 3/2/2012 6:51:37 PM


Queues 5.9

OUTPUT
The Elements of queue are as follows:-
11 12 13 14 15 16 17
Initial values rear=6 front=0
How many elements u want to delete: 3
rear=6 front=1
rear=6 front=2
rear=6 front=3
Queue elements are: 0 0 0 14 15 16 17

Explanation:
This program is the second part of the first program. We have started exactly from where we
ended the last program. The output of the last program is starting of this program. The array is
initialized with entered values and rear and front are initialized to six and zero, respectively.

The user is asked to enter number of elements to be deleted. The loop is executed for n times and zero
to n elements of the array are nullified. At every deletion operation the front is shifted to inside. It is
shifted from 0 to 3 when three elements are deleted. The output of the program is easy to understand.

5.5 DISADVANTAGES OF SIMPLE QUEUES

In the previous sections we have studied implementation of queues using arrays. There are some disad-
vantages in simple queue implementation using arrays. In the following example, it is considered that the
elements after deletion are not shifted to beginning of an array. Consider the following example:
Queue [5] is a simple queue declared. The queue is initially empty. In the following figures insertion and
deletion operations will be performed.

0 1 2 3 4

The above figure is an empty queue. Initially the queue is always empty. Here, rear = –1 and front = –1.
The user can also assign 0 instead of –1. However, the –1 is suitable because we are implementing this
problem with arrays and an array element counting begins always with zero. Thus, it is suitable for problem
logic.

5
0 1 2 3 4

In the above figure, one element is inserted. So, the new values of front and rear are increased and
reaches to 0 (zero). This is the only stage where front and rear have same values.

5 7 9
0 1 2 3 4

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 9 3/2/2012 6:51:37 PM


5.10 Data Structures Using C

In the above figure, two elements are appended in the queue. At this moment, the value of rear = 2 and
front = 0.

7 9
0 1 2 3 4

In the above figure one element is deleted and the value of rear = 2 and f = 1. The value of front is
increased due deletion of one element.

7 9 8 1
0 1 2 3 4

In the above figure, two more elements are appended to queue. The value of rear = 4 and front = 1.
If more elements are deleted, the value of front will be increased and as a result, the beginning portion
of queue will be empty. In such a situation if we try to insert new elements to queue, no elements can
be inserted in the queue. This is because, new elements are always inserted from the rear and if the last
location of queue (rear) holds an element, even though the space is available at the beginning of queue, no
elements will be inserted. The queue will be treated as overflow.
To overcome this problem, we have to update the queue. Let us take an example, suppose we have allo-
cated n number of bytes to pointer *p using either malloc()(c) or new (c++) function. After successful
allocation of memory (though the program is not utilizing the memory), memory will be part of the
program and cannot be used by other program or cannot be allocated to other program. To utilize this
memory, memory must be released using free or delete functions. Thus, whatever the portion of
memory is not in use, can be used. In our example of queue the beginning portion of queue which is empty
due to delete operations, can be filled by shifting following element to beginning of the array. Thus, the
space will be available at the rear end and new elements can be inserted at the end. Thus, entire queue can
be used to store the element. This approach also has a problem when the queue contains more elements.
The solution to this problem is circular queue, which is discussed separately in this chapter.
Here, a program is provided with menu driven with different choices such as insertion, deletion,
display, etc.

Example 5.5 Write a program to perform different operations with queue such as insert, delete
and display of elements.

# include <stdio.h>
# include <conio.h>
int queue[8];
int r;
void insert(void);
void del();
void show(void);

void main()
{
int c;
clrscr();
printf("\n 1] Insert Element ");

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 10 3/2/2012 6:51:37 PM


Queues 5.11

printf("\n 2] Delete Element ");


printf("\n 3] Display element/s");
printf("\n 4] Exit");
printf("\n Enter your choice:- ");
scanf("%d",&c);
switch(c)
{
case 1: insert(); break;
case 2: del(); show();break;
case 3: show(); break;
default: exit(0);
}
main();
}

void insert()
{
char ans='Y';
if(r>=7)
{
printf("\n Queue is full \n\n\n");
main();
}

while(ans=='Y'|| ans=='y')
{
printf("\n Enter element:- ");
scanf("%d",&queue[r]);
if(r==7)
{
clrscr();
printf("\n Queue is Full");
getch();
break;
}
else
r++;
printf("\nContinue [Y/N]:-");
ans=getche();

}
}
void show()
{
int j;
for(j=0;j<r;j++)
printf(" %d ",queue[j]);
getch();
}
void del()
{
int j;
if(r==0)

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 11 3/2/2012 6:51:37 PM


5.12 Data Structures Using C

{
clrscr();
printf("\n Queue is empty \n\n\n");
main();
}

for(j=0;j<r;j++)
queue[j]= queue[j+1];
queue[r]=0;
r––;
}

OUTPUT
1] Insert element
2] Delete element
3] Display element/s
4] Exit
Enter your choice:- 1
Enter element:- 23
Continue [Y/N]:-y
Enter element:- 45
Continue [Y/N]:-

Explanation:
In this program, the different tasks such as insert, delete and display of elements are performed
using individual functions. A menu appears on the screen and user is required to enter choice.
When user enters 1, the insert() function is executed. The integers entered by the user are
stored in the queue one after another.

When the choice is 2, the element at the front is deleted. In queue, the elements are inserted from the
rear side and deleted from the front side. The display option displays the elements presently stored in
the queue. When del() function is executed, the element present at front is deleted. Here, the elements
are shifted to front side. This is accomplished by the statement queue [j ] = queue [ j+1]; the next element
is shifted to the previous location and the last element is replaced with zero.
In the above program, necessary care is taken to prevent overflow and underflow. When queue is full
with the elements, a message will be displayed “Queue is Full” and further no elements can be added.
When queue is empty user cannot delete any element. The function show() is used to display elements,
this is achieved by using for loop and printf() statement.

1 2 3 4 5 6 7

Figure 5.6 Queues with elements

2 3 4 5 6 7

Figure 5.7 Queue (After delete operation)

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 12 3/2/2012 6:51:37 PM


Queues 5.13

2 3 4 5 6 7 8

Figure 5.8 Queue (After Insert Operation)

As shown in Fig. 5.6, element 1 is at the front and seven is at the rear. When delete operation is per-
formed one is deleted first and the element two is shifted at front as shown in the Fig. 5.7. When an ele-
ment is inserted, it is inserted after seven as shown in the Fig. 5.8. When eight is inserted, it is inserted
after seven. Consider another program that explains the operation insertion and deletion.

Example 5.6 Write a program to perform different operations with queue such as insert, delete and
display of elements.

# include <stdio.h>
# include <process.h>
# include <conio.h>

create();
void insert();
void del();
void show();

int m,n=10,fr=0, queue[11],re=0,num,cur;

void main()
{
int choice;
clrscr();
puts("1] Create");
puts("2] Insert");
puts("3] Delete");
puts("4] Show");
puts("5] End");
puts("\nEnter Your choice: ");
scanf("%d",&choice);

switch(choice)
{
case 1: create(); break;
case 2: insert(); break;
case 3: del(); break;
case 4: show(); break;
case 5: puts("Bye"); exit(0);
}
main();
}

create()
{
puts("Insert number of elements <11 in the queue: ");
scanf("%d",&cur);

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 13 3/2/2012 6:51:37 PM


5.14 Data Structures Using C

puts("Enter elements: ");

if( fr==0)
{
fr++;
scanf("%d",&num);

if(num==0) return 0;
queue[fr]=num;
re=fr;
}
do
{
++re;

if(re>cur) break;
scanf("%d",&num);

if(num==0) break;
queue[re]=num;
}while(re<cur);
return 0;
}
void insert()
{

if(re<cur)
{
puts("Queue is full");
exit(0);
}

puts("Enter a number to be inserted ");


scanf("%d",&num);
queue[re]=num;
}

void del()
{

if(fr==re)
{
puts("The queue is empty"); exit(0); }
fr++;
num=queue[fr];
if(fr==n)
{
fr=1;
re=1;
}
}
void show()
{
for(m=fr;m<=re;++m)

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 14 3/2/2012 6:51:37 PM


Queues 5.15

printf(" %d ",queue[m]);
getch();
}

OUTPUT
1] Create
2] Insert
3] Delete
4] Show
5] End
Enter Your choice:
4
2 3 0

Explanation:
We are already familiar with the operation create, insert and delete in the previous program. In
this program, separate functions are defined for different tasks such as create, insert, and delete
operation. Now, we will discuss one by one.

In the create function, user has to enter number of elements to be entered in the queue. User also needs
to enter elements. If zero is inserted the control exits from the function. The zero will not be considered as
an element, it is entered to exit from the function. If elements entered are less than the capacity entered,
the remaining portion remains vacant.
The insert()function is used to insert elements if the space is available. If the queue is already
filled, this function will not work. The del()function is used to delete element. To display the element
show()function is used. You might have noticed that the function main()is invoked recursively by
itself. This is to enable the user to enter choice of operation.

5.6 DYNAMIC IMPLEMENTATION (POINTERS)

Dynamic implementation is carried out using pointers. By applying increment operation on pointer suc-
cessive locations of memory can be accessed and an element can be stored in that location. Thus, the series
of elements can be contiguously stored up to any number of elements. The programmer has to keep the
starting address of the pointer in which first element is stored. Thus, in the same way the numbers can be
viewed or altered. Here is the simple example.

Example 5.7 Write a program to implement queue using pointers.

# include <stdio.h>
# include <conio.h>
# include <process.h>

void main()
{
int *q;
int rear=0;
clrscr();

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 15 3/2/2012 6:51:38 PM


5.16 Data Structures Using C

while(1)
{
printf("Enter element: ");
scanf("%d",q);
q++;
rear++;
if(rear==7)
{
printf("\n Queue is full ");
break;
}
}

q=q-rear;
printf("\n Elements of Queue are: ");
rear=0;

while(rear<7)
{
printf("\n Element: %d rear=%d", *(q+rear),rear);
rear++;

}
}

OUTPUT
Enter element: 4
Enter element: 2
Enter element: 3
Enter element: 4
Enter element: 7
Enter element: 8
Enter element: 9
Queue is full
Elements of Queue are:
Element: 4 rear=0
Element: 2 rear=1
Element: 3 rear=2
Element: 4 rear=3
Element: 7 rear=4
Element: 8 rear=5
Element: 9 rear=6

Explanation:
In this program, pointer *q and integer rear are declared. The variable rear is initialized with
zero. Using scanf(), statement elements are entered. In the while loop pointer q and rear
are increased. If the rear reaches to seven, the break statement terminates the loop. After
the execution of while loop, the pointer q points to last memory location of the queue. The
starting address of the queue is again set by the statement q = q–rear; Finally, using second
while loop and continuous increment operation with rear, successive memory locations are
accessed and elements are displayed.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 16 3/2/2012 6:51:38 PM


Queues 5.17

5.7 INSERTION AND DELETION OPERATION

The insertion and deletion operations can also be performed with the queue. The following program explains
both the insertion and deletion operation with the queue. Queue implementation is done with an array.

Example 5.8 Write a program to perform insert and delete operation with queue.

# include <stdio.h>
# include <conio.h>
void create();
insert();
erase();
void show();
int k,j=10,f=0, queue[11],r=0, e_ment, crn,s;

void main()
{
int option;
clrscr();
do
{
puts("\n\n QUEUE OPERATIONS\n");
puts("1: Create");
puts("2: Insertion");
puts("3: Erase");
puts("4: Show");
puts("5: Exit");
puts("Enter your option: ");
scanf("%d",&option);
switch(option)
{
case 1: create(); continue;
case 2: s=insert(); continue;
case 3: erase(); continue;
case 4: show(); continue;
case 5:
printf("\n s=%d",s);
return 0;
}
getche();
clrscr();
}while(option!=5);
}

void create()
{
puts("Insert number of elements<11 in the queue: ");
scanf("%d",&crn);
puts("Enter elements:");

if(f==0)
{

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 17 3/2/2012 6:51:38 PM


5.18 Data Structures Using C

f++;
scanf("%d",&e_ment);
queue[f]=e_ment;
r=f;
}

do
{
++r;
if(r>crn) break;
scanf("%d",&e_ment);
queue[r]=e_ment;
} while(r<crn);
}

insert()
{
r++;
if(r>j)
{
puts("Queue is full "); return(1); }
puts("Enter number to be inserted: ");
scanf("%d",&e_ment);
queue[r]=e_ment;
return 0;
}

erase()
{
if(f==r)
{
puts("The queue is empty "); return(0); }
f++;
e_ment=queue[f];

if(f==j)
{
f=1;
r=1;
}
return 0;
}

void show()
{
for(k=f;k<=r;++k)
printf(" %d ",queue[k]);
}

OUTPUT
1 2 2 4 5

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 18 3/2/2012 6:51:38 PM


Queues 5.19

QUEUE OPERATIONS
1: Create
2: Insertion
3: Erase
4: Show
5: Exit
Enter your option:
4
1 2 2 4 5

Explanation:
In this program, required variables and function prototypes are declared before main(). The
user can perform different operations and they are displayed. Program will ask the user to enter
a choice. The option entered by user is passed to switch() case statement where appropriate
case statement is executed. Actually, the case statement body invokes function and operation
gets started.

The create function is used to insert numbers into the queue. In this function user has to enter number
of elements to be inserted and followed by this user has to enter numbers. The if block is executed if
the value of f (front) is zero. The element entered is stored in the queue. Using while loop repeatedly
elements are entered and stored in the queue. The variable r is incremented in every loop. The insert()
function is used to insert an element at the given position in the queue. The variable j has value 10 and
it shows maximum number which the queue can hold. If the value of r (rear) is greater than j its simple
meaning is that queue is full and the return statement suspends the function execution. If the queue is
empty and in the next available location, the entered element is stored.
In the erase() function, first value of r (rear) and f (front) are compared and if they are same its meaning
is that queue is empty. Because value of front and rear are same means the queue has no element. If f and j
(maximum number) are same, both these variables are set to one.
The show() function is used to display the element as output. The loop is executed from value of front vari-
able to rear. In the erase() function, the elements are not actually erased, just position of front is increased.
The same value of front is used to display the elements. Before the fth position, the elements exist physically. We
can also erase them physically, but then we have to move the elements to the beginning of the array.

5.8 TYPES OF QUEUES

In the last few topics, we have studied simple queue and already seen the disadvantages. When rear pointer
reaches to the end of the queue (array), no more elements can be added in the queue, even if beginning
memory locations of array are empty. To overcome the above disadvantage, different types of queues can
be applied. Different types of queues are:

5.8.1 Circular Queue


The simple or in a straight line queue there are several limitations we know, even if memory locations
at the beginning of queue are available, elements cannot be inserted as shown in the Fig. 5.9. We can
efficiently utilize the space available of straight-line queue by using circular queue.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 19 3/2/2012 6:51:38 PM


5.20 Data Structures Using C

5 8 7

0 1 2 3 4 5
Front = 3 rear = 5

Figure 5.9 Simple Queues with Empty Spaces

In the above discussion, it is supposed that front is not shifted to the beginning of the queue. As shown
in the Fig. 5.10 a circular queue is like a wheel or a perfect ring. Suppose, c [4] is an array declared for
implementation of circular queue. However, logically elements appear in circular fashion but physically in
computer memory, they are stored in successive memory locations.

C [0] C [1]

C [3] C [2]

Figure 5.10 Circular Queue

In the circular queue, the first element is stored immediately after last element. If last location of the
queue is occupied, the new element is inserted at the first memory location of queue implementing an
array (queue). For example, C[n], C is queue of n elements. After inserting, storing an element in the
last memory location [(n–1th) element], the next element will be stored at the first location, if space is
available. It is like a chain of where starting and ending points are joined and a circle is formed. When an
element is stored in the last location wrapping takes place and element inserting routine of the program
pointed to beginning of the queue.
Recall that a pointer (stack and queue pointer) plays an important role to know the position of the ele-
ments in the stack and queue. Here, as soon as last element is filled, the pointer is wrapped to the begin-
ning of the queue by shifting the pointer value to one.
A circular queue overcomes the limitation of the simple queue by utilizing the entire space of the
queue. Like a simple queue, the circular queue also have front and rear ends. The rear and front ends
help us to know the status of the queue after the insertion and deletion operations. In the circular
queue implementation, the element shifting operation of queue that we apply in the simple queue is
not required. The pointer itself takes care to move at vacant location of the queue and element is placed
at that location. In order to simulate the circular queue a programmer should follow the following
points:
1. The front end of the queue always points to the first element of the queue.
2. If the values of front and rear of queue are equal, the queue is empty. The values of front and rear
pointers are only increased/decreased after insertion/deletion operation.
3. Like simple queue, rear pointer is incremented by one when a new element is inserted and front
pointer is incremented by one when an element is deleted.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 20 3/2/2012 6:51:38 PM


Queues 5.21

Insertion
Front

C [0] C [1]

5 7

C [3] C [2]

REAR

Figure 5.11 (a) Insertion in a Queue


As per Fig. 5.11 (a), the insertion of an element in a queue will be same as in a linear queue. The pro-
grammer must have to trace the values of front and rear variables.
In Fig. 5.11 (a), only two elements are there in the queue. If we continue to add elements, the queue
would be as shown in Fig. 5.11 (b). The new element is always inserted from the rear end. The position
where the next element is to be placed can be calculated by the following formula.
REAR = (1+REAR) % MAXSIZE
C[REAR] = NUMBER
FRONT

C [0] 7 C [1]
5

C [3] 3 9 C [2]

REAR

Figure 5.11 (b) Full Queue

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 21 3/2/2012 6:51:38 PM


5.22 Data Structures Using C

From the Fig. 5.11 (b), the value of rear is three and the capacity to store maximum element of queue
is four. Therefore,
REAR = (1+REAR) % MAXSIZE
REAR = (1+3)%4
REAR = 4%4 = 0.
The operator % is modular divisor operator and returns remainder. Thus, in the above equation the
remainder obtained is zero. The value of front as well as rear is zero, it means stack is full. Any attempt to
insert new element will display the “queue full”. message.
Consider, the following Fig. 5.11 (c),

C[0] C[1]

C[0] C[1]

Figure 5.11 (c) Circular Queue

Example 5.9 Write a program to perform insert, delete operations with circular queue and display
elements.

# include <stdio.h>
# include <conio.h>
# include <process.h>

int queue[8];int r,f=0,x=0;


void insert(void);
void del();
void show(void);

main()
{
int c;
clrscr();
printf("\n 1] Insert Element ");
printf("\n 2] Delete Element ");
printf("\n 3] Display element");
printf("\n 4] Exit");
printf("\n Enter your choice: ");
scanf("%d",&c);
switch(c)
{
case 1: insert(); break;
case 2: del(); show();break;
case 3: show(); break;
default: exit(0);

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 22 3/2/2012 6:51:38 PM


Queues 5.23

}
main();
}

void insert()
{
int n;
char ch,ans='Y';
if(r>=7)
{

while(queue[x]==0)
{
printf("\n Enter a Number: ");
scanf("%d",&n);
queue[x]=n;
x++;
puts("\n Continue Y/N: ");
ch=getch();

if(ch!='Y') break;

}
printf("\n Queue is full \n\n\n");

main();
}

printf("\n Enter elements: ");


while(ans=='Y')
{
scanf("%d",&queue[r]);
if(r==7)
{
clrscr();
printf("\n Queue is Full");
getch();
break;
}
else
r++;
printf("\n Continue Y/N: ");
ans=getche();
}
}

void show()
{
int j;
for(j=0;j<8;j++)
printf(" %d ",queue[j]);
getch();
}

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 23 3/2/2012 6:51:38 PM


5.24 Data Structures Using C

void del()
{
int j;
if(r==0)
{
clrscr();
printf("\n Queue is empty \n\n\n");
main();
}

if(f==8) f=0;

queue[f]=0;
f++;
}

OUTPUT
1] Insert Element
2] Delete Element
3] Display element
4] Exit
Enter your choice: 2
0 2 0 0 0 0 0 0

Explanation:
In this program, various operations such as insert, delete and display are performed. When an
insert operation is performed and elements are inserted, elements appear one after another in
sequence. If we remove element, the beginning location remains empty. If the last location holds
an element and if insertion request is made by the user, the new element inserted is stored at
the starting location. If we go on continuously performing remove operation, the elements at
the beginning are not removed first (see Fig. 5.12).

6 2

5
3

Figure 5.12 Circular Queue (Before Deletion)

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 24 3/2/2012 6:51:38 PM


Queues 5.25

In the above program, assume the elements inserted are 1,2,3,4,5 and 6 and consider their position in
the array is from 0th to 5th. The status of the queue is full. If we keep on removing elements, the elements
would be removed one by one. On deletion of element of the 0th location, this location remains empty.
Now, if an element is inserted, suppose seven, it will be stored in the 0th location as in Fig. 5.13.
Due to circular queue mechanism, if last location is occupied and the beginning locations are empty,
the element is inserted at the empty location. If we keep on removing elements, the elements will be
removed in the order from 2,3,4,5,6 and 7. However, the seven is stored at 0th location of the array but
it was the last element inserted.

6 2

5
3

Figure 5.13 Circular Queue (After Deletion and Insertion)

5.8.2 Double Ended Queues


Till now, we have studied stack and queue. The stack has only one end and can be used alternately to
insert and delete elements. On the other hand, the double-ended queue has two ends, front and rear. The
front end is used to remove element and rear end is used to insert elements. Here, in the double-ended
queues, insertion and deletion can be performed from both the ends and therefore, it is called as double-
ended queue and in short deque. It is a homogenous list of elements. The deque is a general representation
of both stack and queue and can be used as stack and queue. There are various methods to implement
deque. Linked list and array can be used to perform the deque. The array implementation is easy and
straightforward.
Consider the following Fig. 5.14:

Deletion Insertion
1 2 3 4 5
Insertion Deletion

FRONT REAR

Figure 5.14 Deque

In deque, it is necessary to fix the type of operation to be performed on front and rear ends. The deque
can be classified into two types:

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 25 3/2/2012 6:51:38 PM


5.26 Data Structures Using C

Input Restricted Deque In the input restricted deque, insertion and deletion operation are performed
at rear end whereas only deletion operation is performed at front end. The Fig. 5.15 represents the input
restricted deque.
The following operations are possible in the input restricted deque:
1. Insertion of an element at the rear end.
2. Deletion of element at both front and rear ends.

Front Rear

Insertion
Deletion
Deletion

Figure 5.15 Input Restricted Deque

Thus, input restricted deque allows insertion at one and deletion at both ends.

Example 5.10 Write a program to demonstrate input restricted deque.

# include <stdio.h>
# include <conio.h>
int ird[5];

void main()
{
int r=0,c=1,op,f=-1;
int insert(int);
void deleter(int,int);
void deletef(int,int);
void show(void);

while(1)
{
clrscr();
printf("\n (1) Insert ");
printf("\n (2) Delete from rear");
printf("\n (3) Delete from front");
printf("\n (4) Display ");
printf("\n (0) Exit");
printf("\n Enter Your choice:- ");
scanf("%d",&op);
switch(op)
{
case 1: while(c && r<5)
{
c=insert(r);
r++;
}
if(c==0)

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 26 3/2/2012 6:51:38 PM


Queues 5.27

{
c=1;
r—;
}
else
if(f<0)
printf("\n Deque is full ");
getch();
break;
case 2: deleter(—r,f);break;
case 3: deletef(r,++f);
break; case 4: show (); break;
default: exit(0);
}
}
}

void show()
{
int j;
printf("\n Elements of deque are: ");
for(j=0;j<5;j++)
printf(" %d ",ird[j]);
getche();
}

int insert(int h)
{
int k;
printf("\n Enter an element (enter 0 to exit): ");
scanf("%d",&k);
ird[h]=k;
return(k);
}

void deleter(int m,int n)

{
if(m<=n)
printf("Deque is empty");
else
{
printf("\n %d The element deleted: %d",m,ird[m]);
ird[m]=0;
}
getch();

void deletef(int f,int j)


{
if(f<j)

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 27 3/2/2012 6:51:39 PM


5.28 Data Structures Using C

printf("Deque is empty");
else
{
printf("\n %d The element deleted:- %d",j,ird[j]);
ird[f]=NULL;
}
getch();
}

OUTPUT:
(1) Insert
(2) Delete from rear
(3) Delete from front
(4) Display
(0) Exit
Enter Your choice:- 1
Enter an element (enter 0 to exit): 2
Enter an element (enter 0 to exit): 3
Enter an element (enter 0 to exit): 5
Enter an element (enter 0 to exit): 8
Enter an element (enter 0 to exit): 6
Deque is full
(1) Insert
(2) Delete from rear
(3) Delete from front
(4) Display
(0) Exit
Enter Your choice:- 4
Elements of deque are: 2 3 5 8 6

Explanation:
The output of the program is not fully displayed here. User can see it by executing it. Recall that
in input restricted queue, insertion can be done only from rear end and it is carried out by the
function insert(). The while loop is executed for continuous execution of the insert()
function. User can enter element and when zero is entered, the loop is terminated. Thus, insertion
of elements is carried out. The variable r(rear) is incremented and its value should not exceed
the maximum capacity of the array, i.e. 5 and the same is done in the while loop condition.

We have a choice to remove the elements. We can remove elements from both the ends. If we go for
second choice, elements from rear side are removed. The variable r (rear) is decremented and the r th ele-
ment of the deque is erased. This option has a side effect. The empty locations generated by the deletion
operation can be filled using insertion operation. However, if we go for option 3 the case is different. In
this case, the elements are deleted from front and vacant space is created at the beginning of the deque.
If we want to insert the element in that place, the insert option will fail here. This is because it is pro-
grammed in circular fashion. This is the drawback of input restricted deque.

Out Restricted Deque In the output restricted deque insertion of an element can be done at both front
and rear end and deletion operation can be done only at front end. The output restricted deque is shown
in Fig. 5.16.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 28 3/2/2012 6:51:39 PM


Queues 5.29

Front Rear

Insertion
Insertion
Deletion

Figure 5.16 Output Restricted Deque

The following operations are possible in the output restricted deque:


1. Insertion at both front and rear end.
2. Deletion at only front end.
An example to demonstrate output restricted deque is illustrated below.

Example 5.11 Write a program to demonstrate output restricted deque.

# include <stdio.h>
# include <conio.h>
# include <process.h>

int ird[5];

void main()
{
int r=0,c=1,op,f=-1;
int insertr(int);
int insertf(int);
void deletef(int);
void show(void);
clrscr();

while(1)
{

printf("\n 1 Insert from rear: ");


printf("\n 2 Insert from front");
printf("\n 3 Delete from front");
printf("\n 4 Display ");
printf("\n 0 Exit");
printf("\n Enter Your choice: ");
scanf("%d",&op);

switch(op)
{
case 1:
while(c && r<5)
{
c=insertr(r);
r++;
}

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 29 3/2/2012 6:51:39 PM


5.30 Data Structures Using C

if(c==0)
{
c=1;
r⎯;
}
else if(f<0)
printf("\n Deque is full ");
getch();
break;
case 2: f=insertf(f); break;
case 3: deletef(++f); break;
case 4: show(); break;
default: exit(0);
}
}
}
void show()
{
int j;
printf("\n Elements of deque are: ");
for(j=0;j<5;j++)
printf(" %d ",ird[j]);
getche();
}
int insertr(int h)
{
int k;
printf("\n Enter a Element(enter 0 to exit): ");
scanf("%d",&k);
ird[h]=k;
return(k);

}
int insertf(int m)
{
int h;
if(ird[m]==0 && m>=0)
{
printf("\n Enter a element: ");
scanf("%d",&h);
ird[m]=h;
}
else
printf("\n no space available ");
return ⎯m;
}
void deletef(int f) { ird[f]=NULL; }

OUTPUT
1 Insert from rear:
2 insert from front
3 Delete from front

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 30 3/2/2012 6:51:39 PM


Queues 5.31

4 Display
0 Exit
Enter Your choice: 1
Enter a Element (enter 0 to exit): 1
Enter a Element (enter 0 to exit): 2
Enter a Element (enter 0 to exit): 3
Enter a Element (enter 0 to exit): 0
1 Insert from rear:
2 insert from front
3 Delete from front
4 Display
0 Exit
Enter Your choice: 4
Elements of deque are: 1 2 3 0 0

Explanation:
In the output restricted queue, insertion can be done at both the ends and deletion can be done
only at front end. The deletion procedure is same as the last program. In addition, insertion
from rear end follows the same instruction as described in the previous program. The newly
introduced function is insertf (), which performs insertion of elements from front of the
deque. First, the space availability is checked. If space is available and request is made, the
user has to insert the element and the same is stored in the empty location. The variable f is
decremented. This is because while performing deletion operation the front is shifted forward
and to reverse it, the value of f is decremented.

5.8.3 Priority Queues


We know that queue is based on the technique first come first out (FIFO). The element inserted first will
be deleted first. A priority queue is another type of queue. Here, the priority is determined according to
the position of the queue, which is to be entered. Various real life problems are based on priority queues.
For example, in the buses few seats are reserved for ladies and handicapped; if a company is providing any
scheme, the employees of the same company are given second priority.
Priority queue is a data structure in which prioritized insertion and deletion operations on elements can be
performed according to their priority values.
There are two types of priority queues:

Ascending Priority Queues In this queue elements can be inserted randomly. The smallest element of
the queue is deleted first.

Example 5.12 Write a program to create ascending priority queue. Insert and remove the element.

# include <stdio.h>
# include <conio.h>

int prq[5]={0};
int insert();

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 31 3/2/2012 6:51:39 PM


5.32 Data Structures Using C

void remove1();
void show();

void main()
{
int j,c=1;
while(c!=0)
{
clrscr();
printf("\n 1. Insert");
printf("\n 2. Remove");
printf("\n 3. Display");
printf("\n 0. Exit");
printf("\n Enter Your choice: ");
scanf("%d",&c);
switch(c)
{
case 1: insert(); break;
case 2: remove1(); break;
case 3: show(); break;
default: exit(0);
}
}
}
int insert()
{
int n,j;
printf("\n Enter the position: ");
scanf("%d",&n);
n⎯;
if(n>4 || prq[n]!=0)
{
printf("\n Location is not available");
return 0;
}
printf("\n Enter Element: ");
scanf("%d",&j);
prq[n]=j;
return 0;
}

void remove1()
{
int j,k,min=0,s=0;
for(j=0;j<=4;j++)
s=s+prq[j];
for(j=s;j>0;j⎯)
{
for(k=0;k<5;k++)
{
if(j==prq[k])
min=prq[k];
}
}

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 32 3/2/2012 6:51:39 PM


Queues 5.33

for(j=0;j<5;j++)
{
if(prq[j]==min)
{
prq[j]=0;
break;
}
}
}
void show()
{
int h;
for(h=0;h<5;h++)
printf(" %d ",prq[h]);
getch();
}

OUTPUT
1. Insert
2. Remove
3. Display
0. Exit
Enter Your choice: 1
Enter the position: 1
Enter Element: 3

Explanation:
In this program an array prq[] is defined. The array prq[] is used to implement priority
queue. The insert() function is used to insert an element in the queue. The position and
element number are to be provided by the user. According to user entered values, the process
is executed. User can randomly insert position numbers from 1 to 5. If the user repeats the
same location number in which the element is already stored, the insertion will be terminated.
The replacement of element is not allowed here. If the location is empty then only insertion of
element is possible.

The show() function is used to display elements only. The remove1() function is used to remove
the element. Before the removal of an element, it must be sorted first (in ascending or descending order).
We know that in ascending order queue, the smallest element is deleted first. Hence, instead of arranging
all the elements of the queue in ascending order, here the smallest element of the queue is searched and it
is removed. In the priority queue, we can insert an element anywhere in the queue. Hence, it may not be
compulsory to arrange the numbers in ascending order. If we arrange the elements in ascending order and
then begin the removal operation, it will also change the exact position of the element. The user can also
implement this program by sorting the queue elements, storing elements temporarily and then the small-
est element can be erased. The program for descending priority queue can be done in the same fashion.

Descending Priority Queue In this queue also, elements can be inserted randomly but the largest element
is deleted first.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 33 3/2/2012 6:51:39 PM


5.34 Data Structures Using C

Example 5.13 Write a program to create descending priority queue. Insert and remove the element.

# include <stdio.h>
# include <conio.h>

int prq[5]={0};
int insert(void);
void remove1(void);
void show(void);

void main()
{
int j,c=1;
clrscr();

while(c!=0)
{
printf("\n 1. Insert");
printf("\n 2. Remove");
printf("\n 3. Display");
printf("\n 0. Exit");
printf("\n Enter Your choice: ");
scanf("%d",&c);

switch(c)
{
case 1: insert(); break;
case 2: remove1(); break;
case 3: show(); break;
}
}
}
int insert()
{
int n,j;
printf("\n Enter the position: ");
scanf("%d",&n);
n––;

if(n>4 || prq[n]!=0)
{
printf("\n Location is not avaliable");
return 0;
}

printf("\n Enter Element: ");


scanf("%d",&j);
prq[n]=j;
return 0;

void remove1()

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 34 3/2/2012 6:51:39 PM


Queues 5.35

{
int j,k,max=0,s=0;
for(j=0;j<=4;j++)
s=s+prq[j];

for(j=0;j<s;j++)
{
for(k=0;k<5;k++)
{
if(j==prq[k]) max=prq[k];
}
}

for(j=0;j<5;j++)

if(prq[j]==max)
{
prq[j]=0;
break;
}
}
}
void show()
{
int h;
for(h=0;h<5;h++)
printf(" %d ",prq[h]);
}

OUTPUT
1. Insert
2. Remove
3. Display
0. Exit
Enter Your choice: 3
8 3 1 10 9
1. Insert
2. Remove
3. Display
0. Exit
Enter Your choice: 2
1. Insert
2. Remove
3. Display
0. Exit
Enter Your choice: 3
8 3 1 0 9

Explanation:
This program is same as previous one. Here, only the largest element is deleted first. It is an
example of descending order queue.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 35 3/2/2012 6:51:39 PM


5.36 Data Structures Using C

In both the above types, if elements with equal priority are present, the FIFO technique is applied.
In case the queue elements are sorted, the deletion of an element will be quick and easy because elements
will appear either in ascending or descending order. However, the insertion operation will be easier said
than done because empty locations will have to be searched and only then elements can be placed at that
location.
In case the queue elements are not in order, i.e. not sorted, insertion operation will be quick and easy.
However, the deletion operation will take place after the priority value set.
Therefore, we can say that in both the above types insertion operation can be carried out easily. How-
ever, the deletion operation, which is, based on certain priority, i.e. the smallest or largest is first searched
out and later it is removed from the queue. The locations of that element do not matter. In stack and
queues deletion operation is performed at the ends. Conceptually, there is no provision for deleting an
element, which is neither first nor last element of the list.
In the above program, we have not arranged the elements in an ascending or descending order. Just
smallest or largest element is searched and erased.
In deletion operation the element may not be physically removed from the queue and it can be kept
inaccessible in the program. Alternatively, special character called empty indicator such as #, $ can be
placed at that place. Both the insertion and deletion operation perform scanning of the queue elements.
While performing deletion operation the element must be deleted physically. It is possible to make its
access denied. However, for other computation operation, the element logically deleted but physically
existing will be taken into account and will change the result. So, for sure result, the element must be
removed.
The elements of the queue can be number, character or any complex object which is a composition
of one or more basic data types.
In priority queue every element has been assigned with a priority value called priority. The elements can
be inserted or deleted randomly anywhere in the queue. Consider the following points of queue:
1. An element of upper priority is processed prior to an element of lower priority.
2. If two elements have the same priority, they are processed depending on the order they are inserted in
the queue, i.e. FIFO.

Front Rear

1 2 3 5 7 8 9 Elements

5 1 8 2 9 4 3 Priority Value

Figure 5.17 Priority Queue

As shown in Fig. 5.17, the element 7 is deleted first. However, the element 1 is nearer to the front as
compared to 7, but 7’s priority value is nine, which is higher, and hence it is deleted first. Though the
queue is based on FIFO technique, the priority queue is not based on FIFO operation firmly. A program
on priority queue is provided below for detailed understanding.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 36 3/2/2012 6:51:39 PM


Queues 5.37

Example 5.14 Write a program to demonstrate priority queue. Enter number and priority value.
Perform insert and deletion operation.

# include <stdio.h>
# include <conio.h>

int pq[2][5]={0};

void main()
{
int c=1;
int insert(void);
void show(void);
void remove1(void);
clrscr();
do
{
printf("\n1 Insert");
printf("\n2 Remove ");
printf("\n3 Display");
printf("\n0 Exit");
printf("\n Enter Your Choice: ");
scanf("%d",&c);
switch(c)
{
case 1: insert(); break;
case 2: remove1(); break;
case 3: show(); break;
case 0: c=0;
}
}
while(c!=0);
}

int insert()
{
int p,e,r;
printf("\n Position: ");
scanf("%d",&p);
if(p>5 || p<0)
{
printf("\n Invalid Argument ");
return 0;
}
p⎯;
printf("\n Element: ");
scanf("%d",&e);
if(pq[0][p]==0)
pq[0][p]=e;
printf("\n Priority: ");
scanf("%d",&r);
pq[1][p]=r;
return 0;

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 37 3/2/2012 6:51:39 PM


5.38 Data Structures Using C

void show()
{

int j,k;
for(j=0;j<2;j++)
{
if(j==0)
printf("\n Elements: ");
else
printf("\n Priority: ");
for(k=0;k<5;k++)
printf(" %d ",pq[j][k]);
printf("\n");
}
}

void remove1()
{
int j,maxp=0;
for(j=0;j<5;j++)
{
if(pq[1][j]>maxp)
maxp=pq[1][j];
}
for(j=0;j<5;j++)
{
if(pq[1][j]==maxp)
{
pq[0][j]=pq[1][j]=0;
break;
}
}
}

OUTPUT
Elements: 1 2 8 9 4
Priority: 1 3 9 8 3
1 Insert
2 Remove
3 Display
0 Exit
Enter Your Choice: 2
1 Insert
2 Remove
3 Display
0 Exit
Enter Your Choice: 3
Elements: 1 2 0 9 4
Priority: 1 3 0 8 3

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 38 3/2/2012 6:51:39 PM


Queues 5.39

Explanation:
This program is the same as the last few programs. Here, in this program two-dimensional array
is defined. Using insert, function elements position number, element and its priority value
are entered. Replacement of element is not allowed. When remove function is executed, the
element with higher priority is detected and removed. The show() function is used to display
the elements and priority value.

5.9 APPLICATIONS OF QUEUES

There are various applications of computer science, which are performed using data structure queue.
This data structure is usually used in simulation, various features of operating system, multiprogramming
platform systems and different type of scheduling algorithm are implemented using queues. Round robin
technique is implemented using queues. Printer server routines, various applications software are also
based on queue data structure.

5.9.1 Round Robin Algorithm


Round Robin (RR) algorithm is an important scheduling algorithm. It is used especially for the time-
sharing system. The circular queue is used to implement such algorithms.
For example, there are N procedures or tasks such as P 1, P 2, P 3 . . . PN . All these tasks are to be
executed by the central processing unit (CPU) of the computer system. The execution times of the tasks
or processes are different. The tasks are executed in sequence P1, P2, P3 and PN .
In time, sharing mode the tasks are executed one by one. The algorithm forms a small unit of time, say,
from 10 to 100 milliseconds for each task. This time is called time slice or time quantum of a task. The
CPU executes tasks from P1 to PN allocating fixed amount of time for each process. On allocating time to
all tasks, CPU resumes the first task. That is, when all tasks are completed, it returns to P1. In the time-
sharing system, if any task is completed before the estimated time, the next task is taken up for execution
immediately. Consider the following table:

Tasks Expiry Time (Units)


P1 10
P2 19
P3 8
P4 5

There are total four tasks and the total time to complete all the tasks would be (10+19+8+5) 42 units.
Suppose, the time slice is of 7 units. The RR scheduling for the above case would be as given the following
paragraph.
In the first pass each task takes seven units of time-task P4 is executed in the first pass whereas task
P1, P2, P3 requires more than 7 units of time. Hence, in the second round task P1 and P3 are executed.
At last, P2 is executed.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 39 3/2/2012 6:51:39 PM


5.40 Data Structures Using C

5.9.2 Simulation
It is an extremely powerful tool used for experimentation purpose. Without performing real experiments
simulation permits to take the results and if necessary modification can be done as per expected results.
One of the standard applications of queue can be implemented with simulation. Simulation is a method
of managing a theoretical illustration of a real life problem with the purpose of understanding the effect
of modification, concern factors and implementing some approaches to get reliable solution. The main
goal of simulation is to help the user or to guess for obtaining the output of the program after implement-
ing some approaches. It permits the user to make several trials for getting the actual results and planned
situations without disturbing the real situation.
There are few disadvantages in the simulation. Lengthy simulation creates execution over-head on
computer. For solving a real life problem, various assumptions are made to find out the key solution. If the
assumption is straightforward, the outcome will be less reliable. In contrast, if the assumption is having
more particulars, the outcome will be reliable and better. If the primary assumptions are wrong, even
though, the program source code is given in detail, the guess obtained will be incorrect. In this situation,
the program developed becomes futile.

5.10 TYPES OF SYSTEMS

A system may be isolated or continuous. The continuous system has some arguments, which can receive
any real value in some gaps. Simulation of this system runs on these continuous arguments. In the discrete
system, the method is different, it takes only selected set of values. The moving of a fan at home is a discrete
system and its speed can be controlled. The motion of earth or sun is an example of continuous system
and its motion is out of our control. The input and output parameters also defines system. The system can
be either deterministic or stochastic. The input and output parameters also have a relationship. The various
systems are descried in Fig. 5.18.

Deterministic System In this case if input values and initial state are available the result can be
determined.

Stochastic System This system necessitates efforts for simulation. There is no standard clarification for
this system.

System

Discrete Continuous Deterministic Stochastic


System System System System

Figure 5.18 Types of Systems

To simulate a system a model is formed. It is a body of detailed particulars and applied to represent
the system in various forms. There are various models as event-driven, simulation and time-simulation

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 40 3/2/2012 6:51:39 PM


Queues 5.41

model and selection of model depends upon particulars of information available. The first step in solving
the problem is selecting structure of model because the model indicates the system and it is easier than
the problem. The model should be restricted and should not provide information out of the system.
To facilitate the formation of model for a state, the characteristics, entities, activities and operations
of the system must be determined. Activity refers to change of system state. The entities indicate the
mechanism of the system and serves as an object in the simulation. The objects have characteristics. The
characteristics of objects denote the state of the system and association between various entities at that
particular movement. The program must execute given steps and activities (change of state) must occur
in sequence.

SUMMARY
1. A queue is a non-primitive, linear data structure and a sub-class of list data structure. It is
an ordered, homogenous collection of elements in which elements are appended at one
end called rear end and elements are deleted at other end called front end.
2. The static implementation means the array implementation. In this implementation,
we should be assured about the number of elements we want to have in the queue.
3. Two operations can be carried out on queue:
a. insertion of element
b. deletion of element.
4. Dynamic implementation is carried out using pointers. By applying increment, operation
on pointer successive locations of memory can be accessed and an element can be stored
in that location.
5. There are three types of queue, i.e. circular queue, deque and priority queue.
6. In the circular queue, the first element is stored immediately after last element. If last
location of the queue is occupied then the new element is inserted at the first memory
location of queue implementing array (queue).
7. In the double-ended queue, insertion and deletion can be performed from both the ends
and therefore, it is called double-ended queues and in short called deque. It is a homog-
enous list of elements.
8. In the input restricted deque, insertion and deletion operation are performed at rear end
whereas only deletion operation is performed at front end.
9. In the output restricted deque, insertion of an element can be done at both front and rear
end and deletion operation can be done at only front end.
10. Priority queue is a data structure in which prioritized insertion and deletion operations on
elements can be performed according to their priority value.
11. Ascending priority queue: In this, queue elements can be inserted randomly. The smallest
element of the queue is deleted first.
12. Descending priority queue: In this queue also, elements can be inserted randomly and the
largest element is deleted first.
13. Simulation is a method of organizing a theoretical representation of a real life problem with
the purpose of understanding the effect of alteration, concern factors and implementing
some approaches to get reliable solution.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 41 3/2/2012 6:51:39 PM


5.42 Data Structures Using C

EXERCISES
A. Answer the following questions:

1. What is queue? Explain it with real life examples.


2. Explain the terms front and rear with relevance to queue. Which operations are to be
performed at these ends?
3. Explain different types of queues.
4. How is implementation of queue done?
5. What are the limitations of simple queue?
6. Explain the insertion and deletion operations of queue.
7. Differentiate between simple and circular queues.
8. Differentiate between stack and queue.
9. Distinguish between FIFO and LIFO.
10. Give the definition of priority queue. Explain its types.
11. Explain types of deque.
12. Explain types of priority queues.
13. Explain system and types of systems.

B. Attempt the following programs:

1. Write a program to insert and display the eight alphabetic characters in a queue.
2. Write a program to declare a priority queue using two-dimensional array, store elements and
priority. Display the elements according to priority from higher to lower.
3. Write a program to implement circular queue with the pointers.
4. Write a program to insert and display the elements of deque, with the array and pointers.
5. Write a program to insert five elements in the ascending priority queue. Sort the elements in
ascending order. Perform the deletion operation and shift the empty location at the end of array.
6. Write a program to create a priority queue. Store element and priority value. Assume square
root of entered number as its priority value. Insert and delete the elements.
7. Write a program to implement a circular queue containing eight elements and perform the
insertion and deletion operation.

C. Select the appropriate option for each of the following questions:

1. Queue follows the rule


(a) FIFO (c) LILO
(b) LIFO (d) FILO.
2. The rear end of the queue is used
(a) to insert an element (c) both (a) and (b)
(b) to remove an element (d) none of the above.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 42 3/2/2012 6:51:40 PM


Queues 5.43

3. The front end of the queue is used


(a) to insert an element (c) both (a) and (b)
(b) to remove an element (d) none of the above.
4. When an element is inserted in queue, the position of rear
(a) increases (c) remains constant
(b) decreased (d) none of the above.
5. When an element is inserted in queue, the position of front
(a) increments (c) unchanged
(b) decrements (d) none of the above.
6. Which one of the following is not a type of queue?
(a) output restricted deque (c) deque
(b) circular queue (d) priority queue.
7. In this queue elements can be inserted randomly
(a) priority queue (c) circular queue
(b) simple queue (d) none of the above.
8. In the input restricted queue
(a) deletion of element at both front and rear ends is done
(b) insertion of element at both front and rear ends is done
(c) deletion at only front end
(d) all of the above.
9. In this queue, smallest element of the queue is deleted first.
(a) ascending priority queue (c) circular queue
(b) descending priority queue (d) simple queue.
10. When the circular queue is full, and if one element is removed the next inserted element is
stored at
(a) first location (c) intermediate location
(b) last location (d) none of the above.

D. Find the output

1. printf("\n Elements of Queue are: ");


# include <stdio.h> r=0;
# include <conio.h> while(r<7)
void main() {
{ printf(" %d ", que[r]);
int que[8]; r++;
int r=0; }
clrscr(); }
while(r<7)
{ 2.
printf("Enter # include<stdio.h>
element: "); # include <conio.h>
scanf("%d",&que[r]);
void main()
r++;
{
}
int q[7];

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 43 3/2/2012 6:51:40 PM


5.44 Data Structures Using C

int r=0,f=0,j; 4.
clrscr(); # include<stdio.h>
while(r<6) # include <conio.h>
{ void main()
printf("rear=%d front=%d Enter {
element:",r,f); int q[6];
scanf("%d",&q[r]); int i,r=6,f=0,n;
r++; clrscr();
} printf("Enter the seven elements
printf("\n Queue elements are: of a queue:- ");
"); for(i=0;i<7;i++)
for(j=0;j<6;j++) scanf("%d",&q[i]);
printf(" %d ",q[j]);
printf("\nThe queue element are
}
as:-\n");
for(i=0;i<7;i++)
3. printf("%2d ",q[i]);
# include<stdio.h> printf("\nValues of at start
# include<conio.h> rear=%d front=%d",r,f);
printf("\n\nHow many elements you
void main() want to delete: ");
{ scanf("%d",&n);
int q[7]; while(f<n)
int r=0,f=0,j; {
char ch; q[f]=NULL;
clrscr(); f++;
while(r<6) printf("\nrear=%d front=%d",
{ r,f);
printf("rear=%d front=%d Enter }
element:",r,f); printf("\n Queue elements are:
scanf("%d",&q[r]); ");
r++; for(n=0;n<7;n++)
} printf(" %d ",q[n]);
printf("\nQueue elements }
are: ");
for(j=0;j<6;j++)
printf(" %d ",q[j]); 5.
printf("\nWould you like # include <stdio.h>
to delete one element from # include <conio.h>
queue?[Y/N]:-"); # include <process.h>
scanf("%s",&ch); int qe[8];
if(ch=='y'||ch=='Y') int r=0,j;
{ char ans='Y';
q[f]=0; void insert();
f++; void del();
printf("\nAfter deletion of one void show();
element main()
rear=%d front=%d\n ",r,f); {
printf("\nQueue elements are:- int c;
"); while(1)
for(j=f;j<6;j++) {
printf(" %d ",q[j]); clrscr();
} printf("\n 1] Insert
} Element ");

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 44 3/2/2012 6:51:40 PM


Queues 5.45

printf("\n 2] Delete printf("\n Queue is Full");


Element "); getch();
printf("\n 3] Display element"); break;
printf("\n 4] Exit"); }
printf("\n Enter your else
choice: "); r++;
scanf("%d",&c); printf("\n Continue Y/N: ");
switch(c) ans=getch();
{ }
case 1: insert(); break; }
case 2: del(); show();break; }
case 3: show(); break; void show()
default: exit(0); {
} int j;
} for(j=0;j<r;j++)
}
printf(" %d ",qe[j]);
void insert()
getch();
{
}
if(r>=7)
void del()
printf("\n Queue is full
{
\n\n\n");
if(r<=0)
else
{
{
clrscr();
ans='y';
while(ans=='Y'||ans=='y') printf("\n Queue is empty
{ \n\n\n");
printf("\n Enter }
element:- "); for(j=0;j<r;j++)
scanf("%d",&qe[r]); qe[j]= qe[j+1];
if(r==7) qe[r]=0;
{ r––;
clrscr(); }

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 45 3/2/2012 6:51:40 PM


This page is intentionally left blank.

M05_ASHOK NAMDEV KAMTHANE5067_01_SE_C05.indd 46 3/2/2012 6:51:40 PM


Chapter 6

Linked List
CHAP TER O U T LIN E
6.1 Introduction 6.13 Insertion of Node at a Given Position
6.2 Linked List 6.14 Representation of Stacks Using Linked
Lists
6.3 Illustration of Linked List for Storing
a String 6.15 Representation of Queues Using Linked
Lists
6.4 Important Terms
6.16 Reversing the Singly Linked List
6.5 Memory Allocation and De-allocation
6.17 Concatenation of Two Lists
6.6 Operations on Linked Lists
6.18 Splitting of a Linked List
6.7 Singly Linked List
6.19 Circular Linked List
6.8 Linked List with Header
6.20 Method for Detecting End
6.9 Linked List Without Header
6.21 Doubly Linked List
6.10 Insertion in the Linked List
6.22 Circular Doubly Linked List
6.11 Insertion of Node at Start
6.23 Applications of Linked List
6.12 Insertion of Node at End

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 1 3/2/2012 6:52:07 PM


6.2 Data Structures Using C

6.1 INTRODUCTION

A list is a series of linearly arranged finite elements (numbers) of same type. The data elements are called
nodes. The list can be of two types, i.e. basic data type or custom data type. The elements are positioned
one after the other and their position numbers appear in sequence. The first element of the list is known
as head and the last element is known as tail.

Head Tail

Elements
1 5 8 4 3 2

0 1 2 3 4 5 Element
Position

Figure 6.1 Static List

As shown in Fig. 6.1, the element 1 is at head position (1st position) and element 2 is at tail posi-
tion (6th). The element 5 is the predecessor of element 8 and 4 is the successor. Every element can act as
a predecessor excluding the first element because it does not have a predecessor in the list. The list has
following properties:
a. The list can be enlarged or reduced from both the ends.
b. The tail (ending) position of the list depends on how long the list is extended by the user.
c. Various operations such as traverse, insertion and deletion can be performed on the list.
d. The list can be implemented by applying static (array) or dynamic (pointer) implementation.

6.2 LINKED LIST

A linked list is a dynamic data structure. It is an ideal technique to store data when the user is not aware
of the number of elements to be stored. The dynamic implementation of list using pointers is also known
as linked list. Each element (data and link) of the linked list is called as node. Each node points to the next
node. In the linked list, a node can be inserted or deleted at any position. Each node of linked list has two
components. The first component contains the information or any data field and second part the address
of the next node. In other words, the second part holds address of the next element. This pointer points to
the next data item. The pointer variable member of the last record of the list is generally assigned a NULL
value to indicate the end of the list. Fig. 6.2 indicates the linked list.

data data data data

pointer pointer pointer NULL

Figure 6.2 Linked List

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 2 3/2/2012 6:52:08 PM


Linked List 6.3

The basic data type in the linked list can be int, float and user defined data types can be created by
struct cla. The link structure as well as a pointer of structure type to the next object in the link is observed
in it.
A simple example describing the operation of linked list is illustrated in the following section.

6.3 ILLUSTRATION OF LINKED LIST FOR STORING A STRING

In this example, a linked list containing a string of characters to be stored in the memory, is described. The
linked list has two field data, i.e. actual data stored and links, i.e. pointing to the next node of the linked
list. These two fields are shown with two arrays such as data[j] and link[j] where ‘j’ is the position of an
element. A variable begin is initiated which contains the beginning location of the list. The field ‘No.’ is
taken for numbering the nodes of the linked list. It is not the part of the linked list. It is given simply for
understanding. In the link[j] ‘0’ (zero) indicate the NULL pointer which is end of the string. In this type
of lists the nodes or elements are not stored in the successive memory locations. Many links have been
shown between data and link.
The nodes of the linked list are not ordered sequentially. The characters are stored dynamically with
their link fields. The link field shows the link to the next node of the linked list. The information obtained
from the above linked list is ‘computer’. It is shown in Fig. 6.3 and the explanation is as follows:
a. Begin =5, data[5] is ‘c’ and link[5]= ‘3’.
b. Link[3]=6 and data[3]= ‘o’.
c. Link[6]=1 and data[6]= ‘m’.
d. Link[1]=2 and data[1]= ‘p’.

No DATA LINK

1 p 2

2 u 8

3 o 6

Begin 5 c 3

6 m 1

7 e 9

8 t 7

9 r 0

Figure 6.3 Illustration of Linked List for Storing a String

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 3 3/2/2012 6:52:08 PM


6.4 Data Structures Using C

e. Link[2]=8 and data[2]= ‘u’.


f. Link[8]=7 and data[8]= ‘t’.
g. Link[7]=9 and data[7]= ‘e’.
h. Link[9]=NULL (0) and data[9]= ‘r’.
The string stored in the memory as per above listing is ‘computer’.

6.4 IMPORTANT TERMS

We have already discussed in previous sections that a linked list is a non-sequential collection of elements
called nodes. These nodes are nothing but objects. These nodes are declared using structure or classes.
Every node has two fields and they are:
1. Data field: In this field, the data or values are stored and processed.
2. Link field: This field holds address of the next data element of the list. This address is used to access
the successive elements of the list.
In the linked list the ordering of elements is not done by their physical location in the memory but by
logical links, which are stored in the link field.

Node The components or objects which form the list are called nodes.

Null Pointer The link field of the last record is assigned a NULL value instead of any address. It means
NULL pointer not pointing to any element.

External Pointer It is a pointer to the starting node. The external pointer contains the base, i.e. address
of first node. Once a base address is available, its next successive nodes can be accessed.

Empty List When there is no node in the list, it is called as empty list. If the external pointer were
assigned a value NULL, the list would be empty.

6.4.1 Static List Versus Linked List

1. The static list is implemented using arrays. The linked list uses pointer in which memory can be allo-
cated or de-allocated during program execution. The linked list is more efficient in memory manage-
ment. The linked list can be expanded or shrunk as per requirement whereas in static list once an array
is defined its size remains the same throughout the program.
2. Once an array is declared, its size remains the same. The memory allocated for array may be extra or
insufficient. The user cannot determine the exact amount of memory required. Due to this, the pro-
gram execution may not be safe. The pointer has intrinsic flexibility to enlarge or reduce the capacity
of storage. We are acquainted with pointer arithmetic operations increment/decrement, which enables
pointer to access any memory location. The use of pointer to point the next node in the linked list data
structure indicates that elements which are logically contiguous due to linear organization need not be
physically contiguous in the memory. This type of memory allocation is called linked allocation.
3. The elements are stored in order logically as well as physically. Array elements are stored in successive
memory locations. This is not the case in the linked list. Insertion and deletion with static list are time con-
suming and shifting of elements is done to rearrange the numbers in order. In the linked list the insertion

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 4 3/2/2012 6:52:08 PM


Linked List 6.5

and deletion operations are done very easily. The element can be deleted by de-allocating the memory of
that particular element. The insertion can be done by allocating space at the specified position.
4. A list has been created to hold an ordered set of elements without knowing the number of nodes. The
simple method to create link is to enlarge each node and it should contain reference of the next node.
This is called singly linked linear list or one-way chain as shown in Fig. 6.4. The arrow (first) indicates
the address of the first node.

First

2 & 3 & 8 & 9

Figure 6.4 Singly Linked Linear List

5. By using linked list more complex data structures such as circular linked list, doubly linked list, stack
and queues can be formed.
6. A pointer plays an important role in the dynamic implementation of linked list. The interpretation of
pointer is an address, which is in-built, and the programmer need not take care of how the addresses
are assigned in the memory. Mostly, all computer systems use addresses to know the instruction to be
executed. Pointers of any data type always are of same length and occupy equal space in the memory,
i.e. 2 bytes only. The pointer is always of unsigned integer type. Consider the following program:

Example 6.1 Write a program to demonstrate the size of pointers of different data types.

# include <stdio.h>
# include <conio.h>

struct node {long int a;}*s;

void main()
{
int *p;
float *f;
clrscr();

printf("\n Integer Pointer Size=%d",sizeof(p));


printf("\n Float Pointer Size=%d",sizeof(f));
printf("\n Structure pointer Size=%d",sizeof(s));
}

OUTPUT
Integer Pointer Size=2
Float Pointer Size=2
Structure pointer Size=2

Explanation:
In this program, pointers of int,float and struct type are declared. The sizeof ()
operator returns the size of pointers. The size of any pointer is always two bytes. The address is
always of unsigned integer having range 0 to 65535.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 5 3/2/2012 6:52:08 PM


6.6 Data Structures Using C

7. In the above program we have demonstrated that pointers occupy only two bytes irrespective of the
type of data. This property of pointers makes it possible for the pointer to operate in carrying out the
referencing of structure in a homogeneous manner with easy allocation methods. The prototype of
structure does not matter. In the sequential allocation, the address of any node in the list can be calcu-
lated if the storage allocation must be in same pattern.

Example 6.2 Write a program to create a simple linked list.

# include <stdio.h>
# include <conio.h>
struct list
{
int n;
int *p;
};
void main()
{
struct list item0,item1, item2;
item2.n=3;
item2.p=NULL;
item1.n=5;
item1.p=&item2.n;
item0.n=7;
item0.p=&item1.n;
clrscr();
printf("\n Linked list elements are: ");
printf(" %d ",item0.n);
printf(" %d ",*item0.p);
printf(" %d ",*item1.p);
printf(" %d ",*item2.p);
}

OUTPUT
Linked list elements are: 7 5 3 0

Explanation:
In this program the structure list is declared with two elements int n and *p. The pointer
*p recursively points to the same structure. The struct item0, item1 and item2 are three
variables of type list. Consider the initialization.

item2.n=3;
item2.p=NULL;

The item2 is the third (last) node of the list. The pointer p is initialized with null because next to this
no node is present and thus no need to point any address.
item1.n=5;
item1.p=&item2.n;

In this node, n is assigned with five. The pointer points to the data field of the next node i.e.
item2.n (7).

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 6 3/2/2012 6:52:08 PM


Linked List 6.7

item0.n=7;
item0.p=&item1.n;

This is the first node. The n is assigned 7 and pointer points to data field of item 1, i.e. 5. Figure 6.5
simulates the operation more clearly.

Item0 Item1 Item2

7 5 3
& item1.n & item2.n NULL

Figure 6.5 Linked List

Example 6.3 Write a program to display string using linked list.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>
struct link
{
char str[30];
struct link *next;
};

typedef struct link linked;


void main()
{
linked *begin, node1,node2,node3, node4;
int j;
clrscr();
printf("\nEnter four words in four lines:-\n ");
begin=(struct link*) malloc(sizeof(linked));
begin=&node1;
gets(node1.str);
node1.next=&node2;
gets(node2.str);
node2.next=&node3;
gets(node3.str);
node3.next=&node4;
gets(node4.str);
node4.next='\0';
printf("Output: ");

printf("%s ",begin->str);

do
{
begin=begin->next;
printf("%s ",begin->str);
}

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 7 3/2/2012 6:52:08 PM


6.8 Data Structures Using C

while(begin->next!='\0');
}

OUTPUT
Data
Structure
with
C
Output: Data Structure with C

Explanation:
In this program, structure link is declared. The str [] char array is used to store string. The
pointer *begin and objects node1, node2, node3 and node4 are declared. In the address
field of object address of other object is stored. For example, in address field of node1 address
of node2 is stored. In address field of node2, address of node3 is stored and so on. Similarly,
using gets () in str [] array string (entered by user) is stored. Using while loop successive
addresses are accessed and complete string is displayed.

6.4.2 Types of Linked List


The linked lists are classified in the following types:

Singly Linked List In this type of linked list two successive nodes of the linked list are linked with each
other in sequential linear manner. An example of a singly linked list can be cited as train in which two
successive compartments are connected as shown in Fig. 6.6.

START 5 & 7 & 9

Figure 6.6 Singly Linked List

Doubly Linked List In this type of linked list each node holds two-pointer field. In the singly linked
list, address of only next element is pointed. Unlike that, in doubly linked list addresses of next as
well as preceding elements are linked with current node. An example of doubly linked list is shown
in Fig. 6.7.

START

5 & & 7 & & 8

Previous Next

Figure 6.7 Doubly Linked List

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 8 3/2/2012 6:52:09 PM


Linked List 6.9

A Circular Linked List Recall that in circular list the first and last elements are adjacent. This type of list
has neither end node nor starting node. A linear single linked list can be circled by storing the address of
first node in the link field of last node as shown in Fig. 6.8.

START Node 1 Node 2 Node 3

3 & 8 & 9 &

Figure 6.8 A Circular Linked List

A Circular Doubly Linked List In this type of linked list each node contains three fields: two link fields
and one data field. The link field holds address of previous and next elements. The address of end node is
linked to first node and vice-verse. Figure 6.9 shows the circular double link list.

START

& 9 & & 3 & & 4 &

Figure 6.9 A Circular Doubly Linked List

6.5 MEMORY ALLOCATION AND DE-ALLOCATION

malloc(): This library function is used to allocate memory space in bytes to the variable. The func-
tion reserves bytes of requested size and returns the base address to pointer variable. The prototype of this
function is declared in the header file alloc.h and stdlib.h. One of the header files must be included in the
header. The syntax of the malloc() function is as follows:
Syntax: pnt=(data type*)malloc(size);

Here, pnt is a pointer.


Example: pnt =(int*)malloc(20);

In the above statement, 20 bytes are allocated to integer pointer pnt. In addition, there are other various
memory allocation functions and its complete description is out of the scope of this book.
free(): This function is used to release the memory allocated by the malloc()function.
Syntax: free(pointer variable)
Example: free(pnt)
The above statement releases the memory allocated to pointer pnt. Consider the following program
based on this concept:

Example 6.4 Write a program to demonstrate the use of malloc() and free() functions.

# include <stdio.h>
# include <conio.h>
# include <alloc.h>

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 9 3/2/2012 6:52:09 PM


6.10 Data Structures Using C

void main()
{
char *str;
str=(char *) malloc(6);
clrscr();
printf("Enter string:-");
scanf("%s",str);
printf("\n str=%s",str);
free(str);
}

OUTPUT
Enter string:-India
str=India

Explanation:
In this program a character pointer variable str is declared. The malloc () function allocates
seven bytes to character pointer *str. The string "India" is assigned to pointer str and it is
displayed. The free () function releases the memory from pointer str.

6.6 OPERATIONS ON LINKED LISTS

The following primitive operations can be performed with linked list:


1. Creation
2. Display
a. Ascending
b. Descending
3. Traversing
4. Insertion
a. At beginning
b. Before or after specified position
5. Searching
6. Concatenation
7. Merging

Creation The linked list creation operation involves allocation of structure size memory to pointer of the
same structure. The structure must have a member which points recursively to the same structure. In this
operation, constituent node is created and it is linked to the link field of preceding node.

Traversing It is the procedure of passing through (visiting) all the nodes of the linked list from starting
to end. When any given record is to be searched in the linked list, traversing is applied. When the given
element is found, the operation can be terminated or continued for next search. The traversing is a
common procedure and it is necessary because operations like insertion, deletion, listing cannot be carried
out without traversing linked list.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 10 3/2/2012 6:52:09 PM


Linked List 6.11

Display The operation in which data field of every node is accessed and displayed on the screen. In the
display operation from beginning to end, link field of every node is accessed which contains address of
next node. The data of that field is displayed. When NULL is detected the operation ends. Each node
points to the next node and this recursion fashion enables the pointer to reach the successive elements.
The above three operations are common and every program involves these operations. Hence, separate
program is not given.

Searching The searching is a process, in which a given element is compared with all the linked list
elements. The if statement is placed and it checks entire list elements with the given element. When an
element is found it is displayed.
Besides the above operations additional operations such as concatenation and merging of list can be done.

6.7 SINGLY LINKED LIST

Recall that linked list is a dynamic data structure with ability to expand and shrink as per the program
requirement. The singly linked list is easy and straightforward data structure as compared to other struc-
tures. By changing the link position other type of linked list such as circular, doubly linked list can be
formed. For creating linked list the structure is defined as follows,
struct node
{
int number;
struct node *p;
};

The above structure is used to implement the linked list. In the number, variable entered numbers are
stored. The second member is pointer to the same structure. The pointer *p points to the same structure.
Here, though the declaration of struct node has not been completed, the pointer declaration of the
same structure type is permitted by the compiler. However, the variable declaration is not allowed. This is
because, the pointers are dynamic in nature whereas variables are formed by early binding. The declara-
tion of objects inside the struct leads to preparation of very complex data structure. This concept is called
object composition and its detailed discussion is out of the scope of this book.
We are familiar with the array and we know the importance of base address. Once a base address is
obtained, successive elements can also be accessed. In the linked list, list can be created with or without
header node. The head holds the starting address.

6.8 LINKED LIST WITH HEADER

The following steps are used to create linked list with header:
1. Three pointers, i.e. header, first and rear are declared. The header pointer is initialized with NULL. For
example, header=NULL where, header is a pointer to structure. If it remains NULL, it implies that the
list has no element. Such list is known as NULL list or empty list, which is shown in Fig. 6.10 (a).

NULL header

Figure 6.10 (a) Empty List

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 11 3/2/2012 6:52:09 PM


6.12 Data Structures Using C

2. In the second step, memory is allocated for the first node of the linked list. For example, the address of first
node is 1888. An integer, say 3, is stored in the variable num and value of header is assigned to pointer next
(Fig. 6.10 (b)).

1888 3 NULL

Figure 6.10 (b) Link List


The address of first node is initialized by both the header and rear.
The statement would be,
header=first;
rear=first;

3. The address of pointer first is assigned to pointers header and rear. The rear pointer is used to identify
the end of the list and to detect the NULL pointer.
4. Again, create a memory location suppose 1890 for the successive node (Fig. 6.10 (c)).
node node->next

1890 10 NULL

Figure 6.10 (c)


5. Link the element of 1890 by assigning the value of node rear ->next. Move the rear pointer to the last node
(Fig. 6.10 (d)).

1888 8 1890 10 NULL

Figure 6.10 (d)


The following program explains the above concept.

Example 6.5 Write a program to create linked list with header.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>

struct num
{
int num;
struct num *next;
}*header,*first,*rear;

void main()
{
void create(void);
clrscr();

create();

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 12 3/2/2012 6:52:09 PM


Linked List 6.13

printf("\n Linked list elements are: ");

while(header!=NULL)
{
printf(" %d ",header->num);
header=header->next;

void create(void)
{
struct num *node;
printf("\n Enter number(0 exit): ");

if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
}

while(1)

{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;

node->next=NULL;
rear->next=node;
rear=node;

}
}

OUTPUT
Enter number(0 exit): 1 3 4 8 7 9 0
Linked list elements are: 1 3 4 8 7 9

Explanation:
This program is an example of linked list with header. Three structure pointers *header,
*first, and *rear are declared after structure declaration. Initially, these pointers are NULL
because they are declared as global. The create function is used to create linked list nodes. Inside
the function create () another structure pointer *node is defined and its scope is local
to the same function. The procedure for creating first and later successive nodes is different.
The if statement checks the value of header. The value of header is NULL. The malloc ()

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 13 3/2/2012 6:52:09 PM


6.14 Data Structures Using C

function allocates memory to pointer first and the entered number is stored in variable num of
the node. In the same if block, both the pointers header and rear are assigned the value of
first. Once, the first node is created, next time the execution of if block is not required. The
while loop iterated continuously and successive nodes are created by allocating memory to
pointer node. Consider the following statements:

1. node->next=NULL;
The above statement, assigns NULL to the pointer next of current node. The user can initiate
this step if no further elements are desired in the linked list.
2. rear->next=node;
The rear pointer keeps track of last node; the address of current node (node) is assigned to
link field of previous node.
3. rear=node;
Before creating next node, the address of last created node is assigned to pointer rear, which is used
for statement (2). In function main (), using while loop the elements of linked list are displayed.
The pointer header is very useful in the formation of linked list. The address of first node (1888)
is stored in pointer header. The value of header remains unchanged until it turns out to be NULL.
The starting location of the list only can be determined by pointer header only.

while(header!=NULL)
{
printf(" %d ",header->num);
header=header->next;
}

6.8.1 Traverse a List with Header


We are familiar with traverse operation, which involves visiting all the elements of the queue. The above
while() loop and associated statement are used to traverse and display the elements of the list.

6.9 LINKED LIST WITHOUT HEADER

In the previous topic, we discussed how linked list is created using header. The implementation of linked
list without header is similar to the linked list with header. The only difference in manipulation is that in
the header list pointer header contains address of first node. In the list without header list, pointer first
itself is starting of the linked list. Consider the following program:

Example 6.6 Write a program to create a linked list without header.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 14 3/2/2012 6:52:09 PM


Linked List 6.15

struct num
{
int num;
struct num *next;
}*first,*rear;

void main()
{
void create(void);
clrscr();

create();
printf("Double linked list elements: ");

while(first!=NULL)
{
printf(" %d",first->num);
first=first->next;
}
}

void create(void)
{
struct num *node;
printf("\n Enter number(0 to exit): ");

if(first==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=first;
rear=first;
}

while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
node->next=NULL;
rear->next=node;
rear=node;
}
}

OUTPUT
Enter number(0 to exit): 1 5 9 8 7 4 2 0
Double linked list elements: 1 5 9 8 7 4 2

Explanation:
In this program only two pointers, first and rear, are declared. They are global pointers;
hence, their contents are NULL. The function create () is invoked and the rest of the
execution of the program is the same as the previous program.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 15 3/2/2012 6:52:09 PM


6.16 Data Structures Using C

6.9.1 Traverse a List Without Header


In the list without header, the lists are traversed with the first node as shown in the above code.

Example 6.7 Write a program to create a single linked list and display the elements.

# include <stdio.h>
# include <conio.h>

struct node
{
int number;
struct node *p;
} *h,*f,*t;

void main()
{
char c;
clrscr();
f=NULL;
do
{
h=(struct node *)malloc(sizeof(struct node));
printf("Enter a number: ");
scanf("%d",&h->number);

if(f!=NULL)
{
t->p=h;
t=h;
}
else f=t=h;
fflush(stdin);
printf("Continue(y/n): ");
scanf("%c",&c);

} while(c=='y');

t->p=NULL;
t=f;
printf("\nThe list elements are: ");
while(t!=NULL)
{
printf(" %d ",t->number);
t=t->p;
}
}

OUTPUT
Enter a number: 5
Continue(y/n): y

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 16 3/2/2012 6:52:09 PM


Linked List 6.17

Enter a number: 3
Continue(y/n): y
Enter a number: 8
Continue(y/n): y
Enter a number: 9
Continue(y/n): n
The list elements are: 5 3 8 9

Explanation:
In this program, the structure node is declared. The struct node contains integer variable
number and pointer to the same structure *p. The structure pointer variables *h, *f and *t
are also declared. In function main (), variable of character type c is defined. The pointer f is
initialized to NULL.

In the do–while, loop using malloc() function memory equal to size of structure node (4 byte) is
allocated to pointer h. The entered number is stored in the number variable. The if statement checks
the pointer f. If it is NULL, the h is assigned to other two pointers, i.e. f and t. Here, f is first node. h is
header and t is used for temporary storage. The user has to enter ‘y’ to enter next elements. First time,
the value of f is NULL and hence, else block is executed. The purpose of assignment of h to f and t is
as follows:

1. In if() block t is used to assign address of newly created next node to the current, i.e. h.
2. Only for the first time else block is executed and in which address of h (when first node is created) is
assigned to f. f contains address of first node.

When the user finishes entering number, t->p=NULL; this statement assigns NULL to pointer p and
link ends here. The address of the first node (f ) is assigned to t. Using while, loop, the pointer p is accessed
and elements are accessed. When NULL pointer is encountered, the while loop terminates.
In Fig. 6.11, the number contains the actual data of the node. The structure node pointer is used to
point to the next node in the linked list hence it is called as the linked field. The link field refers to itself
in recursive form.

struct node
{

int number; Data Field

struct node *p; Link Field

};

Figure 6.11 Structure for Linked List Creation

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 17 3/2/2012 6:52:09 PM


6.18 Data Structures Using C

Example 6.8 Write a program to create a list. Display the list up to specified element.

# include <stdio.h>
# include <conio.h>

struct node
{
int number;
struct node *p;
} *h,*f,*t;

void main()

{
char c,n;
clrscr();
f=NULL;
do
{
h=(struct node *)malloc(sizeof(struct node));
printf("Enter a number: ");
scanf("%d",&h->number);
if(f!=NULL)
{
t->p=h;
t=h;
}
else f=t=h;
fflush(stdin);
printf("Continue(y/n): ");
scanf("%c",&c);
} while(c=='y');
t->p=NULL;
t=f;
printf("\n Enter a element to search: ");
scanf("%d",&n);
printf("\nThe list elements are: ");

while(t!=NULL)
{
printf(" %d ",t->number);
if(t->number==n)
break;
t=t->p;
}
}

OUTPUT
Enter a number: 1
Continue(y/n): y
Enter a number: 3
Continue(y/n): y
Enter a number: 5

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 18 3/2/2012 6:52:10 PM


Linked List 6.19

Continue(y/n): y
Enter a number: 4
Continue(y/n): y
Enter a number: 9
Continue(y/n): n
Enter a element to search: 4
The list elements are: 1 3 5 4

Explanation:
This program is based on searching operation. In this program, the specific element is compared
with every element of the linked list. When the given element is found in the list, the while
loop terminates.

6.10 INSERTION IN THE LINKED LIST

Insertion of an element in the linked list leads to several operations. The following steps are involved in
inserting an element:

a. Creation of node: Before insertion, the node is created. Using malloc() function memory space for
node is booked.
b. Assignment of data: Once the node is created, data values are assigned to members.
c. Adjusting pointers: The insertion operation changes the sequence. Hence, according to the sequence,
the address of next element is assigned to inserted node. The address of current node (inserted) is
assigned to previous node.

The insertion of node can be done in different positions in the list by the following ways:

a. Insertion of the node at the starting: The created node is inserted before the first element. After inser-
tion, the newly inserted element will be the first element of the linked list. In this insertion only the
contents of successive node’s pointer are changed.
b. Insertion at the end of the list: A new element is appended at the end of the list. This operation is easy
as compared to other two (a) and (c) operations. In this insertion only the contents of previous node’s
pointer is changed.
c. Insertion at the given position in the list: In this operation, the user has to enter the position number.
The given position is counted and the element is inserted. In this insertion contents of both previous
and next node’s pointer are altered.

6.11 INSERTION OF NODE AT START

Inserting an element at the beginning involves updating links between link fields of two pointers. After
insertion of new node, the previously existing nodes are moved to the front. Figures 6.12 (a) and (b) and
Example 6.9 illustrates the insertion at the starting.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 19 3/2/2012 6:52:10 PM


6.20 Data Structures Using C

Header

5 & 8 & 3
Node 1 Node 2 Node 3

9 &
New node

Figure 6.12 (a) Before Insertion

The arrow indicates the location of insertion of new node.

Header

9 & 5 & 8 & 3


Node 1 Node 2 Node 2 Node 3

Figure 6.12 (b) After Insertion

After insertion, the new node will be first node and its link field points to the second element, which
was ex-first element.
The program given below explains the insertion of an element in the list.

Example 6.9 Write a program to insert an element at the beginning.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>

struct num
{
int num;
struct num *next;
} *header,*first,*rear;

void main()
{
void atbeg(void);
void create(void);
void show(void);
clrscr();
printf("\n Operation creation:");
create();

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 20 3/2/2012 6:52:10 PM


Linked List 6.21

show();
atbeg();
printf("\n The elements after insertion: ");
show();
atbeg();
show();
atbeg();
show();
}

void create(void)
{
struct num *node;
printf("\n Enter numbers(0 to exit): ");

if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
}

while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
node->next=NULL;
rear->next=node;
rear=node;
}
}

void atbeg()
{
struct num *node,*t;
node=(struct num*) malloc(sizeof(struct num));
printf("\n Insert an element at starting: ");
scanf("%d",&node->num);
t=first;
header=node;
header->next=t;
first=header;
}

void show()
{
printf("\n Linked list elements are: ");

while(header!=NULL)

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 21 3/2/2012 6:52:10 PM


6.22 Data Structures Using C

{
printf(" %d ",header->num);
header=header->next;
}
}

OUTPUT
Operation creation:
Enter numbers(0 to exit): 1 2 3 4 0
Linked list elements are: 1 2 3 4
Insert an element at starting: 5
The elements after insertion:
Linked list elements are: 5 1 2 3 4
Insert an element at starting: 9
Linked list elements are: 9 5 1 2 3 4
Insert an element at starting: 3
Linked list elements are: 3 9 5 1 2 3 4

Explanation:
Here, an element is inserted at the beginning. The function void atbeg() performs this task. In
this function two pointers *node (local to this function) and *t are declared. The malloc()
function allocates memory to pointer node. The entered element is placed in the newly created
node.

Consider the following statements:


t=first;
header=node;
header->next=t;
first=header;

The above four statements adjust the pointer links:

t=first This statement assigns contents of first to pointer t. This is essential because the newly created
node will become first. Hence, before changing pointer first, it is assigned to pointer t.

Header=node We know that header always points to the first node. The newly created node, that is to
be inserted at starting is assigned to pointer header.

header->next=t The pointer t holds address of first element (before insertion). After insertion, it will
be second. The address of second node is assigned to first. The pointer header holds address of first node
and pointer t holds address of second element. Thus, these two successive elements are linked by this
statement.

first=header Before execution of this statement the first points to second node. If we remove this
statement, only one element can be inserted. If we try to insert second element, it will be replaced by the
first element. After assignment of address of header to first, the insertion can be carried out successfully.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 22 3/2/2012 6:52:10 PM


Linked List 6.23

6.12 INSERTION OF NODE AT END

A new element is inserted or appended at the end of existing linked list. The address of newly created node
is linked to previous node that is NULL. The new node link field is assigned a NULL value. Figure 6.13
shows the insertion operation at the end.

Header

5 & 8 & 3

New Node

(a) Before Insertion

Header

5 & 8 & 3 & 2

(b) After Insertion

Figure 6.13 Insertion of Element at the End

Example 6.10 Write a program to insert an element at the end of the linked list.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>

struct num
{
int num;
struct num *next;
}*header,*first,*rear;

void main()
{
void atend(void);
void create(void);
void show(void);
clrscr();
printf("\n Operation creation:");
create();
show();
atend();
show();
atend();
show();
}
void create(void)

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 23 3/2/2012 6:52:10 PM


6.24 Data Structures Using C

{
struct num *node;
printf("\n Enter numbers(0 to exit): ");

if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
}

while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
node->next=NULL;
rear->next=node;
rear=node;
}
}

void atend()
{
struct num *node,*t;
t=rear;
rear=(struct num*) malloc(sizeof(struct num));
printf("\n Insert an element at end: ");
scanf("%d",&rear->num);
t->next=rear;
rear->next=NULL;
}
void show()
{
printf("\n Linked list elements are: ");

while(header!=NULL)
{

printf(" %d ",header->num);
header=header->next;
}

header=first;
}

OUTPUT
Operation creation:
Enter numbers(0 to exit): 1 2 3 0
Linked list elements are: 1 2 3

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 24 3/2/2012 6:52:10 PM


Linked List 6.25

Insert an element at end: 4


Linked list elements are: 1 2 3 4
Insert an element at end: 5
Linked list elements are: 1 2 3 4 5

Explanation:
In this program the function atend() is used to insert element at the end of the list.

Consider the following statements:

t=rear This statement assigns address of last node to pointer t.

rear=(struct num*) malloc(sizeof(struct num)) After assigning address of rear pointer to t, new
memory location is allocated to pointer rear. The new element entered is stored in the data field of
pointer rear.

t->next=rear Now, the pointer t holds the last but one node of the linked list. The address of new
inserted end node is assigned to link field of node through pointer t.

rear->next=NULL The rear pointer holds address of last node and its link field is assigned a NULL
value.

6.13 INSERTION OF NODE AT A GIVEN POSITION

Insertion of node can be done at a specific position in the linked list. Figure 6.14 and the program explain
insertion of a node at the specific position in the linked list. If we want to insert a node at third position,
then observe Figs. 6.14 (a) and 6.14 (b).

Header

5 & 8 & 9

3 &

Figure 6.14 (a) Formed Linked List

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 25 3/2/2012 6:52:10 PM


6.26 Data Structures Using C

Node is inserted at third position and after insertion, the linked list would be as shown below.

Header

5 & 8 & 3 & 9

(b) Linked List After Insertion

Figure 6.14 (b) Linked List After and Before Insertion

Example 6.11 Write a program to insert an element at a specific position.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>

struct num
{
int num;
struct num *next;
} *header,*first,*rear;

int count;
void main()
{
void atpo(int);
void create(void);
void show(void);
int p;
clrscr();

printf("\n Operation creation:");


create();
show();
printf("\n Enter position (upto %d)number:",count);
scanf("%d",&p);
atpo(––p);
show();
}

void create(void)
{
struct num *node;
printf("\n Enter numbers(0 to exit): ");
if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 26 3/2/2012 6:52:10 PM


Linked List 6.27

}
while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
node->next=NULL;
rear->next=node;
rear=node;
}
}

void atpo(int k)
{
struct num *nw,*su,*pr;
int c=1;

while(header!=NULL)
{
c++;
header=header->next;

if(k==1) pr=first;
if(c==k) pr=header;
if(c==(k+1)) su=header;
}

nw=(struct num*) malloc(sizeof(struct num));


printf("\n Enter an element: ");
scanf("%d", &nw->num);

pr->next=nw;
nw->next=su;
header=first;
}

void show()
{
printf("\n Linked list elements are: ");

while(header!=NULL)
{
printf(" %d ",header->num);
count++;
header=header->next;
}
header=first;
}

OUTPUT
Operation creation:
Enter numbers(0 to exit): 1 2 3 4 5 0

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 27 3/2/2012 6:52:10 PM


6.28 Data Structures Using C

Linked list elements are: 1 2 3 4 5


Enter position(upto 5)number:3
Enter an element: 8
Linked list elements are: 1 2 8 3 4 5

Explanation:
In this program the operation creation and display of linked nodes is similar as explained in the
last programs. Here, we are going to discuss insertion at a specified position carried out by a
function atpo().

The position number specified by the user after reducing value by one is passed to function atpo().
The variable k, formal argument of p, gets this value. Another variable c is declared in the body of atop().
The variable c is incremented and successive nodes of the linked list are accessed by the statement
header=header->next;
Consider the statements
a. if (k==1) pr-first;
b. if (c==k) pr=header;
c. if (c==(k+1)) su=header;
The insertion of node can be done in between two nodes and hence the preceding and succeeding
nodes must be stored in separate pointer variables. When the user specifies two, the entered value is
reduced by one and becomes one and stored in variable k.
When value of k is one, i.e. the address of first node is stored in the pointer pr. When k is one the
statement (b) has no reason to consider. The address of succeeding node is obtained in the statement
(c). The address obtained is stored in the pointer variable su. Thus, by using following statements proper
links are connected:
a. pr->next=nw;
b. nw->next=su;
c. header=first;
Before execution of the above statements, the new node is created using nw pointer. The nw is a node
to be inserted.
The address of data field of node nw is linked to the previous node (pr) by the statement
pr->next=nw.
The address of succeeding node is stored in the linked field of new node nw by the statement
nw->next=su.

6.13.1 Counting Nodes


Sometimes, it may be essential to know how many nodes exist in the linked list. The linked list elements
can be counted and displayed. The solution is very easy. In the last few programs, the procedure applied
for displaying elements can be applied here. A counter variable can be inserted there to count the nodes.
One can get the number of nodes simply by incrementing the counter variable. Consider the following
program for counting the total number of nodes in the list.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 28 3/2/2012 6:52:10 PM


Linked List 6.29

Example 6.12 Write a program to count the total nodes of the linked list.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>
struct num
{
int num;
struct num *next;
} *header,*first,*rear;

void main()
{
void create(void);
int count=0;
clrscr();

create();
printf("\n Linked list elements are: ");

while(header!=NULL)
{
printf(" %d ",header->num);
header=header->next;
count++;
}
printf("\n Total Nodes are: %d ",count);
}
void create(void)
{
struct num *node;
printf("\n Enter number: ");
if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
}
while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
node->next=NULL;
rear->next=node;
rear=node;
}
}

OUTPUT
Enter number: 1 2 3 4 5 6 7 8 0

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 29 3/2/2012 6:52:10 PM


6.30 Data Structures Using C

Linked list elements are: 1 2 3 4 5 6 7 8


Total Nodes are: 8

Explanation:
This program is same as the last few programs. The count variable is placed in the while loop
and incremented. The count variable displays the number of nodes.

6.13.2 Deletion
An element that is to be deleted from the linked list is to be searched first. For this, the traversing opera-
tion must be carried out thoroughly on the list. Deleting a node from the linked list means
1. Deleting the first node
2. Deleting the last node
3. Deleting a specified node.
If first node is to be deleted, then the second node is assigned to header.
If the last node is to be deleted, NULL value is assigned to link field of the last but one node.
If the node which is to be deleted is in between the linked list then access the predecessor and successor
node of the specified node and link them. Figure 6.15 shows the deletion of first node.
1. Deleting the first node
Header Last Node

9 & 2 & 7 & 3

Element to be Deleted
(a) Before Deletion

Header Last Node

2 & 7 & 3

(b) After Deletion

Figure 6.15 Deletion Operation with Linked List

Example 6.13 Write a program to remove elements from the beginning of the linked list.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 30 3/2/2012 6:52:10 PM


Linked List 6.31

struct num
{ int num;
struct num *next;
} *header,*first,*rear,*k;

void main()
{
void erase(void);
void create(void);
void show(void);
clrscr();

printf("\n Operation creation:");


create();
show();
printf("\n After deletion: ");
erase();
show();
erase();
show();
erase();
show();
}

void create(void)
{
struct num *node;
printf("\n Enter numbers(0 to exit): ");
if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
}
while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
node->next=NULL;
rear->next=node;
rear=node;
}
}
void erase()
{
struct num *s;
s=header;
free(s);
header=first->next;

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 31 3/2/2012 6:52:10 PM


6.32 Data Structures Using C

first=first->next;
}
void show()
{
printf("\n Linked list elements are: ");
while(header!=NULL)
{
printf(" %d ",header->num);
header=header->next;
}

OUTPUT
Operation creation:
Enter numbers(0 to exit): 1 2 3 4 5 0
Linked list elements are: 1 2 3 4 5
After deletion:
Linked list elements are: 2 3 4 5
Linked list elements are: 3 4 5
Linked list elements are: 4 5

Explanation:
In this program erase() function is used to remove the beginning node of the linked list. The
creation of linked list is similar as discussed in the last few program. In the erase() function
another object *s is declared. The pointer header is assigned to pointer *s. The pointer *s
occupies same amount of memory like header. The free() function is used to release the
memory. The memory allocated with pointer *s is released. The address of second node
is assigned to header and first node. Thus, whenever the function erase() is invoked, the
beginning element is removed and the updated list is displayed by the function show().

2. Deleting the last node


This operation is shown in Fig. 6.16.

Header Last Node

9 & 2 & 7 & 3

Element to be Deleted
(a) Before Deletion

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 32 3/2/2012 6:52:11 PM


Linked List 6.33

Header Last Node

9 & 2 & 7

(b) After Deletion

Figure 6.16 Deletion Operation with Linked List

6.14 REPRESENTATION OF STACKS USING LINKED LISTS

The representation of stacks using linked lists is discussed in this section. 34 & Top
The stack grows vertically as shown in the Fig. 6.17. The stack moves
from the bottom to the top element.
5 &
The following steps are used to represent stacks using linked lists:
1. The list is empty initially. So the top pointer is NULL (stack is empty).
7 &
2. The insertion of elements into the stack can be performed in the
following ways:
(a) Allocate memory using dynamic memory allocation for new node. 4

top = struct(node*)malloc(sizeof(node));

(b) Insert element ‘x’ at the top. Where ‘x’ may be any value. Figure 6.17 Stack Elements
top->data=x

X Top

(c) Make top of next as NULL.


top->next=NULL

Top

3. Similarly, other elements can be inserted into the stack through the following steps.
(a) node *p;
(b) Dynamic memory allocation for new node p
top = struct(node*)malloc(sizeof(node));
(c) Insert the new element ‘y’ into the newly allocated node p.
p->data=y;

Y P

X Top

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 33 3/2/2012 6:52:11 PM


6.34 Data Structures Using C

(d) Before the insertion of y, the position of top is at X


Y

X Top

p->next=top.

(e) After insertion, the top position changes. Pointer points to the top i.e. newly inserted node ‘Y’

Y Top

Example 6.14 A program to implement stack operations using linked list is given below.

# include<stdlib.h>

struct node
{
int data;
struct node *link;
};
struct node *top=NULL,*temp;

void main()
{
int ch,data;
clrscr();

while(1){
printf("\n1.Push\n2.Pop\n3.Display\n4.Exit\n");
printf("\nEnter Your choice:");
scanf("%d",&ch);

switch(ch)
{
case 1:
temp=(struct node *)malloc(sizeof(struct node));
printf("Enter a node data :");
scanf("%d",&data);
temp->data=data;
temp->link=top;
top=temp;
break;
case 2:
if(top!=NULL)

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 34 3/2/2012 6:52:11 PM


Linked List 6.35

{
printf("The poped element is %d",top->data);
top=top->link;
}
else
{
printf("\nStack Underflow");
}
break;

case 3:
temp=top;
if(temp==NULL)
{
printf("\nStack is empty\n");
}

while(temp!=NULL)
{
printf("->%d->",temp->data);
temp=temp->link;
}
break;
case 4:
exit(0);
}

}
}

OUTPUT:
1.Push
2.Pop
3.Display
4.Exit

Enter your choice:1


Enter a node data :3

1.Push
2.Pop
3.Display
4.Exit

Enter your choice:1


Enter a node data :5

1.Push
2.Pop
3.Display
4.Exit

Explanation:
In this program, using switch, various operations are performed. Stack of elements operation is
done with case 1. Case 2 deals with pop, case 3 is for display and case 4 is for exit.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 35 3/2/2012 6:52:11 PM


6.36 Data Structures Using C

Example 6.15 Write a program to remove last elements of the linked list.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>

int c;
struct num
{
int num;
struct num *next;
} *header,*first,*rear,*k;

void main()
{
void create(void);
void show(void);
clrscr();
printf("\n Operation creation:");
create();
show();
printf("\n After deletion: ");
show();
show();
show();
}

void create(void)
{
struct num *node;
printf("\n Enter numbers(0 to exit): ");
if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
c++;
}
while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
c++;
node->next=NULL;
rear->next=node;
rear=node;
}
}
void show()
{

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 36 3/2/2012 6:52:11 PM


Linked List 6.37

struct num *pr;


int k=c;
printf("\n Linked list elements are: ");
while(header!=NULL)
{
printf(" %d ",header->num);
header=header->next;
k––;
if(k==1)
{
free(rear);
rear=header;
header=first;
break;
}
}
c––;
}

OUTPUT
Operation creation:
Enter numbers(0 to exit): 1 5 9 7 5 3 2 0
Linked list elements are: 1 5 9 7 5 3
After deletion:
Linked list elements are: 1 5 9 7 5
Linked list elements are: 1 5 9 7
Linked list elements are: 1 5 9

Explanation:
This program demonstrates the deletion from the end of the list. Here, the show() function
performs the deletion function and after the function is executed, the rear pointer of the list is freed
and an address of previous node is assigned to it. The show() function also displays the elements.

3. Deleting the specific node


Header Element to be Deleted

9 & 2 & 7 & 3

Last Node

Figure 6.18 Deleting a Specific Node

So far, we have studied how to remove the first and last node of the list. Now, we want to remove the
node randomly from the list. This case is different from the last two cases. In this deletion operation,
when a specific node is removed, the previous and next nodes are linked. The memory of the given node
is released. The removal of node is shown in Fig. 6.18.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 37 3/2/2012 6:52:11 PM


6.38 Data Structures Using C

Example 6.16 Write a program to remove a specific element from the list.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>
# include <process.h>
struct num
{
int num;
struct num *next;
} *header,*first,*rear,*k;
int count;

void main()
{
void remove1(int);
void create(void);
void show(void);
int n;
clrscr();
printf("\n Operation creation:");
create();
show();
printf("\n Enter position of number for removal < %d ",count);
scanf("%d",&n);
remove1(n);
getch();
}
void create(void)
{
struct num *node;
printf("\n Enter numbers(0 to exit): ");
if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
count =1;
}
while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
count++;
node->next=NULL;
rear->next=node;
rear=node;
}
}
void remove1(int j)
{

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 38 3/2/2012 6:52:11 PM


Linked List 6.39

int p,h;
void show(void);
j––;

p=j-1;
if(j==0)
{
header=header->next;
show();
}
for(h=0;h<count;h++)
{
if(h==p)
{
header->next=header->next->next;
header=first;
show();
}
header=header->next;
}
}

void show()
{
printf("\n Linked list elements are: ");
while(header!=NULL)
{
printf(" %d ",header->num);
header=header->next;
}
header=first;
}

OUTPUT
Operation creation:
Enter numbers(0 to exit): 4 8 6 5 9 7 4 0
Linked list elements are: 4 8 6 5 9 7 4
Enter position of number for removal < 7 4
Linked list elements are: 4 8 6 9 7 4

Explanation:
In this program the element specified by the user is removed. After entering the number, the list
of number is displayed. User has to specify only element number. Using for loop the specified
location is searched. The address of next element is assigned to previous element by skipping the
element to be deleted. Thus, the link between previous and next element is joined.

6.15 REPRESENTATION OF QUEUES USING LINKED LISTS

There are only a few differences between the functioning of a queue and a linked list. Elements can be
deleted or inserted from anywhere in a linked list. However, in a queue the element in the front is deleted.
The addition of elements is performed at the rear.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 39 3/2/2012 6:52:11 PM


6.40 Data Structures Using C

The representation of queue by linked list is illustrated in Fig. 6.19.

15 & 45 & 23 & 11

Front Rear

Figure 6.19 Representation of Queue


The following steps are used to represent queue by linked list:
1. The queue is empty initially. As the queue is empty, the rear and the front pointer of the queue are set
to NULL. If the front element is denoted by F and the rear by R.
R = F = NULL

2. The insertion of an element into the queue depends upon two cases.
Case 1: If the queue is empty.
(a) Allocate memory for new node.
R= F= struct(node*)malloc(sizeof(node));

FR

(b) Insert the element ‘A’ into the empty queue. As the queue is empty after insertion, rear (R) and
front (F) will point to the inserted A.
R->data=A;

FR

Case 2: If the queue is not empty, i.e. the insertion of a new element is to be done from rear.
(a) Allocate memory for new node.
R=struct(node*)malloc(sizeof(node));

F R

A &

Memory allocated to
insert new element

(b) R=R->next
F R

A &

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 40 3/2/2012 6:52:11 PM


Linked List 6.41

(c) Insert the new element ‘B’ from the rear end.
R->data=B;
R->next=NULL;
F R

A & B

6.16 REVERSING THE SINGLY LINKED LIST

Conceptually, the singly linked list can be traversed in only forward direction. The structure of singly
linked list contains only one pointer, pointing to the next node. The same list can be displayed in reverse
fashion using the following program.

Example 6.17 Write a program to reverse the singly linked list.

# include <stdio.h>
# include <conio.h>
struct node
{
int value;
struct node *next;
};
void create(void);
void reverse(void);
void show(void);
struct node *rear;
int nodes;
struct node *head;
void main()

{
clrscr();
create();
reverse();
show();
}
void create()
{
struct node *item;
printf("Enter numbers(0 to exit): ");
if(head==NULL)
{
head=(struct node*)malloc(sizeof(struct node));
scanf("%d",&head->value);
head->next=NULL;
rear=head;
}
while(1)

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 41 3/2/2012 6:52:12 PM


6.42 Data Structures Using C

{
item=(struct node *)malloc(sizeof(struct node));
scanf("%d",&item->value);
if(item->value==0) break;
item->next=NULL;
rear->next=item;
rear=item;
}
}
void reverse()
{
struct node *prv, *cur, *next;
if(head==NULL)
{
printf("List is empty");
return;
}
cur=head;
prv=NULL;
while(cur !=NULL)
{
next=cur->next;
cur->next=prv;
prv=cur;
cur=next;
}
head=prv;
}
void show()
{
printf("\n Reverse list is: ");
while(head!=NULL)
{
nodes++;
printf(" %d ",head->value);
head=head->next;
}
nodes=0;
}

OUTPUT
Enter numbers(0 to exit): 1 2 3 4 5 6 7 0
Reverse list is: 7 6 5 4 3 2 1

Explanation:
In this program the pointer *first is global and hence has an initial value NULL. The logic of
the program is very simple. The three pointers *prv, *cur, *next; are used for swapping
of the addresses. The end of the list is obtained and the address of previous is assigned to first.
Thus, the link list is reversed. The pointer head now points to the last node and every node
contains an address of the previous node instead of next node.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 42 3/2/2012 6:52:12 PM


Linked List 6.43

6.17 CONCATENATION OF TWO LISTS

Concatenation of two lists means adding a list at the end of another list as shown in Fig. 6.20. Consider
the following program.

List (1)
1 & 5 & 9 &

1 & 5 & 9 List (2)

Figure 6.20 Concatenation of Lists

Example 6.18 Write a program to concatenate two linked lists and display the elements.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>

struct node
{
int value;
struct node *next;
};
struct node *rear,*start,*f;
struct node *create(void);
void concat(void);
void print(void);
int count=1;
struct node *one,*two;
void main()
{
clrscr();
one=create();
two=create();
concat();
print();
}
struct node *create()
{
struct node *item,*temp;
temp=(struct node *)malloc(sizeof(struct node));
printf("\nEnter numbers of list (%d) (0) to exit: ",count);
scanf("%d",&temp->value);
temp->next=NULL;
rear=temp;
while(1)

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 43 3/2/2012 6:52:12 PM


6.44 Data Structures Using C

{
item=(struct node*)malloc(sizeof(struct node));
scanf("%d",&item->value);
if(item->value==0)

{
break;
}
item->next=NULL;
rear->next=item;
rear=item;
if(count==1)
f=rear;
}
count++;
return(temp);
}
void concat()
{
f->next=two;
start=one;
}
void print()
{
printf("Merged list: ");
while(start!=NULL)
{
printf(" %d ",start->value);
start=start->next;
}
}

OUTPUT
Enter numbers of list (1) (0) to exit: 1 5 9 0
Enter numbers of list (2) (0) to exit: 7 3 4 0
Merged list: 1 5 9 7 3 4

Explanation:
The creation() function is used to create linked lists. In this program, two lists are created.
The starting address of the list(2) is assigned to the rear of the first list. Here, the same
function is used to create both the lists. Hence, the contents of the local variables used in
create() function alters. In order to obtain the address of last node of the first list, if
condition is inserted and the address of the rear node is stored in the pointer *f. All this
process is carried out by the function concat(). In the function concat(), the starting
address of the list(2) is assigned to rear of the list(1). The pointer start is assigned the
address of the list(1). Using the same starting address the function print() prints the
element.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 44 3/2/2012 6:52:12 PM


Linked List 6.45

6.18 SPLITTING OF A LINKED LIST

Once a singly linked list is formed, it can split many sub-lists. The technique involved in splitting is very
simple. Put the NULL value in the node where you want to finish the first sub-list in the main list. Later,
the next node will act as first node of the second sub-list. Thus, two or more sub-lists can be created from
a single list (see Fig. 6.21).

NULL
Partition

1 & 2 & 3 4 & 5 & 6

New Head

Figure 6.21 Partition of a Single List

Example 6.19 Write a program to split a single linked list in two separate lists and display the
elements.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>
struct node
{
int value;
struct node *next;
};
struct node *rear,*start,*f;
struct node *create(void);
struct node * split(int);
void print(struct node *);
int count=0;
struct node *one,*two;

void main()
{
clrscr();
one=create();
two=split(count/2);
printf("The two separated list are:-");
print(one);
print(two);
}
struct node *create()
{
struct node *item,*temp;
temp=(struct node *)malloc(sizeof(struct node));

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 45 3/2/2012 6:52:12 PM


6.46 Data Structures Using C

printf("\nEnter numbers of list(0 to exit): ");


scanf("%d",&temp->value);
count++;
temp->next=NULL;
rear=temp;
if(count==1) start=temp;
while(1)
{
item=(struct node*)malloc(sizeof(struct node));
scanf("%d",&item->value);
if(item->value==0)
break;
count++;
item->next=NULL;
rear->next=item;
rear=item;
}
count++;
return(temp);
}
struct node * split (int j)
{
int c=0;
while(one!=NULL)
{
c++;
if(c==j)
{
two=one->next;
one->next=NULL;
one=start;
break;
}
one=one->next;
}
return two;
}
void print(struct node *s)
{
static c;
c++;
printf("\n list (%d): ",c);

while(s!=NULL)
{
printf(" %d ",s->value);
s=s->next;
}
}

OUTPUT
Enter numbers of list(0 to exit): 1 2 3 4 5 6 7 8 0
The two separated list are:

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 46 3/2/2012 6:52:12 PM


Linked List 6.47

list (1): 1 2 3 4
list (2): 5 6 7 8

Explanation:
In the create() function the counter variable c is incremented and keep an eye on the number
of nodes created. In the split(), function c is divided by two, i.e. to divide the list elements. In
case, odd number of nodes are created then, the first sub-list gets more nodes. In the split()
function, exactly half of the nodes are traversed and the node in the middle is assigned a value
NULL. Thus, the first sub-list ends here. The next node is considered as a head node for the
second sub-list. The address of head node of the second sub-list is assigned to pointer two. Thus,
using pointers one and two with function print() two sub-lists are displayed.

6.19 CIRCULAR LINKED LIST

In circular linked list the last node points to the header node. The linear link list can be converted to circu-
lar linked list by linking the last node to the first node. The last node of the linear linked list holds NULL
pointer, which indicates the end of linked list but performance of linked list can be advanced with minor
adjustment in the linear linked list. Instead of placing the NULL pointer, the address of the first node can
be given to the last node, such a list is called circular linked list (as shown in Fig. 6.22).
The circular linked list is more helpful as compared to singly linked list. In the circular linked list, all
the nodes of the list are accessible from the given node. Once a node is accessed, by traversing all the nodes
can be accessed in succession.

First Node

data data data data

pointer pointer pointer pointer

Figure 6.22 Circular Linked List

In this type of list, the deletion operation is very easy. To delete an element from the singly linked list, it is
essential to obtain the address of the first node of the list. For example, we want to delete the element, say 5,
which exists in the middle of the list. To remove the element five, we need to find predecessor of five. Obviously,
a particular element can be searched using searching process in which all elements are visited and compared.
In the circular linked list, no such process is needed. The address of predecessor can be found from the given
element itself. In addition, the operation splitting and concatenation of the list (discussed later) are easier.
Though the circular linked list has advantages over linear linked list, it also has some limitations. This
list does not have first and last node. While traversing the linked list, due to lack of NULL pointer, there
may be a possibility to get into an infinite loop. Thus, in the circular linked list it is necessary to identify

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 47 3/2/2012 6:52:12 PM


6.48 Data Structures Using C

the end of the list. This can be done by setting up the first and last node by convention. We detect the
first node by creating the list head, which holds the address of the first node. The list head is also called as
external pointer. We can also keep a counter, which is incremented when nodes are created and end of the
node can be detected. Figure 6.23 gives an example of circular linked list with header.
Header Last Node

9 & 2 & 7 & 3

Element to be Deleted

Figure 6.23 Circular Linked List with Header

6.20 METHOD FOR DETECTING END

There are two methods for finding or detecting the end of the circular linked list. They are:
1. Detecting end with counter
2. Detecting end with pointer.

6.20.1 Detecting End with Counter


This is the first method for detecting the end point of the circular linked list. The program 6.26 is similar
to the program used for the creation of circular linked list. But only one change is done as compared to pre-
vious program, i.e. last node is pointing to the first node. Instead of assigning NULL pointer, the address of
first node is assigned. Figure 6.24 and Example 6.20 explain the method for detecting end with counter.

First Node

data data data data

pointer pointer pointer pointer

Head Node Last Node

data data data

pointer pointer pointer pointer

Figure 6.24 Detecting End with Counter

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 48 3/2/2012 6:52:12 PM


Linked List 6.49

Example 6.20 Write a program to create a circular linked list and display the elements.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>
struct num
{
int num;
struct num *next;
} *header,*first,*rear;
int count=0;

void main()
{

void create(void);
int j,k=0;
clrscr();
create();
printf("\n Linked list elements are: \n");
printf("The circular linked list traversing\n");
for(j=0;j<5;j++)
{
printf("\n In (%d) round: ",j+1);
while(k<count)
{
printf(" %d ",header->num);
header=header->next;
k++;
}
k=0;
}
}
void create(void)
{
struct num *node;
printf("\n Enter numbers(0 to exit): ");

if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
count++;
}
while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
count++;

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 49 3/2/2012 6:52:12 PM


6.50 Data Structures Using C

node->next=header;
rear->next=node;
rear=node;
}
}

OUTPUT
Enter numbers(0 to exit): 1 5 9 8 7 0
Linked list elements are:
The circular linked list traversing
In ( 1 ) round: 1 5 9 8 7
In ( 2 ) round: 1 5 9 8 7
In ( 3 ) round: 1 5 9 8 7
In ( 4 ) round: 1 5 9 8 7
In ( 5 ) round: 1 5 9 8 7

Explanation:
Consider the following statement node->next=header;. The address of the first node
(header node which points to the first node) is assigned to last. If you see the same statement
in the creation of singly linked list, the statement is node->next =NULL;. Instead of NULL,
header is assigned.

With creation operation, the counter variable is incremented. The counter variable is used to count the
total number of nodes in the linked list. The for loop iterates from zero to 5 and the linked list elements
are displayed five times. The while loop takes loops and it contains the condition k <counter. The variable
k is incremented and when it is one less than counter it means end of the circular linked lists is reached.
Again, in second iteration of for loop, k is initialized to zero. The value of k is nothing but the position
of the node in the list. The value 0 means first node, 1 means second node and so on. Thus, first and last
node of the list can be obtained.
If we remove the counter and the condition statements, which terminate the loop, we get into the infinite
loop. After the last node, immediately first node is accessed. After removing the statement printf(“ \nRound
(%d):” , j+1); (after for loop) the output of the program would be

OUTPUT
Enter number: 1 2 3 0
Linked list elements are:
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3

From the output, you can observe that sequence is preserved after last element (3). First, element 1
appears and displays the remaining elements. This process would be continued.

6.20.2 Detecting End with Pointer


This is the second method to detect the end of the circular linked list. In the last few programs, a rear
pointer is declared which points to the last node and useful to find the end of the singly linked list. The

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 50 3/2/2012 6:52:12 PM


Linked List 6.51

same pointer is used here to detect the end of the circular linked list. Recall that in the circular linked lists
the last node points to the first node, i.e. the pointer field of the rear pointer points to the data field of the
first node as per the Fig. 6.25.

First Node Rear Pointer

data link data link

Figure 6.25 Detecting End with Pointer

While scanning the circular linked list in order to get the end of the list, we have to check contents of
all the pointer fields of the nodes. A link field of a node in a circular linked list pointing to the data field
of the first node is the last node of the linked list. To implement this idea into a practical program we have
to follow the following theory.
1. Obtain the address of the data field of the first node.
2. While traversing, compare the obtained address with the link field.
3. If the address obtained and the address pointing link field is same, i.e. that node is the last node.
Consider the following program,

Example 6.21 Write a program to detect the last node of the list using external pointer.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>

struct num
{
int num;
struct num *next;

} *header,*first,*rear;
void main()
{

void create(void);
int j;
clrscr();
create();
printf("\n Elements of circular linked list are:\n");
for(j=0;j<5;j++)
{
printf("\nRound(%d): ",j+1);

do
{

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 51 3/2/2012 6:52:12 PM


6.52 Data Structures Using C

printf(" %d ",header->num);
header=header->next;
if(rear->next==(struct num *)&(header->num))
break;
}while(1);
}
printf("\nAddress of rear link field = %u",rear->next);
printf("\nAddress of first data field = %u",(struct num *)&(header->num));
}
void create(void)
{
struct num *node;
printf("\n Enter numbers(0 to exit): ");
if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
}
while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
node->next=header;
rear->next=node;
rear=node;
}
}

OUTPUT
Enter numbers(0 to exit): 5 4 8 7 0
Elements of circular linked list are:
Round (1): 5 4 8 7
Round (2): 5 4 8 7
Round (3): 5 4 8 7
Round (4): 5 4 8 7
Round (5): 5 4 8 7
Address of rear link field = 1970
Address of first data field = 1970

Explanation:
This program is similar to the previous program.

Consider the statement,


if(rear->next==(struct num *)&(header->num))
break;

As soon as the last node is detected, the above statement terminates the while loop. The if statement
compares the address of data field of first node with pointer field of each node. When it is found that both

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 52 3/2/2012 6:52:13 PM


Linked List 6.53

are same, the end of linked list is spotted. Here, the address of the data field is obtained by the typecasting
statement (struct num *) &(header->num).
Here, typecasting is essential because an address of integer cannot be assigned to pointer of structure
type. The syntax (struct num*) converts the address of integer header->num to pointer rear->next. In the
output, addresses are also displayed.

6.20.3 Insertion in Circular Linked List


Insertions in the circular linked list are possible in three different ways:
1. Insertion at the beginning
2. Insertion at the end
3. Insertion at the specified position.

1. Insertion at the beginning

5 & 8 & 9 &

4 &

New Node
(a) A Circular Linked List Before Insertion

5 & 5 & 8 & 9 &

(b) After Insertion

Figure 6.26 Insertion Operation with Circular List


Insertion of new node at the beginning involves memory allocation. Moreover, the value is assigned to
the data field of the new node. When a new node is created for insertion, the address of data field of this
new node is assigned to pointer of last node. Similarly, the address of data field of previously first node
is assigned to new node. Thus, the new node becomes first node and the previous first node is moved to
second position. Figure 6.26 illustrates the insertion operation in circular linked list.
2. Insertion at the end

5 & 8 & 9 &

4 &

New Node

Figure 6.27 Insertion at End

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 53 3/2/2012 6:52:13 PM


6.54 Data Structures Using C

When a new node is inserted at the end, the address of new node is given to the last node. The address
of first node is given to the new node. Figure 6.27 shows the insertion operation at end.

Example 6.22 Write a program to demonstrate insertion of element at the beginning and at end of
the circular linked list.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>
struct num
{
int num;
struct num *next;
} *header,*first,*rear;
void main()
{
void create(void);
void iatend(void);
void iatbeg(void);
void show(void);
clrscr();
create(); /* creation of linked list*/
show(); /* display of linked list*/
iatbeg(); /* insertion at beginning*/
show(); /* display of elements*/
iatend(); /* insertion at the end*/
show();
}
void create(void)
{
struct num *node;
printf("\n Enter numbers(0 to exit): ");
if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
}
while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
node->next=header;
rear->next=node;
rear=node;
}
}

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 54 3/2/2012 6:52:13 PM


Linked List 6.55

void iatend()
{
struct num *node;
node=(struct num*) malloc(sizeof(struct num));
printf("\nEnter a number to be inserted at end: ");
scanf("%d",&node->num);
node->next=header;
rear->next=node;
rear=node;
}
void iatbeg()
{
struct num *node;
node=(struct num*) malloc(sizeof(struct num));
printf("\nEnter a number to be inserted at beginning: ");
scanf("%d",&node->num);
node->next=header;
header=node;
rear->next=header;
}
void show()
{
printf("Linked list elements are: ");
do
{ printf(" %d ",header->num);
header=header->next;
if(rear->next==(struct num *)&(header->num))
break;
} while(1);
}

OUPUT
Enter numbers(0 to exit): 1 2 3 0
Linked list elements are: 1 2 3
Enter a number to be inserted at beginning: 4
Linked list elements are: 4 1 2 3
Enter a number to be inserted at end: 5
Linked list elements are: 4 1 2 3 5

Explanation:
The reader is already aware of the creation and display of linked list. The function iatbeg()
inserts the element at the beginning of the list and the function iatend() inserts the element
at the end.

We know that the statement node=(struct num*) malloc(sizeof(struct num)); is


used to create a new node. After creation of new node, only pointer adjustment is done. When we want
to insert an element at the beginning the pointer adjustment is done as follows:
node->next=header;
header=node;
rear->next=header;

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 55 3/2/2012 6:52:13 PM


6.56 Data Structures Using C

Remember the following points:


1. The pointer node is a new node.
2. The header points to the first node.
3. The pointer rear points to the last node.
Since we are going to insert at the beginning, the new node created will be the first node of the list. Then
to accomplish this the link field of new node is assigned the address of first node, i.e. header. After this, the
first node will be the second node and the new node will be the first node. The pointer header is always used
to point first node. Hence, after insertion its contents must be updated. Thus, the statement header=node;
changes the contents of the pointer header. The last pointer adjustment to be done is, to assign the address
of the first node data field to last node. The statement rear->next=header; serves the same purpose.
The following program explains insertion at the specified position.

Example 6.23 Write a program to insert an element at a given position in the circular linked list.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>
struct num
{
int num;
struct num *next;
} *header,*first,*rear;

void main()
{
void create(void);
void show(void);
void atgiven(int);
int n;
clrscr();
create();
printf("\n Enter position number: ");
scanf("%d",&n);
n––;
atgiven(n);
show();
}
void create(void)
{
struct num *node;
printf("\n Enter numbers(0 to exit): ");

if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
}

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 56 3/2/2012 6:52:13 PM


Linked List 6.57

while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
node->next=header;
rear->next=node;
rear=node;
}
}
void show()
{
printf("Linked list elements are: ");
do
{ printf(" %d ",header->num);
header=header->next;
if(rear->next==(struct num *)&(header->num))
break;
} while(1);
}
void atgiven(intj)
{
int c=0,k=j-2;
struct num *node,*prv;
printf("\nLinked list upto %d element are: ",j);
do
{ printf(" %d ",header->num);
header=header->next;
if(k==c) prv=header;
c++;
} while(c<j);
node=(struct num*) malloc(sizeof(struct num));
printf("\n Enter a element: ");
scanf("%d",&node->num);
node->next=header;
prv->next=node;
header=first;
}

OUTPUT
Enter numbers(0 to exit): 1 2 3 5 6 7 0
Enter position number: 3
Linked list up to 3 element are: 1 2 3
Enter a element: 4
Linked list elements are: 1 2 3 4 5 6 7

Explanation:
In this program, the function atgiven() is used to insert the element at the specified position.
The user specifies the position number where number is to be inserted. The position number is
passed to the function atgiven(). In this function, using while loop the linked list is traversed
and the previous and next node of the given element are stored in the pointers prv and header.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 57 3/2/2012 6:52:13 PM


6.58 Data Structures Using C

node->next=header;
prv->next=node;
header=first;

The new node created is given the address of header. At this point header is not pointing to the
first node. Due to traversing in the while loop, it is pointing to the nth element, see the statement
(header=header->next;). The new node is assigned the address of next node. The prv is assigned the
address of new node. Again, the header is assigned the address of first node.
Some authors describe the insertion before and after. I think there is no need to classify it differently.
The above program inserts the element after the specified position. In order to insert an element before the
given position, only decrease the value of variable n before passing to function atgiven(). By changing
the value of n, the user can accomplish the operation insertion before, after and exactly at given position.

6.20.4 Deletion in Circular Linked List


Like insertion, deletion of element in the circular linked list can be done at various positions and they are
as follows:

1. Deletion at beginning
2. Deletion at the end
3. Deletion at the specified position.

The pointer adjustment is same in insertion and deletion. However, in insertion, an element is inserted
and memory is allocated. In deletion, a node from the list is removed and memory is released. Consider
the following program. Refer Figures 6.28 and 6.29.

1 & 2 & 3 &

Figure 6.28 Deletion at Beginning

1 & 2 & 3 &

Figure 6.29 Deletion at End

Example 6.24 Write a program to delete an element from end and beginning of the linked list.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>
struct num
{
int num;
struct num *next;

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 58 3/2/2012 6:52:13 PM


Linked List 6.59

} *header,*first,*rear;
static int c;

main()
{
void create(void);
void datend(void);
void datbeg(void);
void show(void);
clrscr();
create();
show();
printf("\nAfter deletion of beginning element");
datbeg();
show();
printf("\nAfter deletion of end element");
datend();
show();
}
void create()
{
struct num *node;
printf("\n Enter numbers(0 to exit): ");
if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
c++;
}
while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
node->next=header;
rear->next=node;
rear=node;
c++;
}
}
void datend()
{
int k=0;
while(k++<(c-2))
header=header->next;
free(rear);
rear=header;
rear->next=first;
header=first;
c––;

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 59 3/2/2012 6:52:13 PM


6.60 Data Structures Using C

}
void datbeg()
{
struct num *node;
node=first;
first=header=header->next;
free(node);
rear->next=header;
c––;
}
void show()
{
printf("\nLinked list elements are: ");
do
{
printf(" %d ",header->num);
header=header->next;
if(rear->next==header) break;
} while(1);
header=first;
}

OUTPUT
Enter numbers(0 to exit): 1 2 3 4 5 6 7 0
Linked list elements are: 1 2 3 4 5 6 7
After deletion of beginning element
Linked list elements are: 2 3 4 5 6 7
After deletion of end element
Linked list elements are: 2 3 4 5 6

Explanation:
In this program to erase the element from beginning and end, help of counter variable is taken. The
variable c is incremented in the function create() when a new node is created. Similarly, when
an element is removed the counter c is decremented. The counter variable is needful only in the
function datend(), because to erase the last element, the last but one element is obtained and
it is connected to first node.

Example 6.25 Write a program to delete the specified element from the linked list.

# include<stdio.h>
# include<conio.h>
# include<malloc.h>
struct num
{

int num;
struct num *next;
} *header,*first,*rear;

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 60 3/2/2012 6:52:13 PM


Linked List 6.61

static int c;
main()
{
void create(void);
void atgiven(int);
void show(void);
int n;
clrscr();
create();
show();
printf("\n Enter position number:");
scanf("%d",&n);
atgiven(n);
show();
getch();
}
void create()
{
struct num *node;
printf("\n Enter numbers(0 to exit):");
if(header==NULL)
{
first=(struct num*)malloc(sizeof(struct num));
scanf("%d",&first->num);
first->next=header;
header=first;
rear=first;
c++;

}
while(1)
{
node=(struct num*) malloc(sizeof(struct num));
scanf("%d",&node->num);
if(node->num==0) break;
node->next=header;
rear->next=node;
rear=node;
c++;
}
}
void atgiven(int g)
{
struct num *prv,*temp;
int k=0,p;
p=g-2;
while(k++<g)
{
header=header->next;
if(k==p) prv=header;
if(k==(p+1))temp=header;
}
c––;

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 61 3/2/2012 6:52:13 PM


6.62 Data Structures Using C

prv->next=header;
header=first;
free(temp);

}
void show()
{
printf("\nLinked list elements are:");
do
{
printf("%d ",header->num);
header=header->next;
if(rear->next==header) break;

} while(1);
header=first;
}

OUTPUT
Enter numbers(0 to exit: 5 8 7 4 5 3 2 0
Linked list elements are: 5 8 7 4 5 3 2
Enter position number: 3
Linked list elements are: 5 8 4 5 3 2

Explanation:
In this program the function atgiven() deletes the specified element from the circular linked
list. The user enters the position number and it is passed to the function atgiven(). In this
function using while loop entire list is scanned and predecessor and successor of the given
element are stored in the pointer *prv and header. The node, which is to be removed, is
stored in the pointer temp. Using free() function the memory allocated is released. Then, a
link between pointer prv and header is established by the following statements.

6.21 DOUBLY LINKED LIST

The singly linked list and circular linked list contain only one pointer field. Every node holds an address
of next node. Thus, the singly linked list can traverse only in one direction, i.e. forward. This limitation
can be overcome by doubly linked list. Each node of the doubly linked list has two pointer fields and
holds the address of predecessor and successor elements. These pointers enable bi-directional traversing,
i.e. traversing the list in backward and forward direction. In several applications, it is very essential to
traverse the list in backward direction. The pointer pointing to the predecessor node is called left link and
pointer pointing to successor is called right link. A list having such type of node is called doubly linked
list. The pointer field of the first and last node holds NULL value, i.e. the beginning and end of the list
can be identified by NULL value. The structure of the node is as shown in Fig. 6.30.
Previous Next
Link Data Link

Figure 6.30 Structure of Node

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 62 3/2/2012 6:52:13 PM


Linked List 6.63

The structure of node would be as follows:


struct node
{
int number;
struct node *llink
struct node *rlink;
}

The above structure can be represented by using Fig. 6.31.


First Node Last Node

pointer pointer pointer

data data data data

pointer pointer pointer

Next Pointer Previous


Pointer

Figure 6.31 Doubly Linked List

Example 6.26 Write a program to create the doubly linked list. Display the elements in original and
reverse sequence.

# include<stdio.h>
# include<conio.h>
# include<malloc.h>

struct dlist
{
struct dlist *prev;
int number;
struct dlist *next;
};
struct dlist *end,*start;
struct dlist *node=NULL;
void create(void);
void showl(void);
void showr(void);

void main()
{

clrscr();
create();
showl();
showr();
getch();

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 63 3/2/2012 6:52:13 PM


6.64 Data Structures Using C

}
void create()
{
node=(struct dlist*)malloc(sizeof(struct dlist));
printf("\n Enter Numbers (0 to stop):");
while(1)
{
scanf("%d",&node->number);
if(node->number==0) break;
else
{
node->prev =end;
end=node;
node=(struct dlist*) malloc(sizeof(struct dlist));
}
}
node=end;
start=NULL;
while(node!=NULL)
{
node->next=start;
start=node;
node=node->prev;
}

}
void showl()
{
printf("\n Original List:");

while(start!=NULL)
{
printf("%d",start->number);
start=start->next;

}
}
void showr()
{
printf("\n Reverse List: ");

while(end!=NULL)
{
printf("%d",end->number);
end=end->prev;

}
}

OUTPUT
Enter Numbers(0 to stop): 1 2 4 7 5 0
Original List: 1 2 4 7 5
Reverse List: 5 7 4 2 1

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 64 3/2/2012 6:52:13 PM


Linked List 6.65

Explanation:
The create() function is used to create the doubly linked list. The method of creation of node
is same as in the previously discussed methods of the linked list. Here, an additional one pointer
field is present and we will discuss that in detail in next section.

We know the use of next pointer and how we have used it previously to access the next node. Every time
a new node is inserted, the address of new node is assigned to the next pointer of previous node. This is
required for details of manipulating the next pointer. The pointer *prev (pointing to data field of previous
node) is not different case. The pointer next is right hand and *prev is the left hand of the node. Every time a
new node is created, the address of data field of previous node is assigned to the previous pointer. The rest of
the operations are same for accessing the elements. Go through the functions showl()and showr().

6.21.1 Insertion and Deletion with Doubly Linked List


We are aware of insertion process in which an element can be inserted at beginning, at end and at the
specified position. Figure 6.32 shows the insertion in the doubly linked list.

Head

8 & & 3 & & 7

5 New node

Figure 6.32 Inserting a Node at the Beginning

We know that the head node of the doubly linked list contains NULL value. When a new node is to be
inserted at the beginning, the address of the head node is assigned to the new node. The previous pointer
of the node is assigned a NULL value. The arrow ↔ indicates that the node has both previous and next
pointer.
When a node is inserted at the end, the next pointer of the new node is assigned a NULL value and the previ-
ous pointer of the node is assigned the address of last node. Figure 6.33 describes the insertion at the end.

3 & & 9 & & 4

Figure 6.33 Inserting a Node at the End

In the deletion operation as shown in the Fig. 6.34 when a node is deleted, the memory allocated to
that node is released and the previous and next nodes of that node are linked.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 65 3/2/2012 6:52:13 PM


6.66 Data Structures Using C

Head

3 & 9 & & 4

Figure 6.34 Deleting a Node from Beginning

When a node is to be deleted from the beginning of the node, the head pointer points to the second
node. Because after deletion of first node, the second node becomes the first. The symbol X indicates the
link will be destroyed. This is shown in Fig. 6.35.

Head

3 & & 9 & 4

Figure 6.35 Deleting a Node from the End

Example 6.27 Write a program to perform insertion and deletion operation on the doubly
linked list.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>

struct dlist
{
struct dlist *prev;
int number;
struct dlist *next;
};
struct dlist *end,*start;
struct dlist *node=NULL;
void create(void);
void show(void);
void insert(void);
void re_move(void);

void main()

{
clrscr();
create();
insert();

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 66 3/2/2012 6:52:14 PM


Linked List 6.67

show();
re_move();
show();
getch();
}
void create()
{
node=(struct dlist*)malloc(sizeof(struct dlist));
printf("\n Enter Numbers(0 to stop):");
while(1)
{
scanf("%d",&node->number);
if(node->number==0) break;
else

{
node->prev=end;
end=node;
node=(struct dlist*) malloc(sizeof(struct dlist));
}
}
node=end;
start=NULL;
while(node!=NULL)
{
node->next=start;
start=node;
node=node->prev;
}
}
void show()
{
struct dlist *x;
printf("\n Origional List:");

x=start;

while(start!=NULL)
{
printf("%d",start->number);
start=start->next;
}
start=x;

}
void insert()
{
struct dlist *q,*r,*p;
int number,k=1;
p=start;
printf("(Insertion)Enter position of node:");
scanf("%d",&number);
if(number==1)

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 67 3/2/2012 6:52:14 PM


6.68 Data Structures Using C

{
q=(struct dlist*)malloc(sizeof(struct dlist));
printf("\n (Insertion) Enter the Number:");
scanf("%d",&q->number);
q->prev=NULL;
q->next=start;
start=q;
}
while(start!=NULL)
{
if(++k==number)
{
q=(struct dlist*)malloc(sizeof(struct dlist));
printf("\n Enter the Number:");
scanf("%d",&q->number);
r=start->next;
r->prev=q;
q->next=r;
q->prev=start;
start->next=q;
break;
}
else
start=start->next;
}
if(number==1)start=q;
else start=p;
}
void re_move()
{
struct dlist *q,*r,*p,*n;
int number,c=0;
printf("\n (Deletion) Enter position of node:");
scanf("%d",&number);
r=start;
if(number==0)
{
p=start;
free(p);
start=start->next;
start->prev=NULL;
}
else
while(r!=NULL)
{
c++;
if(c==(number-1)) p=r;

if(c==number)
{
q=r;
free(q);
}
if(c==(number+1)) n=r;

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 68 3/2/2012 6:52:14 PM


Linked List 6.69

r=r->next;

}
p->next=n;
}

OUTPUT
Enter Numbers(0 to stop): 1 2 3 4 5 6 7 0
(Insertion)Enter position of node:3
Enter the Number:8
Original List: 1 2 8 3 4 5 6 7
(Deletion) Enter position of node:6
Original List: 1 2 8 3 4 6 7

Explanation:
In this program both insertion and deletion operations are performed. The method of adjusting
pointer is same as explained in the programs of singly and circular linked list operations. The
user can insert or delete the element of any position including beginning and end.

6.21.2 Advantages of Doubly Linked List

1. The doubly linked list is bi-directional, i.e. it can be traversed in both backward and forward direction.
2. The operations such as insertion, deletion and searching can be done from both ends.
3. Predecessor and successor of any element can be searched quickly.
4. It is very helpful to implement arithmetic operations on large integer numbers.

6.21.3 Disadvantages of Doubly Linked List

1. It consumes more memory space.


2. There is large pointer adjustment during insertion and deletion of element.
3. It consumes more time for few basic list operations.

6.22 CIRCULAR DOUBLY LINKED LIST

A circular doubly linked list has both successor and predecessor pointers. Using the circular fashioned
doubly linked list the insertion and deletion operation, which are little complicated in the previous types
of linked list are easily performed. Consider Fig. 6.36:

& 8 & & 9 & & 4 &

Head

Figure 6.36 Circular Doubly Linked List

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 69 3/2/2012 6:52:14 PM


6.70 Data Structures Using C

6.22.1 Insertion and Deletion Operation


The insertion operation is similar to what we have already learnt in previous types. The only difference
is the way we link the pointer fields. Consider Fig. 6.37.

& 3 & & 8 & & 9 & & 4 &

Head

Figure 6.37 Inserting the Node at the Beginning

The × indicates that the previous links are destroyed. The pointer links from ex-first node are removed
and linked to new inserted node at the beginning. The element 8 was previous first node and 3 is the new
node inserted and becomes first node now after inserting it at the beginning.

& 3 & & 8 & & 9 & & 4 &

Head

Figure 6.38 Inserting the Node at the End

The × indicates, that the previous links are destroyed. The pointer links from ex-last node are removed
and linked to new inserted node at the end. The address of last node is given to first node to form circular
list. The node 9 was previously the last node but after insertion of the node at the end, newly inserted node
is the last node (Fig. 6.38). Figure 6.39 shows the deletion of the node at beginning.

& 3 & & 8 & & 9 & & 4 &

Head

Figure 6.39 Deleting a Node from the Beginning

The × indicates that the previous links are destroyed. After deletion of the first node, the second
node becomes first node. The pointer head also points to the newly appeared first node. Thus, when a
node from the beginning is removed, the node followed by it will become the head node (first node).
Accordingly, pointer adjustment is performed in the real application.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 70 3/2/2012 6:52:14 PM


Linked List 6.71

& 8 & & 9 & & 4 &

Head

Figure 6.40 Deletion of the Node at the End

The × as usual is the symbol destroying previous links. When the last node is removed, one node will be
the last node and its links are established with the first node. The removal operation is shown in Fig. 6.40.

6.23 APPLICATIONS OF LINKED LIST

The most useful linear data structure is linked list. This section introduces you to a few applications
of linked lists which are useful in computer science.

6.23.1 Polynomial Manipulation


A polynomial can be represented and manipulated using linear link list. Various applications on polynomi-
als can be implemented with linked lists. We perform various operations such as addition, multiplication
with polynomials. To get better proficiency in processing, each polynomial is stored in decreasing order.
These arrangements of polynomial in series allow easy operation on them. Actually, two polynomials can
be added by checking each term. The prior comparison can be easily done to add corresponding terms of
two polynomials.
A polynomial is represented with various terms containing coefficients and exponents. In other words,
a polynomial can be expressed with different terms, each of which comprises of coefficients and exponents.
The structure of a node of linked list for polynomial implementation will be as follows. Its pictorial
representation is shown in Fig. 6.41.

Coefficient Exponent Link

Figure 6.41 A Term of a Polynomial

The coefficient field contains the value of coefficient of the term. Similarly, the exponent field contains
the value of exponent. As usual, the link field points to the term (next node).
The structure for the above node would be as follows:
struct poly
{
double coeff;
int exp;
struct poly *next;
};
Consider a polynomial
P = P 8 + 5P 4 – 7P 2 + 6P

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 71 3/2/2012 6:52:14 PM


6.72 Data Structures Using C

In this equation 1,5,7 and 6 are coefficients and exponents are 8,4,2 and 1. The number of nodes
required would be the same as the number of terms in the polynomial. There are four terms in this poly-
nomial hence it is represented with four nodes.

1 5 −7 6
8 4 2 1

& & &

Figure 6.42 Polynomial Representation


The top of every node represents coefficients of the polynomial, exponents are at the centre and the
pointers are (next) at the bottom. The terms are stored in order of descending exponent in the linked list.
It is assumed that no two terms have the similar exponents. Figure 6.42 shows the polynomial.
Consider the following equations,
P = P 8 + 5P 4 – 7P 2 + 6P
Q = 2P 9 + 7P 5–3P 4 + 2P 3
The representation of the above two polynomials can be shown in Fig. 6.43.

P 1 8 & 5 4 & −7 2 & 6 1

Q 2 9 & 7 5 & −3 4 & 2 3

Figure 6.43 Addition of Two Polynomials


If the term is shown without coefficient then the coefficient is assumed to be 1. In case the term is without
variable, the coefficient is zero. Such terms are not required to be stored in the memory. The arrow in the figure
indicates that the two exponents are compared. Where the link of arrow is disconnected, exponent of both
the terms is same. The term, which has no touch of any arrow, means it is the last node and inserted in the
resulting list at the end. The arrow indicates two terms, which are compared systematically from left to right.

Table 6.1 Exponent


Exponent Comparison from List P and Q List R (Inserted Exponent) Smaller Exponent
8<9 9 8 is carried forward
8>5 8 5 is carried forward
5>4 5 4 is carried forward
4= =4 4 No term is carried
(Sum of coefficient is taken)
2<3 3 2 is carried forward
1 is taken (last node of P) 1 End of linked list

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 72 3/2/2012 6:52:14 PM


Linked List 6.73

Traverse the list P and Q. Compare the corresponding terms of list P and Q. In case one node has
larger exponent value than the other then insert the larger exponent node in the third list and forward the
pointer to next node of the list whose current term is inserted in the third list. The pointer of the list whose
exponent is smaller will not be forwarded. The pointer of the lists forwarded only when the current nodes
from the lists are inserted into the third list. Table 6.1 shows these operations.
If exponents are equal, add the coefficients and insert their addition in the third list. In this step, expo-
nents from both the expressions are same, move the pointer to next node in both the list P and Q. Repeat
the same process until one list is scanned completely.
expo(P) = expo(Q).

The possible conditions can be stated as follows:


1. If exponent of list P is greater than corresponding exponent of list Q, insert the term of P into the list
R and forward the pointer in list P to access the next term. In this case, the pointer in the list Q will
point to the same term (will not be forwarded).
2. If exponent of list Q is greater than exponent P, the term from Q is inserted in the list R. The pointer of
list Q will be forwarded to point to next node. The pointer in the list P will remain at the same node.
3. If exponents of both nodes are equal, addition of coefficients is taken and inserted in the list R. In this
case, pointers in both the lists are forwarded to access the next term.
The steps involved,
1. Traverse the two lists (P) and (Q) and inspect all the elements.
2. Compare corresponding exponents P and Q of two polynomials. The first terms of the two polynomials
contain exponents 8 and 9, respectively. Exponent of first term of first polynomial is smaller than the
second one. Hence 8<9. Here, the first exponent of list Q is greater than the first exponent of list P.
Hence, the term having larger exponent will be inserted in the list R. The list R initially looks like as
shown in Fig. 6.44 (a).

2 9

Figure 6.44 (a)


Next, check the next term of the list Q. Compare it with the present term (exponent) of list P. The next
node from P will be taken when current node is inserted in the list R because 8>5. Here, the exponent of
current node of list P is greater that list Q. Hence, current term (node) of list P will be inserted in the list
R and the list R becomes as Fig. 6.44 (b).

R= 2 9 & 1 8

Figure 6.44 (b)


After moving to next node in list P, the exponent is 4, and exponent of Q is 5. Compare 4 with 5.
Of course 4<5. Here, the term of list Q is greater than term of P. Therefore, the term of list, Q (7,5) will
be inserted to list R. The list R becomes Fig. 6.44 (c).

R= 2 9 & 1 8 & 7 5

Figure 6.44 (c)

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 73 3/2/2012 6:52:14 PM


6.74 Data Structures Using C

In this step a node from list Q is inserted and therefore, the pointer in the list Q will be forwarded and
point to the term (–3,4) and from list P we have the current node (5,4). Compare exponent of these two
terms. The condition observed here is 4==4. Here, exponents of both the terms are equal. Therefore, addi-
tion of coefficients is taken and result is inserted in the list R. The addition is 2 (5–3). The list R becomes
as the Fig. 6.44 (d).

2 9 & 1 8 & 7 5 & 2 4

Figure 6.44 (d)

Move forward the pointers to next nodes in both the lists, since, the previous terms were having same
exponents. The next comparison is 2<3. Here, the exponent of current node of list Q is greater than of P.
The node from Q will be inserted to list R. The list R will be shown as Fig. 6.44 (e).

R= 2 9 & 1 8 & 7 5 & 2 4 & 2 3

Figure 6.44 (e)

The list Q is completely scanned and reached to end. The remaining node from the list P will be
inserted to list R. The list R is as Fig. 6.44 (f ).

R= 2 9 & 1 8 & 7 5 4 2 4 &

2 3 & −7 2 & 6 1

Figure 6.44 (f)

A program on the above is provided for understanding.

Example 6.28 Write a program to perform addition of two polynomials.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>
struct term
{

float coef;
int expn;
struct term *next;

};
struct term *ployadd(struct term *, struct term *);
struct term *poly_in(st ruct term *);
struct term *insert(struct term *,float,int);
struct term *show(struct term *);

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 74 3/2/2012 6:52:15 PM


Linked List 6.75

void main()
{
struct term *t1,*t2,*t3;
clrscr();
t1=t2=t3=0;
puts("Polynomial(A):");
t1=poly_in(t1);
puts("Polynomial(B):");
t2=poly_in(t2);
t3=ployadd(t1,t2);
puts("Polynomial(A):");
show(t1);
puts("Polynomial(B):");
show(t2);
puts("Added Polynomial(C):");
show(t3);
}
struct term *poly_in(struct term *begin)
{
int j,ex,n;
float cof;
printf("\n Enter number of terms:");
scanf("%d",&n);
for(j=1;j<=n;j++)
{
printf("Enter coefficient for term %d:",j);
scanf("%f",&cof);
printf("Enter exponent for term %d:",j);
scanf("%d",&ex);
begin=insert(begin,cof,ex);
begin=insert(begin,cof,ex);
}
return begin;
}
struct term *insert(struct term *begin,float co, int e_x)
{
struct term *pt,*temp;
temp=(struct term*)malloc(sizeof(struct term));
temp->coef=co;
temp->expn=e_x;
if(begin==0 || e_x>begin->expn)
{
temp->next=begin;
begin=temp;
}
else
{
pt=begin;
while(pt->next!=0 && pt->next->expn>e_x)
pt=pt->next;
temp->next=pt->next;
pt->next=temp;
if(pt->next==0) temp->next=0;

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 75 3/2/2012 6:52:15 PM


6.76 Data Structures Using C

}
return begin;
}
struct term *ployadd(struct term *g1,struct term *g2)
{
struct term *t3=0,*p3, *temp;
if(g1==0 && g2==0) return t3;
while(g1!=0 && g2!=0)
{
temp=(struct term*)malloc(sizeof(struct term));
if(t3==0)
{
t3=temp;
p3=t3;
}
else
{
p3->next=temp;
p3=p3->next;
}

if(g1->expn>g2->expn)
{
temp->coef=g1->coef;
temp->expn=g1->expn;
g1=g1->next;
}
else if(g2->expn>g1->expn)
{
temp->coef=g2->coef;
temp->expn=g2->expn;
g2=g2->next;
}
else if(g1->expn==g2->expn)
{
temp->coef=g1->coef+g2->coef;
temp->expn=g1->expn;
g1=g1->next;
g2=g2->next;
}
}
while(g1!=0)
{
temp=(struct term*)malloc(sizeof(struct term));
temp->coef=g1->coef;
temp->expn=g1->expn;
if(t3==0)
{
t3=temp;
p3=t3;
}
else
{

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 76 3/2/2012 6:52:15 PM


Linked List 6.77

p3->next=temp;
p3=p3->next;
}
g1=g1->next;
}
while(g2!=0)
{
temp=(struct term*)malloc(sizeof(struct term));
temp->coef=g2->coef;
temp->expn=g2->expn;
if(t3==0)
{
t3=temp;
p3=t3;
}
else
{
p3->next=temp;
p3=p3->next;
}
g2=g2->next;
}
p3->next=0;
return t3;
}
struct term *show(struct term *pt)
{
if(pt==0)
{
printf("Empty\n");
return 0;
}
while(pt!=0)
{
printf("%.1fx^%d)+",pt->coef,pt->expn);
pt=pt->next;
}
printf("\b\b\bn");
return 0;
}

OUTPUT
***
Polynomial(A):
Enter number of terms: 1
Enter coefficient for term 1: 2
Enter exponent for term 1:3
Polynomial(B):
Enter number of terms: 1
Enter coefficient for term 1: 2
Enter exponent for term 1:3
Polynomial(A):
2.0x^3)+

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 77 3/2/2012 6:52:15 PM


6.78 Data Structures Using C

Polynomial(B):
2.0x^3)+
Added Polynomial(C):
4.0x^3)+

Explanation:
In this program at the beginning three pointers t1,t2, and t3 are declared and initialized to
NULL (0). The value zero means NULL. The pointers t1 and t2 denotes address of polynomial
t1 and t2 respectively. The pointer t3 points to the added polynomial. The pointer t3 always
points to the term added. In case the polynomials are empty, the resulting polynomial will be
empty. That is why we are returning NULL value through the pointer t3. The NULL value of
t3 indicates that the polynomial is empty.

Both polynomials are traversed, i.e. each and every node is visited. The new node is inserted to the third
polynomial and followed by it coefficient and exponent are assigned.
We have written a ladder of if-else conditions.
1. if t1->expo > t2->expo: In this case, the value of current node of t1 is assigned to current node of t3.
The polynomial linked list (A) is traversed and pointer t1 will point to the next node.
2. If t2->expo>t1->expo: In this case, the value of current node of polynomial (B) is assigned to current
node of t3. The node from polynomial is added hence, the linked list (B) is traversed and pointer t2
will point to next node.
3. If (t1->expo==t2->expo): In this case, where terms of both polynomials are same, the coefficient of
both terms are added and the resulting value is assigned to node of third list. Here, both the lists are
traversed and pointer t1 and t2 will point to next node of polynomial (A) and (B).
The same addition of two polynomials can be done from the following example.

Example 6.29 Write a program to perform addition of two polynomials.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>

struct poly
{
float coef;
int expo;
struct poly *nterm;
};
int j,num;
struct poly begin;
void create_poly(struct poly *node)
{
char h;
begin.nterm=NULL;
node=&begin;

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 78 3/2/2012 6:52:15 PM


Linked List 6.79

j=0;
printf("\n Input n for end:");
h=getchar();
while(h!='n')
{
node->nterm=(struct poly*) malloc(sizeof(struct poly));
node=node->nterm;
printf("\n Enter coefficient value %d:", j+1);
scanf("%g",&node->coef);
printf("\n Enter exponent value %d:",j+1);
scanf("%d",&node->expo);
node->nterm=NULL;
fflush(stdin);
printf("\n Input n for end:");
h=getchar();
j++;
}
printf("\n Total Nodes = %d",j);
}
void show(struct poly *node)
{
node=&begin;
node=node->nterm;
while(node)
{
printf("\n + %g", node->coef);
printf("X^%d", node->expo);
node=node->nterm;
}
}
void main()
{
struct poly *node=(struct poly*)malloc(sizeof(struct poly));
clrscr();
create_poly(node);
show(node);
getch();
}

OUTPUT
Input n for end:
Enter coefficient value 1: 4
Enter exponent value 1: 5
Input n for end:
Enter coefficient value 2: 9
Enter exponent value 2: 8
Input n for end: n
Total Nodes = 2
+ 4X^5 + 9X^8

Explanation:
The logic of this example is the same as the logic used in Example 6.28.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 79 3/2/2012 6:52:15 PM


6.80 Data Structures Using C

6.23.2 Linked Dictionary


In compiler, creation of the linked dictionary has an important role. In compiler, the organization and
maintenance of dictionary holding names and their corresponding values are maintained in the linked
dictionary. This linked directory is called symbol table. While designing compiler, two factors, i.e. time
and memory space are considered.
The process of compiler designing has various steps. The memory space and speed of symbol table
algorithm have opposite relationship. The construction and referencing is an important factor of linked
dictionary. Construction means insertion of symbols with their values available. Referencing means,
obtaining values from the table.
The ratio of estimated number of insertion to reference is significant factor. In symbol tables, access
retrieve time and insertion time are very much associated. The quick symbol table can be simply con-
structed if large memory space is available. When a reference is obtained from arithmetic value of character
(forming name), each name is stored in a unique memory location.
The easiest way to access the symbol table is linear search method. Using simple linked list the symbols
are organized in a sequence. The insertion can be easily done by adding symbols at the rear of the list. If
any particular symbol is to be searched, by traversing each node the required element can be searched.
The symbol table can also be searched using binary search. All the entries in the symbol table are sorted
in ascending order. A middle entry is spotted and its value is determined. A separate topic is given for
search techniques in this book. However, this method has some drawbacks.

6.23.3 Addition of Long Positive Integers


The application of adding long positive integers can be solved using circular list. There is always a restric-
tion or limitation in the programming language that every data type has a lower and upper limit. The
variables of a particular data type can have the values as per the range. Some time, it is very essential if any
problem to be solved is having maximum range, which exceeds the limit of the range. In order to add two
long integers, below mentioned steps are followed:

1. The digits of the given numbers are individually traversed from left to right.
2. In parallel, i.e. corresponding digits and a carry from prior digits sums are added.

6.23.4 Searching in a Linked List


Finding some specific element in a given set of elements is called searching. Assume, we have a linked list
of 10 numbers. In order to search a particular number in the list, all the elements of list are visited and
compared with the expected one. When the given number matches with some number, search process
completes. Occurrence of a particular number in a list for number of times can also be found. In other
words, we can find out for how many times a particular number exist in the list. A program is illustrated
below on this point.

Example 6.30 Write a program to create a linked list of integers and search for a given element.

# include <stdio.h>
# include <conio.h>
# include <malloc.h>

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 80 3/2/2012 6:52:15 PM


Linked List 6.81

struct node
{
int data;
struct node *next;
};
int j;
struct node begin;
void search(struct node*);
void create_list(struct node*);
void show(struct node*);
void create_list(struct node *node)
{
int n=1;
begin.next=NULL;
node=&begin;
j=0;
printf("\n Input integers (0 to stop):");
while(n)
{
scanf("%d", &n);
if(n==0) break;
else node->next=(struct node*) malloc(sizeof(struct node));
node->data=n;
node=node->next;
node->next=NULL;
fflush(stdin);
}
}
void search(struct node *node)
{
int node_num=0;
int s_node;
int flag=0;
node=&begin;
printf("\n Enter number to be searched:");
scanf("%d",&s_node);
if(node==NULL)
printf("\n List is empty");
while(node)
{
if(s_node==node->data)
{
printf("\n search is successful");
printf("\n Position of %d from beginning of the list:
%d",s_node,node_num+1);
node=node->next;
flag=1;7
}
else
node=node->next;
node_num++;
}
if(!flag)

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 81 3/2/2012 6:52:15 PM


6.82 Data Structures Using C

{
printf("\n Search is unsuccessful");
printf("\n %d does not found in the list", s_node);
}
}
void show(struct node *node)
{
node=&begin;
while(node->next)
{
printf(" %d",node->data);
node=node->next;
}
}
void main()
{
struct node *node=(struct node*) malloc
(sizeof(struct node));
clrscr();
create_list(node);
printf("\n List: ");
show(node);
search(node);
}

OUTPUT
Input integers(0 to stop):
1
2
3
4
5
9
7
5
0
List: 1 2 3 4 5 9 7 5
Enter number to be searched: 3
search is successful
Position of 3 from beginning of the list:3

Explanation:
In this program a list is created with create()function. The number, which is to be searched,
is entered. In the search()function the entered number is compared with the linked list
elements. When equal number is found the number along with its position in the linked list is
displayed. The show()function is used to display all the linked list elements. Thus, through
traversing and comparing elements search process is done.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 82 3/2/2012 6:52:15 PM


Linked List 6.83

6.23.5 Sorting a Linked List

Example 6.31 Write a program to create linked list and sort the list in ascending order.

# include <stdio.h>
# include <conio.h>

struct node
{
int value;
struct node *next;
};
void create(void);
void sort(void);
void show(void);
struct node *rear;
int nodes;
struct node *head;
void main()
{
clrscr();
create();
sort();
show();
}
void create()

{
struct node *item;
printf("Enter numbers(0 to exit):");
if(head==NULL)
{
head=(struct node*)malloc(sizeof(struct node));
scanf("%d",&head->value);
head->next=NULL;
rear=head;
}
while(1)
{
item=(struct node*)malloc(sizeof(struct node));
scanf("%d",&item->value);

if(item->value==0) break;
item->next=NULL;
rear->next=item;
rear=item;
}
}
void sort()
{
int temp;

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 83 3/2/2012 6:52:15 PM


6.84 Data Structures Using C

struct node *nlink,*count;


if(head==NULL)
{
printf("List is empty");
}
nlink=head;
for(;nlink->next!=NULL;nlink=nlink->next)
for(count=nlink->next;count!=NULL;count = count->next)
if(nlink->value>count->value)
{
temp=nlink->value;
nlink->value=count->value;
count->value=temp;
}
}
void show()
{
printf("\n Sorted list is:");
while(head!=NULL)
{
nodes++;
printf("%d",head->value);
head=head->next;
}
nodes=0;
}

OUTPUT
Enter numbers(0 to exit): 12 1 2 34 5 65 4 0
Sorted list is: 1 2 4 5 12 34 65

Explanation:
In this program the create()function is used for inputting the elements into the linked list.
The sort()is used to sort the linked list elements in ascending order. The struct num is used
to store the linked list. The show()displays the sorted elements of linked list.

SUMMARY
1. Series of linearly arranged numbers is a list. The list can be of basic data type or custom
data type. The first element of the list is called HEAD and the last element TAIL.
2. Static implementation of list can be implemented using arrays. Examples have been illus-
trated on this point.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 84 3/2/2012 6:52:15 PM


Linked List 6.85

3. Pointers are used for implementation of linked list. The linked list is a major application of
the dynamic implementation.
4. In the list of elements, for any location n, (n–1) is predecessor and (n+1) is successor. In other
words, for any location n in the list, the left element is predecessor and the right element is
successor.
5. The merging is a procedure in which two or more lists can be combined and third list is
created.
6. A linked list is a dynamic data structure. It is an ideal technique to store data when user
does not know in advance how many elements are to be stored. The dynamic implementa-
tion of list using pointers is also known as linked list.
7. Singly linked list: In this type of linked list two successive nodes of the linked list are linked
with each other in sequential linear manner.
8. Doubly linked list : In this type of linked list the data structure holds two-pointer fields.
9. Circular list : In this list the first and last elements are adjacent. This type of list has neither
end nor starting node.
10. A circular doubly linked list : In this type of linked list the structure field contains three fields.
Two link fields and one data field.
11. Creation: The linked list creation operation involves allocation of structure size memory to
pointer of the same structure.
12. Traversing: It is the procedure of passing through (visiting) all the nodes of the linked list
from starting to end.
13. Display: The operation in which data field of every node is accessed and are displayed on
the screen.
14. Splitting of a linked list: Once a singly linked list is created, it can be divided into many sub-
lists. The technique is very simple. Put the NULL value in the node where you want to
finish the first sub-list in the main list. Later, the next node will act as first node for the
second sub-list.
15. Doubly linked list: Each node of the doubly linked list has two pointer fields and holds
the address of predecessor and successor elements. These pointers enable bi-directional
traversing, i.e. traversing the list in backward and forward direction.
16. Circular doubly linked list: A circular doubly linked list has both successor and predecessor
pointers. In this type insertion and deletion operations are easily performed as compared
to other type of linked lists.
17. Polynomial manipulation: The linked list is used for implementation of polynomial. The operations
such as addition, multiplication etc., are performed. To get better proficiency in processing
each polynomial is stored in decreasing order.
18. Linked dictionary: While compiling a program the linked dictionary has an important role.
In compiler, the organization and maintenance of dictionary holding names and their
corresponding values are maintained in the linked dictionary. This linked directory is
called symbol table. While designing compiler, two factors, i.e. time and memory space are
considered.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 85 3/2/2012 6:52:15 PM


6.86 Data Structures Using C

EXERCISES
A. Answer the following questions:

1. Explain merging operation of two lists.


2. Differentiate between static and dynamic list.
3. Explain the use of pointer head in the linked list.
4. Mention types of linked lists with explanation. On which basis are the linked lists classified?
5. Explain applications of linked list.

B. Select the appropriate options from the following:

1. The elements of linked lists are stored in


(a) successive memory locations (c) alternate memory locations
(b) random memory locations (d) all of the above.
2. Name the function that is used for memory allocation in implementation of linked list
(a) malloc() (c) free()
(b) realloc() (d) both (a) and (c).
3. If it is decided to create the linked list in C++, function that allocates memory is
(a) malloc() (c) delete
(b) new (d) both (a) and (b).
4. The free() function is used to
(a) release the memory (c) to unlink the first and last node
(b) to unlink the node (d) none of the above.
5. The pointer head points to the
(a) first node (c) either first or last node
(b) last node (d) none of the above.
6. This type of linked list does not have null value in the last node
(a) circular linked list (c) static list
(b) singly linked list (d) none of the above.
7. The first node of this type of linked list has NULL value
(a) doubly linked list (c) singly linked list
(b) doubly circular linked list (d) all of the above.
8. This type of linked list does not have first and last node
(a) circular linked list (c) doubly linked list
(b) singly linked list (d) static list.
9. When the malloc () function returns NULL value it means
(a) memory is not allocated (c) memory is allocated
(b) memory is allocated but no data entered (d) none of the above.
10. If memory is not allocated, what further action will you suggest?
(a) try again (c) both (a) & (b)
(b) exit from the program (d) continue the program.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 86 3/2/2012 6:52:15 PM


Linked List 6.87

C. Attempt the following programs:

1. Write a program to remove first and last node of the linked list.
2. Write a program to duplicate a linked list from other linked list. Remove all odd numbers from
the new list and display both of the linked lists.
3. Write a program to create the linked list and remove all the duplicate elements of the list. The
list should have unique elements.
4. Write a program to find successor of the given element in a linked list.
5. Write a program to create and display the elements of a circular linked list.
6. Write a program to terminate the program when malloc () returns to NULL.
7. Write a program to find the number of even and odd elements in a linked list.
8. Write a program to find the average value of elements of a linked list.
9. Write a menu driven program to perform the following operations on linked list:
1. Create
2. Insert
3. Delete
4. Display
5. Exit.
10. Write a program to multiply two polynomials.
11. Write a program to create and display circular linked list containing five elements.
12. Write a program to find the minimum and maximum value from the linked list.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 87 3/2/2012 6:52:15 PM


This page is intentionally left blank.

M06_ASHOK NAMDEV KAMTHANE5067_01_SE_C06.indd 88 3/2/2012 6:52:15 PM


Chapter 7

Storage Management
CHAP TER O U T LIN E
7.1 Introduction 7.6 Storage Release
7.2 Allocation Techniques 7.7 Buddy System
7.3 Memory Representation 7.8 Binary Buddy System
7.4 Boundary Tag System 7.9 Compaction
7.5 Storage Allocations 7.10 Garbage Collection

7.1 INTRODUCTION

The fundamental purpose of any program is to manipulate data and its storage in the computer memory.
Storage management consists of techniques that are used to manage the heap. Two memory management
techniques are used for this purpose. They are:
1. Static storage management
2. Dynamic storage management.

Static Storage Management It is necessary to load the program into the memory before execution of
a program. Before execution of a program, it is essential that the system should have enough memory.
When program execution starts, it takes memory through operating system. Once the memory is allocated
to the program, the memory allocated cannot be increased or decreased during program execution. The
same memory cannot be used by other programs. All these are taken care of by the operating system. For
example, an array is best example of static implementation in which the memory allocated is fixed in size.

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 1 3/2/2012 6:52:40 PM


7.2 Data Structures Using C

Dynamic Storage Management The dynamic storage management allows the user to manage the
memory during program execution. According to the request made by the program, memory can be
allocated. In this technique, wastage of memory can be avoided. This is efficient for multiprogramming and
single user environment, in which more than one program is executed simultaneously. The exact amount of
memory needed for the programs can be estimated only during program execution. The operating system
performs dynamic storage management. The linked list is an example of dynamic storage management.
In linked list, we have noticed during program execution that when new node is created memory is
allocated. Thus, depending upon the need of the user, any number of nodes can be created. Following are
the techniques of dynamic memory management.

7.2 ALLOCATION TECHNIQUES

1. Fixed block allocation


2. Variable block allocation.
The variable block allocation is further divided into following types:
1. First fit
2. Next fit
3. Best fit
4. Worst fit.

De-allocation Techniques The different ways of de-allocation techniques are mentioned below:

1. Ordered de-allocation
2. Random de-allocation.

7.3 MEMORY REPRESENTATION

The free blocks of memory storage are nothing but a collection of non-contiguous memory blocks. They
can be accessed in sequence by pointer from one block to another. The size of block depends on the
method applied as given below.

7.3.1 Fixed Block Storage


This is a straightforward method in which, all the blocks are of identical size. The user can decide the
size of the block. The operating system keeps a pointer called AVAIL. This pointer points to memory as
shown in the Fig. 7.1.

Avail Fixed Size Node

Figure 7.1 Free Storage with Fixed Block Memory

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 2 3/2/2012 6:52:41 PM


Storage Management 7.3

There are two functions getnode() and freenode(). Using these functions, the user program
communicates with operating system. The getnode() is used to obtain memory from the heap for stor-
age of data. The argument passed denotes amount of memory required. When the user program makes
a call to this function, a pointer to block in heap is returned after successful allocation otherwise returns
NULL. The NULL value indicates that there is not enough memory available. The returnnode() is
opposite of the getnode() function in which when a node is no longer needed its allocated memory is
released and returned to pool as shown in Fig. 7.2.

Avail Fixed Size Node

Return to Called Function

Figure 7.2 Obtaining Memory Block

Though the above method is straightforward, it consumes more memory. For example, the size of
each block is 1 KB (1024 bytes) and the program requests the memory of 1.2 KB, in such a situation
the memory allocated is 2 KB, hence, the extra memory allocated is of no use. If the size of the block is
decreased, it reduces the program performance.

7.3.2 Variable Block Storage


We know that fixed size block method has a limitation, and this can be overcome by the use of variable
block storage. The functions getnode() and freenode() suppose that the blocks of memory are
ordered in assscending order according to their sizes. The node has an extra field that holds the size of
block as per the Fig. 7.3. The function getnode() returns a memory block which is more than or equal
to the requested memory by the caller function.

Avail Fixed Size Node

Returning Memory Block


to Free Store

Figure 7.3 Mechanism of Return Node ()

In static storage management, memory blocks of fixed sizes are allocated for storing the programs
whereas in many applications there is a need to have memory of different sizes. In getnode() and
returnnode() function, we discussed that memory blocks of different sizes are present and blocks
are connected with each other. However, in reality when there is no program in the memory, the whole

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 3 3/2/2012 6:52:41 PM


7.4 Data Structures Using C

memory is considered as a block. In this situation, the blocks of required sizes are automatically made
through use of system by calling the functions many times. The blocks returned in all executions are
together shaped as a block as per the Fig. 7.4 (a to d). Suppose, the pointer returns M1, M2, M3 and M4.

Figure 7.4 (a) Total Block Memory Without Any Program

In the above Fig. 7.4 (a), no program is loaded and hence total block of memory is available.

M1 M2 M3 M4 Unused memory

Figure 7.4 (b) Four Programs are Loaded in Memory

As per the above Fig. 7.4 (b), four programs M1 to M4 are loaded and memory is allocated to them in
sequence of their order. The Fig. 7.4 (b) also indicates the unused memory, which is available for use.

M1 M2 free M4 Unused memory

Figure 7.4 (c) Three Programs and Unused Memory

The execution of programs M3 is completed and when it quits from the memory the space is returned
to main storage. Here, blocks of variable sizes are generated.

M1 M2 free M4 M5 Unused memory

Figure 7.4 (d) Program and Memory

Another program (M5) requests for memory and the memory needed is allocated to it. Thus, the
dynamic memory management performs the following tasks:
1. It searches requested blocks of memory and allocates memory.
2. Supervises the released blocks of memory.
3. Combines the tiny blocks of memory to bigger blocks.
In order to provide the above services two memory management systems are used. They are (i) bound-
ary tag system and (ii) buddy system.

7.4 BOUNDARY TAG SYSTEM

The boundary tag system is a resourceful memory system for dynamic memory management system. It
works on a node structure as per the Fig. 7.5. In the node structure for a specified block, first and last words
are set aside for block information. The LL and RL are pointers to predecessor and successor blocks from

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 4 3/2/2012 6:52:41 PM


Storage Management 7.5

LL TAG S RL

FREE SPACE

TAG UPLINK

Figure 7.5 Node Structure

the current block. The argument S contains amount of free memory available. The TAG is flag field and
stores values 0 (free) or 1 (engaged). There are two flag fields on the two boundaries of the block. Hence,
the system is called boundary tag system. The filed UPLINK points to beginning of the same block. The
uses of all the above fields are explained at appropriate situations. These systems sustain a circular linked
list of free memory blocks. Using circular doubly linked implementation a block can be easily released.
The header node is also used in the boundary tag system and holds the value zero in field S and TAG.

7.5 STORAGE ALLOCATIONS

As discussed in the list structure, the request for memory block to system can be made in the following ways:
1. First-fit storage allocation
2. Best-fit storage allocation
3. Worst-fit storage allocation
4. Next-fit storage allocation.

7.5.1 First-fit Allocation


This is a straightforward way of memory allocation. In this method when a request is made, first avail-
able free blocks are searched. When a free block of memory is obtained, a pointer pointing to the same
block is returned to call function. In this method, the memory allocated is always larger than the memory
required. This process requires a minimum search for the needed size of memory. The first fit method
allocates lowest memory addresses.

7.5.2 Best-fit Storage Allocation


In this type, the required memory and allocated memory are calculated. The memory is allocated in such a
way that the need of memory and allocated amount of memory is nearly the same. For example, required
memory is R and allocated memory is A and assume the difference is D. Then, D is very small. In the
examples, so far we have observed that whenever memory is needed for a single node it is requested by
the program using malloc() function. Hence, our unit of memory is node. This technique reduces
consumption of memory as the required memory and allocated memory is very close.

7.5.3 Worst-fit Storage Allocation


This method is opposite of best-fit method. Instead of finding a smaller block close to request size of block,
this method searches the largest block and allocates it. The worst-fit allocation decreases the creation of
small block as created in best-fit allocation.

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 5 3/2/2012 6:52:41 PM


7.6 Data Structures Using C

7.5.4 Next-fit Storage Allocation


We have already learnt the first-fit allocation method and in this method searching starts from the
beginning of the free list. In case of next fit storage allocation searching starts from the last allocation in
the list. In this method pointer pointing to the free list is stored next to the allocation node. It is utilized
to start the next call. The main goal of this method is to trim down the search process by recoiling from
checking of smaller blocks, which is lengthy in execution.

7.5.5 External Fragmentation


Let us assume that a request is made for bulky amount of storage blocks and as soon as the request is
released, the linked list of existing blocks are searched and if returned it means adjacent blocks are not
merged into one. This also means that the average block size available is small and larger blocks are not
available as per the request. In case if a request for a bigger block is accepted, it may possibly have to
be ignored due to lack of a single block on the free list that is large enough, although the total amount
of free storage is much greater than the requested storage amount. This process of decomposing the total
available storage into a larger number of comparatively small blocks is known as external fragmentation.

7.5.6 Internal Fragmentation


It is possible to reduce external fragmentation to some extent by allocating a larger block than the requested
size. It can be done by avoiding partition of a block into various parts. If we apply this method, it could
happen that a request for storage is rejected due to the lack of blocks of the desired size. This can occur
even if the amount of storage that is wasted is more than enough to fulfil the required amount. Internal
fragmentation is nothing but dividing the total unused storage into available blocks. Further these blocks
are allocated with some parts of these blocks remains unused, but not made available to other programs.
Fragmentation must be done cautiously as it is a main problem in dynamic memory management.

7.6 STORAGE RELEASE

The de-allocation of the memory is a very essential process and utmost care must be taken by the programmer
to shun the wastage of memory. In static implementation of data structure the wastage of memory is more
than that in the dynamic implementation. This topic is devoted for discussion of de-allocation of allocated
memory, which is returned to free store. It is one type of re-cycling. The system sources allocated must be
returned to the system if the program is not in use. This way the performance of the system is maintained.
We have observed in the boundary tag system that it inserts the block to the list of free blocks and merge
recently inserted blocks with its neighbouring blocks.

7.7 BUDDY SYSTEM

The buddy system is the alternative storage management system. This system limits the sizes of the block
to some fixed set of sizes. Till now we have learnt that the block sizes are fixed or totally arbitrarily. The
linked list keeps the size of blocks of buddy system to a restricted size. When a request is made for size S
then the size X, which is the minimum of the fixed sizes but equivalent to or larger than S, is searched and
block of size X is allocated.
In case if block of size S is not available, then a larger block is split into two sub-buddies (block). The
blocks splitted are also of equal and fixed sizes. This procedure is repetitively done until a block of size X

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 6 3/2/2012 6:52:41 PM


Storage Management 7.7

is formed. The restricted block sizes in buddy system are as F0, F1 to FM. According to the recurrence, the
requirement of block sizes can be expressed by the following equation:
Fn = Fn-1 + Fn-g, g ≤ n ≤ M (7.1)

M is maximum size.
For given values of g and M
F0=V0,F1=V1,..., Fg-1=Vg-1

If values of g = 1 and F0 = 8 the block sizes are 8,16,32,64,128. These values can be obtained from
Eq. 7.1. We can also observe that the block sizes are successive powers of two. The buddy system based on
the above condition is called binary buddy system.
One more buddy system, which restricts the fixed sizes to the Fibonacci series sequence, is known
as Fibonacci buddy system. The initial value is g = 2 and F0 = 8, F1 = 13. The sizes of the blocks are
8,13,21,34,55,89…. The values of F0, F1 and F2 are depending according to the application.
When a request is made to get memory space to the system, the system searches for a block, which is
closely equal to but not less than the requested memory block. When the above-described block is found
it is immediately allocated, else next larger block in the list will be divided until the block of nearest size
is found. On the contrary, when a block of memory is returned to the system (de-allocated), the returned
block is pooled with another free block into larger free blocks.
In order to illustrate the above allocation and de-allocation methods, consider the fibonacci buddy
system in which the restricted block sizes are 8,13,21,34,55,89 and 144. The 144 is the biggest possible
block from the memory available. Figure 7.6 illustrates the allocation and de-allocation.
From Fig. 7.6 the following points are observed. In the beginning, the system keeps a free block of size
144. When a demand for memory comes for size 25, the system divides and creates two buddies of sizes
89 and 55, respectively. The second buddy, i.e. 55 is divided into two buddies as 21 and 34. The block of
size 34 is closely nearest further and hence it is used for allocation as per Fig. 7.6.
For a succeeding request for a block of size say 40, the system searches for a matching block and sets the
block of size 89 as obtainable but it is too huge for the made request. That is why the partition is done as
55 and 34, the block size 55 is allocated, and the request is fulfilled. Figure 7.7 illustrates this point.

144

89 34 21

144

89 55

21 34

Figure 7.6 Allocation Procedure for Size 25

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 7 3/2/2012 6:52:41 PM


7.8 Data Structures Using C

144

89 34 21
55 34

144

55 89

55 34
34
21

Figure 7.7 Allocation Procedure for Size 40

144

89 34 21

144

89 55

34 21
55
34

Figure 7.8 Releasing of Block of Size 55

Consider the situation if block of size 55 is de-allocated and returned to the system as shown in Fig. 7.8. The
two buddies namely 55 and 34 are free buddies. These two free buddies come together and block of size 89 is
formed. We know that the block 89 is a free buddy and the combination comes to the end of the procedure.
While deallocation of a block of size 34 as shown in Fig 7.9, the first blocks of size 34 and 21 are com-
bined as they are free buddies of size 55.
So far we have seen theoretical representation. The use of structure of a node to implement above
operations can be defined as follows:
There are two fields and they are right and left link. These two link fields store the address of the
predecessor and successor of the block. The size is stored in the size field. In the field, the absolute size is
not stored and only index value according to the recurrence relation is stored. Suppose, Fibonacci system
is applied then the equation would be,

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 8 3/2/2012 6:52:41 PM


Storage Management 7.9

FN = FN-1 + FN-2 (7.2)

Let F0= 8 and F1=13


144

144

89 55

34 21

Figure 7.9 De-allocation of Block Size (34)


The value of size field are as under
Absolute size (Fn) Sizes (n)
F0 = 8 0
F1 = 13 1
F2 = 21 2
F3 = 34 3
F4 = 55 4
F5 = 89 5
The field CODE is used to get information about the blocks, that is, whether the two blocks are bud-
dies or not. The buddy property can be determined by the solution given by Hinds as follows:
Initially, the block is largest, then field CODE = 0.
After partition of parent block, two blocks left and right are created. Then,
CODEL = CODEP+1
CODER = 0

After combining these two buddies the ensuing block CODE field is one less as compared to its left
buddy as follows:
CODEP=CODEL-1

By the following method, various partitions from biggest block to the smallest block can be created.
Depending upon the value of code field we can determine whether the block is left block or right block.
When the value of CODE=0 then it is right block and if the value is greater than 0 then it is a left block
(buddy). The code value denotes the number of splits of some larger block so far made by the buddy.
Consider two cases of allocation,
1. Best-fit strategy
2. Fibonacci buddy system.
According to Fibonacci buddy system, Fn = Fn−1 + Fn−2
Also,
2 ≤ n ≤ M = 6 When F0 = 8 and F1 = 13

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 9 3/2/2012 6:52:42 PM


7.10 Data Structures Using C

HEADER

0 5 1 3 1 0 2 0

1 89 123 144

Figure 7.10 (a)

At the starting the block of block of size 34 is allocated as shown in the Fig. 7.10 (a).
Assume that the successive request is made for a block size 50. The system will search for the required
closer block from header. When the block of size 89 is found which is larger than the requested one,
partition is carried out. After partition, we get two buddies of 55 and 34 size. The block of size 55 is allo-
cated as per the Fig. 7.10 (b).

1 4 2 0 3 0 1 3 1 0 2 0

1 55 89 123 144

Figure 7.10 (b)


When memory is not required it is released, i.e. the memory block allocated is returned to heap.
Consider Fig. 7.10 (c).

HEADER

0 5 1 1 3 1 0 2 0

1 89 123 144

Figure 7.10 (c)

When a block of size 34 is returned as shown in the Fig. 7.10 (c) the code of free block is one and hence
it is a left buddy of any larger buddy. Its right corresponding block is free; they can be combined as shown

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 10 3/2/2012 6:52:42 PM


Storage Management 7.11

in Fig. 7.10 (c). The size of newly formed block will be 55 and it is a free buddy. We can notice that it is a
left buddy. One more combination can be done if we find its right corresponding block. Figures 7.10 (d)
and 7.10 (e) show this block. This is the largest block and no further combinations are possible. Thus,
de-allocation is complete.

0 5 1 0 4 0

1 89 144

Figure 7.10 (d)

0 6 0
1 144

Figure 7.10 (e)

7.8 BINARY BUDDY SYSTEM

After studying the buddy system now, it is time to turn to binary buddy system (BBS). The BBS is based
on the recurrence relation given as follows:
Fi= Fi-1 + Fi-1 (7.3)
1 ≤ I ≤ MAX

In the binary system, the block sizes are power of base 2. In this system the block of memory is accu-
rately partitioned into two sections of fifty-percent each. This system also has one advantage that the base
address of other buddy system can be easily computed, if the size along with base address of at least one
buddy is available for the block of size 2k. In this way when a block of memory is released, its amalgama-
tion with its other matching part is straightforward.

7.9 COMPACTION

The part of free memory is mixed together with the dynamically used partitions throughout the memory
and this is one of the critical problem in dynamic storage allocation. For example, consider the system
whose memory picture is as per the Fig. 7.11. When all requirements for storage are of fixed size, then it
is sufficient to link all unused available blocks together into an existing space list and the request received
can be fulfilled. On the other hand, when storage requests received are of different sizes, it might be too
expensive. For example, assume that a request for a block of size 256 KB is accepted even if total free

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 11 3/2/2012 6:52:42 PM


7.12 Data Structures Using C

0 KB
M0 Available
100 KB Memory
M1
200 KB
M2 From 360 KB
340 KB
160 KB 160 KB
500 KB
M3
700 KB
700 KB
100 KB 100 KB
800 KB
M4
900 KB
900 KB
100 KB 100 KB
1000 KB

Figure 7.11 Dynamic Partitioning of Memory

space available is 360 KB. The space available is more than the storage amount needed. However, the
needed storage space cannot be allocated. This is because of external fragmentation. It is usually detected
in dynamic memory management systems with different size blocks.
We have already learnt in previous sections that combining of contiguous free portions when free
blocks are returned is a technique frequently followed to decrease fragmentation and thus the amount
of unused wasted memory is prohibited. Nevertheless, the above techniques are inclined to put off the
impact moderately than to avert the problem. Comprehensive study provides the fact that after some
time of operation, the system is likely to attain a status of constancy and maintain a rule which is called
fifty per cent rule. This rule points out that the number of used and free blocks are same, i.e. 50% each.
In addition, the study divulges that more or less one-third of memory is not used and wasted because
of fragmentation. This is the case even if contiguous free areas are re-combined every time a block is
returned. Furthermore, this type of implementation slows down execution speed of program as the system
has a task of releasing and coalescing block at the same time during program execution.
When memory is fragmented, it can be re-allocated a few or entire portion into one last part of memory
and consequently coalesce the small holes into one big free part. This practice of recovering memory
storage is known de-fragmentation or compaction. Compaction mechanism is shifting of used blocks
from one place in memory to other location. To accomplish this all the active processes are required to be
suspended and in fact copied from one part of memory into a different part.
The process of memory compaction is possibly carried out whenever required. In some memory man-
agement methods, compact process is performed when a free portion of memory is available. In this way,
gathering maximum of the free memory into one large portion takes place. A substitute way is to compact
only when the request received cannot be fulfilled and system fails to allocate the memory. If the com-
bined sizes of free portions of memory go above the requested amount of memory available, or else, free
memory cannot satisfy the pending need in any case then compaction may not be useful.
There are two approaches:
1. Incremental compaction
2. Selective compaction.

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 12 3/2/2012 6:52:42 PM


Storage Management 7.13

Figure 7.12 shows used and unused (free) memory for mapping with the above two techniques.
0 KB
M0
Free
100 KB Memory
M1
200 KB
M2
340 KB Used
160 KB Memory
500 KB
M3
700 KB
100 KB
800 KB
M4
900 KB
100 KB
1000 KB

Figure 7.12 Actual Memory

Incremental Compaction In this type every free block is moved into one end of the memory to compose a big
hole. This procedure is very straightforward to apply but costly. The Fig. 7.13 shows incremental compaction.

0 KB
M0
100 KB
M1
200 KB
M2
340 KB

M3
Used
540 KB Memory
M4
640 KB

Unused
360 KB
Memory

1000 KB

Figure 7.13 Incremental Compaction

Selective Compaction Selective compaction seeks for least number of free blocks, movement of which
produces a larger free hole. The obtained hole may be at any place in the memory and need not be at the
end of the memory. Figure 7.14 shows a memory picture of selective compaction.

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 13 3/2/2012 6:52:42 PM


7.14 Data Structures Using C

0 KB
M0
100 KB
M1
200 KB
M2
340 KB

360 KB

700 KB
M3
900 KB
M4
1000 KB

Figure 7.14 Selective Compaction

Through selective compaction, only by moving block M3 of size 200 KB from location 500 KB to the
location 700 KB; continuing this way we can create the largest possible free holes of size 360 KB at the
location 340 KB.
Therefore, time for shifting data is minimum. However, with the incremental method we have to move
first the memory portion of the block M3 from 500 KB location to 340 KB location, then the memory
content of the block M4 at 540 KB location. Therefore, here, total movement is 200 KB + 100 KB =
300 KB instead of 200 KB in selective method. Selective compaction approach is seldom applied because of
the overhead in evaluating the option while selecting the most advantageous moving method. Time for select-
ing such block may be more than the time required to shift the block one-by-one at the end of the memory.
Consequently, a more general approach to compaction is to reallocate all free blocks to one end of memory.

7.9.1 Memory (Storage) Allocation


The operating system of the computer controls entire system resources and permits or denies the use of
system resources by other programs. The other programs need to request the operating system for any
requirement of memory. The operating system manages the entire process and allocates the memory to
other programs. It performs the memory allocation using the following two systems:

Linked Allocation We know that a linked list is nothing but a sequence of nodes linked with the pointer.
Every node has two parts, i.e. data field and link field. The data is stored in the data filed and link field
stores address of next field.

Fixed Sized Partition Technique In this type memory space is partitioned into fixed sections and each
block holds given memory. The size of the block is predetermined and cannot be modified at run time.
If the program size is less than the block of memory, the memory more than the requirement remains
unused. If the memory of the block is less than the program size, the program will not be executed.

7.9.2 Storage Pools


Storage pools mean every node present in memory. There are two ways to manage the pools:

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 14 3/2/2012 6:52:43 PM


Storage Management 7.15

Bit Tables/Paging Technique When all the nodes of the data structure are of identical size, this method
is applicable. In this technique, every program is split into fixed size pages. Later, each page is sub-divided
into fixed blocks of nodes known page frames. For example, memory size is 20 KB and every page frames
needs 200 KB. The memory space divided as following table.

Page Frame Bit


0 1
1 1
2 1
3 1
4 1
5 1
6 1
7 1
8 1
9 1

In the above table one shows free space and initially for page frame 0 to 9 the page frame status is zero.
For example, five programs are to be executed and memory needed is as follows:

Program Memory Needed

Program –1 60 KB
Program –2 80 KB
Program –3 80 KB
Program –4 40 KB
Program –5 40 KB

For the preceding table the memory allocation will be as follows:

Program No. Page No. Part of Page No. Bit Status (a) Bit Status (b)

1 0 0 0 1
1 1 1 0 1
2 0 2 0 0
2 1 3 0 0
2 2 4 0 0
3 0 5 0 1
3 1 6 0 1
3 2 7 0 1
4 0 8 0 0
5 0 9 0 0

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 15 3/2/2012 6:52:43 PM


7.16 Data Structures Using C

In the above table, the bit status 1 specifies that all the nodes of the memory be already allocated
to 1 to 5 programs. Assume, program 3 and 1 complete their execution and the memory engaged due
to these programs is released. The status bit 2 points the altered bit status. The paging technique has
some drawbacks and undergoes trouble for searching the best possible page frame size. In case the size of
the program is larger and memory space allocated is more then memory is wasted. Similarly, if the page
frame is small, the program has to undergo several partitions and it will be very tedious to match the frame
with the required size. In paging technique, the entire program must be memory resident. In this situation,
if program size is larger than available memory, the program will not be executed.

Demand Paging Method To overcome the limitations of the paging technique, demand paging method
is followed. In this method, a large program is divided into small sizes of program segments and first page is
then loaded in the memory. If few functions or statements of first pages, which are currently executed in
the memory having relation with statements which are in next page, then the required page is loaded from
disk to memory. In this procedure, the operating system can take part and transfer the required page to
the disk and vice-versa. This is known as thrashing.

7.10 GARBAGE COLLECTION

Garbage collection means the de-allocation of unused memory. Deciding when to release the allocated
memory is very simple. The memory de-allocation is done when the programmer requests by executing a
specific function. Languages like Java have in-built garbage collection system. The function free() in C
and delete in C++ are used to release the memory. The garbage collection system checks the entire memory,
marks the unused nodes and releases the memory associated with them.
The garbage collection consists of two steps:

Marking In this process, all the accessible nodes are marked and one field is kept for marking. The field
is marked with true or false.

Collection In this process, memory allocated of all the nodes, which are not marked, are released.
The garbage collection is a complex procedure and has the following disadvantages:
1. The garbage collection technique is applied when there is not much space.
2. The garbage collection may not be helpful if the pointers associated with the list are not properly
pointed.
However, the memory de-allocation is not as easy as it appears. The memory allocated during compile
time can be freed easily. The memory allocated dynamically at run time can be de-allocated but some care
must be taken. The dynamic structure such as linked list contains nodes, which are dynamically created
and contains reference of next nodes.

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 16 3/2/2012 6:52:43 PM


Storage Management 7.17

SUMMARY
1. In this chapter, the reader is exposed to the allocation and release of memory. Different
techniques of allocation of memory are discussed. Memory is one of the precious
resources and it is essential to manage it efficiently. Two methods are used for management
of memory.
2. Static storage management When program execution starts, it takes memory through
operating system. Once a memory is allocated to the program, the memory allocated cannot
be increased or decreased during program execution.
3. Dynamic storage management The dynamic storage management allows the user to
manage the memory during program execution. According to the request made by the pro-
gram, memory can be allocated. Under dynamic memory management various techniques
have been discussed in this chapter. The best-fit, first-fit and worst-fit memory management
techniques have been briefed.

EXERCISES
A. Answer the following questions:

1. What do you mean by static memory management? Explain in detail.


2. Distinguish between the static and dynamic memory management techniques.
3. Explain the various methods used to allocate memory under dynamic memory management.
4. Explain the demand paging method.
5. What is compaction?

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 17 3/2/2012 6:52:43 PM


This page is intentionally left blank.

M07_ASHOK NAMDEV KAMTHANE5067_01_SE_C07.indd 18 3/2/2012 6:52:43 PM


Chapter 8

Applications of Stacks

CHAP TER O U T LIN E


8.1 Introduction 8.6 Stack Frames

8.2 Infix, Prefix and Postfix Notations 8.7 Conversion of Number System

8.3 Evaluation of Postfix Expression 8.8 Recursion

8.4 Conversion of Expression from Infix 8.9 Activation Record Organization


to Postfix
8.10 Scope Rules
8.5 Reverse String
8.11 Scope Rules Through Stack

8.1 INTRODUCTION

Stacks have various real-life applications. Stacks are used to maintain the sequence of processing. In solving
arithmetic expressions, stacks are used. Stacks are used to convert bases of numbers. In a large program,
various functions are invoked by the main() function; all these functions are stacked in the memory.
Most of the calculators work on stack mechanism.

8.2 INFIX, PREFIX AND POSTFIX NOTATIONS

Arithmetic expressions can be defined in three kinds of notation: infix, prefix and postfix. The prefixes in,
pre and post indicate the relative location of the operator with two operands.

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 1 3/2/2012 6:56:33 PM


8.2 Data Structures Using C

Infix Notation Expressions are generally expressed in infix notation with binary operator between the
operands. The binary operator means the operator requires two operands such as +, *, / and %. In this
type, the operator precedes the operands. Following are examples of infix notation:
1. x+y
2. x+y*z
3. (x+y)*z
4. (x+y)*(p+q)
Every single letter (A-Z) and an unsigned integer is a legal infix expression. If X and Y are two valid
expressions then (X+Y ), then (X–Y ) and (X/Y ) are legal infix expressions.

Prefix Notation The prefix notation is also called polish notation. The polish mathematician Lukasiewicx
invented it. In this type also the operator precedes the operands. Following are the examples of prefix notation:
1. +xy
2. +x*yz
3. *+xyz
4. *+xy+pq

Postfix Notation The postfix notation is also called as reverse polish notation. The operator trails the
operand. Following are the examples of postfix notation:
1. xy+
2. xyz*+
3. xy+z*
4. xy+pq*+
Consider the following example:
X+Y*Z

In the above expression, we know that the multiplication has higher precedence than addition. The
expression X +(Y *Z ) is same as the expression X +Y *Z. By applying rules of priority, we can convert the
above expression to postfix notation.
X+(Y*Z)

Here, parentheses are not necessary.


X+(YZ*)
Here, multiplication is converted to postfix.
X(YZ*)+
Here, addition is converted to postfix.
XYZ*+
The above equation is postfix form. While doing the conversion operations, following points are
important.
1. When we convert an expression from prefix to postfix form, it is essential that properties like, prece-
dence, commutability and well-formed expressions of operators must be preserved.
2. The operations with high priority are converted first and after the remaining part of the expression
are converted to postfix form. Table 8.1 shows infix to postfix of an expression. The remaining part is
considered as a single operand.

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 2 3/2/2012 6:56:33 PM


Applications of Stacks 8.3

Table 8.1 Infix to Postfix


Infix Postfix

X+Y XY+

Here, XY is considered as single operand.


3. In suffix and prefix equivalent of an infix expressions, the variables must be in the relative place. The
expressions in prefix or suffix are without parenthesis. The operators are set according to precedence
rule of operators.
4. A fully parenthesized infix expression converted directly to postfix form, starting the conversion from
innermost parenthesis to outer most parenthesis. For example
(X + Y + (P + Q + (T +Y)))

The innermost parenthesis (T +Y ) is solved first.


The precedence can be changed on purpose by insertion of parenthesis. Consider the following
example:
(X+Y)*Z

In the above example, if parenthesis is not inserted the multiplication operation gets first priority. Due
to parenthesis the addition operation gets first priority.
(XY+)*Z

Here, the addition is converted in the postfix form.


(XY+)Z*

Here, the multiplication is converted to postfix form.


There are five binary operations such as addition (+), subtraction (–), multiplication (*), division (/)
and exponentiation. In C/C++, there is no exponentiation operator. Here, ^ is used to denote exponent
operation.
The equation X ^Y means X raised to Y. 2^ 3 means 8. When any expression is without parenthesis the
order of operation is left to right. Only in exponent the order is from right to left.
X + Y + Z means (X + Y )+Z, on the other hand X ^Y ^Z means X ^(Y ^Z ). The operation inside the
parenthesis gets first priority. Consider the following Table 8.2 which converts infix to postfix to make
your understanding perfect.

Table 8.2 Infix to Postfix


Infix Postfix

X+Y XY+
X+Y–Z XY+Z–
(X+Y)*(P–Q) XY+PQ–*
L^M*N–O+P/Q/(R+S) LM^N*O–PQ/RS+/+
((L+M)*N–(O–P)^(Q+R) LM+N*OP––QR+^
L-M/(N*O^P) LMNOP^*/–

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 3 3/2/2012 6:56:33 PM


8.4 Data Structures Using C

For converting an expression from infix to prefix the rules are same as like conversion from infix to
postfix. In the prefix conversion the operator is placed before the operand. Table 8.3 converts the infix
expression to the prefix.
Table 8.3 Infix to Prefix
Infix Prefix

X+Y +XY
X+Y–Z –+XYZ
(X+Y)*(P–Q) *+XY–PQ
L^M*N–O+P/Q/(R+S) +–*^LMNO//PQ+RS
((L+M)*N–(O–P)^(Q+R) ^–*+LMN–OP+QR
L–M/(N*O^P) –L/M*N^OP

The postfix form doesn’t require parenthesis. Consider the following expressions:
X+(Y*Z) and (X+Y)*Z
Table 8.4 Postfix
Infix Postfix

X+(Y*Z) XYZ*+
(X+Y)*Z XY+Z*

You can see from Table 8.4 that postfix expressions do not have parenthesis. In the postfix expressions,
sequence or precedence of operators decides sequence of operation. While converting infix expression to
postfix, it is difficult to know the operation associated with operand.
To write a valid expression whole parenthesization should be applied. However, the parenthesis must
not be large. The expression (X +Y )*Z is valid expression and need not be written like ((X +Y )*Z ). Here,
the outer parenthesis can be omitted and has no purpose. Consider the following expression. The above
expression can be written as (P+(Q*R))+(S *T ). To evaluate the expression it must be scanned from left to
right. Fig. 8.1 illustrates the expression.
If parentheses are present in the expression, then the precedence will be changed. For example, in
expression (P +Q )*R, first P +Q is solved and then multiplication takes place. Actually, it is possible to
declare an expression that makes the sequence of evaluation of expression independent of the priority of
the operators. This can be done by putting sub-expressions in the parentheses. The operators and oper-
ands are enclosed in the parentheses. Thus, we have several parenthetical levels as shown in the Fig. 8.2.
Such expressions are called fully parenthesized expressions. Consider the following example,

P + Q * R + S * T
(P + ((Q * R) + (S + T )))

1 2

1 3 2 3
3 4

Figure 8.1 Expression and Operation Precedence Rank Figure 8.2 Fully Parenthesized Expressions

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 4 3/2/2012 6:56:33 PM


Applications of Stacks 8.5

The numbers indicate parenthetical level of operators. When such an expression is solved, the
sub-expression having the operator with top parenthetical level is solved first. When two parentheses have
equal parenthetical levels, the left-sided parentheses are evaluated first. Followed by parenthesis 2 and 1.
In case the expression is partially parenthesized, a repetitive scanning from left to right is essential to
evaluate the expressions. This is because the operators present in conjunction with the operands within
the expression. The scanning is shunned in case the infix expression is converted to postfix or prefix
expression.

8.3 EVALUATION OF POSTFIX EXPRESSION

The postfix expressions are very simple. On the other hand, programming of evaluation of expression is
complicated. This is because the numbers and characters are mixed in one string. The programmer needs
to separate digits and symbols and perform arithmetic operation.
Each operator in the postfix expression is associated with the previous two operands. When we read an
operand from a given expression it is pushed onto the stack. When an operator symbol is read, the oper-
ands associated with it are the top elements of the stack. We can pop these two elements from the stack
and perform the operation. The obtained result from the last operation is again pushed onto the stack.
Table 8.5 describes the algorithm for conversion of the infix expression to postfix.

Table 8.5 Algorithm for Conversion of Infix to Postfix


Algorithm

1. Insert a ‘)’. at the end of X, where X is an expression


2. Check X from left to right and go back over the next 3 and 4 steps for every element of
X until ‘)’ is found.
3. In case operands are found, push it on the stack.
4. a. If any operator is found, pop the top-most two elements from stack.
b. Evaluate the expression formed by top two elements.
c. Push the result obtained onto the stack.
5. Allocate value equal to top stack element.
6. Quit.

Example 8.1 Write a program to evaluate postfix expressions.

# include <stdio.h>
# include <conio.h>
# include <ctype.h>
# include <math.h>

float stack[10];
int top=-1;
void push(char);
float pop();
float exp_eval(char[],float[]);

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 5 3/2/2012 6:56:34 PM


8.6 Data Structures Using C

void main()
{
int j=0;
char s_fix[20];
float number[20],res;
clrscr();
printf("\n Enter a postfix expression: ");
gets(s_fix);

while(s_fix[j]!='\0')
{
if(isalpha(s_fix[j]))
{

fflush(stdin);
printf("\n Enter number for %c: ",s_fix[j]);
scanf("%f",&number[j]);
}
j++;
}

res=exp_eval(s_fix, number);
printf("The res of %s =%f", s_fix,res);
getch();
}

float exp_eval(char s_fix[], float data[])


{
int j=0;
float opA,opB,fs;
char ch;

while(s_fix[j]!='\0')
{
ch=s_fix[j];
if (isalpha(s_fix[j]))
{
push(data[j]);
}
else
{
opB=pop();
opA=pop();

switch(ch)
{
case '+': push(opA+opB); break;
case '-': push(opA-opB); break;
case '*': push(opA*opB); break;
case '/': push(opA/opB); break;

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 6 3/2/2012 6:56:34 PM


Applications of Stacks 8.7

case '^': push(pow(opA,opB)); break;


}
}
j++;
}
fs=pop();
return(fs);
}

void push(char c)
{
top=++top;
stack[top]=c;
}

float pop()
{
float n;
n=stack[top];
top=––top;
return(n);
}

OUTPUT
Enter a postfix expression: jk*
Enter number for j: 4
Enter number for k: 5
The res of jk* =20.000000

Explanation:
In this program before main () function, the float type array stack [10] and integer variable
top are defined. They are initialized with –1. The prototype of functions push (), pop () and
exp_val () are declared. User has to enter expression and the gets () function activates the
input stream and the entered expression is stored in the s_fix[] character array.

The expression is checked and for every alphabet user has to enter a number. Immediately after this, the
function exp_eval() is invoked with two arguments, i.e. s_fix and number. Both the arguments are
array name and holds base address. This function returns result and is stored in variable res.
In the exp_eval() function the variable ch holds the arithmetic operation. The switch()
case structure determines the operation to be carried out. The pop() function is invoked and the two
popped values are stored in variables popB and popA. These variables are passed to push() function in
switch() case structure.

8.4 CONVERSION OF EXPRESSION FROM INFIX TO POSTFIX

In any expression, there are two types of components clubbed together. They are operand and operators.
The operator indicates the operation to be carried out and the operand indicates the values. The operands
are the variables on which the operator operates. Operators have their priority of execution. When one

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 7 3/2/2012 6:56:34 PM


8.8 Data Structures Using C

or more operations are clubbed together in a single expression the priority decides which operation is to
be performed first. Suppose, an expression contain two operations with high and low priority. We can
force the low priority operation to evaluate first by putting that particular operation in parenthesis. When
nested parenthesis are present in the expression the inner-most parenthesis is solved first. In any expression
the parenthesis are solved first. The operations are generally solved from left to right. Table 8.6 shows the
operator precedence.

Table 8.6 For Operator Precedence


Operator Precedence

Exponent High
Multiplication (*), Division (/) Next
Addition (+), Subtraction (–) Low

Consider the following example:


x-y/(p^q)+(u*v)

The operators are -,/,^,+,* and x,y,p,q,u and v are variables. The parenthesis are used to provide higher
priority to the operation (p^q) and (u*v).
Consider the example
Expression: X +Y *Z

Table 8.7 Conversion of X+Y*Z into Postfix


Character Postfix String Stack

X X
+ X +
Y XY +
* XY +*
Z XYZ +*
XYZ* +
XYZ*+

The expression is scanned and when operators are found, they are pushed on the stack. The operators
are pushed according to priority of execution of the stack. When operator + is found it is pushed onto the
stack. The precedence of * is higher than +. The symbol * is pushed onto the stack. At last, when string
reaches to end the stack is popped and its content is appended to the postfix string. These operations are
illustrated in Table 8.7.
Expression: (P +Q )*C
In the above example, opening parenthesis is found. Until the left parenthesis is not found the entire
stack is popped. Here, the parentheses provide first priority to addition. Table 8.8 explains the conversion.
Table 8.9 describes the algorithm for infix to postfix.

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 8 3/2/2012 6:56:34 PM


Applications of Stacks 8.9

Table 8.8 Conversion of (P+Q)*C into Postfix


Character Postfix String Stack

( (
P P (
+ P (+
Q PQ (+
) PQ+
* PQ+ *
R PQ+R *
PQ+R*

Table 8.9 Algorithm for Conversion Infix Expression into Postfix


Algorithm for Conversion of Infix Expression to Postfix

1. Push to the end of X, where X is an arithmetic expression.


2. Check expression from left to right and follow the steps 3 to 6 for every element of X until the stack is vacant.
3. In case an operand is found, add it to R, where R is the equivalent postfix expression.
4. In case left ‘(’ parenthesis is found push it onto stack.
5. In case an operator is found, then follow the following steps:
a. Continually pop from the stack and add each operator to R at the top of stack. The pushed item should have
same or upper precedence than the former operator encountered.
b. Append operator (recently encountered) onto stack.
6. In case ‘)’ right parenthesis is found, then follow the following steps:
a. Continually pop from the stack and append to every operator to R until left parenthesis is found.
b. Eliminate the left parenthesis.

Example 8.2 Write a program to convert infix expression to postfix form.

# include <stdio.h>
# include <conio.h>
# include <string.h>
# include <process.h>

char stack[20];
int T=-1;

void topost(char in_fix[]);


void push(char);
char pop();

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 9 3/2/2012 6:56:34 PM


8.10 Data Structures Using C

void main()
{
char in_fix[25];
clrscr();
puts(" Enter an infix expressions: ");
gets(in_fix);
puts("\n Postfix Expression: ");
topost(in_fix);
}

void push(char s)
{
if(T>=19)
{
puts("Stack overflow");
exit(0);
}
else
{
T=T+1;
stack[T]=s;
}
}

char pop()
{
char num;

if(T==-1)
{
puts("Stack is Empty");
getch();
return(0);
}
else
{
num=stack[T];
T––;
}

return(num);
}

int prefix(char ch)


{
if(ch=='/') return(5);
else if(ch=='*') return(4);
else if(ch=='+') return(3);
else return(2);
}

void topost(char in_fix[])


{

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 10 3/2/2012 6:56:34 PM


Applications of Stacks 8.11

int len;
static int index=0,pos=0;
char s,t;
char postfix[40];
len=strlen(in_fix);
push('#');

while(index<len)
{
s=in_fix[index];

switch(s)
{
case '(': push(s); break;
case ')': t=pop();

while(t!='(')
{
postfix[pos]=t;
pos++;
t=pop();
}

break;
case '+':
case '-':
case '*':
case '/':
case '^':

while(prefix(stack[T])>prefix(s))
{
t=pop();
postfix[pos]=t;
pos++;
}

push(s); break;
default: postfix[pos++]=s; break;
}
index++;
}

while(T>0)
{
t=pop();
postfix[pos++]=t;
}
postfix[pos++]=’\0’;
puts(postfix);
return;
}

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 11 3/2/2012 6:56:34 PM


8.12 Data Structures Using C

OUTPUT
Enter an infix expressions: m+s+p
Postfix Expression: msp++

Explanation:
In this program an infix expression is converted to postfix form. The prototype of function
topost (), push () and pop () are declared. The array stack [20] is declared. In addition,
the integer variable T is declared and initialized with –1. In function main (), a character array
in_fix[] is declared. The infix expression is entered by the user. The function topost () is
invoked and in_fix is sent as an argument.

In the function topost(), length of in_fix array is counted. Using push() function ‘# ’ is pushed.
The integer variable index is initialized to zero. The while loop executes until the value of index is less than
len. The variable s contains the value of in_fix[index] character. If the value of s is ‘(’, it is pushed and if
it contains.‘ )’. and pop() function is executed. The variable s is passed to switch() case statement.
Accordingly, case statements are executed.
Few applications of stack are narrated together with examples.

8.5 REVERSE STRING

We know the stack is based on last-in-first-out rule. It can be achieved simply by pushing each character
of the string onto the stack. The same can be popped in reverse fashion. Thus, reverse string can be done.
Consider the following program.

Example 8.3 Write a program to reverse the string using stack.

# include <stdio.h>
# include <conio.h>

char text[40];
void main()
{
char ch;
void push(char,int);
char pop(int);
int j=39,k;
clrscr();
puts("\n Enter a string(* to end): ");

while(ch!=’*’ && j>=0)

{
ch=getche();
push(ch,j);

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 12 3/2/2012 6:56:34 PM


Applications of Stacks 8.13

j––;
}
k=j;
j=0;

printf("\n Reverse string is: ");

while(k!=40)
{
ch=pop(k);
printf("%c",ch);
k++;
}
}
void push(char c, int j)
{
if(c!=’*’)
text[j]=c;
}

char pop(int j)
{
char c;
c=text[j];
text[j]=text[j+1];
return c;
}

OUTPUT
Enter a string(* to end):
HELLO*
Reverse string is: OLLEH

Explanation: PUSH
In this program the array text[40] is STACK
declared as global. So, other two functions
push() and pop() have access to it.
The character entered is pushed on O L L E H
the stack. When user enters '*' the
character reading loop is interrupted
and immediately pop operation is carried
POP
out. During pop operation the pop()
function returns one character its per
execution. The string is displayed as
reverse because the pop operation is
reverse of push. Figure 8.3 represents
the process. Figure 8.3 Reverse String

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 13 3/2/2012 6:56:34 PM


8.14 Data Structures Using C

8.6 STACK FRAMES

All the programs compiled using high-level language compilers uses stack frame for function invocation.
Operational memory uses stack frames to store the variables declared in the program. During the func-
tion, execution number of data is pushed onto the stack. When the function execution terminates, the
stack content is popped. When a function is invoked, local variables, formal arguments and return address
are pushed onto the stack. Thus, every function executes in a particular or a separate circumstance and
hence recursion of function is also possible. Consider the following program code:
fun(int p, int q)
{
int h;
if(condition) return(value);
h=10;
return joy(int h);
}
joy(int l)
{
int m,u;
m=1, u=2;
return fun(m,u);
}

The above is an example of indirect function in which two functions fun () and joy () invokes
each other. For every invocation of function new stack frame is created and as mentioned earlier new copy
local variables, return address and formal arguments are pushed. Conceptually, the stack is a piece of main
memory, which is used by the program to temporarily store data. When a function is invoked, variables are
pushed onto the stack and when function execution ends, the stack is popped. When a function invokes
another function (other than itself ) the parameters of caller function are pushed onto the stack with
address subsequently called instruction. This is because after execution of called function, the compiler
can keep track of previous path and it can determine where to return after execution.

8.7 CONVERSION OF NUMBER SYSTEM

Suppose, one wants to calculate binary number of a given decimal number, the given number is repeatedly
divided by 2 until 0 is obtained. The binary number can be displayed in reverse order using stack rule
last-in-first-out (LIFO). Consider the following program:

Example 8.4 Write aprogram to convert a given decimal number to binary. Explain the role
of stack mechanism.

# include <stdio.h>
# include <conio.h>

int num[7];

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 14 3/2/2012 6:56:34 PM


Applications of Stacks 8.15

void main()
{
int n,k,T=7;
void show();
void push(int,int);
clrscr();
printf("\n Enter a number: ");
scanf("%d",&n);
printf("\n The binary number is: ");
while(n)
{
k=n%2;
push(––T,k);
n=n/2;
}

show();
}

void push(int j, int b)


{
num[j]=b;
}
void show()
{
int j;
for(j=0;j<7;j++)
printf(" %d ",num[j]);
}

OUTPUT
Enter a number: 9
The binary number is: 0 0 0 1 0 0 1

Explanation:
In this program the binary equivalent is obtained by repeatedly dividing by two. Here, the first
binary digit obtained is pushed on the stack. This process is continued. The show () function
displays the binary digits stored in the stack, i.e. an array.

8.8 RECURSION

The recursion is the fundamental concept of the mathematical logic. Recursion is one of the important
facilities provided in many languages. C also supports recursion. There are many problems, which can
be solved recursively. The loop which performs repeated actions on a set of instructions can be classified
as either iterative or recursive. The recursive loop is different from the iterative loop. In the recursion,
the procedure can call itself directly or indirectly. In the directly called recursion the procedure calls itself

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 15 3/2/2012 6:56:34 PM


8.16 Data Structures Using C

repeatedly. On the other hand, if the procedure calls another procedure then it is an indirect recursion.
In recursion, some statements, which are specified in the function, are executed repeatedly. Every time a
new value is passed to the recursive function till the condition is satisfied. A simple programming example
is given below.

Example 8.5 Write a program and find the greatest common divisor of the given two numbers.

# include <stdio.h>
# include <conio.h>
int stack[40],top=-1;
void main()
{
void gcd(int,int );
int n1,n2;
clrscr();
printf("\nEnter number:- ");
scanf("%d",&n1);
printf("\nEnter number:- ");
scanf("%d",&n2);
gcd(n1,n2);
printf("\nThe gcd of %d & %d is:- %d",n1,n2,stack[top]);
}

void gcd(int a,int b)


{
if(a!=b)
{
if(a>b)
{
top++;
stack[top]=a-b;
printf("\nTop value is:- %d",stack[top]);
gcd(a-b,b);
}
else
{
top++;
stack[top]=b-a;
printf("\nTop value is:- %d",stack[top]);
gcd(a,b-a);
}
}
}

OUTPUT:
Enter number:- 5
Enter number:- 25
Top value is:- 20
Top value is:- 15
Top value is:- 10
Top value is:- 5
The gcd of 5 & 25 is:- 5

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 16 3/2/2012 6:56:34 PM


Applications of Stacks 8.17

Explanation:
In this program the stack[] and the top are the global variables. By using the n1 and n2
variables the two numbers are input by the user. The gcd() function is the recursive function
which is recursively called till the greatest common divisor of the two given numbers is obtained.
The program stores the difference of the two numbers, which are passed by the function into
stack []. The value present at top is the greatest common divisor of the two numbers.

Example 8.6 Write a program to convert decimal to binary by using the concept of recursion.

# include <stdio.h>
# include <conio.h>
int stack[40],top=-1;
void main()
{
void binary(int);
int no;
clrscr();
printf("\nEnter number:- ");
scanf("%d",&no);
binary(no);

printf("\nThe binary of the given number is:-");

while(top>=0)
{
printf(" %d ",stack[top]);
top––;
}
}
void binary(int b)
{
if(b>0)
{ top++;
stack[top]=b%2;
binary(b/2);
}
}

OUTPUT:
Enter number:- 255
The binary of the given number is:- 1 1 1 1 1 1 1 1

Explanation:
This program includes the function binary () which is called recursively for calculating the
binary of a given decimal number. The number is prompted by the user in variable no. On
modulus operation, the reminders are stored in the stack. At first, the least significant bit is
obtained and it is stored on the top of the stack. Subsequently, the other reminders are obtained
and pushed into the stack and the pop operation is carried out for displaying them.

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 17 3/2/2012 6:56:34 PM


8.18 Data Structures Using C

8.9 ACTIVATION RECORD ORGANIZATION

The group of fields such as: a) memory for local variables, b) declaration of function, c) return addresses,
and d) pointer to location are pushed, when a function is invoked and popped, when a function execution
is completed. This particular record of function is known as an activation record.
The details of the fields are described in the following topics. In the block structure programming
languages, the programmer can define variable with same name but with different scopes. Two variables
with the same name cannot be declared in a single block. The scope can be categorized in two types:
a) Local b) Global. The local scope of a variable is limited to a specific block in which a variable is declared.
The global scope covers entire program. The variables declared in a global scope can be accessed by any
sub-program. If, in a program, a variable with same name is declared in local and global variable then the
local variable gets first priority. Consider the following program:

Example 8.7 Write a program to declare same variable within different blocks and display their
values and addresses.

# include <stdio.h>
# include <conio.h>

void main()
{
int j=10;
clrscr();
printf("\n Value of j is %2d & it’s address is = %u",j,&j);
{
int j=5;
printf("\n Value of j is %2d & it’s address is = %u",j,&j);
}
printf("\n Value of j is %2d & it’s address is = %u",j,&j);
}

OUTPUT:
Value of j is 10 & it’s address is = 65496
Value of j is 5 & it’s address is = 65494
Value of j is 10 & it’s address is = 65496

Explanation:
In this program you can observe that a variable int j is declared twice, first, immediately in
main () function and second, declaration is done in a separate block inside the main ()
function.The values and their addresses displayed of both variables are different.The first and last
printf () statement displays the same value and address because they are in main () block.
The second statement is in the sub block.

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 18 3/2/2012 6:56:34 PM


Applications of Stacks 8.19

8.10 SCOPE RULES

The above program is based on scope rule of the variable. The scope rules are of two kinds:
1. Static scope
2. Dynamic scope.

Static Scope The static scope declares the variable in circumstances of syntactic program structure.
In such a program structure, one can easily conclude the declaration of variable by only reading the
program. This is why the rule is known as static. The static rule can be defined as follows:
a. The scope of a variable is limited to the current block in which it is declared, other blocks have no
access to the variable.
b. If a variable is not declared in a particular block, in such a case, the variable declaration of previous
block is considered. If declaration, not found, it searches the nested blocks until the declaration is
found. This rule is called “most closely nested rule”.
For example, consider the following program code from the previous program:
{
int j;
printf("\n Address of j =%u",&j);
}

If we remove the statement int j, the output of the program would be:
Address of j =65524
Address of j =65524
Address of j =65524

This is because, when declaration is not found in the above block, the nearest closely declaration is
considered and this is why the address of variable j declared in main() is printed.

Dynamic Scope The dynamic scope is different from static scope. In the dynamic scope, address of
variable is determined at the time of program execution. The same variable name can be defined several
times in the same program. The variable is activated in the memory when a sub-block is under execution.
However, the variables have same name but their addresses are different. Hence, no ambiguous situation
occurs for compiler.
The declaration of variables is considered from the nearly occurring and currently active definition of
the variable during execution of the program.
Consider the following program:

Example 8.8 Write a program to demonstrate dynamic scope of variable.

# include <stdio.h>
# include <conio.h>

void main()
{
int j;
void A(void);
void B(void);

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 19 3/2/2012 6:56:34 PM


8.20 Data Structures Using C

clrscr();
A();
printf("\n Address of j in main() %u",&j);
B();
}
void A()
{
int j;
printf("\n Address of j in A() is %u",&j);
}

void B()
{
int j;
printf("\n Address of j in B() is %u",&j);
}

OUTPUT
Address of j in A() is 65518
Address of j in main() 65524
Address of j in B() is 65518

Explanation:
In this program, the variable int j is declared in functions main() A()and B(). Only declaration
does not allocates memory, when a program execution starts, only at that time memory is allocated
to the variable. If execution of main() is started, the memory is not allocated to the variables of
other functions. Memory is allocated to variables only when a function is invoked. From the output,
we can observe that though variable names are same, their memory locations are different.

8.11 SCOPE RULES THROUGH STACK

So far, we have studied the scope rules of variable. Now, we will learn its implementation through stack.
While following scope rules with stack, the system programmer needs to take care of memory allocation
of variables declared in different blocks. There are two types of storage allocation:
1. Static storage allocation
2. Dynamic storage allocation.

Static Storage Allocation The static storage allocation is simple to define. It is a compile time binding.
The space required for variables including all sub-programs are reserved. All sub-programs are compiled.
The total memory required can be calculated by adding the total amount of memory required by each
individual program. The amount of memory calculated cannot further increase or decrease during the
program execution. Thus, it is very safe for program execution. Thus, the program is only executed when
the system is able to provide required resources to the program. Otherwise, compile time error or warning
message will be displayed.

Dynamic Storage Allocation In dynamic storage allocation, memory is allocated during program
execution as per the requirement of the program. When a sub-function is invoked, memory is allocated and

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 20 3/2/2012 6:56:35 PM


Applications of Stacks 8.21

de-allocated when control returns. The space requirement is not constant. At different calls of a function,
the amount of memory required may be different. For example, if a function is invoked recursively, one
cannot determine how deep the recursion will proceed and it is not possible to calculate the accurate
amount of memory required by the function. The program related to dynamic storage allocation is
required to take necessary precautions to shun accidental failure of system due to insufficient memory.
Thus, it is as well necessary to check whether the memory allocation is successfully carried or not. If
memory allocation fails, the sub-routine should transfer the control to next statement. The explanation of
such routines is out of the scope of the book.
Now, we are going to discuss scope rules implementation with dynamic memory allocation. The handy
implementation tool is stack. Such implementation is known as run-time stack. When a sub-function is
invoked, memory is allocated and as soon as execution ends the memory is de-allocated. That specific
block of memory is called an activation record. Such record consists of following structure:
• Storage space for all variables including sub functions
• Definition of functions and pointers
• Return address
• A pointer to activation record.
Memory Space
Fig. 8.4 shows activation record. for Local Varaibles
Activation records are stored in the stack. The stack is controlled during
program execution. When a new function is invoked, control passes to Declaration of
it. Its activation record is pushed onto the stack. The return address is Functions and
Beginning Address
stored in return address field. When function execution completes, the
control returns to the caller function. It obtains the return address from
Return Address
the return address field of the activation record. Immediately after that
the activation record is popped. Figure 8.4 shows the activation records. Pointer to Location
Consider the following program code and Fig. 8.5.
Figure 8.4 Activation Record

void main ()
{
P()
}

main () function

P()
Function P ()
{
Q();
R(); Q
}
R

Figure 8.5 Functions

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 21 3/2/2012 6:56:35 PM


8.22 Data Structures Using C

The function main() invokes function P(). The function P() invokes function Q() and R().
When a new function is invoked, the activation record is pushed and when function execution completes
the record is popped. Thus, the stack is updated when new function is invoked and a function completes
its execution. Thus, by maintaining the stack the next function, which is to be executed, is decided.
Table 8.9 shows the stack operation.

Table 8.9 Stack Operation of a Program


Stack Status Operation

MAIN() Activation record of main() is pushed onto the stack


MAIN() P Function main() calls P()
MAIN() P Q Function invokes Q()
MAIN() P Q() execution completes and control returns to P
MAIN() P R P() invokes R()
MAIN() P R() execution completes and control returns to P
MAIN() P() completes execution and return to main().

Consider the following program code. There are five activation records. The total numbers of activa-
tion records are equal to number of functions defined. The filed pointer to the location is defined only in
dynamic scope. At the time of program execution, activation records of functions are pushed and popped
to and from the stack.

Example 8.9 Write a program to demonstrate the above theory with an example.

# include <stdio.h>
# include <conio.h>

void Q(void);
void R(void);

void main()
{
void P(void);
clrscr();
printf("\n main()");
P();
printf("\n Again in main() ");
}
void P()
{
printf("\n In P() ");
Q();
printf("Execution of Q complete");
R();
printf("Execution of R complete");
}
void Q() { printf("\n In Q() "); }
void R() { printf("\n In R() "); }

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 22 3/2/2012 6:56:35 PM


Applications of Stacks 8.23

OUTPUT
main()
In P()
In Q() Execution of Q complete
In R() Execution of R complete
Again in main()

Explanation:
In this program P(), Q() and R() are three functions defined. The main() function invokes
P(). The function P() invokes Q() and R() one by one. Messages are displayed when a
function is invoked which help the user to understand the flow of the program. From the following
Fig. 8.6 we can observe that the program execution sequence is main ()-P()-Q()-P()-
R()-main(). Here, function P() is not invoked twice. After complete execution of Q(),
control returns in function P().

main ()

P ()

R ()

Q ()

Figure 8.6 Flow of Program Execution

SUMMARY
1. Arithmetic expressions can be defined in three kinds of notation: infix, prefix and postfix.
The prefixes ‘pre’, ‘post’ and ‘in’ indicates the relative location of the operator with two
operands.
2. Each operator in the postfix expression is associated with the previous two operands.
When we read an operand from a given expression it is pushed onto the stack. When an
operator symbol is read, the operands associated with it are the top elements of the stack.
We can pop these two elements from the stack and perform the operation.
3. In any expression, two types of components can be clubbed together. They are operand
and operators. The operator indicates the operation to be carried out and the operand
indicates the values. The operands are the variables on which the operator operates. Oper-
ators have their priority of execution. When one or more operations are clubbed together
in a single expression the priority decides which operation is performed first.

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 23 3/2/2012 6:56:35 PM


8.24 Data Structures Using C

4. The group of field such as a) memory for local variables, b) declaration of function, c) return
addresses and d) pointer to location are pushed when a function is invoked and popped
when a function execution completed. This particular record of function is known as an
activation record.
5. The static scope declares the variable in circumstances of syntactic program structure.
6. The dynamic scope is different from static scope. In the dynamic scope, address of a variable
is determined at the time of program execution.
7. The static storage allocation is simple to define. It is a compile time binding.
8. In dynamic storage allocation, memory is allocated during program execution as per the
requirement of the program. When a sub-function is invoked, memory is allocated and
de-allocated when control returns.

EXERCISES
A. Answer the following question:

1.
Explain the terms infix expression, postfix expression, and polish notation.
2.
Distinguish between prefix and postfix expressions.
3.
What are the applications of stacks?
4.
Explain scope rules.
5.
Explain activation record.
6.
Distinguish between static and dynamic implementation of stack.
7.
Explain the stack technique last-in-first-out with two real life examples.
8.
Translate following infix expressions to its equivalent prefix expressions:
a. (x+y–z)/(h+k)–z
b. (j+k)*(c/d)
9. Explain solution for following expressions:
a. From infix to postfix j–k /(g^h)+(n+m)
b. From infix to prefix j–k /(g^h)+(n+m)
c. From infix to postfix x*(c+d)+(j/k)*n+m*p
d. From infix to postfix A^B^C
e. From infix to postfix A&&B|| ! (A>B)
10. Evaluate the expression 123+*78 3/–. Show the contents of stack after every step in tabular
form

B. Select the appropriate option for each of the following questions:

1. The stack is based on the rule


(a) first-in-last-out (c) both (a) and (b)
(b) last-in-first-out (d) first-in-first-out

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 24 3/2/2012 6:56:35 PM


Applications of Stacks 8.25

2. The prefix notation is also called as


(a) polish notation (c) infix notation
(b) postfix notation (d) none of the above.
3. From the given options one is not a stack application
(a) template (c) reverse string
(b) recursion (d) conversion of number.
4. An expression containing more than one operation are solved according to
(a) priority of operators (c) from left to right
(b) priority of operands (d) right to left.
5. The following brackets changes the priority
(a) () (c) {}
(b) [] (d) &
6. The postfix notation is also called as
(a) reverse polish notation (c) prefix notation
(b) polish notation (d) postfix notation.

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 25 3/2/2012 6:56:35 PM


This page is intentionally left blank.

M08_ASHOK NAMDEV KAMTHANE5067_01_SE_C08.indd 26 3/2/2012 6:56:35 PM


Chapter 9

Trees

CHAP TER O U T LIN E


9.1 Introduction 9.10 Traversal of a Binary Tree
9.2 Basic Terms 9.11 Conversion of Expression
into Postfix
9.3 General Tree
9.12 Binary Search Tree
9.4 Binary Trees
9.13 Threaded Binary Tree
9.5 Complete Binary Tree
9.14 B-Tree (Balanced Multi-way Tree)
9.6 Strictly Binary Tree
9.15 B-Tree of Order 5
9.7 Extended Binary Tree
9.16 B+ Tree
9.8 Binary Tree Representation
9.17 AVL Tree
9.9 Operations on Binary Trees

9.1 INTRODUCTION

In the previous chapters, we have studied various data structures such as arrays, stacks, queues and linked list.
All these are linear data structures. In these data structures the elements are arranged in a linear manner, i.e.
one after another. Tree is an equally useful data structure of non-linear type. In tree, elements are arranged in
non-linear fashion. A tree structure means data is organized in branches. Figure 9.1 is a sample tree.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 1 3/2/2012 6:57:50 PM


9.2 Data Structures Using C

Figure 9.1 Sample Tree

A tree is a non-linear data structure and its elements are arranged in sorted order.
Tree has several practical applications. It is immensely useful in manipulating data and to protect
hierarchical relationship among data. The fundamental operations such as insertion, deletion etc. is easy
and efficient in tree data structure than in linear data structures. Fig. 9.2 represents family hierarchy,
which keeps relations among them. The hierarchy gives relations between associates of family members.
In this tree, node ‘A’ can be assumed as a parent of ‘B’ and ‘C’, ‘D’ and ‘E’ are the children of ‘B’. ‘F’ is the
child of ‘C’. This tree represents the relation between the family members.

B C

D E F

Figure 9.2 A Family Hierarchy in Tree Structure

For example, suppose the left side member is male and right side member is female. Then, various rela-
tions such as sister, brother, grandfather, grandmother can also be implied.
The algebraic expression can be represented with a tree. Consider the following example of an algebraic
expression.
Z=(J-K)/((L*M)+N)

The operators of the above equation have different priority. The priority of the operators can be repre-
sented by the tree structure. The operators of high priority are at low level and operator and associated oper-
ands are represented in tree structure. Figure 9.3 illustrates the representation of an algebraic expression.

9.2 BASIC TERMS

Some of the basic concepts relevant to trees are described in this section. These are node, parents, roots,
child, link, leaf, level, height, degree of node, sibling, terminal nodes, path length, and forest.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 2 3/2/2012 6:57:51 PM


Trees 9.3

− +

J K * N

L M

Figure 9.3 An Algebraic Expression in Tree Form

Root It is the mother node of a tree structure. This is the most important node of any tree. This node
does not have parent. It is the first node in the hierarchical arrangement.

Node It is the main component of the tree. The node of a tree stores the data and its role is same as the
linked list. Nodes are connected by means of links with other nodes. This is shown in Fig. 9.4.

Data

Right Child Left Child

Figure 9.4 Right and Left Nodes of a Tree

Parent It is an immediate predecessor of a node. In Fig. 9.5, A is the parent of B and C.

B C

Figure 9.5 Parent Nodes with Child Nodes

Child When a predecessor of a node is parent then all successor nodes are called child nodes. In Fig. 9.5,
B and C are child nodes of A. The node at left side is called left child node and node at right side is called
right child node.

Link The link is nothing but pointer to node in a tree structure. In other words, link connects the two
nodes. The line drawn from one node to other node is called a link. Fig. 9.5 shows left and right child.
Here, two links are shown from node A. More than two links from a node may be drawn in a tree. In a
few textbooks the term edge is used instead of link. Functions of both of them are same.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 3 3/2/2012 6:57:51 PM


9.4 Data Structures Using C

Leaf This node is located at the end of the tree. It does not have any child hence it is called as leaf node.
Here, ‘H’, ‘I’, ‘F’, and ‘J’ are leaf nodes in Fig. 9.6.

Level Level is a rank of tree hierarchy. The whole tree structure is levelled. The level of root node is always
at 0. The immediate children of root are at level 1 and their immediate children are at level 2 and so on.
If children nodes are at level n+1 then parent node would be at level n. Fig. 9.6 shows the levels of tree.

Root A
Level 0
B C
Level 1

D E F G
Level 2

H I J
Level 3

Figure 9.6 Levels of Tree

Height The highest number of nodes that is possible in a way starting from the first node (root) to a leaf
node is called the height of tree. In Fig. 9.6, the height of tree is 4. This value can be obtained by referring
three different paths from the source node to leaf node. The paths A-B-D-H, A-B-E-I, and A-C-G-J have
the same height. The height can be obtained from the number of levels, which exists in the tree. The
formula for finding the height of the tree h = imax +1, where h is the height and imax is maximum level of
the tree. In the above Fig. 9.6 the maximum level of the tree is 3(imax=3). By substituting the value into the
formula the h will be 4. The term depth can be used in place of height.

Degree of a Node The maximum number of children that can exist for a node, is called as the degree of
the node. In Fig. 9.6 the node A, B and C have maximum two Children. So, the degree of A, B and C is
same and it is equal to 2.
Sibling The child nodes of same parent are called sibling. They are also called brother nodes. A, B and C
nodes in the Fig. 9.6 have two child nodes. B and C are the siblings of the node A, whereas D and E are
the siblings of the node B.

Terminal Node A node with degree zero is called terminal node or leaf. Fig. 9.6 shows 4 terminal nodes
and they are H, I, F and J.

Path Length It is the number of successive edges from source node to destination node. In Fig. 9.6, the
path length from the root node A to H is three because there are three edges.

Forest It is a group of disjoint trees. If we remove a root node from a tree then it becomes the forest.
If we remove root node A then the two disjoint sub-trees will be observed. They are left sub-tree B and
right sub-tree C.

Labelled Trees In the labelled tree the nodes are labelled with alphabetic or numerical values. The
labels are the values allotted to the nodes in the tree. Fig. 9.7 shows the diagram of a labelled tree. Finally
obtained tree is called as labelled tree.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 4 3/2/2012 6:57:52 PM


Trees 9.5

3 7

1 5 2 9

11 10 14

17

Figure 9.7 Labelled Tree

Fig. 9.7 shows the labelled tree having 11 nodes; root node is 4 and leaf nodes 11,10,17, and 2. The
parent and children relationship between them is shown in Table 9.1.
There is one more relationship, which is called left node left child and right node right child. This is
useful for traversing the binary tree.
Table 9.2 describes the relationship between the parents, left and right nodes, which is drawn from the
Fig. 9.7. The ‘—’ indicate that root node (parent) does not have child node. The 11,10 and 17 labelled
nodes are the leaf nodes of the tree.

Table 9.1 Parent and Children Relationship

Parent Nodes Children Nodes

4 3,7
3 1,5
1 11
5 10
7 2,9
9 14
14 17

Table 9.2 Relationship Between Parent, Left and Right Nodes


Parent Node Left Child Right Child

4 3 7
3 1 5
1 – 11
5 – 10
7 2 9
9 – 14
14 – 17

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 5 3/2/2012 6:57:52 PM


9.6 Data Structures Using C

A program is provided based on the above relationships. It finds the number of nodes in a tree and leaf
nodes.

Example 9.1 Write a program to find number of nodes and leaf nodes in the given tree.

# include <stdio.h>
# include <conio.h>
struct tree
{
long data;
struct tree *left;
struct tree *right;
};
int node=1,lev;
struct tree *bt=NULL;
struct tree *insert(struct tree*bt,long no);
void lev_count(struct tree*bt);
void node_count(struct tree*bt);

void main()
{
long no;
clrscr();
puts("Enter the nodes of tree in preorder: and 0 to quit");
scanf("%ld",&no);
while(no!=0)
{
bt= insert(bt,no);
scanf("%d",&no);
}
node_count(bt);
printf("The tree contains %d nodes\n",node);
lev_count(bt);
printf("\nThe tree contains %d leaf nodes\n", lev);
}
struct tree*insert(struct tree*bt,long no)
{
if(bt==NULL)
{
bt=(struct tree*) malloc(sizeof(struct tree));
bt->left=bt->right=NULL;
bt->data=no;
}
else
{
if(no<bt->data)
bt->left=insert(bt->left,no);
else
if(no<bt->data)
bt->right=insert(bt->right,no);
else

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 6 3/2/2012 6:57:52 PM


Trees 9.7

if(no==bt->data)
{
puts("Duplicates nodes: Program exited");
exit(0);
}
}
return(bt);
}
void node_count(struct tree*bt)
{
if(bt!=NULL)
{
if(bt->left!=NULL)
{
node++;
node_count(bt->left);
}
if(bt->right!=NULL)
{
node++;
node_count(bt->right);
}
}
}
void lev_count(struct tree*bt)
{
if(bt!=NULL)
{
if((bt->left==NULL)&&(bt->right==NULL))
lev++;
else
lev_count(bt->left);
lev_count(bt->right);
}
}

OUTPUT
Enter the nodes of tree in preorder: and 0 to quit
5 3 11 0
The tree contains 3 nodes
The tree contains 2 leaf nodes

Explanation:
This program contains three functions insert(), lev_count(), and node_count().
The insert() is used to insert the element into the binary tree. The lev_count()
function is used to count the total leaf nodes of the binary tree. The global variable lev
stores the total number of the leaf nodes. The function node_count() is initialized to
count number of the nodes which are present in the binary tree. The global variable node is
used to store the total number of nodes present in the tree.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 7 3/2/2012 6:57:52 PM


9.8 Data Structures Using C

9.3 GENERAL TREE

A general tree is similar to the family tree. The origin of the family tree is called the root node. The
various generations are represented in hierarchical structure with nodes. A tree is a finite set of one or
more nodes. A root node T may have n number of children named T1,T2 … Tn. The total number of
children may vary.

T1 T2 T3

T11 T12 T13 T31

Figure 9.8 General Tree

In Figure 9.8, T is the root node and T1, T2, T3 are the children of the root node T. T11, T12, and T13
are the children of the node T1. Similarly T31 is the child of the node T3. So it is clear from the figure that
the number of children may vary from node to node.

9.4 BINARY TREES

A binary tree is a finite set of data elements. A tree is binary if each node of it has a maximum of two
branches. The data element is either empty or holds a single element called root along with two disjoint
trees called left sub-tree and right sub-tree, i.e. in a binary tree the maximum degree of any node is
two. The binary tree may be empty. However, the tree cannot be empty. The node of tree can have any
number of children whereas the node of binary tree can have maximum two children. Fig. 9.9 shows
a sample binary tree.
In Fig. 9.9, A is the root and B and G are its child nodes. The nodes B and G are non-empty nodes,
hence they are called left successor and right successor of the root A. The node root without successor is
called the terminal node of that root. In Fig. 9.9 the node E, F, J, and K are the terminal nodes.
The right tree is G and left tree is B. Next B has left tree C and right tree D. The right tree further has
left tree H and right tree I. This will be continued up to last level.

9.5 COMPLETE BINARY TREE

A tree is called complete binary tree if each of its nodes has two children, except the last nodes. In other
words, every non-terminal node of it must have both children except the last leaf nodes. So, at any

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 8 3/2/2012 6:57:52 PM


Trees 9.9

A A
B G B C

C D H I
D E F G

E F J K H I J K L M N O

Figure 9.9 (a) A Sample Binary Tree Figure 9.9 (b) Complete Binary Tree

level the maximum number of nodes is equal to 2. At level 0, there must be only one node and that
is the root node. A at level 1 the maximum nodes must be 2. At level 3 the maximum nodes must be
equal to 8. Figures 9.9 (a) and 9.9 (b) show a complete binary tree.
The advantages of this complete binary tree is that one can very easily locate the position of the parent
and also left and right child nodes of a complete binary tree. Left child node and right child nodes are
located at 2N and 2N+1. V=2n+1−1, where V is the total number of nodes, and n is the depth of the tree.
Similarly, the parent node of any node would be at floor (N/2).
Parent of D would be floor (5/2) = 2, i.e. B is the parent and its left and right child are 2*2 = 4 and
2*2+1=5. 4 and 5 are the C and D child nodes in Fig. 9.9.

9.6 STRICTLY BINARY TREE

When every non-leaf node in binary tree is filled with left and right sub-trees, the tree is called strictly
binary tree. It is shown in Fig. 9.10.

I K

J
L

M N

Figure 9.10 Strictly Binary Trees

In the strictly binary tree shown in Fig. 9.10, L and I are non-terminal nodes with non-empty left and
right sub trees.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 9 3/2/2012 6:57:52 PM


9.10 Data Structures Using C

9.7 EXTENDED BINARY TREE

When every node of a tree has either 0 or 2 children then such a tree is
called an extended binary tree or a 2-tree. The nodes with two children
are called internal nodes. The nodes without children are known as exter-
nal nodes. At some places in order to identify internal nodes in Figures
9.11 to 9.14 circles are used. To identify external nodes squares are used.
The nodes in binary tree that have only one child can be extended with
one more child. This extended binary tree can be used for implement-
ing the algebraic equation because in the algebraic equation the left and
right child nodes are operands and the parent of the child represents the Figure 9.11 Binary Tree
operator.

Figure 9.12 Extended 2-Tree

1 2 3

4 5 6

Figure 9.13 Binary Trees

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 10 3/2/2012 6:57:52 PM


Trees 9.11

Figure 9.14 2-Trees

9.8 BINARY TREE REPRESENTATION

Binary tree can be represented by two ways:


1. Array representation
2. Linked representation

9.8.1 Array Representation of Binary Tree


In any type of data structure array representation plays an
X
important role. The nodes of trees can be stored in an array. 0
The nodes can be accessed in sequence one after another. In
array, element counting starts from zero to (n–1) where n is
Y Z
the maximum number of nodes. In other words, the number-
1 2
ing of binary tree nodes will start from 0 rather than 1.
Assume an integer array. Its declaration is as follows: Figure 9.15 Array Representation of Tree
int array tree[n];

The root node of the tree always starts at index zero. Then, successive memory locations are used for
storing left and right child nodes. Consider the following Fig. 9.15,
TREE[0] X
TREE[1] Y
TREE[2] Z

In Fig. 9.15, X is the root and Y and Z are the children. X is the father of child Y and Z. Consider
Fig. 9.16 with one more level.

X
1 2

Y Z

3 4 5 6

S T U V

Figure 9.16 Array Representation of a Tree

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 11 3/2/2012 6:57:53 PM


9.12 Data Structures Using C

The array representation with one more level would be as follows:

Node Number Node Name


1 Y
2 Z
3 S
4 T
5 U
6 V

It is very easy in this representation to identify the father, left and right child of an arbitrary node.
For any node n, 0 ≤ n ≤ (MAXSIZE –1), the following can be used to identify the father and child
nodes.

Father (n) The location of the father node can be identified in a given tree by using the ((n–1)/2)
where n is the index of child node, provided that n! =0 (not equal to zero). In case if n=0, the said
node is root node. It has no father node. Consider the node 3 in Fig. 9.16 i.e. S. The father of node S
is Y and the index of Y is 1. By substituting these values in the equation we identify the index of the
father node.
Floor ( (3-1)/2) ) i.e. (2/2)=1

Lchild(n) The left child of a node (n) is at position (2n+1).

1. Lchild(Xn) =lchild(0)
=2 * 0+1
=1
The node with index 1 is Y.
2. lchild (Z) = lchild(2)
= 2*2+1 = 5
The node with index 5 is U.

rchild (n) The right child of node (n) can be recognized by (2n+2)

1. rchild (X)=rchild (0)


=2*0+2
=2
The node with index 2 is Z.
2. rchild ( Y ): rchild(1)
= 2 *1+2=4
The node with index 4 is T.

Siblings In case the left child at index n is known then its right sibling is at (n+1). Likewise, if the
right child at index n is known then is left sibling is at (n–1). The array representation is perfect for

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 12 3/2/2012 6:57:53 PM


Trees 9.13

complete binary tree. However, this is not appropriate for other tree types and if we use array for their
representation, it results in inefficient use of memory. Consider the binary trees shown in Figs. 9.17 (a)
and 9.17 (b).
The above is skewed binary tree. Here, every left sub-tree again represents left sub-tree. Such type of binary
tree is called left skewed binary tree. Similarly, right skewed binary tree is also present [See Figs. 9.17 (a)
and 9.17 (b)]. Fig. 9.18 shows the array representation of left and right skewed trees.

X
X
0
Y Z
1
S V
3

Figure 9.17 (a) Left Skewed Binary Tree Figure 9.17 (b) Right Skewed Binary Tree

0 X
1 Y Left Skewed
2 Z Binary Tree
Right Skewed
3 S
Binary Tree
4 T
5 U
6 V

Figure 9.18 Left-Right Skewed Binary Tree

9.8.2 Linked Representation of Binary Tree


Another way of representation of binary tree is
linked list, which is known to be more memory
lchild Data Rchild
efficient than array representation. The funda-
mental component of binary tree is node. We
know that the node consists of three fields, which Node
is shown in Fig. 9.19.
• Data Figure 9.19 Linked List Representation of Binary Tree
• Left child
• Right child.
The data field stores the given values. The lchild field is link field and holds the address of its left
node. Similarly, the rchild holds the address of right node. The node can be logically represented as follows.
Figures 9.20 and 9.21 show the linked list representation of a binary tree.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 13 3/2/2012 6:57:53 PM


9.14 Data Structures Using C

struct node
{ M
int data;
struct node *rchild;
struct node *lchild;
N O
};

P Q R S

Figure 9.20 Binary Tree

N O

P Q R S

Figure 9.21 Linked List Representation of Binary Tree

Binary tree has one root node and few non-terminal and terminal nodes. The terminal nodes are called
leafs. The non-terminal nodes have their left wand right child nodes. However, the terminal nodes are
without child. While implementing this, fields of lchild and rchid are kept NULL. The non-terminal
nodes are known as internal nodes and terminal nodes are known as external nodes.

9.9 OPERATIONS ON BINARY TREES

The following fundamental operations are performed on binary trees:


Create This operation creates an empty binary tree.
Make This operation creates a new binary tree. The data field of this node holds some value.
Empty When binary tree is empty, this function will return true else it will return false.
Lchild A pointer is returned to left child of the node. When the node is without left child, a NULL
pointer is returned.
Rchild A pointer is returned to right child and if the node is without right child a NULL pointer is
returned.
Father A pointer to father of the node is returned or else the NULL pointer is returned.
Sibling (Brother) A pointer to brother of the node is returned or else NULL pointer is returned.
Data Value stored is returned.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 14 3/2/2012 6:57:53 PM


Trees 9.15

In addition to above mentioned operations, following operations can also be performed on binary tree:

1. Tree traversal
2. Insertion of nodes
3. Deletion of node
4. Searching for a given node
5. Copying the binary tree.

9.10 TRAVERSAL OF A BINARY TREE

Three parameters are needed for formation of binary tree. They are node, left and right sub-trees. Travers-
ing is one of the most important operations done on binary tree and frequently this operation is carried
on data structures. Traversal means passing through every node of the tree one by one. Every node is tra-
versed only once. Assume, root is indicated by O, left sub-tree as L and right sub-tree as R. The following
traversal combinations are possible:

1. ORL - ROOT - RIGHT-LEFT


2. OLR - ROOT - LEFT-RIGHT
3. LOR - LEFT - ROOT- RIGHT
4. LRO - LEFT - RIGHT- ROOT
5. ROL - RIGHT - ROOT - LEFT
6. RLO - RIGHT - LEFT-ROOT

Out of six methods only three are standard and are discussed in this chapter. In traversing always right
sub-tree is traversed after left sub-tree. Hence, the OLR is preorder, LOR is inorder and LRO is postorder.
Figure 9.22 shows a model tree (binary tree)

N O

P Q R S

Figure 9.22 A Model Tree

The inorder representation of the above tree is P-N-Q-M-R-O-S-V. Traversing is a common operation
on binary tree. The binary tree can be used to represent an arithmetic expression. Here, divide and conquer
technique is used to convert an expression into a binary tree. The procedure to implement it is as follows.
The expression for which the following tree has been drawn is (X*Y)+Z. Fig. 9.23 represents the expression.
Using the following three methods, the traversing operation can be performed. They are:

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 15 3/2/2012 6:57:54 PM


9.16 Data Structures Using C

1. Preorder traversal +
2. Inorder traversal
3. Postorder traversal.
All the above three types of traversing methods are * Z
explained below.

9.10.1 Inorder Traversal


X Y
The functioning of inorder traversal of a non-empty
binary tree is as follows: Figure 9.23 An Arithmetic Expression in Binary
Tree Form
1. Firstly, traverse the left sub-tree in inorder.
2. Next, visit the root node.
3. At last, traverse the right sub-tree in inorder.
In the inorder traversal firstly the left sub-tree is traversed recursively in inorder. Then the root node
is traversed. After visiting the root node, the right sub-tree is traversed recursively in inorder. Fig. 9.22
illustrates the binary tree with inorder traversal. The inorder traversal for the tree is P-N-Q-M-R-O-S-V.
It can be illustrated as per Fig. 9.24.
The left part constitutes P, N, and Q as the left sub-tree of root and R, O, S, and V are the right
sub-tree.
Figure 9.25 depicts another example of inorder traversal. The inorder traversal of Fig. 9.25 is C-B-D-
A-F-E-G.

P N Q M R O S V

Left Root Right

Figure 9.24 Inorder Traversal

B E

C D F G

Figure 9.25 Inorder Traversal

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 16 3/2/2012 6:57:54 PM


Trees 9.17

Example 9.2 Write a program for inserting the elements into the tree and traverse the tree by the
inorder.

# include <stdio.h>
# include <conio.h>
struct tree
{
long data;
struct tree *left;
struct tree *right;
};
struct tree *btree=NULL;
struct tree *insert(struct tree*btree,long digit);
void inorder(struct tree*btree);
void main()
{
long digit;
clrscr();
puts("Enter integers: and 0 to quit");
scanf("%ld",&digit);
while(digit!=0)
{
btree= insert(btree,digit);
scanf("%d",&digit);
}
puts("Inorder traversing of btree:\n");
inorder(btree);
}
struct tree*insert(struct tree*btree,long digit)
{
if(btree==NULL)
{
btree=(struct tree*) malloc(sizeof(struct tree));
btree->left=btree->right=NULL;
btree->data=digit;
}
else
{
if(digit<btree->data)
btree->left=insert(btree->left,digit);
else
{
if(digit>btree->data)
btree->right=insert(btree->right,digit);
else
if(digit==btree->data)
{
puts("Duplicates nodes: Program exited");
exit(0);
}
}
return(btree);
}

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 17 3/2/2012 6:57:54 PM


9.18 Data Structures Using C

void inorder(struct tree*btree)


{
if(btree!=NULL)
{
inorder(btree->left);
printf("%4ld",btree->data);
inorder(btree->right);
}
}

OUTPUT
Enter integers: and 0 to quit
6 1 2 3 7 8 9 0
Inorder traversing of btree:
1 2 3 6 7 8 9

Explanation:
This program is used to evaluate the inorder of the given tree. The given binary tree is stored
in *btree. The elements are inserted by using the insert(). The inorder traversing, i.e. left,
root and right is done by inorder(). Fig. 9.26 illustrates the binary tree.

The inorder of binary tree is 1, 2, 3, 6, 7, 8, and 9 as shown in Fig. 9.26.

1 7

2 8

3 9

Figure 9.26 Binary Tree for Inorder

9.10.2 Preorder Traversal


The node is visited before the sub-trees. The following is the procedure for preorder traversal of non-
empty binary tree.
1. Firstly, visit the root node (N).
2. Then, traverse the left sub-tree in preorder (L).
3. At last, traverse the right sub-tree in preorder R.
The preorder is recursive in operation. In this type, first root node is visited and later its left and right
sub-trees. Consider the Fig. 9.27 for preorder traversing.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 18 3/2/2012 6:57:54 PM


Trees 9.19

N O

P Q R S

Figure 9.27 Tree for Preorder Traversal

The preorder traversing for Fig. 9.27 is M, N, P, Q, O, R, S, and V. This can also be shown in Fig. 9.28.
In this traversing the root comes first and the left sub-tree and right sub-tree at last.

M N P Q O R S V

Root Left Right

Figure 9.28 Preorder Traversal

In the preorder the left sub-tree appears as N, P, and Q and right sub-tree appears as O, R, S, and V.

Example 9.3 Write a program for inserting the elements in the tree and display them in preorder.

# include <stdio.h>
# include <conio.h>
struct tree
{
long data;
struct tree *left;
struct tree *right;
};
struct tree *btree=NULL;
struct tree *insert(struct tree*btree,long digit);
void preorder(struct tree*btree);
void main()
{
long digit;
clrscr();
puts("Enter integers: and 0 to quit");
scanf("%ld",&digit);
while(digit!=0)
{
btree= insert(btree,digit);
scanf("%d",&digit);
}

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 19 3/2/2012 6:57:55 PM


9.20 Data Structures Using C

puts("Preorder traversing btree:\n");


preorder(btree);
}
struct tree*insert(struct tree*btree,long digit)
{
if(btree==NULL)
{
btree=(struct tree*) malloc(sizeof(struct tree));
btree->left=btree->right=NULL;
btree->data=digit;
}
else
{
if(digit<btree->data)
btree->left=insert(btree->left,digit);
else
if(digit>btree->data)
btree->right=insert(btree->right,digit);
else
if(digit==btree->data)
{
puts("Duplicates nodes: Program exited");
exit(0);
}
}
return(btree);
}
void preorder(struct tree*btree)
{
if(btree!=NULL)
{
printf("%4ld",btree->data);
preorder(btree->left);
preorder(btree->right);
} 5
}

OUTPUT 2 7
Enter integers: and 0 to quit
5 2 1 7 0
Preorder traversing btree: 1
5 2 1 7
Figure 9.29 Binary Tree
Explanation:
The program stores the binary tree in *btree structure variable of the structure tree. By
invoking the insert() the elements are inserted. The preorder traversing is done by using
preorder(). Fig. 9.29 shows the *btree, which is inserted in this program.

The preorder of the binary tree is 5, 2, 1, 7.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 20 3/2/2012 6:57:55 PM


Trees 9.21

9.10.3 Postorder Traversal


In the postorder traversal the traversing is done firstly left and right sub-trees before visiting the root. The
postorder traversal of non-empty binary tree is to be implemented as follows:
1. Firstly, traverse the left sub-tree in postorder style.
2. Then, traverse the right sub tree in postorder.
3. At last, visit the root node (N).
In this type, the left and right sub-trees are processed recursively. The left sub-tree is traversed first
in postorder. After this, the right sub-tree is traversed in post order. At last, the data of the root node is
shown.
The postorder traversing for Fig. 9.30 is P, Q, N, R, V, S, O, and M. This can also be shown as in
Fig. 9.31. In this traversing the left sub-tree is traversed first, then right sub-tree and at last root.
In the postorder the left sub-tree is P, Q and N and the right sub-tree is R, V, S and O.

N O

P Q R S

Figure 9.30 Tree for Post Order

P Q N R V S O M

Left Right Root

Figure 9.31 Postorder Traverse

Example 9.4 Program for inserting the nodes in tree and traversing these nodes by using the
postorder method.

# include <stdio.h>
# include <conio.h>
struct tree
{
long data;
struct tree *left;
struct tree *right;
};
struct tree *btree=NULL;
struct tree *insert(struct tree*btree,long digit);

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 21 3/2/2012 6:57:55 PM


9.22 Data Structures Using C

void postorder(struct tree*btree);


void main()
{
long digit;
clrscr();
puts("Enter integers: and 0 to quit");
scanf("%ld",&digit);
while(digit!=0)
{
btree= insert(btree,digit);
scanf("%d",&digit);
}
puts("Postorder traversing btree:\n");
postorder(btree);
}
struct tree*insert(struct tree*btree,long digit)
{
if(btree==NULL)
{
btree=(struct tree*) malloc(sizeof(struct tree));
btree->left=btree->right=NULL;
btree->data=digit;
}
else
{
if(digit<btree->data)
btree->left=insert(btree->left,digit);
else
if(digit>btree->data)
btree->right=insert(btree->right,digit);
else
if(digit==btree->data)
{
puts("Duplicates nodes: Program exited");
exit(0);
}
}
return(btree);
}
void postorder(struct tree*btree)
{
if(btree!=NULL)
{
postorder(btree->left);
postorder(btree->right);
printf("%4ld",btree->data);
}
}

OUTPUT
Enter integers: and 0 to quit
5 3 4 1 9 6 7 0
Postorder traversing btree:
1 4 3 7 6 9 5

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 22 3/2/2012 6:57:55 PM


Trees 9.23

Explanation:
In this program, *btree is used to store the binary tree. The *btree is the structure variable
of the structure tree. In this program the insert() is invoked to insert the elements in
the *btree. postorder() is used to traverse the binary tree in the post order manner.
Fig. 9.32 shows the btree which is inserted in the program.

The postorder traversing of the tree in Fig. 9.32 is 1, 4, 3, 7, 6, 9 and 5.

3 9

1 4 6

Figure 9.32 B-tree of Example 9.4

Example 9.5 Write a menu-driven program for various traversals such as (1) inorder (2) preorder
and (3) postorder.

# include <stdio.h>
# include <conio.h>
struct tree
{
long data;
struct tree *left;
struct tree *right;
};
struct tree *btree=NULL;
struct tree *insert(struct tree*btree,long digit);
void inorder(struct tree*btree);
void preorder(struct tree*btree);
void postorder(struct tree*btree);

void main()
{
long digit;
int ch;
clrscr();
puts("Enter integers: and 0 to quit");
scanf("%ld",&digit);
while(digit!=0)
{
btree= insert(btree,digit);
scanf("%d",&digit);

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 23 3/2/2012 6:57:55 PM


9.24 Data Structures Using C

}
while(1)
{
clrscr();
printf(" 1] For Inorder traversal of btree\n");
printf(" 2] For Preorder traversal of btree\n");
printf(" 3] For Postorder traversal of btree\n");
printf(" 4] For Exit\n");
printf("Enter the choice:-");
scanf("%d",&ch);
switch(ch)
{
case 1: printf("The inorder traversing of tree\n");
inorder(btree);
getch();break;
case 2: printf("The preorder traversing of tree\n");
preorder(btree);
getch();break;
case 3: printf("The postorder traversing of tree\n");
postorder(btree);
getch();break;
default: exit(0);
}
}
}
struct tree*insert(struct tree*btree,long digit)
{
if(btree==NULL)
{
btree=(struct tree*) malloc(sizeof(struct tree));
btree->left=btree->right=NULL;
btree->data=digit;
}
else
{
if(digit<btree->data)
btree->left=insert(btree->left,digit);
else
if(digit>btree->data)
btree->right=insert(btree->right,digit);
else
if(digit==btree->data)
{
puts("Duplicates nodes: Program exited");
exit(0);
}
}
return(btree);
}
void inorder(struct tree*btree)
{
if(btree!=NULL)

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 24 3/2/2012 6:57:55 PM


Trees 9.25

{
inorder(btree->left);
printf("%4ld",btree->data);
inorder(btree->right);
}
}
void preorder(struct tree*btree)
{
if(btree!=NULL)
{
printf("%4ld",btree->data);
preorder(btree->left);
preorder(btree->right);
}
}
void postorder(struct tree*btree)
{
if(btree!=NULL)
{
postorder(btree->left);
postorder(btree->right);
printf("%4ld",btree->data);
}
}

OUTPUT
Enter integers: and 0 to quit
5 3 1 4 11 8 12 0
1] For Inorder traversal of btree
2] For Preorder traversal of btree
3] For Postorder traversal of btree
4] For Exit
Enter the choice:-1
The inorder traversing of tree
1 3 4 5 8 11 12
1] For Inorder traversal of btree
2] For Preorder traversal of btree
3] For Postorder traversal of btree
4] For Exit
Enter the choice:-3
The postorder traversing of tree
1 4 3 8 12 11 5

Explanation:
This program uses the switch() and case for the menu-driven purpose, the structure tree
is used to store the whole tree and the left and right pointer of the tree is used to maintain
the left and right sub-tree. The function inorder() is used for displaying the tree in inorder
and similarly, the postorder() and preorder() used for the traversing purpose. The tree,
which is used in this program, is shown in Fig. 9.33.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 25 3/2/2012 6:57:55 PM


9.26 Data Structures Using C

3 11

1 4 8 12

Figure 9.33 Tree Representation

Example 9.6 Find the inorder, preorder and postorder traversals for the tree shown in Fig 9.34.

B E

C D F G

Figure 9.34 Tree for Example 9.6


Inorder: CBDAFEG

Preorder: ABCDEFG
Postorder: CDBFGEA

Example 9.7 Find the inorder, preorder, and postorder traversals for the tree shown in Fig 9.35.

Q T

R S U

Figure 9.35 Tree for Example 9.7

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 26 3/2/2012 6:57:55 PM


Trees 9.27

Inorder: RQSPTVU
Postorder: RSQVUTP
Preorder: PQRSTUV

9.10.4 Creation of a Binary Tree from its Traversals


We can construct a binary tree from its traversals. A unique binary tree can be created from two traversals.
The process is as follows:
• If the preorder traversal is given, then the first node is the root node.
• If the postorder traversal is given, then the last node is the root node.
• After identifying the root node, one can easily find the nodes of the left and right sub-tree.
Some examples are given below.

Example 9.8 Construct a binary tree from the given inorder and postorder traversal.

Inorder: CBDAFEG
Postorder: CDBFGEA

1. It is clear that A is the root of the tree since the root is traversed last in the postorder traversal.
2. The inorder traversal indicates all the nodes that are on the left side of A belonging to the left sub-
tree and those on the right side of A belonging to the right sub-tree.

Step 1:
Figure 9.36 indicates that CBD is the left sub-tree of the root node A and FEG is the right sub-
tree of the root node A. From the left sub-tree CBD, one can obtain the root from the postorder
traversal, i.e. B is the root node. Thus, from the inorder traversal we can say that C is the left child
of B and D is the right child of B. Similarly, for the right sub-tree of A, i.e. FEG, one can obtain
E as the root node from the given postorder traversal. From the inorder traversal, one can obtain
F as the left node of node E and G as the right node of node E. Thus, the final binary tree is as
follows (Fig. 9.37).

A
B E

CBD FEG C D F G

Figure 9.36 Step 1 Figure 9.37 Final Binary Tree

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 27 3/2/2012 6:57:55 PM


9.28 Data Structures Using C

Example 9.9 Construct a binary tree from the given inorder and postorder traversal.

Inorder: 24316587
Postorder: 43268751
The steps are as follows (Figs. 9.38–9.41):

Step 1:
1

243 6587

Figure 9.38 Step 1

Step 2: Step 3:

1 1

2 5 2 5

43 6 87 43 6 87

Figure 9.39 Step 2 Figure 9.40 Step 3

Step 4:

The final binary tree is as follows:

2 5

3 6 7

4 8

Figure 9.41 Final Binary Tree

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 28 3/2/2012 6:57:56 PM


Trees 9.29

Example 9.10 Construct a binary tree from the given inorder and preorder traversals.

Inorder: RTSUQPWYXZV
Preorder: PQRSTUVWXYZ
1. We obtain the root nodes as we traverse from left to right. P is the root of the tree from the given
preorder traversal.
2. One can obtain all the nodes that are on the left side of P belonging to the left sub-tree and those
on the right side of P belonging to the right sub-tree from the inorder traversal.
The steps are depicted in Figures 9.42–9.46.
Step 1:

RTSUQ WYXZV

Figure 9.42 Step 1

Step 2:

Q V

RTSU WXYZ

Figure 9.43 Step 2

Step 3:

Q V

R W

TSU
YXZ

Figure 9.44 Step 3

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 29 3/2/2012 6:57:56 PM


9.30 Data Structures Using C

Step 4: Step 5: Final binary tree

P P

Q V
Q V

R W
R W

X
X
S
S

Y Z Y Z
T U T U

Figure 9.45 Step 4 Figure 9.46 Step 5

9.11 CONVERSION OF EXPRESSION INTO POSTFIX

The arithmetic expression can be converted from infix to postfix. Consider the following example:
(A+B)*(D/E)

In the conversion of the expression into binary tree the operator divides the expression into two parts,
and on that basis the binary tree is formed. Always the operators are at the root nodes and the operands
are at the leaf nodes.
In above expression at first the ‘*’ operator divides the expression into the two parts, i.e. (A+B) and
(D/E). The ‘*’ is at the root of the tree.

(A+B) (D/E)

Figure 9.47 Expression in Binary Tree


Further, the (A+B) and (D/E) can be converted into the binary tree as shown in Fig. 9.48.

+ I

A B D E

Figure 9.48 Binary tree for (A+B) and (D/E)

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 30 3/2/2012 6:57:56 PM


Trees 9.31

Example 9.11 Write a program to convert infix to postfix expression.

# include <stdio.h>
# include <conio.h>
# include <string.h>
char stack[50];
int top=-1;
void post(char inexp[]);
void push(char);
char pop();
int preced(char c);

void main()
{
char inexp[25];
clrscr();
printf("\nEnter the inexp expression:- ");
scanf("%s",inexp);
post(inexp);
getch();
}
void push(char sy)
{
if(top>=49)
{
printf("\nstack overflow");
getch();
}
else
{
top=top+1;
stack[top]=sy;
}
}
char pop()
{
char item;
if(top==-1)
{
printf("\nStack is empty");
getch();
return 0;
}
else
{
item=stack[top];
top––;
}
return(item);
}
int preced(char ch)
{
if(ch==47)

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 31 3/2/2012 6:57:56 PM


9.32 Data Structures Using C

return(5);
if(ch==42)
return(4);
if(ch==43)
return(3);
return(2);
}
void post(char inexp[])
{
int len;
static int index=0,pt=0;
char oper,temp;
char postf[40];
len=strlen(inexp);
push('#');
while(index<len)
{
oper=inexp[index];
switch(oper)
{
case '(': push(oper);
break;
case ')': temp=pop();
while(temp!='(')
{
postf[pt]=temp;
pt++;
temp=pop();
}
break;
case '+':
case '-':
case '*':
case '/':
case '^':
while(preced(stack[top])>=preced(oper))
{
temp=pop();
postf[pt]=temp;
pt++;
}
push(oper);
break;
default: postf[pt++]=oper;
break;
}
index++;
}
while(top>0)
{
temp=pop();
postf[pt++]=temp;

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 32 3/2/2012 6:57:56 PM


Trees 9.33

}
postf[pt++]='\0';
printf("\nThe expression into postfix:-");
printf("%s",postf);
}

OUTPUT
Enter the inexp expression:- (A+B)*(C/D)
The expression into postfix:-AB+CD/*

9.12 BINARY SEARCH TREE

A binary search tree is also called as binary sorted tree. Binary search tree is either empty or each node N
of tree satisfies the following property:

1. The key value in the left child is not more than the value of root.
2. The key value in the right child is more than or identical to the value of root.
3. All the sub-trees, i.e. left and right sub-trees follow the two rules mentioned above.

Binary search tree is shown in Fig. 9.49.


In Fig. 9.49 number 7 is the root node of the binary tree. There are two sub-trees to root 7. The left
sub-tree is 4 and right sub-tree is 8. Here, the value of left sub-tree is lower than root and value of right
sub-tree is higher than root node. This property can be observed at all levels in the tree.

4 8

3 5 1 9

4 6

Figure 9.49 Binary Search Tree

9.12.1 Searching an Element in Binary Search Tree


The item which is to be searched is compared with the root node. If it is less than the root node then the
left child of left sub tree is compared otherwise right child is compared. The process would be continued
till the item is found. A program based on the above point is given below.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 33 3/2/2012 6:57:57 PM


9.34 Data Structures Using C

Example 9.12 Write a program to search an element from the binary tree.

# include <stdio.h>
# include <conio.h>
struct tree
{
long data;
struct tree *left;
struct tree *right;
};
int sn;
struct tree *bt=NULL;
struct tree *insert(struct tree*bt,long no);
void search(struct tree *bt, long sn);

void main()
{
long no;
clrscr();
puts("Enter the nodes of tree in preorder: and 0 to quit");
scanf("%ld",&no);
while(no!=0)
{
bt= insert(bt,no);
scanf("%d",&no);
}
printf("\nEnter the number to search:-");
scanf("%d",&sn);
search(bt,sn);
}

struct tree*insert(struct tree*bt,long no)


{
if(bt==NULL)
{
bt=(struct tree*) malloc(sizeof(struct tree));
bt->left=bt->right=NULL;
bt->data=no;
}
else
{
if(no<bt->data)
bt->left=insert(bt->left,no);
else
if(no>bt->data)
bt->right=insert(bt->right,no);
else
if(no==bt->data)
{
puts("Duplicates nodes: Program exited");
exit(0);
}
}
return(bt);

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 34 3/2/2012 6:57:57 PM


Trees 9.35

}
void search(struct tree*bt, long fn)
{
if(bt==NULL)
puts("The number does not exit");
else
if(fn==bt->data)
printf("The number %d is present in tree",fn);
else
if(fn<bt->data)
search(bt->left,fn);
else
search(bt->right, fn);
}

OUTPUT
Enter the nodes of tree in preorder: and 0 to quit
3 5 11 17 34 0
Enter the number to search:-17
The number 17 is present in tree
Enter the nodes of tree in preorder: and 0 to quit
3 5 11 17 34 0
Enter the number to search:-4
The number does not exit

Explanation:
This program contains struct tree which is used to store the binary tree. The insert()
function inserts the nodes into the binary tree. The search() function searches the number
from the tree.The fn variable is used to store the number which the user will not find.The search
function first compares the fn with the root node. If the value of fn is less than the root node then
the function searches the number in the left sub-tree, else it finds the number in the right sub-tree.

9.12.2 Insertion of an Element in Binary Search Tree


Insertion of an element in binary search tree needs to locate the parent node. The element to be inserted
in the tree may be on the left sub-tree or right sub-tree. If the inserted number is lesser than the root node
then left sub-tree is recursively called, otherwise right sub-tree is chosen for insertion. A program based on
the above notion is described below.

Example 9.13 Write a program to insert an element into the binary search tree.

# include <stdio.h>
# include <conio.h>
struct tree
{
long data;
struct tree *left;

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 35 3/2/2012 6:57:57 PM


9.36 Data Structures Using C

struct tree *right;


};
int in;
struct tree *bt=NULL;
struct tree *insert(struct tree*bt,long no);
void inorder(struct tree *bt);

main()
{
long no;
clrscr();
puts("Enter the nodes of tree in preorder: and 0 to quit");
scanf("%ld",&no);
while(no!=0)
{
bt= insert(bt,no);
scanf("%d",&no);
}
printf("Enter the number to insert:- ");
scanf("%d",&in);
bt=insert(bt,in);
printf("The inorder of tree after insertion of an element\n");
inorder(bt);
}
struct tree*insert(struct tree*bt,long no)
{
if(bt==NULL)
{
bt=(struct tree*) malloc(sizeof(struct tree));
bt->left=bt->right=NULL;
bt->data=no;
}
else
{
if(no<bt->data)
bt->left=insert(bt->left,no);
else
if(no>bt->data)
bt->right=insert(bt->right,no);
else
if(no==bt->data)
{
puts("Duplicates nodes: Program exited");
exit(0);
}
}
return(bt);
}
void inorder(struct tree *bt)
{
if(bt!=NULL)
{
inorder(bt->left);

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 36 3/2/2012 6:57:57 PM


Trees 9.37

printf("%d ",bt->data);
inorder(bt->right);
}
}

OUTPUT
Enter the nodes of tree in preorder: and 0 to quit
7 5 9 0
Enter the number to insert:- 2
The inorder of tree after insertion of an element
2 5 7 9

Explanation:
This program invokes a function insert() which inserts the node into the structure pointer
object *bt. Firstly, the nodes which are to be inserted are entered and then program calls
insert() for insertion of new element. The new inserted element firstly checks with the
root of the tree. If the number is lesser than the root node it is recursively checked with the
nodes, which are present on the left sub-tree, otherwise right sub-tree. Appropriate position
of parent node is found and the element is inserted. After insertion, elements are arranged in
inorder using the inorder() and the same numbers are displayed on the screen.

9.12.3 Traversing the Binary Search Tree


The binary search tree can be traversed similar to the binary tree by the inorder, preorder and postorder
traversing methods.

Example 9.14 Program to traverse the binary search tree by using the inorder, preorder and
postorder methods.

# include <stdio.h>
# include <conio.h>

struct rec
{
int data;
struct rec *left;
struct rec *right;
};
struct rec *t1;
struct rec *insert(struct rec * t1, int data);
void inorder(struct rec *t1);
void preorder(struct rec *t1);
void postorder(struct rec *t1)

void main()
{
int digit;
clrscr();

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 37 3/2/2012 6:57:57 PM


9.38 Data Structures Using C

printf("\nEnter the t1 in pre order and 0 to quit\n");


scanf("%d",&digit);
while(digit!=0)
{
t1=insert(t1,digit);
scanf("%d",&digit);
}

printf("\nThe preorder of the t1 is\n");


preorder(t1);

printf("\nThe inorder of the t1 is\n");


inorder(t1);
printf("\nThe post order of the t1 is\n");
postorder(t1);
}
struct rec *insert(struct rec * t1, int digit)
{
if(t1==NULL)
{
t1=(struct rec *) malloc (sizeof(struct rec));
t1->left= t1->right=NULL;
t1->data=digit;
}
else
if(digit< t1->data)
t1->left=insert(t1->left,digit);
else
if(digit > t1->data)
t1->right=insert(t1->right, digit);
else
if(digit==t1->data)
{
printf("Duplicate node: program exited");
exit(0);
}
return(t1);
}
void inorder(struct rec *t1)
{
if(t1!=NULL)
{
inorder(t1->left);
printf("%d ",t1->data);
inorder(t1->right);
}
}
void preorder(struct rec *t1)
{
if(t1!=NULL)
{
printf("%d ",t1->data);
preorder(t1->left);
preorder(t1->right);
}

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 38 3/2/2012 6:57:57 PM


Trees 9.39

}
void postorder(struct rec *t1)
{
if(t1!=NULL)
{
postorder(t1->left);
postorder(t1->right);
printf("%d ",t1->data);
}
}

OUTPUT
Enter the t1 in pre order and 0 to quit
3 2 4 0
The preorder of the t1 is
3 2 4
The inorder of the t1 is
2 3 4
The post order of the t1 is
2 4 3

Explanation:
The program first gets the binary search tree into the structure object t1. And the insert()
is used to insert the element into the tree. The three functions inorder(), preorder()
and postorder() are used to traverse the tree in appropriate manner.

9.13 THREADED BINARY TREE

While studying the linked representation of a binary tree, it is observed that the number of nodes that
have null values are more than the non-null pointers. The number of left and right leaf nodes has number
of null pointer fields in such a representation. These null pointer fields are used to keep some other infor-
mation for operations of binary tree. The null pointer fields are to be used for storing the address fields of
higher nodes in tree, which is called thread. Threaded binary tree is the one in which we find these types
of pointers from null pointer fields to higher nodes in a binary tree. Consider the following tree:
In Fig. 9.50, in the binary tree there are 7 null pointers. These are shown with the dotted lines. There
are total 12 node pointers out of which 5 are actual node pointers, i.e. non-null pointer (solid lines). For
any binary tree having n nodes there will be (n+1) null pointers and 2n total pointers. All the null pointers
can be replaced with appropriate pointer value known as thread. The binary tree can be threaded accord-
ing to appropriate traversal method. The null pointer can be replaced as follows:
Threaded binary tree can be traversed by any one of the three traversals, i.e. preorder, postorder and
inorder. Further, in inorder threading there may be one-way inorder threading or two–way inorder thread-
ing. In one way inorder threading the right child of the node would point to the next node in the sequence
of the inorder traversal. Such a threading tree is called right in threaded binary tree. Also, the left child of
the node would point to the previous node in the sequence of inorder traversal. This type of tree is called
as left in threaded binary tree. In case both the children of the nodes point to other nodes then such a tree
is called as fully threaded binary tree.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 39 3/2/2012 6:57:57 PM


9.40 Data Structures Using C

J Non-Null
Pointer
K
L

M N O

Null
Pointer

Figure 9.50 A Binary Tree with Null Pointers

Figure 9.50 describes the working of right in threaded binary tree in which one can see that the right
child of the node points to the node in the sequence of the inorder traversal method.
J

K L

M N O

Figure 9.51 Right in Threaded Binary Tree

The inorder traversal shown in the Fig. 9.51 will be as M-K-N-J-O-L. Two dangling pointers are shown
to point a header node as shown below:
• rchild of M is made to point to K
• rchild of N is made to point to J
• rchild of O is made to point to L.
Similarly, the working of the left in binary threaded tree is illustrated in Fig. 9.52. In this case the left
child of node points to the previous node in the sequence of inorder traversal.
As shown in Fig. 9.52, thread of N points to K. Here, K is the predecessor of N in inorder traversal.
Hence, the pointer points to K. In this type of tree the pointers pointing to other nodes are as follows:
• lchild of N is made to point to K
• lchild of O is made to point to J.

K L

M N Q

Figure 9.52 Left in Threaded Binary Tree

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 40 3/2/2012 6:57:57 PM


Trees 9.41

Figure 9.53 illustrates the operation of fully threaded binary tree. Right and left children are used for
pointing to the nodes in inorder traversal method.
• rchild of M is made to point to K
• lchild of N is made to point to K
• rchild of N is made to point to J
• lchild of O is made to point to J
• rchild of O is made to point to L.

K L

M N O

Figure 9.53 Fully Threaded Binary Tree

Fully threaded binary tree with header is described in Fig. 9.54.


rchild of M is made to point to K
lchild of M is made to point to Header
lchild of N is made to point to K
rchild of N is made to point to J
lchild of O is made to point to J
rchild of O is made to point to L
rchild of L is made to point to Header.

Header node

K L

M N O

Figure 9.54 Fully Threaded Tree with Header

The working of the fully threaded binary tree is illustrated in Fig. 9.54. In this case the left child
of node points to the previous node in the sequence of inorder traversal and right child of the node
points to the successor node in the inorder traversal of the node. In the previous two methods left

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 41 3/2/2012 6:57:57 PM


9.42 Data Structures Using C

and right pointers of the first and last node in the inorder list are NULL. But in this method the left
pointer of the first node points to the header node and the right pointer of the last node points to the
header node. The header node’s right pointer points to itself, and the left pointer points to the root
node of the tree. The use of the header is to store the starting address of the tree. In the fully threaded
binary thread each and every pointer points to the other nodes. In this tree we do not find any NULL
pointers.
In the Fig. 9.54 the first node in the inorder is M and its left pointer points to the left pointer of the
header node. Similarly, the last node in the inorder is L and its right pointer points to the left pointer of
the header.
In memory representation of threaded binary tree, it is very important to consider the difference
between thread and normal pointer. The threaded binary tree node is represented in Fig. 9.55.

Lthread Data Rthread

Figure 9.55 Representation of the Node

Each node of any binary tree stores the three fields. The left field stores the left thread value and the
right field stores the right thread value. The middle field contains the actual value of the node, i.e. data.

9.14 B-TREE (BALANCED MULTI-WAY TREE)

Binary search tree is, in general called multi-way search tree. The integer m is called the order of the
tree. Each node should have maximum m children. If k< m, where m is number of children, then node
has accurately k-1 keys which divides all the keys into k number of sets. In case some sets are empty, the
children are also empty.
The B-tree is also known as the balanced sort tree. The B-tree is used in external sorting. The B-tree is
not a binary tree. While implementing B-tree following conditions are followed:
1. The height of the tree must be minimum.
2. There should be no empty sub-trees after the leaves of the tree.
3. The leaves of the tree should be at the same level.
4. All nodes excepting the leaves should have at least few children.

9.14.1 B-Tree Insertion


In B-tree insertion at first search is made where the new element is to be placed. If the node is suitable
to the given element then insertion is straightforward. The element is inserted by using an appropriate
pointer in such an order that number of pointers will be one more than the number of records. In case, the
node overflows due to upper bound of node, splitting is mandatory. The node is divided into three parts.
The middle part is passed upward. It will be inserted into the parent. Partition may spread the tree. This
is because the parent into which element is to be inserted spilts into its child nodes. If the root is needed
to be split, a new root is created with two children. The tree grows by one level.
Example: Consider the following B-tree of degree 4. It can be balanced in four ways. Here, each node
holds elements. It also has four branches. Suppose, it has the following values:

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 42 3/2/2012 6:57:57 PM


Trees 9.43

1 5 6 2 8 11 13 18 20 7 9

1 5 6

The value 1 is put in a new node. This node can also hold next two values.

1 2 6 8 11

When value 2 (4th value ) is put, the node is split at 5 into leaf nodes. Here, 5 is parent. The element 8
is added in leaf node. The search for its accurate position is done in the node having value 6. The element
8 also is present in the same node.

1 2 6

The element 13 is to be inserted. However, the right leaf node, in which 1 to 3 values have appropriate
plane, is occupied. Hence, the node splits at median 8 and this moves it up to the parent.

1 2 11 13
6

By following the above procedure the remaining nodes can be included. The final figure would be as
follows:

5 8 13

1 2 6 7 9 11 18 20

9.14.2 B-Tree Deletion


In B-Tree deletion the element which is to be deleted is searched. In case the element is terminal node, the
deletion process is straightforward. The element with a suitable pointer is deleted.
If the element fixed for deletion is not a terminal node, it is replaced by its successor element. Actually, a
copy of successor is taken. The successor is an element with higher value. The successor of any node which
is not at lowest level, be a terminal node. Thus, deletion is nothing but removing of a particular element

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 43 3/2/2012 6:57:57 PM


9.44 Data Structures Using C

or record from a terminal node. While deleting the record the new node size is more than minimum, i.e.
the deletion is complete. If the node size is less than minimum, an underflow happens.
Rearrangement is done if either of adjacent siblings has more than the minimum elements (records).
For rearrangement, the contents of the node (only those nodes having less than minimum records) along
with sorting out records from parent node are gathered. The central record is written back to the parent
and left and right halves are written back to two siblings.
Concatenation is applied if the node with less than minimum number of records has no adjacent sib-
ling. The node is combined with its neighbouring sibling and element is moved from its parent.

B C D E

F G H I J K L M N O P Q R S T

1. Deleting K is straightforward because it is a leaf node.


2. Deleting E is not simple. Hence, its successor is moved up. E is moved down and deleted.

B C D Q

F G H I J I M N O P R S T

3. To delete P, the node has less than minimum numbers of keys. The sibling is carried. R moves up and
Q moves down.
4. Deleting H, again node has less than minimum keys than required. The parent is left with only one
key. Here, sibling cannot be applied. Hence, A, C, D and R form a new node.

ACDR

FGB JL MN OQ ST

9.15 B-TREE OF ORDER 5

We can build a B-tree of order 5.


A

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 44 3/2/2012 6:57:58 PM


Trees 9.45

1. CDF are inserted in the same node.

C A D F

2. Insert B. The node is full. It is splitted. Here, A is median in BCADF. A is parent. The splitting is at
root node. We should make one node.

BC DF

3. Again, insert P, Q, R, S.

RBCS DPQF

4. E can be added in DPQF and here Q is median.

A Q

RBCS D P F E

5. X and Y are entered after Q.

A Q

RBCS D P FEXY

6. After addition of T.

TAQ

RB CS DP F E XY

7. J, K are inserted.

TAQ

RB CS DPJK FEXY

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 45 3/2/2012 6:57:58 PM


9.46 Data Structures Using C

8. L can be added FEXY and X will be median.

TAQX

RB CS DPJK FE LY

9. Z can be placed in DPJK and it will be promoted to TAQX. But this is also full and hence, the root
will split and new root will be created.

T A Q X

R B C S D P J K F E L Y

9.16 B+ TREE

A B+ tree can be obtained with slight modification of indexing in B tree. A B+ tree stores key values repeat-
edly. Fig. 9.56 shows B+ tree indexing.

10

22 13

7 8 9 22 6 10 15 13 12

F F F F F F F F F F F F F

Figure 9.56 B+ Tree

By observing Fig. 9.56, we will come to know that the key values 10, 22 and 13 are stored repeatedly in
the last level (terminal nodes). In these leaf nodes a link is maintained so that the traversing can be done
from the leaf node at the extreme left to the leaf node at the extreme right. B tree and B+ tree are same
except the above differences.
Every leaf node of B+ tree has two parts:
1. Index part It is the interior node stored repeatedly.
2. Sequence set It is a set of leaf nodes.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 46 3/2/2012 6:57:58 PM


Trees 9.47

The interior nodes or keys can be accessed directly or sequentially. B+ tree is useful data structure in
indexed sequential file organization.

9.17 AVL TREE

The AVL tree is a binary search tree. It is also known as height balanced tree. It is used to minimize the
search time by keeping every node of the tree completely balanced in terms of height. The balance factor
plays an important role in the insertion and deletion of elements in an AVL tree. The balance factor
decides whether all the nodes of a tree are completely balanced. The AVL tree was defined as a height bal-
anced tree by two scientists Georgii Adelson-Velskii and E. M. Landis.

9.17.1 Balance Factor (BF)


The height of the left sub-tree minus the height of the right sub-tree gives the balance factor (BF).
Let,
hL = Height of left sub-tree G −1
hr = Height of right sub-tree Height of
BF= hL– hr G from A A I Height of
From Fig. 9.57 , the BF of root node G: G from J
Height of the left sub-tree of G (hL) = 1
Height of the right sub-tree of G (hr) = 2
Therefore, Bf of (G) = (hL) – (hr) H J
= 1– 2
= –1 Figure 9.57
Similarly, we can obtain the balance factor of all the nodes of a given tree.
The AVL tree is said to be a height balanced tree if its nodes have the balance factor 1, 0, or –1.

9.17.2 Characteristics of AVL Tree


The main characteristics of an AVL tree are as follows:
1. If the BF of a node is 0, it means that the height of the left sub-tree and height of the right sub-tree is
equal.
2. If the BF of a node is 1, it means that the height of the left sub-tree is greater than the height of the
right sub-tree.
3. If the BF of a node is –1, it means that the height of the left sub-tree is lesser than the height of the
right sub-tree.
A tree is said to be a complete AVL tree if all the nodes of the tree satisfy all the three conditions
discussed above. Some AVL and non-AVL trees with their balance factors are shown in Figure 9.58.

1 1 0

0 0 0

(a) AVL Trees

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 47 3/2/2012 6:57:59 PM


9.48 Data Structures Using C

2 −2

−1

1
0

0
(b) Non-AVL Trees

Figure 9.58 AVL Tree and Non-AVL Tree

A non-AVL tree can be converted to an AVL tree by performing different types of rotation on a given
tree. Single or double rotation may be performed.
Single rotation can be left rotation (anti-clock-wise rotation) or right rotation (clock-wise rota-
tion). Left and right rotations for AVL and non-AVL trees are shown in Fig. 9.59 and Fig. 9.60,
respectively.

–2
A

Rotate Left
Rotate Left 0 B

−1 B

0 A 0 C
0 C

(a) Non-AVL Tree (b) AVL Tree

Figure 9.59 Left Rotation (Anti-Clock-Wise Rotation)

0
C
0 B

1 Rotate Right
B

0 A 0 C

0
A

(a) Non-AVL Tree (b) AVL Tree

Figure 9.60 Right Rotation (Clock-Wise Rotation)

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 48 3/2/2012 6:57:59 PM


Trees 9.49

Double rotation consists of the following:


O Rotate right and rotate left (Fig. 9.61)
O Rotate left and rotate right (Fig. 9.62)

Rotate Right and Rotate left


0
B
−2 A
−2 A
Rotate Right Rotate Left
1 −1 B
B 0 A 0 C

0 C 0 C

Non-AVL Tree Non-AVL Tree AVL Tree

Figure 9.61 Rotate Right and Rotate Left

2 C 20 C
B

Rotate Left Rotate Right


1 B
−1 A
0 A 0 c

0 B 0 A

Non-AVL Tree Non-AVL Tree AVL Tree

Figure 9.62 Rotate Left and Rotate Right

Example 9.15 Draw an AVL tree and show the balance factor.

5, 15, 9, 2, 8, 17, 23, 18, 11, 20


Step 1: Insert 5 (Fig. 9.63)
0
5

Figure 9.63 Step 1

Step 2: Insert 15

5 –1

15 0

Figure 9.64 Step 2

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 49 3/2/2012 6:57:59 PM


9.50 Data Structures Using C

Step 3: Insert 9

–2 5 –2 9 0
5

Rotate Right Rotate Left 0 0


–1
9 5 15
15 1

0 0
9
15

Figure 9.65 Step 3

Step 4: Insert 2 and 8 Step 5:


0
1
9
9

0 −1
0 0
5 15 5 15

0 0 0 0 0
8
2 2 8 17

Figure 9.66 Step 4 Figure 9.67 Step 5

Step 6: Insert 23

−1 0
9 9
Rotate Left

0 −2 0
5 15 5 0 17

−1 0 0
0 0 0 0
2 8 2 8

Figure 9.68 Step 6

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 50 3/2/2012 6:58:00 PM


Trees 9.51

Step 7: Insert 18 Step 8: Insert 11

−1 9 −1
9

0 −1 0 0
17 5 17
5

0 1 0 0 1 1
0 0
2 8 23
2 8

0 0 0
18

Figure 9.69 Step 7 Figure 9.70 Step 8

Step 9: Insert 20

9 -2
-2
9

5 0 17 -1
0 17 -1
5
Rotate Left

0 0 2
0 1 2 1
0
8 23
8 23

0 1 0 1

18 20

0 0
20 18

-1
9

0 0
5 17

0 0 1 0
2 8 20

0 0 0

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 51 3/2/2012 6:58:00 PM


9.52 Data Structures Using C

SUMMARY
1. Tree is a useful data structure of non-linear type. Elements are arranged in a non-linear
fashion in a tree. A tree structure means that data is organized in branches.
2. Tree has several practical applications. It is immensely useful in manipulating data and to
protect hierarchical relationships among data.
3. Root is the mother node of a tree structure. This is the most important node of any tree.
Node is the main component of the tree. The node of a tree stores the data and its role
is the same as the linked list. Nodes are connected by means of links with other nodes.
4. When the predecessor of a node is a parent, then all successor nodes are called child
nodes. The link is a pointer to a node in a tree structure. In other words, link connects the
two nodes. The line drawn from one node to other node is called a link.
5. The highest number of nodes that is possible starting from the first node (root) to a leaf
node is called the height of a tree.
6. A general tree is similar to the family tree. The origin of the family tree is called the root
node. The various generations are represented in hierarchical structure with nodes. A tree
is a finite set of one or more nodes.
7. A binary tree is a finite set of data elements. A tree is binary if each of its nodes has a maxi-
mum of two branches. The data element is either empty or holds a single element called
root along with two disjoint trees called left sub-tree and right sub-tree, i.e. in a binary tree
the maximum degree of any node is two.
8. A tree is called a complete binary tree if each of its nodes has two children, except the
last nodes. In other words, every non-terminal must have both children except the last leaf
nodes.
9. Three parameters are needed for the formation of binary tree.They are node, left and right
sub-trees.Traversing is one of the most important operations done on binary tree and fre-
quently this operation is carried on data structures. Traversal means passing through every
node of the tree one by one. Every node is traversed only once.
10. A binary search tree is also known as binary sorted tree.
11. The B-tree is also known as the balanced sort tree. The B-tree is used in external sorting.
The B-tree is not a binary tree.
12. The AVL tree is a binary search tree. It is also known as height balanced tree. It is used
to minimize the search time by keeping every node of the tree completely balanced in
terms of height. The balance factor plays an important role in the insertion and deletion
of elements in an AVL tree.

EXERCISES
A. Answer the following questions:

1. Explain trees and binary trees.


2. Give the properties of binary tree.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 52 3/2/2012 6:58:00 PM


Trees 9.53

3. Explain the various types of binary trees.


4. Define the following terminologies of tree:
(a) Height (c) Siblings
(b) Degree of a node (d) Terminal node
5. How are binary trees represented?
6. Give the working of binary trees.
7. What is meant by traversing? List the methods of node traversing. Explain briefly.
8. What are the differences between tree and graph?
9. What is binary search tree? How is an element searched?
10. Explain the procedure of insertion and deletion of data with binary search tree.

B. Select the appropriate option for each of the following questions:

1. Traversing means
(a) visiting all the nodes of the list (c) randomly accessing the elements
(b) shifting all the nodes at forward (d) none of the above
2. Every tree structure must contain
(a) root node (c) both left and right branches with root
(b) either left right branch with root node (d) all of the above
3. When every no-leaf node in binary tree has filled left and right sub-trees, the tree is called
(a) strictly binary tree (c) binary search tree
(b) complete binary tree (d) none of the above
4. The last node of this binary tree contains two branches. Such a tree is called
(a) strictly binary tree (c) extended binary tree
(b) complete binary tree (d) none of the above
5. The following sequence of the traversing is called
Go to the root
Traverse the left sub-tree
Traverse the right sub-trees
(a) inorder (c) preorder
(b) postorder (d) pre-postorder
6. The following sequence of the traversing is called
Traverse the left sub tree in inorder Visit root node.
Traverse the right sub tree in inorder.
(a) inorder (c) preorder
(b) postorder (d) pre-postorder
7. The following sequence of the traversing is called
Traversing the left sub-tree in postorder style.
Traverse the right sub tree in postorder.
Visit the root node (N).
(a) inorder (c) preorder
(b) postorder (d) pre-postorder

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 53 3/2/2012 6:58:00 PM


9.54 Data Structures Using C

8. The tree given below is called as


(a) complete tree (c) right-skewed binary tree
(b) left-skewed binary tree (d) none of above

B C

D E F G

Consider the above figure for the following questions:


9. The tree contains _____ level(s).
(a) one (c) two
(b) zero (d) none of the above
10. Degree of the B node is
(a) one (c) three
(b) two (d) none of the above
11. Height of the tree is
(a) two (c) four
(b) three (d) none of the above
12. Siblings of B are
(a) F and G (c) A and C
(b) D and E (d) none of the above
13. If root node ‘A’ is deleted then the left sub tree contains the elements
(a) C, F, and G (c) A, B, and C
(b) B, D, and E (d) none of the above

C. Attempt the following programs:

1. Write a program to create tree structure, perform insert and delete operations.
2. Write a program to traverse the binary search tree with different traversal methods such as
inorder, preorder and postorder.
3. Construct binary tree for the following data:
Inorder: F E A C D G H B I
Postorder: E F C D H I B G A
4. Construct the binary tree for the following:
1. Inorder: 3 5 6 8 12 15 18 19
Preorder: 12 5 3 6 8 18 15 19
Postorder: 3 8 6 5 15 19 18 12

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 54 3/2/2012 6:58:00 PM


Trees 9.55

2. Preorder: A E F D J H I G B C
Inorder: F E A H J I D B G C
3. Inorder: 1 3 4 5 6 7 9 12
Postorder: 3 5 4 1 7 12 9 6
5. Determine the preorder, inorder and postorder of the following trees:

8 V

K
10

O
18
L

15 R

(1) (2)

B
89
C
45 96
H

25 67
D

F 31 77

(3) (4)

6. Write a C program to insert nodes into a binary tree and traverse them in preorder.
7. Write a program for finding the height of the tree.
8. Write a program to display all the nodes of the binary search tree and then insert data and
display it along with the previous data of the tree.
9. Write a C program to search an element from the binary search tree.
10. Write a program for implementing binary tree traversal.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 55 3/2/2012 6:58:00 PM


9.56 Data Structures Using C

D. What is the output of each of the following exit(0);


}
programs?
}
return(tree);
1. }
# include <stdio.h> void func_trv(struct tree*tree)
# include <conio.h> {
struct tree if(tree!=NULL)
{ {
long num; func_trv(tree->ltree);
struct tree *ltree; printf("%4ld",tree->num);
struct tree *rtree; func_trv(tree->rtree);
}; }
struct tree *btree=NULL; }
struct tree *insert(struct
tree*tree,long digit);
2.
void func_trv(struct tree*tree);
# include <stdio.h>
void main()
# include <conio.h>
{
struct tree
long digit;
{
clrscr();
long no;
puts("Enter integers: and 0 to
struct tree *ls;
quit");
struct tree *rs;
scanf("%ld",&digit);
};
while(digit!=0)
struct tree *btree=NULL;
{
struct tree *creat(struct
tree= insert(tree,digit);
tree*btree,long ele);
scanf("%d",&digit);
void fun1(struct tree*btree);
}
void main()
puts("func_trv traversing
{
tree:\n");
long ele;
func_trv(tree);
clrscr();
struct tree*insert(struct
puts("Enter integers: and 0 to
tree*tree,long digit)
quit");
{
scanf("%ld",&ele);
if(tree==NULL)
while(ele!=0)
{
{
tree=(struct tree*)
btree= creat(btree,ele);
malloc(sizeof(struct tree));
scanf("%d",&ele);
tree->ltree=tree->rtree=NULL;
}
tree->num=digit;
puts("traversing by fun1 tree:\n");
}
fun1(btree);
else
}
{
struct tree*creat(struct
if(digit<tree->num)
tree*btree,long ele)
tree- >ltree=insert(tree->ltree,digit);
{
else
if(btree==NULL)
if(digit>tree->num)
{
tree->rtree=insert(tree->rtree,digit);
btree=(struct tree*)
else
malloc(sizeof(struct tree));
if(digit==tree->num)
btree->ls=btree->rs=NULL;
{
btree->no=ele;
puts("Duplicates nodes: Program
}
exited");

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 56 3/2/2012 6:58:01 PM


Trees 9.57

else scanf("%ld",&no);
{ while(no!=0)
if(ele<btree->no) {
btree->ls=creat(btree->ls,ele); bt= insert(bt,no);
else scanf("%d",&no);
if(ele>btree->no) }
btree->rs=creat(btree->rs,ele); puts("traversing btree by
else fun_t:\n");
if(ele==btree->no) fun_t(bt);
{ }
puts("Duplicates nodes: Program struct tree*insert(struct
exited"); tree*bt,long no)
exit(0); {
} if(bt==NULL)
} {
return(btree); bt=(struct tree*)
} malloc(sizeof(struct tree));
bt->left=bt->right=NULL;
void fun1(struct tree*btree) bt->data=no;
{ }
if(btree!=NULL) else
{ {if(no<bt->data)
printf("%4ld",btree->no); bt->left=insert(bt->left,no);
fun1(btree->ls); else
fun1(btree->rs); if(no>bt->data)
} bt->right=insert(bt->right,no);
} else
if(no==bt->data)
3. {
# include <stdio.h>
puts("Duplicates nodes: Program
# include <conio.h>
exited");
struct tree
exit(0);
{
}
long data;
}
struct tree *left;
return(bt);
struct tree *right;
}
};
void fun_t(struct tree*bt)
struct tree *bt=NULL;
{
struct tree *insert(struct
if(bt!=NULL)
tree*bt,long no);
{
void fun_t(struct tree*bt);
fun_t(bt->left);
void main()
fun_t(bt->right);
{
printf("%4ld",bt->data);
long no;
}
clrscr();
}
puts("Enter integers: and 0 to
quit");

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 57 3/2/2012 6:58:01 PM


This page is intentionally left blank.

M09_ASHOK NAMDEV KAMTHANE5067_01_SE_C09.indd 58 3/2/2012 6:58:01 PM


Chapter 10

Graphs
CHAP TER O U T LIN E
10.1 Introduction 10.4 Graph Representation
10.2 Graphs 10.5 Traversal in Graph
10.3 Terminologies of Graph 10.6 Spanning Trees

10.1 INTRODUCTION

Graphs are frequently used in every walk of life. Every day we come across various kinds of graphs
appearing in newspapers or television. The countries in a globe are seen in a map. A map depends on
the geographic location of the places or cities. As such, a map is a well-known example of a graph. In the
map, various connections are shown between the cities. The cities are connected via roads, rail or aerial
network. How to reach a place is indicated by means of a graph. Using the various types of the links the
maps can be shown.
Fig. 10.1 illustrates a graph that contains the cities of India connected by means of road. Assume that
the graph is the interconnection of cities by roads. As per the graph, Mumbai, Hyderabad and Kolkata are
directly connected to all the other cities by road. Delhi is directly connected to Mumbai, Hyderabad, and
Kolkata. Delhi is connected to Chennai via Hyderabad.
Generally, we provide the address of our office/residence to a stranger who is not aware of our address
and location of city. At this juncture we use the graph for the easiest identification of our residential
location. Figure 10.2 shows the location of place by graph. By using the graph any stranger can easily
find location. For example, a pilgrim wishes to reach the Gurudwara in Nanded. The path is shown
in the figure for reaching the Gurudwara. The devotee has to reach the destination via Shivaji statue,

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 1 3/2/2012 6:58:35 PM


10.2 Data Structures Using C

Mahatma Gandhi statue and then Gurudwara as per the graph. Once a map is provided, any stranger
can reach any destination by using appropriate conveyance.

Delhi

Mumbai K
Kolkata

Hyderabad

Chennai

Bengaluru

Figure 10.1 Map Representation of Connection of Cities

M. Gandhi Shivaji Statue


Statue
Railway Station
Nanded

Gurudwara

Figure 10.2 Representation of a Map

In Fig. 10.2, four places are connected by road links. In the graph the road links are called as edges
and the places are called as vertices. The graph is a collection of the vertices and the edges, hence a map is
treated as graph. The following section describes the graph and relevant theories.
Like tree, graphs are nonlinear data structures. Tree nodes are arranged hierarchically from top to
bottom like a parent is placed at the top and child as successor at the lower level. Tree has some specific
structure whereas graph does not have a specific structure. It varies from application to application.

10.2 GRAPHS
O P
A graph is set of nodes and arcs. The nodes are also termed as
vertices and arcs are termed as edges. The set of nodes as per the
Fig. 10.3 is denoted as {O, P, R, S, Q}. The set of arcs in the fol- R S
lowing graph are {(O ,P), (O, R), (O, Q), (R, S), (Q, S)}. Graph
can be represented as,
G = (V, E) and V(G) = (O, Q, P, R, S) or group of vertices. Q
Similarly, E(G) = ((O, P), (O, R), (O, Q), (R, S), (Q, S)) or
group of edges. Figure 10.3 Graph

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 2 3/2/2012 6:58:35 PM


Graphs 10.3

A graph is linked if there is pathway between any two nodes of the graph, such a graph is called connected
graph or else, it is non-connected graph. Figures 10.4 and 10.5 are connected and non-connected graphs, respec-
tively. In both the figures four nodes are depicted. In the latter all the nodes are not connected by links whereas
in the former case all the nodes are joined by paths or links.

Q
P Q P

S S
R R

Figure 10.4 Connected Graph Figure 10.5 Non-connected Graph

Undirected Graph A graph containing unordered pair of nodes A B


is termed as undirected graph.
The vertices are {A, B, C, D} and edges are {(A, B), (A, D), (A, C),
(B, D), (B, C), (D, C)}. The graph has four nodes and six edges. This
C D
type of graph is known as completely connected network, in which
every node is having out going path to all nodes in the network. For
Figure 10.6 Undirected Graph
a complete network the number of links =N (N–1)/2, where N is the
number of vertices or nodes. In the Fig. 10.6 N is 4. By substituting
its value the number of edges obtained will be equal to 6. A E

Directed Graph This kind of graph contains ordered pairs of vertices.


For example, graph vertices are {A, B, C, D, E} and edges are {(A, B),
(B, D),(C, D)(C, A), (C, E), (E, A) }. Fig. 10.7 represents a graph having
five nodes and six edges. B D
A direction is associated with each edge. The directed graph is also
known as digraph.
V(G) = {A, B, C, D, E} and group of directed edges = {(A, B), (B, D), C
(C, D)(C, A), (C, E), (E, A)}.
Figure 10.7 Directed Graph
10.3 TERMINOLOGIES OF GRAPH

Weighted Graph A graph is supposed to be weighted if its every edge is assigned some value which is
greater than or equal to zero, i.e. non-negative value. The value is equal to the length between two vertices.
Weighted graph is also called as network. Weighted graph is shown in A
Fig. 10.8.
4 5
Adjacent Nodes When there is an edge from one node to another
C B
then these nodes are called adjacent nodes.
5 4
Incidence In an undirected graph the edges v0 , v1 is incident on
D
nodes. In a direct graph the edge v0, v1 is incident from node v0. It is
incident to node v1. Figure 10.8 A Weighted Graph

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 3 3/2/2012 6:58:36 PM


10.4 Data Structures Using C

Path A path from edges u0 to node un is a sequence of nodes u0, u1,u2, u3 .un−1, un. Here, u0 is adjacent to
u1, u1 is adjacent to u2 and un−1 is adjacent to un.

Length of Path Length of path is nothing but total number of edges included in the path from source
node to destination node.

Closed Path When first and last nodes of the path are same, A B
such path is known as closed path. In Fig. 10.9 closed path at
node A is shown.
C D
Simple Path In this path all the nodes are different with an
exception that the first and last nodes of the path can be similar. Figure 10.9 Closed Path for Node A

Cycle Cycle is a simple path. The first and last nodes are same.
A
In other words, a closed simple path is a cycle. In a digraph a path
is known as cycle if it has one or more nodes. The starting node is 4 5
connected to the last node. In an undirected graph a path is called
C B
cycle if it has at least three nodes. The starting node is connected
to last node. In the following figure path ACDBA is a closed path.
5 4
Example of a cycle is shown in Fig. 10.10.
D
Cycle Graph A graph having cycle is called cycle graph. In this case Figure 10.10 Example of a Cycle
the first and last nodes are the same. A closed simple path is a cycle.
This is same as closed path shown in Fig. 10.10.

Acyclic Graph A graph without cycle is called acyclic graph. Examples of acyclic graphs are shown in
Fig. 10.11.

Dag A directed acyclic graph is called dag after its acronym (reduction). Figure 10.12 is a graph showing
the dag.

Degree In an undirected graph, the total number of edges linked to a node is called degree of that node.
In a digraph there are two degrees for every node called indegree and outdegree. In the above Fig. 10.12,
E has two edges hence degree is 2. Similarly, D has degree three and so on.

A A
A B

C B B C C

E D
D

Figure 10.11 Acyclic Graphs Figure 10.12 Dag

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 4 3/2/2012 6:58:38 PM


Graphs 10.5

Indegree The indegree of a node is the total number of edges coming to that node. In Fig. 10.12, C
is receiving two edges hence, the indegree is two.

Outdegree The outdegree of a node is the total number of edges going outside from that node. In the
above Fig. 10.12 the outdegree of D is one.

Source A node, which has only outgoing edges and no incoming edges, is called a source. The indegree
of source is zero. In Fig. 10.12 the node E is the source since it does not have any incoming edges. It has
only the outgoing edges.

Sink A node having only incoming edges and no outgoing edges is called sink node. Node C in
Fig. 10.12 is a sink node because it has only incoming edges but no outgoing edges.

Pendant Node When indegree of node is one and outdegree is zero then such a node is called pendant
node.

Reachable If a path exists between two nodes it will be called reachable from one node to other node.

Isolated Node When degree of node is zero, i.e. node is not connected
A B
with any other node then it is called isolated node. In Fig. 10.13 B node
is the isolated node.

Successor and Predecessor In digraph if a node V0 is adjacent to node C D


V1 then V0 is the predecessor of V1 and V1 is the successor of V0.
Figure 10.13 Isolated Node
Complete Graph The graph in which any V0 node is adjacent to all other
nodes present in the graph is known as a complete graph. An undirected A
graph contains the edges that are equal to edges = n(n–1)/2. The following
figure shows the complete graph.
The ‘n’ is the number of vertices present in the graph. B D

Articulation Point On removing the node the graph gets disconnected,


C
then that node is called the articulation point.

Biconnected Graph The biconnected graph is the graph which does not contain any articulation point.

Multigraph A graph in which more than one edge is used to join


the vertices is called multigraph. Edges of multigraph are parallel to A B
each other.
Figure 10.14 shows the multigraph in which one can see the par- E
allel edges between A and D, D and C, B and C, and A and B.

Regular Graph Regular graph is the graph in which nodes are D C


adjacent to each other i.e. each node is accessible from any other
node. Figure 10.14 Multigraph

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 5 3/2/2012 6:58:39 PM


10.6 Data Structures Using C

10.4 GRAPH REPRESENTATION P

The graph can be implemented by linked list or array. Figure 10.15


Q R
illustrates a graph and its representation and implementation is also
described.
Different possibilities of graph representations are dependent on
two cases:
1. If there is no edge between two nodes. S T

P Q
U
There is no edge between nodes P and Q.
2. If there is an edge between any two nodes. Figure 10.15 Model Graph

P Q

The nodes P and Q are having an edge.


Hence, Table 10.1 provides the representation of the graph (Fig. 10.15).
Table 10.1 Representation of a Graph
Nodes P Q R S T U

P      
Q      
R      
S      
T      
U      

As per Table 10.1, there is an edge in between the nodes P and Q, P and R, and there is no edge between
nodes P and S. The symbol  indicates existence of edge and  indicates absence of edge between two
nodes.
From the above table one can predict the path to reach a particular node. For example, initial node is P
and the destination node is U. We have to find the path to reach node U from P.
There is no edge between P and U. Then, find out the edge for nearest node in forward direction.
By observing, we know there are two edges from P to Q and P to R. We can select either Q or R.
Suppose, we have selected node Q, again find out next nearest successive node to Q by observing
column Q. The next successive forward node will be S. Then, refer column S and it provides two edges
Q and U. The node U is our solution. Thus, by using the above table, paths between any two nodes can
be determined. The path should be P-Q-S-U. The graph can be represented by sequential representation
and linked list representation.

Adjacency Matrix The matrix can be used to represent the graph. The information of adjacent
nodes will be stored in the matrix. Presence of edges from a particular node can be determined easily.

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 6 3/2/2012 6:58:39 PM


Graphs 10.7

The matrix can be represented by two-dimensional array. In a two-dimensional array [][], the first
sub-script indicates row and second, column. For example, there are five nodes in the graph then
the 0th row indicates node1 and so on. Likewise, column represents node1, node2, and so on. For
example, consider a two-dimensional array.
Nodes[j[k] P Q
1 indicates presence of edge between two nodes j and k.
0 indicates absence of an edge between two nodes j and k.
Thus, the matrix will contain only 0 and 1 values. S R
The matrix for the graph given in Fig. 10.16 would be:
Figure 10.16 An Example of Graph

P Q R S
P 0 1 0 1
Matrix X = Q 0 0 1 1
R 0 0 0 0
S 0 0 1 0
A B
In the above matrix, Mat[0][1]=1, which represents an edge
between node P and Q. Entry of one in the matrix indicates that
there is an edge and 0 for no edge. Thus, adjacency is maintained
in the matrix X. One can also represent the undirected graph with
adjacency matrix. Figure 10.17 is an undirected graph. D C
The adjacency matrix for the above graph would be as follows:
Figure 10.17 Undirected Graph
A B C D
A 0 1 0 1
Matrix X = B 1 0 1 0
C 0 1 0 1
D 1 0 1 0

The above matrix is symmetric since x[i][j]= x[j][i].


In undirected graph the sum of row elements and column elements
is the same. The sum represents the degree of the node. In this matrix
the sum of any row or any column is 2, which is nothing but the A B
degree of each node is 2.
We can also represent in the same way a weighted graph with
adjacency matrix. The contents of the matrix will not be only 0 and 1
but the value is substituted with the corresponding weight.
D C
For a null graph, that contains n vertices but no edges, all the
elements of such null graph in an adjacency matrix are 0.
Figure 10.18 represents the null graph and the adjacency matrix is as Figure 10.18 Null Matrix
follows:

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 7 3/2/2012 6:58:40 PM


10.8 Data Structures Using C

A B C D
A 0 0 0 0
X= B 0 0 0 0
C 0 0 0 0
D 0 0 0 0

A program on adjacency of a graph is illustrated below.

Example 10.1 Write a program to demonstrate adjacency of graph.

# include <stdio.h>
# include <conio.h>

void main()
{
int mej=l,k,beg,num, des;
int adj[20][20]={(0,0)};
char g_type;
clrscr();
printf("\nEnter number of nodes:");
scanf("%d",&num);
printf("Bnter type of graph,(d)irected or (u)ndirected:");
g_type=getch();
fflush(stdin);
if(g_type=='u') me=num*(num-1)/2;
else me=num*(num-1);
while(j<=me)
{
printf("\n Enter edges %d ( 0 to exit ): ",j);
scanf("%d %d",&beg,&des);

if((beg==0) && (des==0)) break;

if(beg > num || des > num || beg<=0 || des<=0)


{
printf("Invalid edges !\n");
j––;
}
else
{
adj[ beg ][ des ]=1;
if(g_type== 'u')
adj[beg][des]=1;
if(g_type=='u')
adj[des][beg]=1;
}
j++;
}

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 8 3/2/2012 6:58:41 PM


Graphs 10.9

printf("\n The adjency of matrix is : \n");

for(j=1;j<=num;j++)
{
for(k=1;k<=num;k++)
printf(" %d ",adj[j][k]);
printf("\n");
}
return 0;
}

OUTPUT
Enter number of nodes: 5
Enter type of graph,(d)irected or (u)ndirected: u
Enter edges 1 ( 0 to exit ): 1 1
Enter edges 2 ( 0 to exit ): 2 1
Enter edges 3 ( 0 to exit ): 2 2
Enter edges 4 ( 0 to exit ): 0 1
Invalid edges !
Enter edges 4 ( 0 to exit ): 1 2
Enter edges 5 ( 0 to exit ): 0 0

The adjency of matrix is:


1 1 0 0 0
1 1 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

Explanation:
In this program maximum edges are calculated by using formula. If the graph is directed type, the
formula is me=num*(num-l); where, num is the total number of nodes. When the graph is
undirected then the formula is me=num*(num-l)/2.
After computing maximum edges, the user is prompted to enter edges. When 0,0 are entered
the while loop is terminated. When the entered edges are greater than num and less than or
equal to zero, message “Invalid edges” is displayed. Otherwise, adj[ beg ][ des ]=1.

10.4.1 Adjacency List


Two lists are maintained for adjacency of list. The first list is used to store information of all the nodes.
The second list is used to store information of adjacent nodes for each node of a graph.
In case a graph comprises of N nodes, then two lists are to be prepared.
1. First list keeps the track of all the N nodes of a graph.
2. The second list is used to keep the information of adjacent nodes of each and every node of a graph.
As such there will be N lists that would keep the information of adjacent nodes.
Header node is used to represent each list, which is assumed to be the first node of a list. Figure 10.19
represents a header node.

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 9 3/2/2012 6:58:41 PM


10.10 Data Structures Using C

DATA

Points to the
First Node
Neighboring to
Neader Node

Points to the
Next Node

Figure 10.19 Header Node


struct node
{
struct* next
int num;
struct edge *aj;
};

Structure of an Edge Figure 10.20 is the representation of an edge.

Link to Points to the Next


Destination Node Neighboring
(Int Num) Node of Header

Figure 10.20 An Edge of Graph


struct edge P Q
{
int num;
struct edge *ptr;
}; S R
Consider a graph cited in Fig. 10.21.
Adjacency list for the above graph would be given in Fig. 10.22.
Figure 10.21 An Example of Graph

P Q S

Q R S

R S

S R

Figure 10.22 Adjacency List

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 10 3/2/2012 6:58:41 PM


Graphs 10.11

10.5 TRAVERSAL IN GRAPH

Traversing in a graph is nothing but visiting each and every node of a graph. The following points are to
be noted in a graph:
1. The graph has no first node or root. Therefore, the graph can be started from any node.
2. In graph, only those nodes are traversed which are accessible from the current node. For complete
traversing of graph, the path can be determined by traversing nodes step by step.
3. In the graph, the particular node can be visited repeatedly. Hence, it is necessary to keep the track of
the status of every node whether traversed or not.
4. In graph to reach a particular node, more paths are available.
Two techniques are used for traversing nodes in a graph. They are depth first and breadth first. These
techniques have been elaborated in detail in the following sections.

10.6 SPANNING TREES

A spanning tree is an undirected tree, containing only those nodes that are necessary to join all the nodes
in the graph. The nodes of spanning trees have only one path between them. In spanning trees, the
number of edges are less by one than the number of nodes (see Fig. 10.23).

P Q P Q

R S R S

Figure 10.23 Spanning Trees


Depth first spanning tree is shown in Fig. 10.24.
Breadth first spanning tree is shown in Fig. 10.25.
H
H
M

I J K L M I J K

N L

Figure 10.24 Depth First Spanning Tree Figure 10.25 Breadth First Spanning

Weighted Graph When the edges of the graph contain positive values as weight it is known as weighted
graph or network.
Prim’s Algorithm In this algorithm, the traversing can start from any node and addition can be done in
spanning tree according to the weight of the edge. For example, we start with node n1, and then the next
step is to check the entire connecting path to that node and find out which path has minimum weight. Thus,

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 11 3/2/2012 6:58:43 PM


10.12 Data Structures Using C

the nodes with minimum weight are added in Prim’s algorithms. Here, while program implementation it is
essential to know the weight of the edge. For example, we have two edges e1 and e2 with weights 3 and 5.
The edge e1 has minimum weight than e2 and hence, e1 will be added to spanning tree.

Example 10.2 Write a program to create minimum spanning tree using Prim’s algorithm.

# include <stdio.h>
# include <conio.h>
# include <process.h>

struct prim
{
int pred_sor;
int stat;
int distance;
};
struct node { int x; int w;};
int adjc[10][10],num;

int main()
{
int y=1,wt,counter;
struct node trees[10];
void create(void );
void show(void );
int m_tree(struct node*, int*);
clrscr();
create();
printf("Adjacency of Matrix : ");
show();
counter=m_tree(trees,&wt);
printf("Weight of spanning trees is : %d\n", wt);
printf("Edges to be included in spanning trees :");

while(y<=counter)
{
printf("%d->",trees[y].x);
printf("%d\num",trees[y].w);
y++;
}
return 0;
}
void create()
{
int y=1,m_edge,start,end,wt;
printf("Enter number of vertices :");
scanf("%d",&num);
m_edge=num*(num-1)/2;
while (y<=m_edge)
{
printf("Enter node %d(0 to Exit) : ",y);
scanf("%d %d",&start,&end);
if((start==0)&&(end==0)) break;
printf("Enter weight of this node : ");
scanf("%d",&wt);
if( start > num || end > num || start<=0 ||end<=0

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 12 3/2/2012 6:58:44 PM


Graphs 10.13

{
printf("Wrong node!\n");
––y;
}
else
{
adjc[start][end]=wt;
adjc[end][start]=wt;
}
y++;
}
if(y<num-1)
{
printf("Spanning tree not possible\n");
exit(0);
}
}
void show()
{
int y=1,p;
while (y<=num)
{
for(p=1;p<=num;p++)
printf("%3d",adjc[y][p]);
printf("\n");
y++;
}
}
int m_tree(struct node trees[10],int *wht)
{
struct prim p_ion[10];
int y=1,mm,counter,cur;
int perm(struct prim *);
int uu,vv;
wht=0;
while(y<=num)
{
p_ion[y].pred_sor=0;
p_ion[y].distance = 9999;
p_ion[y].stat = 0;
y++;
}
p_ion[1].pred_sor=0;
p_ion[1].distance=0;
p_ion[1].stat = 1;
cur=1;
counter=0;
while( perm(p_ion) != 1)
{
for(y=1;y<=num;y++)
{
if(adjc[cur][y] > 0 && p_ion[y].stat == 0)
{
if(adjc[cur][y] < p_ion[y].distance)
{

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 13 3/2/2012 6:58:44 PM


10.14 Data Structures Using C

p_ion[y].pred_sor = cur;
p_ion[y].distance = adjc[cur][y];
}
}
}
mm=9999;
for(y=1;y<=num;y++)
{
if(p_ion[y].stat == 0 && p_ion[y].distance < mm)
{
mm = p_ion[y].distance;
cur=y;
}
}
p_ion[cur].stat=1;
uu=p_ion[cur].pred_sor;
vv=cur,counter++;
trees[counter].x=uu;
trees[counter].w=vv;
*wht=*wht+adjc[uu][vv];
}
return(counter);
}
int perm(struct prim p_ion[10] )
{
int y=1;
while(y<=num) if( p_ion[y++].stat == 0 )
return 0;
return 1;
}

OUTPUT
Enter number of vertices : 5
Enter node 1( 0 to Exit) : 1 1
Enter weight of this node : 5
Enter node 2( 0 to Exit) : 1 1
Enter weight of this node : 3
Enter node 3( 0 to Exit) : 0 0
Spanning tree not possible

Explanation:
In this program the Structure prim is defined as follows:
struct prim
{
int pred_sor;
int stat;
int distance;
};
struct node {int x; int w;};
The function create() is used to compute maximum edges. The m_tree() function is used
to calculate the edges. The show() function is used to display the nodes.

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 14 3/2/2012 6:58:44 PM


Graphs 10.15

10.6.1 Breadth First Search


This is one of the popular methods of traversing graph. This method
uses the queue data structure for traversing nodes of the graph. Any P Q R
node of the graph can act as a beginning node. Using any node as
starting node, all other nodes of the graph are traversed. To shun
repeated visit to the same node an array is maintained which keeps S T U
status of visited node.
Take the node P of Fig. 10.26 as a beginning node. Initially, the Figure 10.26 A Model Graph
node P is traversed. After this, all the adjacent nodes of P are traversed,
i.e. Q, T and S. The traversal of nodes can be carried in any sequence.
For example, the sequence of traverse of nodes is Q, S and T. The traversal will be
P Q S T

First, all the nodes neighbouring Q are traversed, then neighbouring nodes of S and finally T
are taken into account. The adjacent node of Q is R and T is U. Similarly, the adjacent node of T
is U and S does not have any adjacent node. Hence, in this step the traversal now should be in the
following way:
P Q S T R U

Now, the new nodes obtained are R and U after traversing. The new adjacent node of R is U and U
node does not have any adjacent node. Node U has been visited in the previous case hence it must be
ignored in this step.

10.6.2 Depth First Search P Q R

In this method, also a node from graph is taken as a starting node.


Traverse through all the possible paths of the starting node. When the
last node of the graph is obtained and path is not available from the S T U
node; then control returns to previous node. This process is imple-
mented using stack. Figure 10.27 A Model Graph
Consider the graph shown in Fig. 10.27.
Consider, P as starting node. Then, traverse the node adjacent to P and we will get Q and then R
(adjacent to Q) and U (adjacent to R). The traversal will be
P Q R U

The search is always carried in forward direction. After reaching to U, we reach the end of the path and
further movement in forward direction is not possible. Hence, the controls go to the previous node and
again traverse through the available paths for non-traversed nodes.
In reverse direction, we get the node R and it has unvisited node. Hence, Q is taken and it gives T.
The node T gives U, but it is already visited. Therefore, control in reverse direction checks all the nodes.
It takes P and it gives node S. The sequence of traversal will be
P Q R U T S

The following program explains both the above procedures.

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 15 3/2/2012 6:58:44 PM


10.16 Data Structures Using C

Example 10.3 Write a program to demonstrate breadth first search and depth first search.

# include <stdio.h>
# include <conio.h>
# include <process.h>
# define num 21

int aj[num][num],tra_sed[num],count;
int main()
{
int j,x,select;
int show(void),create(void),dfs(int);
int dfs_rsn(int),bfs(int),adj_edg(int);
void nodes(void);
clrscr();
create();
for(;;)
{
printf("1. Adjacency of matrix\n");
printf("2. Depth First Search with stack\n");
printf("3. Depth First Search with recursion\n");
printf("4. Breadth First Search\n");
printf("5. Adjacent vertices\n");
printf("6. Elements\n");
printf("7. Quit\n");
printf("Enter option:");
scanf("%d",&select);
switch(select)
{
case 1:
printf("Adjacency of Matrix\n");
show();
break;
case 2:
printf("Enter Beginning node for Depth
First Search:");
scanf("%d",&x);
for(j=1;j<=count;j++)
tra_sed[j]=0;
dfs(x);break;
case 3:
printf("Enter Beginning node for Depth
First Search : ");
scanf("%d",&x);
for(j=1;j<=count;j++)
tra_sed[j]=0;
dfs_rsn(x);break;
case 4:
printf("Enter Beginning node for Breadth First Search:");
scanf("%d", &x);
for(j=1;j<=count;j++)
tra_sed[j]=0;
bfs(x);
break;

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 16 3/2/2012 6:58:44 PM


Graphs 10.17

case 5:
printf("Enter node to search adjacent vertices :");
scanf("%d", &x);
printf("Adjacent Vertices :");
adj_edg(x);
break;
case 6:
nodes();
break;
case 7:
exit(0);
default:
printf("Invalid selection\n");
break;
}
}
}
create()
{
int j,m_edges,start,target;
printf("Enter number of nodes:");
scanf("%d",&count);
m_edges=count*(count-1);
for(j=1;j<=m_edges;j++)
{
printf("Enter edge %d( 0 0 to quit) :",j);
scanf("%d %d",&start,&target);
if((start==0) && (target==0))
break;
if(start > count || target > count || start<=0 || target<=0)
{
printf("Invalid edges try again !\n");
––j;
}
else aj[start][target]=1;
}
return 0;
}
show()
{
int j;
for(j=1;j<=count;j++)
{
for(j=1;j<=count;j++)
printf("%5d",aj[j][j]);
printf("\n");
} return 0;
}
dfs_rsn(int x)
{
int j;
tra_sed[x]=1;
printf(" %d ",x);
for(j=1;j<=count;j++)

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 17 3/2/2012 6:58:44 PM


10.18 Data Structures Using C

if(aj[x][j]==1 && tra_sed[j]==0)


dfs_rsn(j);
return 0;
}
dfs(int x)
{
int j,stack[num],TOP=-1,popve;
TOP++;
stack[TOP]=x;
while (TOP>=0)
{
popve=stack[TOP];
TOP––;
if(tra_sed[popve]==0)
{
printf("%d ",popve);
tra_sed[popve]=1;
}
else
continue;
for(j=count;j>=1;j––)
{
if( aj[popve][j]==1 && tra_sed[j]==0)
{
TOP++;
stack[TOP]=j;
}
}
}
return 0;
}
bfs(int x)
{
int j,fr,re;
int queue[20];
fr=re= -1;

printf("%d ",x);
tra_sed[x]=1;
re++;
fr++;
queue[re]=x;

while(fr<=re)
{
x=queue[fr];
fr++;
for(j=1;j<=count;j++)
{
/* Check for adjacent unvisited nodes */
if(aj[x][j]==1 && tra_sed[j]==0)
{
printf("%d ",j);
tra_sed[j]=1;
re++;

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 18 3/2/2012 6:58:44 PM


Graphs 10.19

queue[re]=j;
}
}
}
return 0;
}
adj_edg(int x)
{
int j;
for(j=1;j<=count;j++)
if(aj[x][j]==1)
printf("%d ",j);
printf("\n");
return 0;
}
void nodes()
{
int j;
for(j=1;j<=count;j++)
tra_sed[j]=0;
for(j=1;j<=count;j++)
{
if(tra_sed[j]==0)
dfs_rsn(j);
}
printf("\n");
}

OUTPUT
Enter number of nodes : 5
Enter edge 1( 0 0 to quit ) : 1 1
Enter edge 2( 0 0 to quit ) : 2 2
Enter edge 3( 0 0 to quit ) : 1 5
Enter edge 4( 0 0 to quit ) : 0 0
1. Adjacency of matrix
2. Depth First Search with stack
3. Depth First Search with recursion
4. Breadth First Search
5. Adjacent vertices
6. Elements
7. Quit
Enter option : 1
Adjacency of Matrix
1 1 0 0 0

Explanation:
In this program following user defined functions are defined to perform various tasks. Create()
function when executed prompts user to enter number of edges and corresponding edge values.
When user enters edges, maximum edges are calculated. For complete details of the procedure
read the topic depth first search. The function adj_edg() calculates the edges. The function
bfs() performs breadth first search. For details, refer the topic breadth first search illustrated
in the same topic.

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 19 3/2/2012 6:58:44 PM


10.20 Data Structures Using C

10.6.3 Indegree and Outdegree of Vertex


The number of incoming vertices incident on the specific vertex of a graph is termed as the indegree
of the vertex. The number of outgoing vertices from the specific vertex of a graph is termed as the outde-
gree of the vertex. Table 10.2 shows the calculation of indegrees and outdegrees.

Example 10.4 Calculate the indegree and outdegree of the vertices of Figure 10.28.

V1 V6

V2 V7 V5

V3 V4

Figure 10.28
Table 10.2 Calculation of Indegree and Outdegree
Vertex Indegree Vertices Outdegree Vertices No. of Indegree Vertices No. of Outdegree Vertices
V1 Null V2, V7, V6 0 3
V2 V1, V7 V3 2 1
V3 V2, V7 V4 2 1
V4 V7, V3 V5 2 1
V5 V7, V4, V6 Null 3 0
V6 V1 V7, V5 1 2
V7 V1, V6 V2, V3, V4, V5 2 4

10.6.4 Topological Sorting


Topological sorting is the process of ordering the vertices of a graph such that a path exists from vertex Vi
to Vj in the graph. Topological ordering is possible if the graph is acyclic, i.e. the graph is not cyclic.
Topological ordering is not possible if the graph is cyclic because Vi precedes Vj and Vj precedes Vi . A
cyclic graph doesn’t have a vertex with indegree zero.
The following steps are involved in topological sorting:
1. Find any vertex in the graph the indegree of which is zero.
2. Initially, the ordering set is set to zero.
3. Add the vertex the indegree of which is zero to an ordering set.
4. Remove the vertex the indegree of which is zero. Also remove the edges, which are associated with the
selected vertex the indegree of which is zero.
5. Repeat Steps 1 to 4 till the graph is empty.

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 20 3/2/2012 6:58:44 PM


Graphs 10.21

Example 10.5 Illustrate the topological sorting of the graph shown in Fig. 10.29.

Ordering set = Empty


V1 V4

V5

V2 V3

Figure 10.29 Step 1

Step 1: Initially, set the ordering set as empty.


Step 2: Monitor the above graph and find a vertex the indegree of which is zero. In this example, V1
has an indegree of zero. Remove the vertex V1 and also remove all the edges that are associated with
the vertex V1 and redraw the graph. Place the selected vertex into the ordering set (Fig. 10.30).
Ordering set: V1

V4

V5

V2 V3

Figure 10.30 Step 2

Step 3: Among the vertices V2, V3, V4, and V5, the vertex V2 has an indegree of zero. Hence, remove
all the edges which are associated with the vertex V2.. Redraw the graph and place the vertex in the
ordering set (Fig. 10.31).
Ordering set: V1,V2

V4

V5

V3

Figure 10.31 Step 3

Step 4: Among the remaining vertices V3, V4, and V5, the vertex V4 has an indegree of zero. Remove
all the edges that are associated with the vertex V4, redraw the graph and place the vertex in the
ordering set (Fig. 10.32).

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 21 3/2/2012 6:58:45 PM


10.22 Data Structures Using C

Ordering set: V1, V2, V4


V5

V3

Figure 10.32 Step 4

Step 5: Among the remaining vertices V3 and V5, the vertex V3 has an indegree of zero. Remove all
the edges that are associated with the vertex V3, redraw the graph and place the vertex in the ordering
set (Fig. 10.33).
Ordering set: V1, V2, V4, V3

V5

Figure 10.33 Step 5

Step 6: Only the vertex V5 is remaining the end as the indegree of vertex V5 is zero. Add the vertex V5 to
the previous ordering set. After adding the vertex V5 to the ordering set, the graph becomes empty.
Ordering set: V1, V2, V4, V3, V5

10.6.5 Path Matrix


A graph contains a set of vertices and edges. Consider a graph with n number of vertices such that
V1,V2,V3…Vn. The path matrix is defined as p[i][j]=1 if and only if there exist a path between the two
vertices Vi to Vj. p[i][j] = 0 if there does not exist a path from Vi to Vj.

A B

C D

A B C D
A 0 1 1 0

P= B 0 0 0 1 Adjacency matrix of the above graph


C 0 0 0 1

D 0 0 0 0

Figure 10.34

In the above matrix, p[A][B] = 1 as a path exists from vertex A to B (Fig. 10.34). Similarly W[A][D] = 0
as a path does not exist from A to D. Thus, from the above matrix we can analyze that
P[i][j] = 1 if a path exists from vertex Vi to Vj
P[i][j] = 0 if a path does not exist path from Vi to Vj

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 22 3/2/2012 6:58:46 PM


Graphs 10.23

Example 10.6 Determine the path matrix from the adjacency matrix (Fig. 10.35)

A B

Figure 10.35 Adjacency Matrix

The adjacency matrix of Fig. 10.35 is as follows:


Step 1: Find the adjacency matrix.
A B C
A ⎛0 1 1⎞
A=B ⎜1 0 1⎟
⎜ ⎟
C ⎜⎝ 1 1 0⎟⎠

Step 2: After multiplying the adjacency matrix with itself, we obtain a path matrix of length 2.
A B C
A ⎛0 1 1⎞ ⎛ 0 1 1⎞
B ⎜1 0 1⎟ * ⎜ 1 0 1⎟
⎜ ⎟ ⎜ ⎟
C ⎜⎝ 1 1 0⎟⎠ ⎜⎝ 1 1 0⎟⎠

⎛ 0 1 + 1 0 + 0 1 0 1 + 0⎞ ⎛ 2 1 1⎞
A 2 = ⎜ 0 0 + 1 1 + 0 1 1 0 + 0⎟ = ⎜ 1 2 0⎟
⎜ ⎟ ⎜ ⎟
⎜⎝ 0 1 + 0 1 + 0 0 1 1 + 0 ⎟⎠ ⎜⎝ 0 1 2⎟⎠

Thus, we obtain the path matrix of length 2 after multiplying the adjacency matrix with itself.
Step 3: Multiply the adjacency matrix with the obtained path matrix of length 2 from the above
matrix A2 to obtain a path matrix of length 3.
⎛ 2 1 1⎞ ⎛ 0 1 1⎞
A 2
A = A = ⎜ 1 2 0⎟ * ⎜ 1 0 1⎟
3
⎜ ⎟ ⎜ ⎟
⎜⎝ 0 1 2⎟⎠ ⎜⎝ 1 1 0⎟⎠

⎛ 0 1 + 1 2 + 0 + 1 2 + 1 + 0⎞ ⎛ 2 3 3⎞
A = ⎜ 0 + 2 + 0 1 + 0 + 0 1 + 2 + 0⎟ = ⎜ 2 1 3⎟
3
⎜ ⎟ ⎜ ⎟
⎜⎝ 0 + 1 + 2 0 + 0 + 2 0 + 1 + 0⎟⎠ ⎜⎝ 3 2 1⎟⎠

Thus, we obtain a path matrix of length 3.

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 23 3/2/2012 6:58:46 PM


10.24 Data Structures Using C

From the above path matrix of length 3, we can say as per the definition of a path matrix p[i][j]=1
if there exist a path from vertex Vi to Vj.
Step 4: To obtain the path matrix, as per the definition of a path matrix we can say that there exist
a path from Vi to Vj if p[i][j]=1. The obtained matrix A3 contains all non-zero numbers. Replace all
non-zero entries from matrix A3 to obtain the path matrix.

⎛1 1 1⎞
P = ⎜1 1 1⎟
⎜ ⎟
⎜⎝1 1 1⎟⎠

10.6.6 Transitive Relation


Consider a binary relation R on the set A. The relation R is called a transitive relation if there exists a
relation between aRb and bRc that results in a relation between aRc.
For example, if (a,b) and (b,c) belongs to R then (a,c) belongs to R.

Example 10.7 Find the transitive relation of Fig. 10.36 and redraw the graph.

A B

Figure 10.36
The adjacency matrix of the above graph is as follows:
A B C
A ⎛0 1 1⎞
B ⎜1 0 1⎟
⎜ ⎟
C ⎜⎝ 1 1 0⎟⎠

Another way to represent the adjacency matrix is by using the method of sets. Let G be the graph,
which is the set of vertices and edges (those vertices and edges are selected in which there exist a path
from Vi to Vj, i.e. from one to another vertex.)
G = {(A, B), (A, C), (B, C), (B, A), (C, A), (C, B)}
So by the property of transitive relation the new set of vertices and edges are as follows:
1) ARB and BRA then ARA
2) BRC and CRB then BRB
3) CRA and ARC then CRC

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 24 3/2/2012 6:58:48 PM


Graphs 10.25

After adding the new transitive relation, the set of vertices and edges is as follows in set G.
G ={(A, B), (A, C), (B, C),(B, A),(C, A),(C, B), (A, A),(B, B), (C, C)}
After performing the transitive relation on the above graph, the newly changed graph is shown in
Fig. 10.37.

A B

Figure 10.37

10.6.7 Warshall’s Algorithm


The method used to find the path matrix from its adjacency matrix is not an optimal method. Warshall
has proposed another method to find the path matrix. The technique to find the path matrix by the
Warshall’s algorithm is as follows:

Example 10.8 Find the path matrix from the given graph (Fig. 10.38).

1 2

Figure 10.38
Step 1: Represent the above graph in the form of form of an adjacency matrix.
1 2 3

1 1 1 1

W0 = 0 2 0 0 1

3 1 1 0

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 25 3/2/2012 6:58:49 PM


10.26 Data Structures Using C

To find W1, consider the first row and the first column. Let Pi be the columns and Q j be rows.
P1 : (1,1) P2 : (3,1)
Q1 : (1,1) Q2: (1,2) Q3:(1,3)
As 3R1 and 1R3 then 3R3 (by the transitive relation property) add to the next matrix W1.
Step 2: Thus, W1 is just w0 with one new position (3,3).

1 2 3

1 1 1 1

W1 = 2 0 0 1

3 1 1 1

To find W2, consider the second row and second column. Let Pi be the columns and Q j be rows.
P1: (1,2) P2 : (3,2)
Q1: (2, 1)
By the property of transitive relation, 2R1 and 1R2 then 2R2, add to the next matrix W2.
Step 3: Thus, W2 is just W1 with a new 1 position (2,2)

1 2 3

1 1 1 1

W2 = 2 0 1 1

3 1 1 1

To find W2, consider the second row and second column. Let Pi be the columns and Q j be the
rows.
P1: (1,3) P2: (2,3) P3: (3,3)
Q1: (3,1) Q2: (3,2) Q3: (3,3)
By the property of transitive relation, 2R3 and 3R1 then 2R1, add to the next matrix W3.
Step 4: Thus W3 is just as W2 with a new 1 position (2,1). Thus, the final path matrix is as
follows.

1 2 3
1 ⎛1 1 1⎞
W3 = 2 ⎜1 1 1⎟
⎜ ⎟
3 ⎜⎝1 1 1⎟⎠

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 26 3/2/2012 6:58:49 PM


Graphs 10.27

SUMMARY
1. In this chapter graph theory is described. Also, its implementation is illustrated with
numerous examples.
2. A graph is a set of nodes and arcs. The nodes are also termed as vertices and arcs are
termed as edges.
3. A graph is linked if there is a pathway between any two nodes of the graph, such a graph
is called connected graph or else it is non-connected graph.
4. The graph can be implemented by linked list or array.
5. Explanation on adjacency matrix is provided in the form of matrix. The information of
adjacent nodes can be stored in the matrix. Presence of edges from a particular node can
be determined easily. The matrix can be represented by two-dimensional array. In two-
dimensional, array [][] the first subscript.
6. Traversal in a tree is also explained in this chapter. The node can be visited repeatedly.
Hence, it is necessary to keep the track of node as to whether it has been visited or not.
7. Spanning tree is discussed in detail. Two methods have been elaborated together with
examples. Breadth first and depth first spanning trees have been illustrated in detail.

EXERCISES
A. Answer the following questions:

1. What do you mean by edges and vertices of a graph?


2. Define the following terms applicable to a graph:
(a) Degree (d) Outdegree
(b) Dag (e) Cycle
(c) Indegree
3. Distinguish between the directed and undirected graphs.
4. What do you mean by complete graph?
5. Explain traversing of a graph.
6. Distinguish between the breadth first and depth first traversals in a graph.
7. Describe spanning trees.
8. How are graphs implemented in computer memory?
9. Distinguish between the tree and graph.
10. Define the following terms in a graph:
(a) Source (c) Isolated node
(b) Sink (d) Articulation point

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 27 3/2/2012 6:58:50 PM


10.28 Data Structures Using C

B. Select the appropriate options for each of the following questions:

1. The header is used to point


(a) first node of the list (c) NULL value
(b) last node of the list (d) none of the above
2. Traversing means
(a) visiting all the nodes (c) randomly accessing the elements
(b) shifting all the nodes at forward (d) none of the above
3. Graph is a
(a) linear data structure (c) none of the above
(b) nonlinear data structure
4. Graph contains
(a) edges (c) edges and arcs
(b) arcs (d) none of the above
5. The indegree of a node is
(a) the total number of edges coming to that node
(b) the total number of edges leaving from that node
(c) the total number of edges coming and leave to that node
(d) None of the above
6. The directed graph is also called
(a) trigraph (c) none of the above
(b) digraph
7. Length of path is nothing but
(a) total number of edges included in the path from source to destination node
(b) total number of edges included in the path from destination to source
(c) none of the above
8. When first and last nodes of the path are same such a path is known as
(a) open path (c) none of the above
(b) closed path
9. A directed acyclic graph is called
(a) dag (c) none of the above
(b) a cycle
10. When a degree of node is zero then the node is called
(a) group node (c) none of the above
(b) isolated node
11. Traversal in graph is
(a) to visit only few nodes of a graph (c) none of the above
(b) to visit all nodes of a graph

C. Attempt the following program:

1. Write a program to demonstrate breadth first search and depth first search.
2. Write a program to demonstrate spanning tree.

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 28 3/2/2012 6:58:50 PM


Graphs 10.29

3. Write a program to count the number of nodes of a graph.


4. Write a program to count the indegree and outdegree of every node of a graph.
5. Write a program to find the number of source nodes in a graph.
6. Write a program to find the number of sink nodes in a graph.
7. Write a program to find the successors and predecessors of each node in a graph.
8. Write a program to find the number of isolated nodes in a graph.
9. Find the adjacency matrix for the graph given below:

B C

A D

F E

M10_ASHOK NAMDEV KAMTHANE5067_01_SE_C10.indd 29 3/2/2012 6:58:50 PM


Chapter 11

Sorting
CHAP TER O U T LIN E
11.1 Introduction 11.7 Tree Sort
11.2 Sorting 11.8 Merge Sort
11.3 Insertion Sort 11.9 Heap Sort
11.4 Selection Sort 11.10 Radix Sort
11.5 Bubble Sort 11.11 Partition Exchange Sort
11.6 Quick Sort

11.1 INTRODUCTION

In our daily life, we keep the information in particular order. This helps in accessing any part of it easily.
Likewise, in database programs, large data is maintained in the form of records. It would be very difficult
if data or records were unsorted. It is very difficult and time consuming to find a particular record if data
or records are randomly stored. The process of sorting is essential for database applications.
Sorting is a process in which records are arranged in ascending or descending order. A group of fields is
called record. For example, consider the following structure:
struct employee
{
char *name;
int age;
float height;
} s;

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 1 3/2/2012 6:59:12 PM


11.2 Data Structures Using C

We are familiar with the above declarations and definitions. The object s contains three fields as
described in the structure. The database is a collection of such fields. Each record contains the above
fields, and it may vary depending upon the structure defined. The sorting can be done on any one or a
combination of one or more fields. Suppose we sort the records based on name, then the field name will
be the key field. A record is quickly searched in a sorted database. Thus, sorting is a very useful concept
of data structure.

11.2 SORTING

As already defined in the previous section sorting is a process in which records are arranged in ascending
or descending order. In real life we come across several examples of sorted information. For example, in
telephone directory the names of the subscribers and their phone numbers are written in alphabetial order.
The records of the list of these telephone holders are to be sorted by their names. By using this directory,
we can access the telephone number and address of the subscriber very easily.
Bankers or businesspersons sort the currency denomination notes received from customers in the
appropriate form. Currency denominations of Rs 1000, 500, 100, 50, 20, 10, 5, and 1 are separated first
and then separate bundles are prepared.
While we play the cards, initially the cards appear random but we keep them in ascending or descending
order. In most of the offices the officials keep the files in a specific order for tracing them easily in future.
Even at our homes, many times we keep the utensils in particular order such as increasing or decreasing
height. This helps us in accessing a particular item without difficulty. The sort method has great impact
on data structures in our dally life.
For example, consider the five numbers 5, 9, 7, 4, 1.
The above numbers can be sorted in ascending or descending order.
The representation of these numbers in
Ascending order (0 to n): 1 4 5 7 9
Descending order (n to 0): 9 7 5 4 1
Similarly, alphabets can also be sorted.
Consider the alphabets B, A, D, C, E. These can be sorted in ascending or descending order.
Ascending order (A to Z): A B C D E
Descending order (Z to A): E D C B A.

11.3 INSERTION SORT

In insertion sort the element is inserted at appropriate place. For example, consider an array of n elements.
In this type, swapping of elements is done without taking any temporary variable. The greater numbers
are shifted towards the end of the array and smaller are shifted to beginning. Here, a real life example of
playing cards can be cited. We keep the cards in increasing order. The card having least value is placed
at the extreme left and the largest one at the other side. In between them the other cards are managed in
ascending order.
Consider an example of playing cards. The playing cards having values 4, 6, 2, 1, 8 can be sorted
according to the method described above, as
Figure 11.1 illustrates the insertion sort.

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 2 3/2/2012 6:59:13 PM


Sorting 11.3

Initial List 4 6 2 1 8

Pass 1 4 6 2 1 8

Pass 2 4 6 2 1 8

Pass 3 2 4 6 1 8

Pass 4 1 2 4 6 8

Figure 11.1 Insertion Sort


The process of insertion sort can be explained with the following steps:
• Get the random integer list. In the above example the list contains elements 4, 6, 2, 1, 8.
• In the first pass the initial key is defined as 6 and compared with 4. As 6 is larger than 4 hence the posi-
tion of 6 remains as it is.
• In the second pass element 2 is compared with the initial key 6 and 4 and element 2 is placed
appropriately. That is, its position is now at first.
• In pass three the element 1 is compared with the earlier three elements and placed appropriately. Its
position is shown in Fig. 11.1.
• In pass 4 the last element 8 is compared with the initial key and it is found greater. Hence, it is placed
on the right side of 6.
The final sorted list appears as 1, 2, 4, 6, 8.
Thus, in the insertion sort we are actually finding the proper place for the element to insert with respect
to the key.
Here, a program is provided on insertion sort.

Example 11.1 Write a program to sort array elements using insertion sort.

# include <stdio.h>
# include <conio.h>

void main()
{
int nums[20],p=0,q=1,r,num;
clrscr();
printf("Enter number of elements:");
scanf("%d",&num);
printf("\n Enter %d elements:",num);
while(p<num)
scanf("%d", &nums[p++]);
while(q<num)
{
r=nums[q];
for(p=q-1;p>=0 && r<nums[p];p––)
nums[p+1]=nums[p];

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 3 3/2/2012 6:59:13 PM


11.4 Data Structures Using C

nums[p+1]=r;
printf("Element %d inserted in appropriate place",r);
p=0;
while(p<num)
printf("%d ", nums[p++]);
printf("\n");
q++;
}
printf("Sorted elements are : ");
for(p = 0; p < num; p++)
printf("%d ", nums[p]);
}

OUTPUT
Enter number of elements: 5
Enter 5 elements: 4 6 2 1 8
Element 6 inserted in appropriate place 4 6 2 1 8
Element 2 inserted in appropriate place 2 4 6 1 8
Element 1 inserted in appropriate place 1 2 4 6 8
Element 8 inserted in appropriate place 1 2 4 6 8
Sorted elements are: 1 2 4 6 8

Explanation:
In this program, the nested while loops are used. The variable q is initialized with 1 and p
with 0. The variable r inside the while loop is used to take elements from array and the same
element is compared with remaining elements. The ‘for’ loop inside the while loop executes
if p>=zero and r (recently assigned value of array element) less than other elements, the
insertion is carried out.

Example 11.2 Write a program to sort given list of elements by using insertion sort. Use pointer.

# include <stdio.h>
# include <conio.h>

void main()
{
int ls[5],limit,*pt,p=0,q=0,tem;
pt=&ls[0];
clrscr();
printf("How many numbers would you like to sort?-");
scanf("%d",&limit);
printf("Enter %d elements:-",limit);
while(q<limit)
scanf("%d",&ls[q++]);
for(q=1;q<limit;q++)
{
tem=*(pt+q);
for(p=q-1;p>=0 && tem<*(pt+p);p––)
*(pt+p+1)=*(pt+p);
*(pt+p+1)=tem;
}

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 4 3/2/2012 6:59:13 PM


Sorting 11.5

printf("Sorted elements are:- ");


for(p = 0; p <limit; p++)
printf("%d ", ls[p]);
}

OUTPUT
How many numbers would you like to sort?-4
Enter 4 elements:-12 3 1 2
Sorted elements are:- 1 2 3 12

Explanation:
In this program, the limit or the array is made available with variable limit. The variable *pt is
used for storing the starting address of the array element. With address location list is sorted
by using the insertion sort method.

Time Complexity of Insertion Sort in Worst Case Consider an example to sort the 5 elements 9, 8, 7, 6
and 5. The comparisons are shown in the different passes in Fig. 11.2.

Number of
Comparisons

P=1 9 8 7 6 5 1

P=2 8 9 7 6 5 2

P=3 7 8 9 6 5 3

P=4 6 7 8 9 5 4

Total
Sorted 5 6 7 8 9 10
Comp
List

Figure 11.2 Insertion Sort in Worst Case

The number of comparisons in worst case can be calculated by referring to Fig. 11.2. The comparisons
in the different passes are made as follows:
1. In pass =1 only one comparison is made between the elements 9 and 8.
2. Pass =2 contains the two comparisons the element 7 is compared with 9 and 8.
3. Three comparisons are made in the pass=3. The element 6 is compared with 7, 8 and 9.
4. Four comparisons are made in the pass=4. The element 5 is compared with 6, 7, 8 and 9.
The total comparisons in the sorting method in worst case = 1+2+3+4=10.
Thus, theoretically f(n) = n(n–1)/2 =5(5–1)/2=10.
Practical values of comparisons are equal to the theoretical value.

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 5 3/2/2012 6:59:13 PM


11.6 Data Structures Using C

11.4 SELECTION SORT

The selection sort is nearly the same as exchange sort. Assume, we have a list containing n elements. By
applying selection sort, the first element is compared with all remaining (n–1) elements. The smallest ele-
ment is placed at the first location. Again, the second element is compared with remaining (n–2) elements.
If the item found is lesser than the compared elements in the remaining (n–2) list then the swap operation
is done. In this type, entire array is checked for the smallest element and then swapped.
Figure 11.3 illustrates the process of sorting elements by selection sort. In each pass, one element is
sorted and kept at the left. Initially, the elements are temporarily sorted and after next pass, they are per-
manently sorted and kept at the left. Permanently sorted elements are covered with squares and temporar-
ily with circles. Element inside the circle “O” is chosen for comparing with the other elements marked in
a circle and sorted temporarily. Sorted elements inside the square “” are shown.

No. 1 2 3 4 5
Pass

1 2 6 4 8 5

2 2 6 4 8 5

3 2 4 6 8 5

4 2 4 5 8 6

5 2 4 5 6 8

SList 2 4 5 6 8

Figure 11.3 Selection Sort

Consider the elements 2, 6, 4, 8, and 5 for sorting under selection sort method.
1. In pass 1, select element 2 and check it with the remaining elements 6, 4, 8, and 5. There is no smaller
value than 2, hence the element 2 is placed at the first position.
2. Now, select element 6 for comparing with remaining (n–2) elements, i.e. 4, 8, and 5. The smaller
element is 4 than 6. Hence, we swap 4 and 6 and 4 is placed after 2.
3. Again, we select the next element 6 and compare it with the other two elements 8 and 5 and swapping
is done between 6 and 5.
4. In the next pass element 8 is compared with the remaining one element 6. In this case, 8 is swapped with 6.
5. In the last pass the 8 is placed at last because it is the highest number in the list.

Time Complexity The performance of sorting algorithm depends upon the number of iterations and
time to compare them. The first element is compared with the remaining n–1 elements in pass 1. Then,
n–2 elements are taken in pass 2. This process is repeated until the last element is encountered. The
mathematical expression for these iterations will be equal to (n–1)+(n–2)+ ... +(n– (n–1)). Thus, the
expression become n*(n–1)/2.

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 6 3/2/2012 6:59:13 PM


Sorting 11.7

Thus, the number of comparisons is proportional to (n2). The time complexity of selection sort is
O(n2).

Comparison with Other Methods 1. This method requires more number of comparisons than quick sort,
tree sort. 2. It is easier to implement than other methods such as quick sort, tree sort. 3. The performance
of the selection sort is quicker than bubble sort.

Example 11.3 Write a program to sort elements of an array using selection sort.

# include <stdio.h>
# include <conio.h>

void main()
{
int nums[15], p=0,q,r,num,t,small;
clrscr();
printf("How many elements to sort ? : ");
scanf("%d",&num);

printf("Enter %d elements : ":,num);

while(p<num)
scanf("%d", &nums[p++]);
for(p=0; p<num-1;p++)
{
small = p;
for(r=p+1; r<num;r++)
if(nums[small] > nums[r])
small = r ;
if( p != small )
{
t = nums[p];
nums[p] = nums[small];
nums[small] = t ;
}
printf("\nAfter %d pass elements are: ",p+1);
q=0;
while(q<num)
printf(" %d ", nums[q++]);
}
printf("\nSorted elements are: ");
p=0;
while(p < num)
printf("%d ", nums[p++]);
}

OUTPUT
How many elements to sort? : 5
Enter 5 elements: 8 6 4 2 5
After 1 pass elements are: 2 6 4 8 5
After 2 pass elements are : 2 4 6 8 5
After 3 pass elements are : 2 4 5 8 6
After 4 pass elements are : 2 4 5 6 8
Sorted elements are: 2 4 5 6 8

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 7 3/2/2012 6:59:14 PM


11.8 Data Structures Using C

Explanation:
This program of selection sort uses nested loops. Using nested loops array elements are
compared with one another. The value of loop variable p is assigned to variable small.
The inner loop executes from (p+1) to num, in which the number present at array position
nums[small] if greater than nums[r], the location indicated by r is assigned to small. The
next if() block carries swapping of elements. Thus, all array elements are compared and
necessary swapping is done.

11.5 BUBBLE SORT

Bubble sort is a commonly used sorting algorithm. In this type, two successive elements are compared and
swapping is done if the first element is greater than the second one. The elements are sorted in ascending
order. It is easy to understand but it is time consuming.
Bubble sort is an example of exchange sort. In this method repetitively comparison is performed between
the two successive elements and if essential swapping of elements is done. Thus, step-by-step entire array
elements are checked. It is different from the selection sort. Instead of searching the minimum element
and then applying swapping, two records are swapped instantly upon noticing that they are not in order.
The Fig. 11.4 illustrates the exchange sort.

Initial List 9 5 1 4 3

Pass 1 5 1 4 3 9

Pass 2 1 4 3 5 9

Pass 3 1 3 4 5 9

Figure 11.4 Bubble Sort

Let us consider the elements 9, 5, 1, 4, and 3 for sorting under bubble sort.
1. In pass 1, first element 9 is compared with its next element 5. The next element is smaller than 9.
Hence, it is swapped. Now, the list is 5, 9, 1, 4, 3. Again 9 is compared with the next element 1. The
next element is smaller than 9. Hence, swapping is done. The same procedure is done with 4 and 3
and at last we get the list as 5, 1, 4, 3, 9.
2. In pass 2, the elements of pass 1 are compared. The first element 5 is compared with its next element
1, 5 and 1 are swapped because 1 is smaller than 5. Now, the list becomes 1, 5, 4, 3, 9. Next, 5 is com-
pared with element 4. Again, 5 and 4 are swapped. This process is repeated until all successive elements
are compared and if the succeeding number is smaller than the present number then the numbers are
swapped. The final list at the end of this pass is 1, 4, 3, 5, 9.

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 8 3/2/2012 6:59:14 PM


Sorting 11.9

3. In pass 3, the first element 1 is compared with the next element 4. The element 4 is having the higher
value than the first element 1, hence they remain at their original positions. Next, 4 is compared with
the subsequent element 3 and swapped due to smaller value of 3 than 4.
4. At last, the sorted list obtained is 1, 3, 4, 5, 9.

Example 11.4 Write a program to sort a given array by using the bubble sort.

# include <stdio.h>
# include <conio.h>

void main()
{
int a[5],i,j,temp;
clrscr();
printf("Enter the elements of an array : ");
for(i=0;i<5;i++)
scanf("%d",&a[i]);
for(i=0;i<5;i++)
{
for(j=i;j<4;j++)
{
if(a[i]>a[j+1])
{
temp=a[i];
a[i]=a[j+1];
a[j+1]=temp;
}
}
}
printf("Sorted elements in ascending order : ");
for(i=0;i<5;i++)
printf(" %d ",a[i]);
}

OUTPUT
Enter the elements of an array: 9 5 1 4 3
Sorted elements in ascending order: 1 3 4 5 9

Explanation:
In this program an array of five elements is declared. The variable j and i are loop variables. The
variable i is used in the outer loop and j is used in the inner loop. The ‘if ’ statement checks the
number, it compares every current element denoted by ith location with (j+1)th element. If the
number ith is greater, it is assigned to temp. The smaller number is assigned to ith location and temp
(holds larger number) assigned to (j+1)th location. Thus, by exchange elements are sorted.

Time Complexity The performance of bubble sort in worst case is n (n–1)/2. This is because in the
first pass n–1 comparisons or exchanges are made; in the second pass n–2 comparisons are made. This is
carried out until the last exchange is made. The mathematical representation for these exchanges will be
equal to (n–1)+(n–2)+ ... +(n– (n–1)). Thus, the expression becomes n*(n–1)/2.
Thus, the number of comparisons is proportional to (n2). The time complexity of bubble sort is 0 (n2).

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 9 3/2/2012 6:59:14 PM


11.10 Data Structures Using C

11.6 QUICK SORT

It is also known as partition exchange sort. It was invented by CAR Hoare. It is based on partition.
Hence, the method falls under divide and conquer technique. The main list of elements is divided into
two sub-lists. For example, a list of X elements are to be sorted. The quick sort marks an element in a
list called as pivot or key. Consider the first element J as a pivot. Shift all the elements whose value is
less than J towards the left and elements whose value is greater than J to the right of J. Now, the key
element divides the main list into two parts. It is not necessary that selected key element must be in the
middle. Any element from the list can act as key element. However, for best performance preference
is given to middle elements. Time consumption of the quick sort depends on the location of the key
in the list.
Consider the following example in which five elements 8, 9, 7, 6, 4 are to be sorted using quick sort.
Figure 11.5 illustrates it.

Pass 1

Iteration 1 8 9 7 6 4

Iteration 2 4 9 7 6 8

Iteration 3 4 8 7 6 9

Iteration 4 4 6 7 8 9

Figure 11.5 Quick Sort

Consider pass 1 under which the following iterations are made. Similar operations are done in pass 2,
pass 3, etc.
In iteration 1 the first element 8 is marked as pivot one. It is compared with the last element whose
value is 4. Here, 4 is smaller than 8 hence the numbers are swapped. Iteration 2 shows the swapping
operation.
In iteration 2, 8 and 9 are compared and swapping is done after iteration 2.
In iteration 3, 8 and 6 are compared and necessary swapping is done. After this, it is impossible to
swap. Hence, the position of 8 is fixed. Because of fixing the position of 8 the main list is divided into
two parts. Towards the left of 8 elements smaller than 8 are placed and towards the right greater than 8
are placed.
Towards the right of 8 only one element is present hence there is no need of further swapping. This may
be considered under pass 2.
However, towards the left of 8 there are three elements and these elements are to be swapped as per the
procedure described above. This may be considered under pass 3.

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 10 3/2/2012 6:59:14 PM


Sorting 11.11

Example 11.5 Write a program to sort the array elements using quick sort.

# include <stdio.h>
# include <conio.h>

void main()
{
int nums[15],num,j=0;
int q_sort(int *,int,int);
int show(int *,int,int);
clrscr();
printf("Enter the number of elements : ");
scanf("%d",&num);
printf("\n Enter %d elements : ",num);
while(j<num)
scanf("%d",&nums[j++]);
q_sort(nums,0,num-1);
printf("Sorted list is :\n");
show(nums,0,num-1);
}
q_sort(int items[],int lower,int upper)
{
int key,temp,l,r,key_placed=0;
int show(int *,int,int);
l=lower;
r=upper;
key=lower;
if(lower>=upper) return 0;
while(key_placed==0)
{
while(items[key]<=items[r] && key!=r)
r––;
if(key==r) key_placed=1;
if(items[key] > items[r])
{
temp=items[key];
items[key]=items[r];
items[r]=temp;
key=r;
}
while(items[key]>=items[l] && l!=key) l++;
if(key==l) key_placed=1;
if(items[key] < items[l])
{
temp=items[key];
items[key]=items[l];
items[l]=temp;
key=l;
}
}
printf(" * Key Placed is %d -> ",items[key]);
show(items,lower,upper);

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 11 3/2/2012 6:59:14 PM


11.12 Data Structures Using C

printf("\n");

q_sort(items,lower,key-1);
q_sort(items,key+1,upper);
return 0;
}
show(int items[],int lower,int upper)
{
while(lower<=upper)
printf("%d ",items[lower++]);
return 0;
}

OUTPUT
Enter the number of elements: 5
Enter 5 elements: 8 9 7 6 4
* Key Placed is 8 -> 4 6 7 8 9
* Key Placed is 4 -> 4 6 7
* Key Placed is 6 -> 6 7
Sorted list is : 4 6 7 8 9

Explanation:
In this program the functions q_sort() and show() are defined. In q_sort() elements
are passed by value and address. The base address of an array nums is passed to function
q_sort(). The variable num holds total number of elements. The q_sort() function is
invoked recursively. In the first execution of q_sort(), value 0 is taken as lower key and (n-1)
is taken as upper key. If value of lower is greater than upper, the q_sort() function terminates.
The value of upper variable is assigned to r. The value of r is decremented continuously until it
reaches to key value. When the value of variables key and r are same the key is placed to one
and the while loop is terminated.The ‘if()’ statement carries swapping if element positioned at
value key is greater than element positioned at value r. The same procedure is carried out when
key is placed at one and swapping is carried out.

Time Complexity The efficiency of quick sort depends upon the selection of pivot. The pivot can
bifurcate the list into compartments. Sometimes, the compartments are having the same sizes or dissimilar
sizes. Assume a case in which pivot is in the middle. Thus, the total elements towards left of it and right
are equal. We can express the size of list with the power of 2. The mathematical representation for the size
is n=2s. The value of s can be calculated as log2 n.
After the first pass is completed there will be two compartments having equal number of elements, i.e.
n/2 elements are on the left side as well as right side. In the subsequent passes, four portions are made and
each compartment contains n/4 elements. In this way, we will be proceeding further until the list is sorted.
The number of comparisons in different passes will be as follows:
Pass 1 will have n comparisons. Pass 2 will have 2*(n/2) comparisons. In the subsequent passes will
have 4*(n/4), 8*(n/8) comparisons and so on. The total comparisons involved in this case would be
0 (n)+0 (n)+0 (n)+ ... +s. The value of expression will be 0 (n log n). Thus, time complexity of quick sort
is 0 (n log n).

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 12 3/2/2012 6:59:14 PM


Sorting 11.13

Comparison with Other Methods


1. This is the fastest sorting method among all.
2. It is somewhat complex, so little difficult to implement than other sorting algorithms.

11.7 TREE SORT

In binary tree, we know that the elements are inserted according to the value greater or less in between
node and the root in traversing. If the value is less than traversing node, insertion is done at left side. If the
value is greater than traversing node, it is inserted at right side. The elements of such tree can be sorted.
This sorting involves creation of binary tree and then in order traversing is done. Few examples are illus-
trated based on the tree such as inorder tree and heap sort.
Consider the list containing elements 1, 3, 4, 2, 9 for sorting. Figure 11.6 illustrates the inorder sort.
1. At first, element 1 is inserted in the tree as root node and element 3 is inserted at right to the root
because the inserted node is larger than the root. Figure 11.6 (a) explains it.
2. The element 4 is inserted at the right of the node 3 because it is larger than it. Insertion of element 4
is shown in Fig. 11.6 (b).
3. As per Fig. 11.6 (c) element 2 is inserted at the left of the node 3 due to lesser value.
4. At last, the element 9 is inserted at right of the node 4. This is shown in Fig. 11.6 (d).
5. The final binary tree is shown in Fig. 11.6 (e). Using the inorder traversing the sorted list is obtained.

1 1 1

3 3 3

4 2 4

(a) (b) (c)

1 1

3 3

2 4 2 4

9 9

(d) (e)

Figure 11.6 Inorder Tree Sort

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 13 3/2/2012 6:59:14 PM


11.14 Data Structures Using C

Example 11.6 Write a C program to insert nodes into a binary tree and to traverse in inorder.

# include <stdio.h>
# include <malloc.h>
# include <conio.h>
# include <process.h>

struct nodes
{
int data;
struct nodes *ls;
struct nodes *rs;
}*tree;

void main()
{
int number;
int insert(int);
int inorder(struct nodes *);
int search(int ele,struct nodes **p,struct nodes **l);
tree=0;
clrscr();
printf("Enter the numbers and 0 to exit :-");
while(1)
{
scanf("%d",&number);
if(number==0)
break;
insert(number);
}
printf("Inorder of the tree is as:-");
inorder(tree);
}
insert(int ele)
{
struct nodes *t,*father,*m_loc;
search(ele,&father,&m_loc);
if(m_loc!=0)
{
printf("Item already present");
return 0;
}
t=(struct nodes *)malloc(sizeof(struct nodes));
t->data=ele;
t->ls=0;
t->rs=0;
if(father==0)
tree=t;
else
if(ele<father->data)
father->ls=t;
else
father->rs=t;
return 0;
}

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 14 3/2/2012 6:59:14 PM


Sorting 11.15

inorder(struct nodes *pr)


{
if(tree==0)
{
printf("Tree is empty");
return 0;
}
if(pr!=0)
{
inorder(pr->ls);
printf("%d ",pr->data);
inorder(pr->rs);
}
return 0;
}
search(int ele,struct nodes **p,struct nodes **l)
{
struct nodes *pr,*p_s;
if(tree==0)
{
*l=0;
*p=0;
return 0;
}
if(ele==tree->data)
{
*l=tree;
*p=0;
return 0;
}
if(ele<tree->data)
pr=tree->ls;
else
pr=tree->rs;
p_s=tree;
while(pr!=0)
{
if(ele==pr->data)
{
*l=pr;
*p=p_s;
return 0;
}
p_s=pr;
if(ele<pr->data)
pr=pr->ls;
else
pr=pr->rs;
}
*l=0;
*p=p_s;
return 0;
}

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 15 3/2/2012 6:59:14 PM


11.16 Data Structures Using C

OUTPUT
Enter the numbers and 0 to exit :-12 3 53 5 0
Inorder of the tree is as:-3 5 12 53

Explanation:
In this program, insert() and inorder()are user defined functions. The insert()
function is invoked to insert the value in the binary tree. When entered number is zero, the
insertion operation is terminated. The inorder() is used for traversing the binary tree. This
function is used for getting the sorted list.

11.8 MERGE SORT

Merging is a process in which two lists are merged to form a new list. The new list is termed as the sorted list.
Before merging, individual lists are sorted and then merging is done. The procedure is very straightforward.
Consider two arrays containing integer elements. The elements of the first array are added successively.
The result of the addition of all the elements of the first array is added with the successive elements of the
second array. Thus, one obtains the summation of all the elements of two arrays. Initially, sum is assumed
to 0. Successively, addition of elements is carried out with the sum. It is then compared with the elements
of the two arrays. In case there is no match, the assumed value is incremented till it matches the array
element value (ascending order). This process is repeated till the assumed value reaches the obtained sum.
A program on merge sort is discussed below.

Example 11.7 Write a program to create two arrays containing integer elements. Sort and store
the elements of both the arrays in the third list.

# include <stdio.h>
# include <conio.h>
# include <math.h>

void main()
{
int m,n,p,sum=0;
int a[5],b[5],c[10];
clrscr();
printf("\n Enter elements for first list : ");
for(m=0;m<5;m++)
{
scanf("%d",&a[m]);
if(a[m]==0)
m--;
sum=sum+abs(a[m]);
}
printf("\n Enter elements for second list : ");
for(n=0;n<5;n++)

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 16 3/2/2012 6:59:14 PM


Sorting 11.17

{
scanf("%d",&b[n]);
if(a[n]==0) n--;
sum=sum+abs(b[n]);
}
p=n=m=0;
m=m-sum;
while(m<sum)
{
for(n=0;n<5;n++)
{
if(m==a[n] || m==b[n])
c[p++]=m;
if(m==a[n] && m==b[n])
c[p++]=m;
}
m++;
}

puts(" Merged sorted list : ");


for(n=0;n<10;++n)
printf(" %d ",c[n]);
return 0;
}

Output:
Enter elements for first list: 1 4 2 6 7
Enter elements for second list: 9 5 3 0 8
Merged sorted list :
0 1 2 3 4 5 6 7 8 9

Explanation:
In the above program, three arrays a[], b[] and c[] are declared. Using for loop, elements
in a[] and b[] are declared. The sum of all the ten elements entered in both the arrays is taken
as the variable sum. The while and nested for loop checks the corresponding elements of
both the lists:
a) If one of the corresponding elements is the same, that element is stored in the c[]
array.
b) If both the corresponding elements are same, they are stored in successive locations in
the c[].
The value of m is initially zero. The sum obtained is again subtracted from m. This is because
negative numbers have to be considered while sorting. For example, the value of sum = 20. In
real execution, the sum may be different depending on the integers entered.
Value of m would be m = –20 (as m = m – 20 when m = 0)
Thus, in the while loop, the value of m varies from –20 to 20. All the entered elements
are covered in this range. The value of m changes from –20 to 20, i.e. –20, –19 up to +20 in
ascending order. Thus, the same order is applied while saving element in c[].

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 17 3/2/2012 6:59:14 PM


11.18 Data Structures Using C

Alternately, the process of merge sort can be performed as follows: In the following program, the elements
of two arrays are compared position-wise. The element which appears to be smaller is placed in the third
array. If all the elements of any one of the arrays are compared completely, then elements from the array con-
taining large elements are placed in the third array. The following program is based on the above concept.

Example 11.8 Write a program to implement merge sort.

# include <stdio.h>
# include <conio.h>
void main()
{
int i=0,j=0,k=0,n1,n2;
int a[]={6,9,17,23};
int b[]={7,16,45,48};
static int c[30];
clrscr();

while(i<4 && j<4)


{
if(a[i]<b[j])
{
c[k]=a[i];
i++;
}

else
{
c[k]=b[j];
j++;
}

k++;
}

while(i<4)
{
c[k]=a[i];
i++;
k++;
}

while(j<4)
{
c[k]=a[j];
j++;
k++;
}

printf(“\nElements after Merge-sort are as follows:”);


for(int w=0;w<k;++w)
{
printf(“ %d”,c[w]);
}

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 18 3/2/2012 6:59:14 PM


Sorting 11.19

getche();
}

Output:
Elements after merge sort are as follows: 6 7 9 16 17 23 17 23

Alternately, the merge sort of array elements can be done using the following method.
Consider a list of 9 elements. They are as follows:
21, 12, 34, 3, 7, 11, 9, 23, 4
Pass 1: In merge sort, the list is first divided into pairs containing two elements. These can be shown
as follows. If numbers are even, then exact pairs are possible. In this case, nine numbers are assumed for
selection. Therefore, 5 pairs are possible. They are as follows.
21 12 34 3 7 11 9 23 4
After dividing the list into pairs, sort the elements of each pair.
12 21 3 34 7 11 9 23 4
Pass 2: Merge the pairs after sorting in the first pass. The elements appear as follows.
12 21 3 34 7 11 9 23 4
Sort the elements of the above merged pairs. The elements will be as follows after sorting.
3 12 21 34 7 9 11 23 4
Pass 3: Again merge two groups as follows.
3 12 21 34 7 9 11 23 4
Sort the elements of the merge groups.
3 7 9 11 12 21 23 34 4
Pass 4: Merge element 4 with the remaining elements.
3 7 9 11 12 21 23 34 4
All the elements get sorted in the last pass.
3 4 7 9 11 12 21 23 34
In the following program, we divide the elements of an array recursively in smaller groups and perform
sorting operations.

Example 11.9 Write a program to implement merge sort based on the above concept.

# include <stdio.h>
# include <conio.h>
int a[5],b[5];
void merge(int,int,int);
void merge_sort(int,int);
void main()
{
int i,n;
clrscr();
printf(“\nEnter the number of elements of the array:”);
scanf(“ %d”,&n);

printf(“\n Enter the elements of the array:”);


for(i=0;i<n;i++)

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 19 3/2/2012 6:59:14 PM


11.20 Data Structures Using C

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

merge_sort(0,n-1);
printf(“\nElements after Merge-sort are as follows:”);

for(i=0;i<n;i++)
{
printf(“ %d”,a[i]);
}
getche();
}

void merge_sort(int low,int high) /*low = initial position && high = Final
position */
{
int mid;
if(low<high)
{
mid=(low+high)/2;
merge_sort(low,mid);
merge_sort(mid+1,high);
merge(low,mid,high);
}
}
void merge(int low,int mid,int high)
{
int h=low,i=low,j=mid+1,k;
while((h<=mid)&&(j<=high))
{
if(a[h]<=a[j])
{
b[i]=a[h];
h++;
}
else
{
b[i]=a[j];
j++;
}
i++;
}

if(h<=mid)
{
for(k=h;k<=mid;k++)
{
b[i]=a[k];
i++;
}
}

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 20 3/2/2012 6:59:15 PM


Sorting 11.21

else
{
for(k=j;k<=high;k++)
{
b[i]=a[k];
i++;
}

for(k=low;k<=high;k++)
{
a[k]=b[k];
}
}

Output:
Enter the number of elements of the array: 5
Enter the elements of the array: 1 7 3 0 5
Elements after merge sort are as follows: 0 1 3 5 7

11.9 HEAP SORT

In heap sort, we use the binary tree in which the nodes are arranged in specific prearranged order. The
rule prescribes that each node should have bigger value than its child node. The following steps are to be
followed in heap sort:
1. Arrange the nodes in the binary tree form.
2. Node should be arranged as per the specific rules.
3. If the inserted node is bigger than its parent node then replace the node.
4. If the inserted node is lesser than its parent node then do not change the position.
5. Do not allow entering nodes on right side until the child nodes of the left are fulfilled.
6. Do not allow entering nodes on left side until the child nodes of the right are fulfilled.
7. The procedure from step 3 to step 6 is repeated for each entry of the node.
Consider the numbers 56, 23, 10, 99, 6, 19, 45, 45, 23 for sorting using heap. Sorting process is
illustrated in Fig. 11.7.
1. At first, we pickup the first element 56 from the list. Make it as the root node.
2. Next, take the second element 23 from the list. Insert this to the left of the root node 56. Refer the
Fig. 11.7 (2).
3. Then, take the third element 10 from the list for insertion. Insert it to the right of the root node.
4. Take the fourth element 99. Insert it to the left side node 23. The inserted element is greater than the parent
element, hence swap the 99 with 23. But the parent node 56 is smaller than the child node 99 hence 99
and 56 are swapped. After swapping 99 becomes the root node. This is shown in Fig. 11.7 (4) and (5).
5. Consider the next element 6 to insert in the tree. Insert it at left side. There exists left node, hence
insert it to the right of the 56. Refer Fig. 11.7 (6).

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 21 3/2/2012 6:59:15 PM


11.22 Data Structures Using C

6. Element 19 is inserted to the right side of 99 because the left side gets full. Insert the element 19 to the
right node 10. However, the parent element is lesser than the child, hence swaps 19 with 10.
7. Now, element 45 is to be inserted at the right side of 19. However, the parent element is having the
value lesser than the child element hence swap the 45 with 19. Refer the Fig. 11.7 (9) and (10).
8. Now, the right side is fully filled hence add the next element 45 to the left. The element 45 is inserted
at the last node of left, i.e. 23. However, the parent element is having the value lesser than the child
element hence swap 45 with 23. Refer the Fig. 11.7 (11) and (12).
9. Insert the last element 23 to the left side node, i.e. 45. The left of the 45 is already filled hence insert
the element 23 at the right of the 45. Refer the Fig. 11.7 (13).
10. At last, we get a sorted heap tree, as shown in Fig. 11.7 (13).

Time Complexity We know that the depth of the complete binary tree is (log2n). In worst case, the
number of comparisons in each step would be equal to the depth of the tree. The number of comparisons
for the above observation would be O (n log2n). Thus, the number of comparisons in this method would
be O (n log2 n).

56 56 56

23 23 10
(1) (2) (3)

56 99

23 10 56 10

99 (4) 23 (5)

99 99

56 10
56 10

23 6
23 6 19

(6) (7)

Figure 11.7 (Continued)

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 22 3/2/2012 6:59:15 PM


Sorting 11.23

99 99

56 19 56 19

23 6 10 23 6 10 45

(8) (9)

99

56 45

23 6 10 19

(10)

99

56 45

45 6 10 19

23
(11)

99 99

56 45 56 45

45 6 10 19 45 6 10 19

23 23 23

(12) (13)

Figure 11.7 Heap Sort

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 23 3/2/2012 6:59:15 PM


11.24 Data Structures Using C

11.10 RADIX SORT

The radix sort is a technique, which is based on the position of digits. The number is represented with
different positions. The number has units, tens, hundreds positions onwards. Based on its position the
sorting is done. For example, consider the number 456, which is selected for sorting. In this number 6 is at
units position and 5 is at tens and 4 is at the hundreds position. 3 passes would be needed for the sorting
of this number with this procedure. In the first pass, we place all numbers at the unit place. In the second
pass all numbers are placed in the list with consents to the tens position digit value. Also, in the third pass
the numbers are placed with consent to the value of the hundreds position digit.
For example:
23,46,12,34,45,49,58,38,10,21.

In the first pass, the numbers are placed as per the value of the unit position digit. First, take number
23, which is present at the first in the list. Insert 23 in the packet labelled 3. Second number 46 is
inserted in packet 6. 12 is inserted in the packet 2. The number 34 is inserted in the packet 4. 45 in the
packet 5, 46 in the packet 6, 58 in the packet 8, 38 is also in the packet 8, 10 is in the packet 0 and 21
is in the packet 1. The numbers are inserted in the packets as per the sequence of that number in the
original list.

Table 11.1 Sorting the Numbers on Unit Place Digit


Pass 38
1st 10 21 12 23 34 45 46 58 49
Packets for unit place 0 1 2 3 4 5 6 7 8 9

In first pass sort the elements as per the value of the unit place digit. The operation is shown in the
above Table 11.1. After the first pass we get the following list as:
10,21,12,23,34,45,46,58,38,49.
Perform the second pass operation on the list, which is sorted list after the first pass. As per the values
of the digit of the tens position, the place of the elements is fixed. At first, take the first element 10 of the
list, which is obtained after the first pass. Insert 10 into the packet 1; insert 21 in the 2(second) packet.
This procedure is repeated until the end of the list. In the second pass, the numbers are as:

Table 11.2 Sorting the Numbers on Ten’s Place Digit

Pass 49
12 23 38 46
2nd 10 21 34 45 58
Packets for unit place 0 1 2 3 4 5 6 7 8 9

Table 11.2 shows the second pass for sorting the numbers. The sorted list after the second pass is as:
10,12,21,23,34,38,45,46,49,58.

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 24 3/2/2012 6:59:15 PM


Sorting 11.25

By appropriately placing numbers, the sorted list of the items or elements is obtained. In this example
of radix sort, two passes are required for complete sorting. The number of passes depends upon the length
of the greatest number in the list. If the list contains the numbers greater than 99, then the number of
passes must be greater than 3 or equal to 3.
Time Complexity Number of comparisons require for radix sort algorithm in the worst case f(n)=O(n2)
and in best case f(n)= O(n log2n).

Example 11.10 Write a program to sort the given single digit numbers by using the radix sort.

# include <stdio.h>
# include <conio.h>

void main()
{
static int bk[10][5],k1,k2,k3,k4,k5,k6,k7,k8,k9,k0,p;
int i,j,no_p,list[5],slist[5];
clrscr();
printf("Enter the one digit elements:-");
for(i=0;i<5;i++)
scanf("%d",&list[i]);
for(i=0;i<5;i++)
{
no_p=list[i]%10;
switch(no_p)
{
case 0: bk[0][k0++]=list[i]; break;
case 1: bk[1][k1++]=list[i]; break;
case 2: bk[2][k2++]=list[i]; break;
case 3: bk[3][k3++]=list[i]; break;
case 4: bk[4][k4++]=list[i]; break;
case 5: bk[5][k5++]=list[i]; break;
case 6: bk[6][k6++]=list[i]; break;
case 7: bk[7][k7++]=list[i]; break;
case 8: bk[8][k8++]=list[i]; break;
case 9: bk[9][k9++]=list[i]; break;
}
}
printf("The elements in table are:-");
printf("\n— — — — — — — — — — — — — — — — — — —");
printf("\n\t\t\tElements");
for(j=0;j<10;j++)
{
printf("\nElements in bucket %d:-",j);
for(i=0;i<5;i++)
if(bk[j][i]>0)
{
printf("%3d",bk[j][i]);
slist[p++]=bk[j][i];
}
}
printf("\n— — — — — — — — — — — — — — — — — — —");

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 25 3/2/2012 6:59:15 PM


11.26 Data Structures Using C

printf("\nThe sorted numbers:-");


for(i=0;i<5;i++)
printf("%2d",slist[i]);
}

OUTPUT
Enter the one digit elements:- 1 6 8 3 6
The elements in table are:
————————————————————————————
Elements
Elements in bucket 0:-
Elements in bucket 1:- 1
Elements in bucket 2:-
Elements in bucket 3:- 3
Elements in bucket 4:-
Elements in bucket 5:-
Elements in bucket 6:- 6 6
Elements in bucket 7:-
Elements in bucket 8:- 8
Elements in bucket 9:-
————————————————————————————
The sorted numbers:- 1 3 6 6 8

Explanation:
In this program the list[] is initialized to store the input numbers from the keyboard. The
static int bk[][] is used to store the numbers in the buckets 0 to 9. The k0 to k9 are the
variables, which are used to limit the buckets. The no_p variable stores the elements in buckets
by the switch() control statement. At last, the sorted list is stored into the slist[].

Example 11.11 Write a program to sort the given two digit numbers by using the radix
sort. Use function.

# include <stdio.h>
# include <conio.h>
int l[5],flag=0;

void main()
{
int i,j;
void place();
clrscr();
printf("Enter five elements with two digits:-“);
for(i=0;i<5;i++)
scanf("%d",&l[i]);
printf("\nThe first sorted table is");
place();
printf("\nFirst sorted list :-");
for(i=0;i<5;i++)
printf("%3d",l[i]);
flag=2;

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 26 3/2/2012 6:59:15 PM


Sorting 11.27

getch();
printf("\n\nThe final sorted table is");
place();
printf("\nFinal sorted list :-");
for(i=0;i<5;i++)
printf("%3d",l[i]);
getch();
}
void place()
{
int k1,k2,k3,k4,k5,k6,k7,k8,k9,k0;
int a,p,q,r;
int n,b[10][5]={0};
k0=k1=k2=k3=k4=k5=k6=k7=k8=k9=a=0;
while(a<5)
{
if(flag==2)
n=l[a]/10;
else
n=l[a]%10;
switch(n)
{
case 0: b[0][k0++]=l[a]; break;
case 1: b[1][k1++]=l[a]; break;
case 2: b[2][k2++]=l[a]; break;
case 3: b[3][k3++]=l[a]; break;
case 4: b[4][k4++]=l[a]; break;
case 5: b[5][k5++]=l[a]; break;
case 6: b[6][k6++]=l[a]; break;
case 7: b[7][k7++]=l[a]; break;
case 8: b[8][k8++]=l[a]; break;
case 9: b[9][k9++]=l[a]; break;
}a++;
}
r=0;
for(p=0;p<10;p++)
{
if(b[p][0]!=0)
printf("\nBucket %d contain:-",p);

for(q=0;q<5;q++)
if(b[p][q]>0)
{
printf("%3d",b[p][q]);
l[r++]=b[p][q];
}
}
}

OUTPUT
Enter five elements with two digits:-99 12 11 48 10
The first sorted table is
Bucket 0 contain:- 10
Bucket 1 contain:- 11
Bucket 2 contain:- 12
Bucket 8 contain:- 48

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 27 3/2/2012 6:59:16 PM


11.28 Data Structures Using C

Bucket 9 contain:- 99
First sorted list :- 10 11 12 48 99
The final sorted table is
Bucket 1 contain:- 10 11 12
Bucket 4 contain:- 48
Bucket 9 contain:- 99
Final sorted list :- 10 11 12 48 99

Explanation:
In this program function place() is used to sort the list. The variable n is used to store either
the reminder or quotient. The modulus operator is used for finding the unit place and the divide
operation for tens place. Then, these elements are stored in buckets by the switch() control
statement. After the first call of the place() the first sorted list is stored into the l[ ] and
after second call the final sorted list is placed into l[ ].

11.11 PARTITION EXCHANGE SORT

The partition exchange sort is the sorting technique in which list of elements is divided into the two sub-
parts. Using the pivot from the list makes the sublist of the list. The left part is called left sublist and the
right part is called right sublist. On the sublist quick or tree sort is performed and the two-sorted parts are
prepared and combined. For example, consider the following list:
24, 30, 27, 32, 11, 21, 19.

Assume the pivot key selected is 24 and the smaller numbers than pivot are shifted on its left side and
remaining greater elements to the right of it. The element 24 divides the list in two parts. The Fig. 11.8
shows the partition exchange sort.

Initial List for


24 30 27 32 11 21 19
Sort

Selecting 24 as
24 30 27 32 11 21 19
Pivot

Pivot Divides
11 21 19 24 30 27 32
List into 2 Parts

After Sorting 2
Lists the Final 11 19 21 24 27 30 32
Sorted List is

Figure 11.8 Partition Exchange Sort

After the swapping the elements towards left of the pivot:


11, 21, 19, 24, 30, 27, 32.

After removing 24 the two sublists become:


11, 21, 19 and 30, 27, 32.

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 28 3/2/2012 6:59:16 PM


Sorting 11.29

The left and right parts after sorting:


11, 19, 21
27, 30, 32

After combining the two parts including the pivot key the sorted list becomes:
11, 19, 21, 24, 27, 30, 32.
Following program is presented on the same concept.

Example 11.12 Write a program to sort the elements by using the partition exchange sort.

# include <stdio.h>
# include <conio.h>

int q_sort(int items[],int lower,int upper);


void main()
{
int arr[7],ltree[7],rtree[7];
int i=0,j,pivot,lcount=0,rcount=0;
clrscr();
printf("\nEnter the 7 elements:");
for(i=0;i<7;i++)
scanf("%d",&arr[i]);
printf("Enter pivot element:-");
scanf("%d",&pivot);
for(j=0;j<7;j++)
{
if(arr[j]<=pivot)
{
++lcount;
ltree[lcount]=arr[j];
}
if(arr[j]>pivot)
{
++rcount;
rtree[rcount]=arr[j];
}
}
q_sort(ltree,0,lcount);
for(j=0;j<lcount;j++)
printf("%d ",ltree[j]);
q_sort(rtree,0,rcount);
for(i=0;i<rcount;i++)
printf("%d ",rtree[i]);
}
int q_sort(int items[],int lower,int upper)
{
int key,temp,l,r,key_placed=0;
l=lower;r=upper;key=lower;
if(lower>=upper)
return 0;
while(key_placed==0)

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 29 3/2/2012 6:59:16 PM


11.30 Data Structures Using C

{
while(items[key]<=items[r] && key!=r)
r––;
if( key==r )
key_placed=1;
if( items[key] > items[r] )
{
temp=items[key];
items[key]=items[r];
items[r]=temp;
key=r;
}
while( items[key]>=items[l] && l!=key )
l++;
if(key==l)
key_placed=1;
if( items[key] < items[l] )
{
temp=items[key];
items[key]=items[l];
items[l]=temp;
key=l;
}
}
q_sort(items,lower,key-1);
q_sort(items,key+1,upper);
return 0;
}

OUTPUT
Enter the 7 elements:- 24 30 27 32 11 21 19
Enter pivot element:- 24
11 19 21 24 27 30 32

Explanation:
In this program seven elements are input for sorting into the arr[ ]. After selecting the
pivot key the elements whose values are lower than pivot key are placed into the ltree[ ]
otherwise [rtreel ]. Then the q_sort() is resurvey called for sorting the left as well
as right side elements of that pivot key. In the function q_sort() the values of the lower
and upper bound are checked. If the value of the lower bound is greater than or equal to the
upper bound then the function is terminated else the remaining elements are to be sorted.
After performing these operations the sorted list is obtained for the ltree[ ] as well as
rtree[ ].

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 30 3/2/2012 6:59:16 PM


Sorting 11.31

SUMMARY
1. Sorting is a process in which records are arranged in ascending or descending order.
2. This chapter presents information on various sorting methods; each of them is illustrated
with suitable example.
3. Insertion sort: In insertion sort the element is inserted at appropriate place. Here, a real
life example of playing cards can be quoted. The cards are kept in increasing order. The
card having least value is placed at the extreme left and the largest one at the other side.
In between them the other cards are inserted in ascending order.
4. Selection sort: The selection sort is almost same as exchange sort. By applying selection
sort, the first element is compared with remaining (n–1) elements. The smallest element
is placed at the first location. Again, the second element is compared with remaining (n–2)
elements. If the item found is lesser than the compared elements in the remaining n–2 list
then the swap operation is done. In this type, entire array is checked for the smallest ele-
ment and then swapped.
5. Bubble sort: Bubble sort is frequently used sorting algorithm. In this method, two succes-
sive elements are compared and exchanging is done if the first element is greater than the
second one. The elements are sorted in ascending order.
6. Quick sort: It is also recognized as partition exchange sort. This method also falls under
divide and conquer technique. The main list of elements is divided into two sub-lists. Any
one element from the list is marked as pivot key in the quick sort. Now, the pivot key
divides the main list into two parts. It is not necessary that selected key element must be
at middle.Any element from the list can act as key element. However, for best performance
preference is given to middle elements. Time consumption of the quick sort depends on
the location of the key in the list.
7. Tree sort: Inorder and heap sort methods are elaborated under tree sorting. Inorder tree
sorting method involves arranging the elements as per rules. In this method, firstly the left
element of tree is chosen, then node and right node.The rule for heap sort prescribes that
each parent node should have bigger value.
8. Heap sort: In heap sort, binary tree is used in which the nodes are arranged in specific
prearranged order. The rule prescribes that each node should have bigger value than its
child node. The heap sort process can be followed from the figure and example given in
this chapter.
9. Radix sort: The radix sort is based on the position of digits. Based on the positions of
digits sorting is done.
10. Partition exchange sort: The partition exchange sort divides the elements into the two
subparts. A pivot is selected among the elements. The elements whose values are smaller
than the pivot are shifted towards left of it. The right part has elements whose values are
greater than the pivot.

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 31 3/2/2012 6:59:16 PM


11.32 Data Structures Using C

EXERCISES
A. Answer the following questions:

1. What is sorting? How is sorting essential for data base applications?


2. Explain different types of sorting methods.
3. Distinguish between selection and exchange sort.
4. Explain the heap sort method.
5. How does the merge sort work?
6. How does radix sort work?
7. Explain the method of partition exchange sort.
8. Explain the insertion sort with its time complexity.
9. Compare the performance of selection and insertion sort.
10. How does the quick sort work? Explain with a suitable example.
11. Describe the working of tree sort.

B. Write following programs:

1. Apply selection sort on given ten numbers and sort them in ascending order.
2. Sort ten names of the students using merge sort.
3. Apply the quick sort to the given ten names and sort them in alphabetic order.
4. Write a program for sorting the given list by descending orders, using selection sort.
5. Apply tree-sorting method (inorder) on given ten numbers and arrange them in ascending
order.
6. Write a program by using heap sort for sorting given numbers.
7. Apply partition sort on twelve numbers.
8. Write a program for sorting two digit numbers using radix sort.
9. Write a function for bubble sort.
10. Use selection sort method for sorting five numbers using pointers.
11. Write a program to sort 15 elements using bubble sort. Assume any suitable elements.
12. Write a program to sort the elements 2,32,45,67,89,4,3,8,10 in descending order using inser-
tion sort.
13. Write a program to sort a given list of elements using tree sort.
14. Write a program to sort one digit number by using the radix sort method. Use pointer.
15. Write a program to sort the following numbers in ascending order using selection sort.
12,34,5,78,4,56,10,23,1,45,65.

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 32 3/2/2012 6:59:16 PM


Sorting 11.33

C. Select the appropriate option for each of the following questions:

1. The process of arranging records in ordered manner is called


(a) sorting (c) indexing
(b) searching (d) none of the above
2. In insertion sort, the shifting of numbers are:
(a) shift greater numbers at end and smaller at beginning of the array
(b) shift greater number at the middle and smaller at right
(c) shift smaller at the center and greater at beginning
(d) none of the above
3. In this type of sort list is divided in two sub-lists:
(a) quick sort (c) merge sort
(b) exchange sort (d) none of the above
4. The exchange sort is also called
(a) bubble sort (c) shell sort
(b) merge sort (d) none of the above
5. In the bubble sort the sorting is done with comparing
(a) successive elements (c) last and middle elements
(b) first and last elements (d) none of the above
6. In tree sort the elements are sorted with
(a) inorder traversing (c) post order traversing
(b) preorder traversing (d) none of the above
7. Radix sort method is based on
(a) the positions of the digits (c) the squares of digits
(b) the cubes of digits (d) none of the above
8. For sorting the elements with partition exchange sort which method is used?
(a) bubble sort (c) heap sort
(b) quick sort (d) none of the above
9. In heap sort the numbers are initially arranged in
(a) ascending order (c) binary tree
(b) descending order (d) none of the above
10. with merge sort number of list that can be sorted are
(a) one list (c) none of the above
(b) more than one lists

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 33 3/2/2012 6:59:16 PM


11.34 Data Structures Using C

D. What is the output of each of the following programs?

1. int ns[5],p=0,q=1,temp;
# include <stdio.h> clrscr();
# include <conio.h> printf("\n Enter 5 elements:");
while(p<5)
void main() scanf("%d", &ns[p++]);
{ for(q=1;q<5;q++)
static int b[10][7],k1,k2,k3,k4,k5, {
k6,k7,k8,k9,k0,p; temp=ns[q];
int i,j,no,l[7],sl[7]; for(p=q-1;p>=0 && temp<ns[p];p—)
clrscr(); ns[p+1]=ns[p];
printf("Enter elements <10:-"); ns[p+1]=temp;
for(i=0;i<7;i++) }
scanf("%d",&l[i]); printf("Sorted elements are:");
i=0; for(p = 0; p < 5; p++)
while(i<7) printf("%d ", ns[p]);
{ }
no=l[i]%10; 3.
switch(no) # include <stdio.h>
{ # include <conio.h>
case 0: b[0][k0++]=l[i]; break; void main()
case 1: b[1][k1++]=l[i]; break; {
case 2: b[2][k2++]=l[i]; break; int p=0,q,r,num,t,small;
case 3: b[3][k3++]=l[i]; break; int arr[5]={12,23,1,4,2};
case 4: b[4][k4++]=l[i]; break; clrscr();
case 5: b[5][k5++]=l[i]; break; for(p=0; p<4;p++)
case 6: b[6][k6++]=l[i]; break; {
case 7: b[7][k7++]=l[i]; break; small = p;
case 8: b[8][k8++]=l[i]; break; for(r=p+1; r<5;r++)
case 9: b[9][k9++]=l[i]; break; if(arr[small] > arr[r])
}i++; small = r ;
} if( p != small )
printf("The table is:-"); {
for(j=0;j<10;j++) t = arr [p];
{ arr[p] = arr[small];
printf("\nBucket %d contain:-",j); arr[small] = t ;
for(i=0;i<5;i++) }
if(b[j][i]>0) }
{ printf("\nSorted elements are:");
printf("%3d",b[j][i]); p=0;
sl[p++]=b[j][i]; for(p=0;p<5;p++)
} printf("%d", arr[p]);
} }
printf("\nSorted list:-");
for(i=0;i<7;i++) 4.
printf("%2d",sl[i]); # include <stdio.h>
# include <conio.h>
}
void main()
2. {
# include <stdio.h> int arr1[5]={12,3,122,321,1},i,j,t;
# include <conio.h> clrscr();
void main() for(i=0;i<5;i++)
{ for(j=i;j<4;j++)

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 34 3/2/2012 6:59:16 PM


Sorting 11.35

if(arr1[i]>arr1[j+1]) }
{ for(n=0;n<5;n++)
t=arr1[i]; {
arr1[i]=arr1[j+1]; sum=sum+l2[n];
arr1[j+1]=t; }
} p=n=m=0;
for(i=0;i<5;i++) m=m-sum;
printf(" %d ",arr1[i]); while(m<sum)
} {
for(n=0;n<5;n++)
5. {
# include <stdio.h>
if(m==l1[n] || m==l2[n])
# include <conio.h>
sl[p++]=m;
# include <math.h>
if(m==l1[n] && m==l2[n])
void main()
sl[p++]=m;
{
}
int m,n,p,sum=0,sl[10]={0};
m++;
int l1[5]={4,2,1,43,3},l2[5]={9,7,
}
6,8,5};
puts("Merged sorted list : ");
clrscr();
for(n=0;n<10;++n)
for(n=0;n<5;n++)
printf(" %d ",sl[n]);
{
}
sum=sum+l1[n];

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 35 3/2/2012 6:59:16 PM


This page is intentionally left blank.

M11_ASHOK NAMDEV KAMTHANE5067_01_SE_C11.indd 36 3/2/2012 6:59:16 PM


Chapter 12

Searching

CHAP TER O U T LIN E


12.1 Introduction 12.7 Division Method
12.2 Searching 12.8 Mid-square Method
12.3 Linear (Sequential) Search 12.9 Folding Method
12.4 Binary Search 12.10 Length-dependent Method
12.5 Hashing Method 12.11 Multiplicative Hashing Function
12.6 Hashing Function 12.12 Digit Analysis Method

12.1 INTRODUCTION

In our day-to-day life there are various applications, in which the process of searching is to be carried.
Searching a name of a person from the given list, searching a specific card from the set of cards, etc., are
few examples of searching.
A typical example where searching technique is applied is personal telephone diary. This diary is used
to store phone/mobile numbers of friends, relatives, etc. For searching the phone number of a person one
can directly search the number by using indexing in that diary. Quick search methods are to be adopted
to search the data from the heap or large records. Two processes such as searching and sorting are essential
for database applications.
In short, searching is a process in which a given record is searched from the set of records. Sorting is a
process in which records are arranged in ascending or descending order. A group of field is called record.
For example, consider the following structure:

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 1 3/2/2012 6:59:38 PM


12.2 Data Structures Using C

struct employee
{
char *name;
int age;
float height;
}s;

We are familiar with the above declarations and definitions. The object s contains three fields as
described in the structure. The database is a collection of such fields. Each record contains the above fields
or may vary depending upon the structure defined. The sorting can be done on any one or combination of
one or more fields. Suppose, we sort the records based on name. Then, the field name will be the key field.
A record is quickly searched in a sorted database. Thus, sorting and searching are very useful concepts of
data structure. This chapter aims to provide the information on searching and its techniques.

12.2 SEARCHING

Searching is a technique of finding an element from the given data list or set of the elements like an array,
list, or trees. It is a technique to find out an element in a sorted or unsorted list. For example, consider an
array of 10 elements. These data elements are stored in successive memory locations. We need to search
an element from the array. In the searching operation, assume a particular element n is to be searched.
The element n is compared with all the elements in a list starting from the first element of an array till
the last element. In other words, the process of searching is continued till the element is found or list is
completely exhausted. When the exact match is found then the search process is terminated. In case, no
such element exists in the array, the process of searching should be abandoned.
In case the given element is existing in the set of elements or array then the search process is said to be
successful as per Fig. 12.1. It means that the given element belongs to the array. The search is said to be
unsuccessful if the given element does not exist in the array as per Fig. 12.2. It means that the given ele-
ment does not belong to the array or collection of the items.
The complexity of any searching method is determined from the number of comparisons performed
among the collected elements in order to find the element. The time required for the operation is depen-
dent on the complexity of the operation or algorithm. In other words, the performance of searching
algorithm can be measured by counting the comparisons in order to find the given element from the list.
There are three cases in which an element can be found.
In the best case, the element is found during the first comparison itself. In the worst case, the element
is found only in the last comparison. Whereas in the average case, number of comparisons should be more
than comparisons in the best case and less than the worst case.
The searching can be classified into following types:
1. Linear search (sequential)
2. Binary search.

12.3 LINEAR (SEQUENTIAL) SEARCH

The linear search is a conventional method of searching data. The linear search is a method of searching
a target element in a list sequence. The expected element is to be searched in the entire data structure in
a sequential method from starting to last element. Though, it is simple and straightforward, it has serious

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 2 3/2/2012 6:59:38 PM


Searching 12.3

limitations. It consumes more time and reduces the retrieval rate of the system. The linear or sequential
name implies that the items are stored in systematic manner. The linear search can be applied on sorted
or unsorted linear data structure.
Figures 12.1 and 12.2 shows the searching by using the linear search method.

Figure 12.1 Successful Search

Figure 12.2 Unsuccessful Search

Example 12.1 Write a program to search an element from the entered numbers. Also, indicate its
position in case the element is found or unavailability.

# include<stdio.h>
# include<conio.h>

void main()
{
int sn,arr[10],a;
clrscr();
printf("Enter ten elements:-");
for(a=0;a<10;a++)
scanf("%d",&arr[a]);
printf("Enter the element to be searched:-");
scanf("%d",&sn);
a=0;
while(a<10)

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 3 3/2/2012 6:59:38 PM


12.4 Data Structures Using C

{
if(arr[a]==sn)
{
printf("The number %d is found %d location",sn,a+1);
break;
}
a++;
}
if(arr[a]!=sn)
printf("The element %d is not found",sn);
}

OUTPUT
Enter ten elements:-12 34 64 23 67 123 346 45 30 19
Enter the element to be searched:-64
The number 64 is found 3 location

Explanation:
In this program the user enters ten elements by involving an array arr[]. The number, which
is to be searched, is initialized with variable sn. By using the for loop ten elements are entered
into the arr[]. By using the while loop the number is searched throughout the array and
appropriate message is displayed.

Example 12.2 Write a program to search the element from the entered numbers using the pointer.

#include<stdio.h>
#include<conio.h>

void main()
{
int sno,i;
int ar[10],*list;
clrscr();
printf("Enter ten elements:-");
for(i=1;i<=9;i++)
scanf("%d",&ar[i]);
printf("Enter the element to be searched:-");
scanf("%d", &sno);
list=&ar[0];
for(i=0;i<=9;i++)
{
if(*list==sno)
{
printf("The number %d is found %d location",sno,i+1);
break;
}
list++;
}
if(*list!=sno)
printf("The element %d is not found",sno);
getch();
}

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 4 3/2/2012 6:59:38 PM


Searching 12.5

OUTPUT
Enter ten elements:-12 44 23 122 45 67 78 56 65 90
Enter the element to be searched:-67
The number 67 is found 6 location

Explanation:
In this program *list is a pointer variable which is used to store the address of the first
element of the array. Ten elements are entered into the arr[] by using the for loop. First
element address is stored into the *list variable. By increasing the address, all elements of the
array are accessed. If the match is found then message is displayed on screen.

Example 12.3 Write a program to create a linked list and search a specific element from the
linked list.

# include<stdio.h>
# include<conio.h>
# include<malloc.h>

struct link
{
int num;
struct link *next;
};
int j;
struct link begin;
void search(struct link*);
void create_list(struct link*);
void show(struct link *);
void create_list(struct link*link)
{
int n=1,c=1;
begin.next=NULL;
ink=&begin;
j=0;
printf("\n Input integers (0 to stop) :\n");
while (n)
{
printf("Enter the %d number:-",c);
scanf ("%d", &n);
if (n==0) break;
else link->next=(struct link*) malloc(sizeof(struct link));

link->num=n;
link=link->next;
link->next=NULL;
fflush(stdin);
c++;
}
}
void search(struct link *link)

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 5 3/2/2012 6:59:39 PM


12.6 Data Structures Using C

{
int node_num=0;
int s_node;
int flag=0;
link=&begin;
printf("\n Enter number to be searched : ");
scanf("%d",&s_node);
if(link==NULL)
printf("\n List is empty ");
while(link)
{
if(s_node==link->num)
{
printf("\n search is successful");
printf("\n Position of %d from beginning of the list : %d",s_node,node_
num+1);
link=link->next;
flag=1;
}
else
link=link->next;
node_num++;
}
if(!flag)
{
printf("\n Search is unsuccessful");
printf("\n %d does not found in the list", s_node);
}
}
void show(struct link * link)
{
link=&begin;
while(link->next)
{
printf(" %d",link->num);
link=link->next;
}
}
void main()
{
struct link *link=(struct link*) malloc(sizeof(struct link));
clrscr();
create_list(link);
printf("\n List :");
show(link);
search(link);
}

OUTPUT
Input integers(0 to stop):
Enter the 1 number:-12
Enter the 2 number:-23
Enter the 3 number:-34

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 6 3/2/2012 6:59:39 PM


Searching 12.7

Enter the 4 number:-45


Enter the 5 number:-56
Enter the 6 number:-76
Enter the 7 number:-0
List : 12 23 34 45 56 76
Enter number to be searched :34
search is successful
Position of 34 from beginning of the list :3

Explanation:
In this program, the struct link is used to store linked list. List is created with create()
function. The number, which is to be searched, is entered. In the search() function the
entered number is compared with the linked list elements. When equal number is found the
number along with its position in the linked list is displayed. The show() function is used to
display all the linked list elements. Thus, through traversing and comparing elements search
process is done.

12.4 BINARY SEARCH

The binary search approach is different from the linear search. Here, search of an element is not passed
in sequence as in the case of linear search. Instead, two partitions of lists are made and then the given ele-
ment is searched. Hence, it creates two parts of the lists known as binary search. Figure 12.3 illustrates the
operation of the binary search.
Binary search is quicker than the linear search. It is an efficient searching technique and works with
sorted lists. However, it cannot be applied on unsorted data structure. Before applying binary search, the
linear data structure must be sorted in either ascending or descending order. The binary search is unsuc-
cessful if the elements are unordered. The binary search is based on the approach divide-and-conquer.
In binary search, the element is compared with the middle element. If the expected element falls before
the middle element, the left portion is searched otherwise right portion is searched.
The binary searching method is illustrated in Fig. 12.3.

Linear Data Structure


1
Half 1 2

3 Given Element < 5


4 Search in Half 1
Middle
5
Element
6 Given Element > 4
7 Search in Half 2
Half 2
8

Figure 12.3 Binary Search

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 7 3/2/2012 6:59:39 PM


12.8 Data Structures Using C

Fig. 12.3 represents the operation of binary search. The total elements in the list are 8, and they are
shown in the ascending order. In case the key element is less than 5 then searching is done in lower half
otherwise in the upper half. The process of searching can be followed from Fig. 12.4.
Consider the array of seven elements. The array can be represented in Fig. 12.4 (a). The elements of an
array are 12, 14, 16, 19, 23, 27, and 31. Assume that we want to search the element 27 from the list of
elements. The steps are as follows:
Arr[0] Arr[1] Arr[2] Arr[3] Arr[4] Arr[5] Arr[6]
12 14 16 19 23 27 31

Figure 12.4 (a) Array in Memory

1. The element 12 and 31 are at positions first and last, respectively.


2. Calculate the mid-value which is as
MID=(FIRST+LAST)/2.
MID = (0+6)/2.
MID=3.
Refer to Fig. 12.4 (b), where the mid position of array is shown.
3. The key element 23 is to be compared with the mid-value. If the key is less than the mid then the key
element is present in the first half else in the other half; in this case the key is on the right half. Hence,
first is equal to middle+1.
First Middle Last

Arr Arr Arr


[0] [3] [6]

12 14 16 19 23 27 31

Figure 12.4 (b) Calculating the Middle at Starting


4. Calculate the middle of the second half.
MIDDLE=(FIRST+LAST)/2.
MIDDLE = (4+6)/2
MIDDLE=5.
5. Again, the middle divides the second half into the two parts, which is shown in Fig. 12.4 (c).
6. The key element 23 is lesser than the middle 27, hence it is present in the left half (towards the
left of 27).
Middle

Arr
[5]

12 14 16 19 23 27 31

Figure 12.4 (c) Finding Element in Second Half

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 8 3/2/2012 6:59:39 PM


Searching 12.9

7. At last, the middle is calculated as


MIDDLE = (FIRST + LAST)/2.
MIDDLE = (4+4)/2.
MIDDLE = 4.
8. Now, the middle is 4 position and the middle element is 23. The key is searched successfully, which is
shown in Fig. 12.4(d).
Middle

Arr
[4]

12 14 16 19 23 27 31

Figure 12.4 (d) Result of Searching


Based on the above concept an example is illustrated below.
Example 12.4 Write a program to sort an array elements using binary search.

# include<stdio.h>
# include<conio.h>

void main()
{
int items[20],s=0,e,n,j,num,mid;
clrscr();

printf("\n Enter number of elements : ");


scanf("%d",&n);
for(j=0;j<n;j++)
{
printf(" Enter element %d : ",1+j);
scanf("%d",&items[j]);
}

printf("\n Enter element to be searched :");


scanf("%d",&num);
e=n-1;
mid=(s+e)/2;
while(num!=items[mid] && s<=e)
{
if(num>items[mid])
s=mid+1;
else
e=mid-1;
mid=(s+e)/2;
}
if(num==items[mid])
printf("\n %d found at position %d ",num,++mid);

if(s>e) printf(" %d not found ", num);


getch();
}

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 9 3/2/2012 6:59:39 PM


12.10 Data Structures Using C

OUTPUT
Enter number of elements: 7
Enter element 1: 7
Enter element 2: 13
Enter element 3: 22
Enter element 4: 31
Enter element 5: 45
Enter element 6: 64
Enter element 7: 77
Enter element to be searched: 7
7 found at position 1

Explanation:
In this program an array items[20] elements is declared. The user is prompted to enter
number of elements to be in the list. The numbers are entered through the keyboard. The
variable s keeps track of the starting of list and the variable e keeps track of the end. The middle
is calculated with the formula mid =(s+e)/2;If the sum of (s+e) is odd number then the
result of division operation would be a float value. However, all the operands (s,e) of equation
are integers, the float value is converted to lowest integer.

The above explanation is illustrated with the following figure, which is self-explanatory.
S M E

7 13 22 31 45 64 77

S M E

7 13 22 31 45 64 77
S M E

7 13 22 31 45 64 77

Example 12.5 Write a program to demonstrate binary search. Use character array and store 10 names.

# include<stdio.h>
# include<string.h>
# include<conio.h>

void main()
{
int beg=1,mid,end=10,i,flag=0,val;
char name[15][10],fn[15];
clrscr();
printf("Enter 10 names :-\n");

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 10 3/2/2012 6:59:39 PM


Searching 12.11

for(i=1;i<11;i++)
scanf("%s",&name[i]);
printf("\n\tEnter the name to search:-");
scanf("%s",&fn);
mid=(beg+end)/2;
printf("\n\tAt starting beg is %d, mid is %d & end is %d",beg,mid,end);
while((strcmp(fn,name[mid]))!=0 && beg<=end)
{
val=strcmp(fn,name[mid]);
if(val>0)
{
beg=mid+1;
mid=(beg+end)/2;
printf("\n\tmid is %d & beg is %d",mid,beg);
}
else
{
end=mid-1;
mid=(beg+end)/2;
printf("\n\tmid is %d & end is %d",mid,end);
}
}
if(strcmp(fn,name[mid])==0){ flag=1;}
if(flag==1)
printf("\n\tThe name %s is traced successfully",fn);
else
printf("\n\tThe number %s is not traced",fn);
getche();
}

OUTPUT
Enter 10 names :-
ashish bhaskar deepak dinesh gajanan ganesh gopal govind raj ramash
Enter the name to search:-deepak
At starting beg is 1, mid is 5 & end is 10
mid is 2 & end is 4
mid is 3 & beg is 3
The name deepak is traced successfully
Enter 10 names :-
ashish bhaskar deepak dinesh gajanan ganesh goval govind raj ramesh
Enter the name to &arch;-amit
At starting beg is 1, mid is 5 & end is 10
mid is 2 & end is 4
mid is 1 & end is 1
mid is 0 & end is 0
The number amit is not traced

Explanation:
This program prompts the user to enter the names. They are stored in the name [15][10],
the fn [15] is used to store the name which we want to search. The program uses the binary
search to search the entered name. In the search method the user must enter the list of name in
ascending order. In this method first the mid is calculated by using beg and end.

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 11 3/2/2012 6:59:39 PM


12.12 Data Structures Using C

12.5 HASHING METHOD

Hashing technique is one of the complex searching techniques. In this section, we consider a class of
search techniques whose search time is dependent on the number of entries available in the table. In this
method, we fix the position of the key (element) into the table or the file, which is determined by the hash
function. The function in which we use this key is known as hashing function.
For example, we want to search a number from the ten numbers of a file. Then, we must find the
number throughout this range from the 1st number to 10th number. When we use the key for fixing its
position in a table then the number can be searched very easily.

12.6 HASHING FUNCTION

In order to follow the operation of hashing function, consider an array that comprises a list containing
some finite number of elements. Each element of it is a key. On performing operations on each key some
value is obtained. The key is assigned to the index, which is having the appropriate value. The table is
prepared with the keys called a hashing table.
Let us assume the following array that will hold the hash table:
12,22,32,17,19,28, 15,29,16,18,13,11.

Let us use the division method for the following hash table. We divide the key by ‘3’ and the key is
placed in the index based on the remainders obtained. The keys having equal remainders are placed in the
same index. Any number divided by 3 always returnes 0,1, or 2. Hash table is prepared with three indices
such as 0,1,2. All above keys are stored in these three indices as shown in Table 12.1.
Take the first key ‘12’, divide it by ‘3’. The reminder is ‘0’, hence insert it into the ‘0’ index.
Then, take the next key ‘22’ divide it by the ‘3’, the reminder is ‘1’. Hence, insert the key in to the ‘1’
index.
In the same way divide the key ‘32’ by the 3, its reminder is 2. Place it into the ‘2’ index in the table.
For the remaining elements, the same procedure is to be continued and by knowing reminders the
numbers can be placed appropriately in the respective index table.
Table 12.1 explains hashing table.

Table 12.1 Hash Table

Index Key

0 12, 15, 18
1 22, 19, 28, 16, 13
2 32, 17, 29, 11

In short, the hashing function takes the key, and maps it to some index to the array. In our example,
division function has been selected. The programmer can take any other function. This function maps
several different keys to the same index. In the above table, key 12,15 and 18 are assigned to the index 0.
While keys, 22, 19, 28, 16 and 13 are placed in index 1. Keys 32,17,29 and 11 are in the index 2.
After preparation of the index table, it becomes easier to search the element from the list. One can use
any searching method to search the element from the hashing table.
Consider the following program for preparation of an index using divide method.

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 12 3/2/2012 6:59:39 PM


Searching 12.13

Example 12.6 Write a program to prepare the hashing table. Enter the elements through the
keyboard and map them in index. Use the division function.

# include<stdio.h>
# include<conio.h>

void main()
{
int n[12],i0[12],i1[12],i2[12];
int rem,a=0,b=0,c=0,i,j;
clrscr();
printf("\nEnter the elements of array:-");
for(i=0;i<12;i++)
scanf("%d",&n[i]);
for(i=0;i<12;i++)
{
rem=n[i]%3;
if(rem==0)
{
a++;
10[a]=n[i];
}
else
{
if(rem==1)
{
b++;
i1[b]=n[i];
}
else
{
c++;
12[c]=n[i];
}
}
}
printf("\n\nThe Hashing Table is as follows\n");
printf("––––––––––––––––\n");
printf("Index 0 :-");
for(j=1;j<=a;j++)
printf("%5d",i0[j]);
printf("\nIndex 1 :-");
for(j=1;j<=b;j++)
printf("%5d",i1[j]);
printf("\nIndex 2 :-");
for(j=1;j<=c;j++)
printf("%5d",i2[j]);
printf("\n––––––––––––––––");
}

OUTPUT
Enter the elements of array:-12 22 32 17 19 28 15 29 16 18 13 11
The Hashing Table is as follows

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 13 3/2/2012 6:59:39 PM


12.14 Data Structures Using C

––––––––––––––––------------
Index 0 :- 12 15 18
Index 1 :- 22 19 28 16 13
Index 2 :- 32 17 29 11
––––––––––––––––-------------

Explanation:
In this program the main array 'n[12]' is declared having 12 elements. In addition to the
above i()[],il[] and i2[] arrays are initialized for storing the index. These arrays also
accommodate 12 elements. In the above program, we calculate the hashing table by using the
division method. The keys are divided by 3. Using the mod operation and the reminders are
computed, they are placed in the appropriate index.

Some of the hashing methods that are commonly used are stated below.

12.7 DIVISION METHOD

The commonly used hashing method is the division method. In this hashing function, the integer key is
divided by some number. The remainder value is taken as the hashing value. This method can be expressed
as follows:
H(k)=k(mod x)+1.
In above equation the H(k) is the hashing function. In addition, the k is the key, which is to be used in
hashing. The k(mod x) shows the result of division k by x.
In the above equation, the ‘k’ is the key and the ‘x’ is the size of list. We can take any value for the x.
For example, key is 25 and x=10
H(25)=25(mod 10)+1 =5+1=6.

Consider an example to prepare a hashing table and search the prompted number from the hashing
table. Each number (key) is divided (mod operation) by 3. No addition of 1 is done after division. It is
up to the user how to deal with the problem. The user can perform simply division operation and note
down the remainders and place them in appropriate index. As such, there will be 3 indices. The following
program illustrates this concept.

Example 12.7 Write a program for division method hashing, and find the given number from the
hashing table.

# include<stdio.h>
# include<conio.h>

void main()
{
int n[5],i0[5],i1[5],i2[5];
int num,rem,a=0,b=0,c=0,i,j;

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 14 3/2/2012 6:59:39 PM


Searching 12.15

clrscr();
printf("\nEnter the elements of array:-");
for(i=0;i<5;i++)
scanf("%d",&n[i]);
for(i=0;i<5;i++)
{
rem=n[i]%3;
if(rem==0)
{
a++;
i0[a]=n[i];
}
else
{
if(rem==1)
{
b++;
i1[b]=n[i];
}
else
{
c++;
i2[c]=n[i];
}
}
}
printf("\n\nThe Hashing Table is as follows\n");
printf("––––––––––––––––----------------------\n");
printf("Index 0 :-");
for(j=1;j<=a;j++)
printf("%5d",i0[j]);
printf("\nIndex 1 :-");
for(j=1;j<=b;j++)
printf("%5d",i1[j]);
printf("\nIndex 2 :-");
for(j=1;j<=c;j++)
printf("%5d",i2[j]);
printf("\n––––––––––––––––----------------------");
printf("\nEnter the key to search:-");
scanf("%d",&num);
rem=num%3;
if(rem==0)
{
for(j=1;j<=a;j++)
if(num==i0[j])
printf("\nThe position of the number is %d in the Index 0",j);
}
if(rem==1)
{
for(j=1;j<=b;j++)
if(num==i1[j])
printf("\nThe position of the number is %d in Index 1",j);
}

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 15 3/2/2012 6:59:40 PM


12.16 Data Structures Using C

if(rem==2)
{
for(j=1;j<=c;j++)
if(num==i2[j])
printf("\nThe position of the number is %d in the Index 2",j);
}
}

OUTPUT
Enter the elements of array:-4 11 5 17 23 12 10 13 6 21
The Hashing Table is as follows
––––––––––––––––----------------------
Index 0:- 12 6 21
Index 1:- 4 10 13
Index 2:- 11 5 17 23
––––––––––––––––----------------------
Enter the key to search:-23
The position of the number is 4 in the Index 2

Explanation:
In this program the main array 'n[]' is declared. In it, five elements are declared. In addition to
the above i0[],il[] and i2[] arrays are also initialized for storing the index. In the program, we
can calculate the hashing table by using the division method. The keys are divided by 3. Using the
mod operation, the remainders are calculated and are placed in the appropriate index.The number,
which is to be searched, is prompted through keyboard using variable num. The number is divided
by 3 and after knowing the reminder; the particular index is searched for searching the element.

Example 12.8 Write a program to prepare hashing table by division method. Use functions and
search number from the hashing table.

# include<stdio.h>
# include<conio.h>

void main()
{
void show(int *a,int *nos);
int search(int gno,int *arr, int lim);
int n[5],i0[5],i1[5],i2[5];
int num,rem,a=0,b=0,c=0,i,j;
clrscr();
printf("\nEnter the elements
of array:-");
for(i=0;i<5;i++)
scanf("%d",&n[i]);
for(i=0;i<5;i++)
{
rem=n[i]%3;

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 16 3/2/2012 6:59:40 PM


Searching 12.17

switch(rem)
{
case 0: a++; i0[a]=n[i]; break;
case 1: b++; i1[b]=n[i]; break;
case 2: c++; i2[c]=n[i]; break;
}
}
printf("\n\nThe Hashing Table is as follows\n");
printf("––––––––––––––––\n");
printf("Index 0 :-");
show( &i0[1],&a);
printf("\nIndex 1 :-");
show(&i1[1],&b);
printf("\nIndex 2 :-");
show(&i2[1],&c);
printf("\n––––––––––––––––");
printf("\nEnter the key to search:-");
scanf("%d",&num);
rem=num%3;
switch(rem)
{
case 0:
printf("\nThe position of the number is %d in the Index
0",search(num,&i0[1],a));
break;
case 1:
printf("\nThe position of the number is %d in Index
1",search(num,&i1[1],b));
break;
case 2:
printf("\nThe position of the number is %d in the Index
2",search(num,&i2[1],c));
break;
}
}
void show(int *a,int *nos)
{
int j;
for(j=1;j<=*nos;j++)
{
printf("%5d",*a);
a++;
}
}
int search(int gno,int *arr,int lim)
{
int j;
for(j=1;j<=lim;j++)
if(gno==*arr)
return j;
else
arr++;
}

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 17 3/2/2012 6:59:40 PM


12.18 Data Structures Using C

OUTPUT
Enter the elements of array:-12 34 65 23 10
The Hashing Table is as follows
––––––––––––––––-------------
Index 0 :- 12
Index 1 :- 34 10
Index 2 :- 65 23
––––––––––––––––-------------
Enter the key to search:-10
The position of the number is 2 in Index 1

Explanation:
In this program the division hashing method is used for storing the numbers. The i()[],il[],
and i2[] are three arrays, which are used for storing results. The variable a,b,c are used for
storing the boundaries of the buckets. The function show() is used to display the elements of
a bucket. Function search() is used for searching the given number into the three buckets. In
function, show() the two arguments are passed and they are the address of bucket array and
address of boundaries. Function search() contains three arguments address of bucket array,
value of boundaries, and the given number to search.

12.8 MID-SQUARE METHOD

In mid-square method the key is multiplied with itself and middle digit is chosen as the address of that
element in the hashing table. It is defined as follows:
H(k)=(k*k)
For example, if the key is k =12
H(12)=(12*12)=144.
In this example, the key is 12, its square is 144 and its middle digit is 4. Hence, 12 is placed in the hash table
in the index 4 as index 4 is the address of 12. Similarly, for other keys the squares are calculated and mid
digits are evaluated. Based on the mid digits the keys are placed in the appropriate index. Here, the mid digit
obtained can be from 0 to 9. Hence, we may need up to 10 indices starting from index 0 through index 9.
For example, if the key is k =10
H(10)=(10*10)=100. Its middle digit is 0. Hence, number 10 would be placed in index 0. Similarly,
the same procedure is adopted for all other numbers and they are placed in different indices based on the
mid digit value. Table 12.2 describes the above concepts.
Consider the following number for constructing the hashing table:
12,14,18,20,36,31,27,35,23,59.
Table 12.2 Table of Key, Square and Mid

Key Square Mid Key Square Mid


12 144 4 31 961 6
14 196 9 27 729 2
18 324 2 15 225 2
20 400 0 23 529 2
26 676 7 23 841 4

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 18 3/2/2012 6:59:40 PM


Searching 12.19

Hashing Table 12.3 is prepared for the above numbers.


Table 12.3 Hashing Table Using the Mid-Square Method
Mid Key Mid Key
0 20 5 –
1 – 6 31
2 18, 27, 15, 23 7 26
3 – 8 –
4 12, 29 9 14

A program is prepared for hashing table using the mid-square method.

Example 12.9 Write a program to display the hash table, which is to be prepared by using the mid-
square method.

# include<stdio.h>
# include<conio.h>

void main()
{
Int msarr[6]={18,21,29,27,12,11},ms1[6],ms2[6],ms3[6],ms4[6];
int a,i,m1,m2,m3,m4,smid;
int squ_mid(int);
void disp(int farr[],int count);
clrscr();
m1=m2=m3=m4=0;
printf("The numbers are as follows :-\n");
for(i=1;i<=7;i++)
printf("\t%d",msarr[i]);
for (a=1;a<7;a++)
{
smid=squ_mid(msarr[a]);
switch (smid)
{
case 1:
{m1++; ms1[m1]=msarr[a]; break;}
case 2:
{m2++; ms2[m2]=msarr[a]; break;}
case 3:
{m3++; ms3[m3]=msarr[a]; break;}
case 4:
{m4++; ms4[m4]=msarr[a]; break;}
}
}
printf("\n\nThe Hash Table with Mid-Square method is as follows");
printf("\n––––––––––––––\n");
printf("Index 1:-");
disp(ms1,m1);
printf("\nIndex 2:-");
disp(ms2,m2);

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 19 3/2/2012 6:59:40 PM


12.20 Data Structures Using C

printf("\nIndex 3:-");
disp(ms3,m3);
printf("\nIndex 4:-");
disp(ms4,m4);
printf("\n––––––––––––––\n");
}
int squ_mid(int ele)
{
int squ=0,mid,n;
squ=ele*ele;
for(n=0;n<2;n++)
{
mid=squ%10;
squ=squ/10;
}
return mid ;
}
void disp(int farr[],int count)
{
int a1;
for(a1=1;a1<=count;a1++)
printf("%5d",farr[a1]);
}
OUTPUT
The numbers are as follows:-
21 29 27 12 11 64 0
The Hash Table with Mid-Square method is as follows
––––––––––––––––-------------
Index 1:-
Index 2:- 27 11
Index 3:-
Index 4:- 21 29 12
––––––––––––––––-------------

Explanation:
In this program the main array 'msarr[]' having six elements are declared. In addition to the
above 'ml[]', 'm2[]', 'm3[]' and 'm4[]' are initialized. These arrays are initialized
for storing the index. Two functions are declared, they are squ_mid(); and dis(). These
two functions are initialized for finding the middle digit of the square and display the keys. By
using the mod operator, the middle digit of the square number is calculated. After finding the
middle digit they are displayed in the hash table.

12.9 FOLDING METHOD

In the folding method, the key is divided into number of parts. The parts, of course, are dependent on the
length of the key. All the parts are added together. If the carry results from this operation it is to be ignored
and the number what remains behind after ignoring the carry is the address of key. By using this method,
we fold the key hence this method is called as folding method.

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 20 3/2/2012 6:59:40 PM


Searching 12.21

For example,
1. If key k= 879987
Then, by using this method, we divide it into two parts like 879 and 987. They are added and then
carry ignored and the number after ignoring the carry becomes the address of the key.
879 +987 = 1866. Its most significant digit is 1. Hence, after ignoring 1, the number that is left is 866
which is the address of the key.
2. If k = 678897678
In this, key is divided into the 3 parts. They are 678, 897 and 678.
By adding, 678+897+678= 2253.
After ignoring last carry 2, the number that is left is 253. Therefore, 253 is the address of the key. Thus,
the folding method is useful in converting multiword key into a single word. By applying hashing func-
tion, the key can be identified. The reader can develop a program on the topic.

12.10 LENGTH-DEPENDENT METHOD

One more hashing technique used is length dependent method. In this method, the length of the key is
measured and the number is placed in the index table appropriately. Here, a simple program is made to
search an element from the array. The program is self-explanatory. Length of an array and length of each
element can be anything but some finite value can be taken.

Example 12.10 Write a program for searching an element by using the length dependent hash
function. Display the hash table and search the element from the table.

#include<stdio.h>
#include<conio.h>
void main()
{
int arr[5],in1[5],in2[5],in3[5],in4[5],in5[5];
int a,i,len,i1,i2,i3,i4,i5,snum;
int length(int);
void disp(int farr[],int count);
void search(int sarr[],int n,int co);
clrscr();
i1=i2=i3=i4=i5=0;
printf("\nEnter the number of the elements:-");
for(i=1;i<=5;i++)
scanf("%d",&arr[i]);
for (a=1;a<6;a++)
{
len=length(arr[a]);
printf("\nThe length of %d is:-%d",arr[a],len);
switch(len)
{
case 1:
{i1++;in1[i1]=arr[a]; break;}
case 2:
{i2++; in2[i2]=arr[a]; break;}

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 21 3/2/2012 6:59:40 PM


12.22 Data Structures Using C

case 3:
{i3++; in3[i3]=arr[a]; break;}
case 4:
{i4++; in4[i4]=arr[a]; break;}
case 5:
{i5++; in5[i5]=arr[a]; break;}
}
}
printf("\nThe Hash Table is as follows");
printf("\n––––––––––––––\n");
printf("Index 1:-");
disp(in1,i1);

printf("\nIndex 2:-");
disp(in2,i2);

printf("\nIndex 3:-");
disp(in3,i3);
printf("\nIndex 4:-");
disp(in4,i4);
printf("\nIndex 5:-");
disp(in5,i5);
printf("\n––––––––––––––\n");
printf("Enter the number to search;-");
scanf("%d",&snum);
len=length(snum);
switch(len)
{
case 1:
{search(in1,snum,i1);printf("in Index 1");break;}
case 2:
{search(in2,snum,i2);printf("in Index 2");break;}
case 3:
{search(in3,snum,i3);printf("in Index 3");break;}
case 4:
{search(in4,snum,i4);printf("in Index 4");break;}
case 5:
{search(in5,snum,i5);printf("in Index 5");break;}
}
}
int length(int ele)
{
int c=0,num;
while(ele>0)
{
if(ele>=10)
{
ele=ele/10;
c++;
}
else

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 22 3/2/2012 6:59:40 PM


Searching 12.23

{
c++;
break;
}
}
return c ;
}
void disp(int farr[],int count)
{
int a1;
for(a1=1;a1<=count;a1++)
printf("%5d",farr[a1]);
}
void search(int sarr[],int n,int co)
{
int a2;
for(a2=1;a2<=co;a2++)
{
if(n==sarr[a2])
{
printf("The position of the number is %d ",a2);
break;
}
}
}
OUTPUT
Enter the number of the elements:-1 12 123 12345 1234
The length of 1 is:-1
The length of 12 is:-2
The length of 123 is:-3
The length of 12345 is:-5
The length of 1234 is:-4
The Hash Table is as follows
––––––––––––––
Index 1:- 1
Index 2:- 12
Index 3:- 123
Index 4:- 1234
Index 5:-12345
––––––––––––––
Enter the number to search;-12345
The position of the number is 1 in Index 5

Explanation:
As usual, the arrays are declared by using arr[], in1[], in2[], in3[], in4[] in5[]
each one having length of 5. By using length(), function length of each key is calculated and the
keys are placed in the appropriate index.The number which is to be searched is inputted through
the keyboard. Here, snum variable is declared. Its length is calculated by using the length();
and by knowing the length it is searched in the hash table.

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 23 3/2/2012 6:59:40 PM


12.24 Data Structures Using C

12.11 MULTIPLICATIVE HASHING FUNCTION

The name itself indicates that the function is having the multiplication operation in it. The multiplicative
hashing function can be written as
H(key)=(b(c*key mod 1))+1.

In this hashing method, the key is multiplied with the number ‘c’. The c is used in this function as
a constant. After performing the mod of this product with 1 again multiplication operation with the
number b is done and 1 is added. The number obtained is the index number for the placing the key.
Mainly, there are two types of searching methods used with hashing function. One is external searching
and other is internal search. When the records are bulky then the records can be stored in the file and the
file is stored on the disk, tape, etc. The record is outside of the computer memory. On that file the search-
ing operation is to be performed. This searching operation is called as the external searching. Two tech-
niques are used for the external search, one is hashing method and other is tree search method. In another
case, when the records are shorter and in less numbers the same can be stored in the computer memory
like array, list, etc. In general, the linear searching and binary search are used in the internal searching.

12.12 DIGIT ANALYSIS METHOD

Digit analysis method is the hashing function in which the analysis is done on the whole digits. In this
method some digits of some positions of the number are taken out. Then, by making the reverse of the
selected digits a value is obtained. The key is transferred to that location. Assume a key 348526917 and just
select the digits at the 2, 5 and 7 position. They are as 1,2 and 8. By combining these digits we get a number
128 and after reversing the number have 821. Now, the key is transferred at the address location 821.

SUMMARY
1. Searching is a technique of finding accurate location of an element in the given item list or
set of the elements of an array, list, or trees.
2. If the given element is present in the collected elements or array then the search process
is said to be successful. The search is said to be unsuccessful if the given element does not
exist in the array.
3. The search method in which an element to be searched, is checked in the entire data
structure in a sequential way from starting to end is called linear search.
4. Binary search is quicker than the linear search. However, it cannot be applied on unsorted
data structure.This is the precondition. Before applying binary search, the linear data structure
must be sorted in either ascending or descending order by using one of the sorted methods.
5. Hash is one of the complex searching techniques. In this method, the position of the key
(element) is fixed into the table or the file, which is determined by the hash function. Divi-
sion method is explained with a suitable example in this method. Other methods have also
been discussed in detail.

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 24 3/2/2012 6:59:40 PM


Searching 12.25

EXERCISES
A. Answer the following questions:

1. What is searching? How is the searching process essential for data base applications?
2. Explain linear and binary search.
3. Differentiate between linear and binary search.
4. What are the different searching techniques known to you? Explain one of them in detail with
a suitable example.
5. Distinguish between the external and internal searching.

B. Select the appropriate option for each of the following questions:

1. The process of finding a particular record is called


(a) sorting (c) indexing
(b) searching (d) none of the above
2. In this type of searching the records must be sorted
(a) linear search (c) selection search
(b) binary search (d) none of the above

C. Write the following programs:

1. Write a program to find the given number in an array of 50 elements. Search how many times
a given element exists in the list.
2. Write a program to demonstrate successful and unsuccessful search. Display appropriate mes-
sages.
3. Write a program to demonstrate binary search. Use character array and store 10 names. Find
the given name.
4. Write a program to search with linear search the given name in string array of 10 names.

D. What is the output of following programs?

1. while(b<=5)
#include<stdio.h> {
#include<conio.h> if(a[b]==n)
{
void main() printf("The number %d is found %d
{ location",n,b);
int n,b=1,a[5]; break;
clrscr(); }
printf("Enter five elements:-"); b++;
while(b<=5) }
{scanf("%d",&a[b]);b++;} if(a[b]!=n)
printf("Enter the element to be printf("The element %d is not
searched:-"); found",n);
scanf("%d",&n); getch();
b=1; }

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 25 3/2/2012 6:59:40 PM


12.26 Data Structures Using C

2. st=mid+1;
# include<stdio.h> else
# include<conio.h> en=mid-1;
mid=(st+en)/2;
void main() }
{ if(num==its[mid])
int no,j; printf("\n %d found at position %d ",
int r[5],*pt; num,++mid);
clrscr(); if(st>en)
printf("Enter five elements:-"); printf(" %d not found ", num);
for(j=1;j<=5;j++) getch();
scanf("%d",&r[j]); }
printf("Enter the element to be 4.
searched:-"); # include<stdio.h>
scanf("%d",&no); # include<string.h>
pt=&r[1]; # include<conio.h>
j=1;
while(j<=5) void main()
{ {
if(*pt==no) int beg=1,mid,end=5,i,flag=0,val;
{ char name[5],fn;
printf("The number %d is found %d clrscr();
location",no,j); printf("Enter name:-\n");
break; for(i=0;i<5;i++)
} scanf("%c",&name[i]);
pt++; printf("\n\tEnter the name to
j++; search:-");
} scanf("%s",&fn);
if(*pt!=no) mid=(beg+end)/2;
printf("The element %d is not printf("\n\tAt starting beg
found",no); is %d, mid is %d & end is
getch(); %d",beg,mid,end);
} while((strcmp(fn,name[mid]))!=0 &&
3. beg<=end)
# include<stdio.h> {
# include<conio.h> val=strcmp(fn,name[mid]);
if(val>0)
void main() {
{ beg=mid+1;
int its[5], st=0,en=4,j,num,mid; mid=(beg+end)/2;
clrscr(); printf("\n\tmid is %d & beg is
for(j=0;j<5;j++) %d",mid,beg);
{ }
printf("Enter element %d:",1+j); else
scanf("%d",&its[j]); {
} end=mid-1;
printf("\n Enter element to be mid=(beg+end)/2;
searched :"); printf("\n\tmid is %d & end is
scanf("%d",&num); %d",mid,end);
mid=(st+en)/2; }
while(num!=its[mid] && st<=en) }
{ if(strcmp(fn,name[mid])==0)
if(num>its[mid]) flag=1;

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 26 3/2/2012 6:59:40 PM


Searching 12.27

if(flag==1) void bucket()


printf("\n\tThe name %c is traced {
successfully",fn); int r,a=0,b=0,i;
else for(i=0;i<10;i++)
printf("\n\tThe number %c is not {
traced",fn); r=n[i]%2;
getche(); switch(r)
} {
case 0: a++; b0[a]=n[i];break;
5. case 1: b++; b1[b]=n[i];break;
# include<stdio.h>
}
# include<conio.h>
}
printf("\nThe elements of bucket 0
void main()
are :-");
{
for(i=1;i<=a;i++)
int n[10],bk0[5],bk1[5];
printf("%3d",b0[i]);
int rem,a=0,b=0,i;
printf("\nThe elements of bucket 1
clrscr();
are :-");
printf("Enter ten numbers:-");
for(i=1;i<=b;i++)
for(i=0;i<10;i++)
printf("%3d",b1[i]);
scanf("%d",&n[i]);
}
for(i=0;i <10;i++)
{ 7.
rem=n[i]%2; # include<stdio.h>
switch(rem) # include<conio.h>
{ int arr[5]={2,9,4,7,10};
case 0: a++; bk0[a]=n[i];
break; void main()
case 1: b++; bk1[b]=n[i]; {
break; int no,pos;
} int search(int n);
} clrscr();
printf("\nIn 0 bkt total number are: printf("Enter number to search:-");
-%d",a); scanf("%d",&no);
printf("\nIn 1 bkt total number are: pos=search(no);
-%d",b); if(pos==0)
} printf("\nNumber is not found");
else
6. printf("\n%d number is at %d",no,pos);
# include<stdio.h>
}
# include<conio.h>
int search(int n)
int n[10]={1,2,9,8,4,6,7,5,3,10},
{
b0[5],b1[5];
int i;
for(i=0;i<5;i++)
void main()
if(n==arr[i])
{
return(++i);
void bucket();
return 0;
clrscr();
}
bucket();
}

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 27 3/2/2012 6:59:40 PM


This page is intentionally left blank.

M12_ASHOK NAMDEV KAMTHANE5067_01_SE_C12.indd 28 3/2/2012 6:59:40 PM


Solved Question Papers
Biju Patnaik University of Technology
Data Structures Using C
(Common for all Branches of Engineering)
Subject Code: BE-2106
2009

Time: 3 hours Full Marks: 70

Question 1 is compulsory. Answer any five questions from the rest. The figures in the right-hand margin indicate
marks.
1. Answer the following questions: (2 10)
(a) Define and differentiate between linear and non-linear data structures.
(b) What do you mean by the efficiency of an algorithm? Discuss time and space complexity?
(c) What is meant by recursion? Which data structure is used to implement recursion?
(d) Find out the postfix expression for the following expression:
A* (B + C) − (G + H)/L/P
(e) Represent the polynomial 2x2 + 5y3 − 7 in a linked list.
(f ) Explain the term garbage collection.
(g) What is the difference between a binary tree and a complete binary tree?
(h) Find the preorder and post order traversal of the following binary tree.

C G

E
Y D

(i) What is an extended binary tree?


(j) Specify the data structures used for DFS and BFS.
2. (a) What is a queue? How does it differ from a stack? Write an algorithm to insert an element into a
queue. What are the applications of a queue data structure? (5)
(b) Evaluate the following postfix expression by using a stack.
12, 5, 2,*, 4, −2, ^, 6, /, + (5)
3. (a) Use a stack to translate the following infix expression to postfix.
x*(y + z)/a − b*(c + d)/e (5)
(b) Write an algorithm to find the first occurrence of a given integer in a single linked list. (5)

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 1 3/3/2012 10:49:43 AM


Q.2 Solved Question Papers

4. (a) Sketch the binary search tree from 50, 72, 99, 100, 62, 12, 9, 2, 25, 57. What will be the new
binary search tree after the insertion of four new numbers, 205, 13, 31 and 301? (5)
(b) Write an algorithm for max heap and create a max heap for 23, 74, 57, 65, 73, 36 and 99. (5)
5. (a) Construct a tree from inorder and postorder traversal where
Inorder: a + b – c * d – e/f + g – h
Postorder: abc – +de – fg + h–/* (5)
(b) Write an algorithm to search a node in a binary search tree. (5)
6. (a) Describe the different methods to represent a graph in computer memory. Represent the following
graph in adjacency matrix form. (5)

V1 V2

V3
V4 V5

V6

(b) Describe DFS algorithm. Find the shortest path from A to H from the given graph. (5)
7. (a) Describe radix sort. Sort the following data using radix sort:
42, 23, 74, 11, 65, 74, 94, 36, 99, 87, 70, 81 (5)
(b) Define quick sort algorithm. Arrange the following elements in ascending order. (5)
5, 14, 2, 9, 21, 34, 17, 19, 1, 44
8. (a) What is hashing? What are the different methods used for calculating hash function. Explain with
an example? (5)
(b) Discuss the Linear Probing Method. Discuss the disadvantages of Linear Probing Method with an
example. (5)

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 2 3/3/2012 10:49:44 AM


Solved Question Papers Q.3

Solutions
1. (a) In linear data structures, data are stored in sequential order and memory is allocated in contiguous
manner, e.g. array, stack, queue. In non-linear data structures, data are stored in random manner
and memory allocation is also carried out in random manner, e.g. trees, graphs.
(b) The efficiency of an algorithm can be determined by finding the complexity of that algorithm.
Complexity refers to time complexity and space complexity. We observe the total time required to
complete an algorithm in time complexity and find the total space required to execute the algo-
rithm in space complexity.
(c) A function is called recursive function if it calls itself. The mechanism is called function recursion.
The stack data structure is used to implement recursion.
(d) A*(BC+) – (GH+)/L+P

(ABC+*) − (GH +)/L+P


(ABC+*) − (GH+L/) +P
(ABC+*GH +L/−)+P
ABC+*GH+L/−P+
(e) The polynomial 2x2 + 5y3–7 can be represented in a linked list as follows:

0 −1 −1 → 2 2 0 → 5 0 3 → −7 0 0 N

(f ) Garbage collection refers to the de-allocation of unused memory. Deciding when to release the
allocated memory is very simple. The memory de-allocation is done when the programmer requests
by executing a specific function. Languages like Java have in-built garbage collection system. The
function free() in C and delete in C++ are used to release the memory. The garbage collec-
tion system checks the entire memory, marks the unused nodes and releases the memory associated
with them.
(g) In a complete binary tree, each node has exactly 2 or 0 degrees. However, in a binary tree each
node has 0, 1, or 2 degrees.
(h) Preorder: B, C, E, G, Y, D
Postorder: E, C, Y, D, G, B
B

C G

E
Y D

(i) A binary tree is called an extended or 2-tree if each node N has either 0 or 2 degrees. At level n, the
number of nodes = 2n.
(j) We use stack data structure for DFS and queue data structure for BFS.

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 3 3/3/2012 10:49:44 AM


Q.4 Solved Question Papers

2. (a) Queue is a linear data structure, which follows the principle of FIFO (First In First Out). In other
words, we can say that if the FIFO principle is implemented with array, then it is termed as queue.
Stack is a linear data structure, which follows the principle of LIFO (Last In First Out). In other
words we can say that if the LIFO principle is implemented with array, then it termed as stack.

Insert (Queue [Size], Front, Rear, No)


Step 1: if (rear=size –1) then:
write: “overflow”
return
[end of if]
Step 2: if(rear= –1) then:
front=0
rear=0
else
rear=rear+1
[end of if]
Step 3: queue [rear] = no
Step 4: return

Queues have applications in topological sorting and BFS.


(b) The expression can be evaluated by using stack as follows.

* – ^ /
2 4 2 6
5 (5*2) ((5*2) – 4) (((5*2) – 4)^2)
12 12 12 12
S1 S2 S3 S4

+
((((5*2)–4)^2)/6)
12 12 + ((((5*2)–4)^2)/6)
S5 S6

3. (a) Conversion from infix to postfix using stack:


(C – D)+ (E^F) + F/ (H + W)*A^B
Procedure for conversion:
Step 1: Insert an opening parenthesis at the beginning and closing parenthesis at the end of the
expression.
Step 2: Arrange the expression in the array.
Step 3: Scan all the elements in the array. If an element is an operand, store it in the postfix and
if an element is an operator then push it into the stack followed by Step 4 and Step 5.
Step 4: If the scanned operator has a lesser or equal precedence to the existing operator, then pop out
the operators from the stack till a precedence operator or opening parenthesis is found.

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 4 3/3/2012 10:49:44 AM


Solved Question Papers Q.5

Step 5: If the scanned operator is a closing parenthesis, then pop the operators from the stack
up to the opening parenthesis and omit them. The poped operators will be stored in the
postfix.
Step 6: Repeat Step 3, Step 4 and Step 5 till all the elements are scanned from the array.
Step 7: Print the postfix as the result.
Example: Convert A + B – (C*D – E + F^G) + (H + I*J) into postfix by using stack.
Array Stack Postfix
( (
A ( A
+ (+ A
B (+ AB
– (– AB +
( (– ( AB +
C (– ( AB + C
* (– (* AB + C
D (– (* AB + CD
– (– (– AB + CD*
E (– (– AB + CD*E
+ (– (+ AB + CD*E –
F (– (+ AB + CD*E – F
^ (– (+^ AB + CD*E – F
G (– (+^ AB + CD*E – FG
) (– AB + CD*E – FG^+
+ (+ AB + CD*E – FG^+ –
( (+( AB + CD*E – FG^+ –
H (+( AB + CD*E – FG^+ – H
+ (+(+ AB + CD*E – FG^+ – H
I (+(+ AB + CD*E – FG^+ – HI
* (+(+* AB + CD*E – FG^+ – HI
J (+(+* AB + CD*E – FG^+ – HIJ
) (+ AB + CD*E – FG^+ – HIJ*+
) AB + CD*E – FG^+ – HI* ++

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 5 3/3/2012 10:49:44 AM


Q.6 Solved Question Papers

(b) The algorithm to find the first occurrence of a given integer in a single linked list is given below.
Struct link
{
Int info;
Struct link *next;
};
Search (start, node, no) [start is the structure type of variable]
[node is the structure type of pointer variable]
[no is the information to search]
Step 1: node=next[start]
Step 2: set count=1
set opt=0
Step 3: repeat while(node!=null)
if(count=no)then
write: infor[node]
write: “is found at”
write: count
write: “position”
opt=1
return
else
node=next[node]
first=next[first]
count=count+1
[end of if]
[end of loop]
Step 4: if(opt!=1)
write: ”the number is not found”
[end of if]
Step 5: return
(

4. (a) A binary search tree is a binary tree that is either empty or in which each node possesses a key that
satisfies the following properties:
• The elements in the left subtree are smaller than the key in the root
• The elements in the right subtree are greater than or equal to the root
• The left and right subtrees are also the Binary Search Tree.
The initial binary search tree is given below:

50

12 72

9 25 62 99

2 57 100

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 6 3/3/2012 10:49:44 AM


Solved Question Papers Q.7

The final binary search tree is given below:

50

12 72

9 25 62 99

2 13 31 57 100

205

301

(b) ALGORITHM Max_Heap(A,i)


1. {
2. l←left_child(index)
3. r←right_child(index)
4. if l d ≤ heapsize [A] and A[l] > A[i]
5. then largest ← l
6. else
7. largest ← i
8. if r ≤ d heapsize [A] and A[r] > A[largest]
9. then largest ← r
10. if largest ≠ l then
11. swap(A[i], A[largest])
12. Max_Heap(A, largest)
13. }

ALGORITHM Build_Heap(A)
1. {
2. heapsize[A] ←length[A]
3. for i←length[A]/2 to l by -1
4. do Max_Heap(A,i)
5. }

ALGORITHM Heap_sort(A)
1. {
2. Build_Heap(A)
3. for i←lenghth[A] to 2 by -1
4. do swap(A[1],A[i])
5. heapsize[A] ← heapsize[A]-1
6. Max_Heap(A,1)
7. }

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 7 3/3/2012 10:49:44 AM


Q.8 Solved Question Papers

Example: Create a Max-heap by considering the numbers 23, 74, 57, 65, 73, 36 and 99.
Step 1:
23

Step 2:
23 74

Interchange

23 23

Step 3:
74

23 57

Step 4:
74 74

23 57 Interchange 65 57

65 23

Step 5:
74 74

65 57 Interchange 73 57

23 73 23 65

Step 6:
74

73 57

23 65 36

Step 7:

74 74

73 57 Interchange 73 99

23 65 36 99 23 65 36 57

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 8 3/3/2012 10:49:44 AM


Solved Question Papers Q.9

The final max heap is given below:

Interchange

99

73 74

23 65 36 57

5. (a) The inorder of the tree: D, B, H, E, A, I, F, J, C, G


The preorder of the tree: A, B, C, D, E, H, C, F, I, J, G
Conversion of a tree from inorder and preorder:
Inorder: D, B, H, E, A, F, C, I, G
Preorder: A, B, D, E, H, C, F, G, I
Choose the root from the preorder and the nodes on the left and right from the inorder. This
process will continue until all the elements are chosen from the preorder/inorder.
Step 1: A is the root as per the preorder. From the inorder, we find that D, B, H, E fall on the left
of A and F, C, I, G fall on the right.
A

(D, B, H, E) (F, C, I, G)

Step 2: B will be chosen as the parent from the preorder and from the inorder D will be on the left
of B, and H and E will be on the right.
A (F, C, I, G)

D (H, E)

Step 3: E will be chosen as the parent from the preorder and H is present in the inorder to the
left.
A (F, C, I, G)

D E

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 9 3/3/2012 10:49:45 AM


Q.10 Solved Question Papers

Step 4: From the postorder, B will be chosen as the parent and from the inorder we observe that
to the right of B (H, E, A) and to the left (D) will be used.
A

B C
(H, E)
D E G

Step 5: From the postorder, we will choose E as the parent and from the inorder to the left of E
(H) will be used.
A

B C

D E F G

H I

(b) An algorithm to search a node in a binary search tree is given below:

Algorithm bst_search(x,num)
Step 1: if(x=null or num = key[x]) then
return x
Step 2: if(num<key[x]) then
return bst_search(left[x], num)
else
return bst_search(right[x],num)
Step 3: exit

6. (a) The major components of the graph are nodes and edges. Graphs can be represented in array rep-
resentation and linked representation.
Overall there are four major approaches to represent graphs:
• Adjacency Matrix
• Adjacency Lists
• Adjacency Multilists
• Incedence Matrix
Adjacency matrix: Adjacency matrix stores the information of adjacent or nearby nodes. This
matrix keeps the information whether the node is adjacent to any other node or not.

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 10 3/3/2012 10:49:45 AM


Solved Question Papers Q.11

Example:

V1 V2

V3
V4 V5

V6

The adjacency matrix is:

V1 V2 V3 V4 V5 V6
V1 0 0 0 0 0 0
V2 1 0 0 0 0 0
V3 0 0 0 0 0 0
V4 1 1 0 0 0 0
V5 0 0 1 1 0 1
V6 0 0 0 0 1 0

If the above is undirected, then the matrix will be:

V1 V2

V3
V4 V5

V6

V1 V2 V3 V4 V5 V6
V1 0 1 0 1 0 0
V2 1 0 0 1 0 0
V3 0 0 0 0 1 0
V4 1 1 0 0 1 0
V5 0 0 1 1 0 1
V6 0 0 0 0 1 0

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 11 3/3/2012 10:49:45 AM


Q.12 Solved Question Papers

Adjacency list: Here, for each vertex we keep a list of all adjacent vertices. We maintain two lists
in the adjacency list representation of graphs. The first list will keep track of all the nodes in the
graph. The second list will contain a list of adjacent nodes for every node. Each list has a header
node, which will be the corresponding node in the first list. The header nodes are sequential pro-
viding easy, random access to the adjacency list for any particular vertex.

V1 V2

V3
V4 V5

V6

V1 V4 N
V2 V1 V3 V5 N
V3
NULL
V4 V2 V5 N
V5 V3 V6 N
V6
NULL

Incidence matrix: This type of representation clearly signifies the vertices to which the edges are
connected. The vertex from where the edge starts is represented by 1 and the vertex at which the
edge ends is represented by –1.
E1
V1
V2
E2 E4

E3
V6 V5
E6
E5 E8
V3 V4
E7

V1 V2 V3 V4 V5 V6
E1 1 –1 0 0 0 0
E2 –1 0 0 0 0 1
E3 0 –1 0 1 0 0
E4 0 1 0 0 –1 0
E5 0 0 1 0 0 –1
E6 0 0 1 0 –1 0
E7 0 0 1 –1 0 0
E8 0 0 0 –1 1 0

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 12 3/3/2012 10:49:45 AM


Solved Question Papers Q.13

(b) The DFS uses stack for the traversal of graph. The procedure is as follows:
1. Push the starting node into the stack.
2. Pop an element from the stack. If it has not been traversed, traverse it. If it has already been
traversed, then just ignore it. After traversing, make the value of the visited array true for this
node.
3. Now push all the unvisited adjacent nodes of the popped elements on stack. Push the element
even if it is already in the stack.
4. Repeat Step 3 and Step 4 until the stack is empty.

1 2 3

4 5 6

7 8 9

Step 1: Push 1 into stack


Top = 0, stack =1
Step 2: Pop 1 and traverse it and add all the unvisited adjacent nodes as 5, 4, 2
Traverse Node = 1
Visited [1]=T
Top = 2 stack = 5, 4, 2
Traversal =1
Step 3: Pop 2 and traverse it and insert 5, 3 into the stack
Traverse node = 2
Visited [2] = T
Top = 3, stack = 5, 4, 5, 3
Traversal =1, 2
Step 4: Pop 3 and traverse it and insert 6 into stack
Traverse Node=3
Visited [3] = T
Top = 3, stack = 5,4,5,6
Traversal =1, 2, 3
Step 5: Pop 6 and traverse it and nothing is to be pushed into stack
Traverse node = 6
Visited [6] = T
Top = 2 stack = 5, 4, 5
Traversal =1, 2, 3, 6
Step 6: Pop 5 and traverse it and push 8 into stack. 6 is also adjacent but it will not push since it
has not been visited
Traverse node = 5
Visited [5] = T
Top = 2 stack = 5, 4, 8

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 13 3/3/2012 10:49:46 AM


Q.14 Solved Question Papers

Traversal =1, 2, 3, 6, 5
Step 7: Pop 8 and traverse it and push 9
Traverse node = 8
Visited [8] = T
Top = 2, stack = 5, 4, 9
Traversal =1, 2, 3, 6, 5, 8
Step 8: Pop 9 and traverse it and nothing is to be pushed into the stack
Traverse node = 9
Visited [9] = T
Top =1, stack = 5, 4
Traversal =1, 2, 3, 6, 5, 8, 9
Step 9: Pop 4 and traverse it and push 7 into the stack
Traverse node = 4
Visited [4] = T
Top =1 stack = 5, 7
Traversal =1, 2, 3, 6, 5, 8, 9, 4
Step 10: Pop 7 and traverse it and nothing is to be pushed into the stack
Traverse node = 7
Visited [7] = T
Top = 0 stack = 5
Traversal =1, 2, 3, 6, 5, 8, 9, 4, 7
Step 11: Pop 5 and traverse it but since visited [5] = T, so just ignore it
Top = 0, stack = empty
7. (a) The radix sort is based upon the positional value of the actual digits of the number being stored.
This method was earlier performed on a mechanical card sorter. For example, the number 245 in
decimal notation is written with a 2 in the hundredth position, 4 in the ten’s position and 5 in the
unit’s position. These three digits will be sorted in a maximum of 3 passes. In the first pass, the
unit’s digit will be sorted, in the second pass the ten’s digit will be sorted and in the third and final
pass the hundred’s digit will be sorted.
The radix sort technique is also used when large lists of names are to be sorted alphabetically.
For example:

42 20 64 51 34 70 31 16 15 12 19 33

Number 0 1 2 3 4 5 6 7 8 9
42 42
20 20
64 64
51 51
34 34
70 70
31 31

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 14 3/3/2012 10:49:46 AM


Solved Question Papers Q.15

16 16
15 15
12 12
19 19
33 33

In the second pass, the unit digits are sorted as shown below:

Number 0 1 2 3 4 5 6 7 8 9

20 20
70 70
51 51
31 31
42 42
12 12
33 33
64 64
34 34
15 15
16 16
19 19

Finally, we get the sorted list as:

12 15 16 19 20 31 33 34 42 51 64 70

(b) It is also known as partition exchange sort. It was invented by C.A. R Hoare. It is based on partition.
The method falls under the divide and conquer technique. The main list of elements is divided
into two sub-lists. For example, a list of X elements is to be sorted. The quick sort marks an ele-
ment in a list called as pivot or key. Consider the first element J as a pivot. Shift all the elements
whose value is less than J towards the left and elements whose value is greater than J to the right
of J. Now, the key element divides the main list into two parts. It is not necessary that the selected
key element be in the middle. Any element from the list can act as the key element. However, for
best performance, preference is given to middle elements. The consumption of quick sort depends
on the location of the key in the list.

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 15 3/3/2012 10:49:46 AM


Q.16 Solved Question Papers

ALGORITHM (Quicksort(A, P, R)
1. If P < R
2. Then Q ← PARTITION(A,P,R)
3. QUICKSORT(A,P,Q)
4. QUICKSORT(A,Q+!,R)

ALGORITHM (Quicksort(A,P,R)
1. X A[P]
2. Low P
3. Up R
4. While(Low < Up)
5. {
6. While(A[low]<=x)
7. Low=Low+1
8. While(A[up]>x)
9. Up=Up-1
10. If(Low<Up) then
11. Exchange(A[Low], A[Up])
12. Else
13. Return(Up)
14. }

The elements 5, 14, 2, 9, 21, 34, 17, 19, 1, 44 can be sorted by using quick sort as follows.
First, choose the first element as the pivot and find the first element larger than the pivot from the
left-hand side and find the smallest or equal number equal to the pivot from the right to the left.
Then swap the larger element with the smallest element and continue the above process till the
smallest element is found after the largest element. Once the smallest element is on the left-hand
side of the largest, interchange the smallest element with the pivot so that the array is sub- divided
into two sub-arrays. Implement the process in both the sub-arrays.

2 9 21 34 17 19 44
5 14 1
Pivot High Less

Swap 1 2 21 34 17 19 14 44
14 and Less 9
1 High
5

Since less < high so interchange the pivot with less


2 1 5 9 21 34 17 19 14 44

First Sub- Second Sub-array


array

2 1 5 9 21 34 17 19 14 44
Pivot/High Less

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 16 3/3/2012 10:49:46 AM


Solved Question Papers Q.17

Since pivot and high are both the same, interchange the value of less with high.
1 2 5 9 21 34 17 19 14 44
Since the left sub-array elements are sorted now implement the sorting logic to right sub-array.
1 2 5 34 17 19 14 44
9 21
Since pivot and less are the same, nothing will change, i.e. the left sub-array will have no
elements but the right sub-array will have the elements from 21 to 44
1 2 5 9 21 34 17 19 14 44

Pivot High Less


1 2 5 9 21 14 17 19 34 44
Less High
19 14 17 21 34 44
1 2 5 9

1 2 5 9 19 14 17 21 34 44
Pivot Less High
1 2 5 9 17 14 19 21 34 44
Pivot Less High
1 2 5 9 14 17 19 21 34 44
8. (a) Hashing technique is a complex searching technique. In this method, we fix the position of the
key (element) into the table or the file, which is determined by the hash function. The func-
tion in which we use this key is known as hashing function. For example, we want to search a
number from the ten numbers of a file. We must find the number throughout this range from
the first number to tenth number. When we use the hash key for fixing its position in a table
then the number can be searched very easily. Some of the hashing techniques are discussed
below:
Division method: This method is considered as the simplest method. In this method, the integer
x is divided by M and then by using the remainder. This method is also known as the division
method of hashing. The format of hash function is H(x) = x mod m;
This method works fine for just about any value of M. Care should be taken while choosing the
value of M. It is better to take a large prime number. The main advantage of the division method
is its simplicity.
Middle-square method: The middle-square method employs a hashing method that avoids the
use of division. In this method, a key is multiplied by itself and the address is obtained by choosing
an appropriate number of bits or digits from the middle of the square. The selection depends upon
the table size and also that they should fit into one computer word of memory. The same positions
in the square must be used for all keys.
Multiplication method: This method is a slight variation of the middle-square method. In this
technique, instead of multiplying the value itself, we have to multiply the number by a constant
and then extract the middle K bits from the result.

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 17 3/3/2012 10:49:46 AM


Q.18 Solved Question Papers

Folding method: In this technique, a key is divided into a number of parts. Each part should have
equal length. The split parts are then added together and the final carry should be ignored.
(b) A simple approach to resolving collisions is to store the colliding record in the next available space.
This technique is known as linear probing. Linear probing resolves has collision by sequential
searching. A has table beginning at the location is returned by the has function. We consider
the array as a circular structure and continue looking for an empty room at the beginning of the
array.
For example: Consider the hash function h(x) = x%7
The numbers 23, 50, 30, 38 are arranged in the hash table as follows:

0 1 2 3 4 5 6
50 23 30 38

The main disadvantage of linear probing is that the elements are stored in different locations in
case of collision. Hence, searching has to be done completely within the sequence starting from the
beginning. Since it is static in nature, the rest of the elements cannot be stored when the memory
allocated is full.

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 18 3/3/2012 10:49:47 AM


Solved Question Papers Q.19

Biju Patnaik University of Technology


Data Structures Using C
(Common for all Branches of Engineering)
Subject Code: BE-2106
2010

Time: 3 hours Full Marks: 70

Question 1 is compulsory. Answer any five questions from the rest. The figures in the right-hand margin indicate
marks.
1. Answer the following questions. (2 10)
(a) Explain the term ADT with a suitable example.
(b) Consider the following stack: #4, 5, 6*. Here # represents bottom and * represents top stack. What
will be the contents of the stack after the following sequence of operations—Push(10), Pop(10),
Push(20), Pop(), Push(30)? Consider that the stack has the size 3.
(c) What is a dequeue? Explain its two variants.
(d) What will be the time complexity in Big oh notation for the following code segment:
int f(int k)
{
if (k==1)return 1;
else
return k+ f(k-1);
}

(e) What will be the minimum and maximum height of a binary tree having 16 key values?
(f ) What is a polynomial list? How can we represent a polynomial in memory?
(g) Given below are two sequences of data obtained from two different binary trees. These data are
inserted into two different one-dimensional arrays sequentially. Out of these two sequences, which
can be a heap?
(i) 42, 35, 37, 20, 14, 18, 7, 10
(ii) 42, 35, 18, 20, 14, 30, 10
(h) Find out the edge matrix for the following graph.
b
1 2

3 c
a

4 7
5
e d
6
(i) What is a height balanced tree?
(j) What is the maximum and minimum number of entries for a leaf node of a B tree of order 6?
2. (a) Why do you check the full and empty condition of a stack? Write a C program to perform the
insertion and deletion in a stack that is implemented using array. (5)

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 19 3/3/2012 10:49:47 AM


Q.20 Solved Question Papers

(b) Write a C program to convert a single link list to a circular link list. Why is a header node used in
a circular list? (5)
3. (a) Define linear queue. Let QUEUE be a non-empty queue implemented using a linear array. Write
a C program to delete m elements from the queue. (5)
(b) Sketch the binary search tree resulting from the insertion of the following integer keys: 39, 24, 12,
11, 43, 73, 26, 35, 29, 13, 6 (5)
(i) Is the tree almost complete?
(ii) Is the tree AVL?
(iii) What is the height of the tree?
(iv) Write the preorder traversal of the tree.
4. (a) Write an algorithm that computes the number of elements and the sum of elements in a linear link
list. (5)
(b) The inorder of the tree: D, B, H, E, A, I, F, J, C, G
The preorder of the tree: A, B, C, D, E, H, C, F, I, J, G
Construct the tree and give a linear array representation of the above tree. Define the node structure in
C, which can be used to implement the tree. (5)
5. (a) Describe the node structure of a double link list. Write an algorithm to delete the last node of a
double link list. (5)
(b) Define binary heap. Explain the process of heap sort. Write an algorithm to construct a min heap.
Construct a min heap from the list: {21, 6, 56, 61, 44, 7, 9, 76, 75, 32, 34, 4, 49, 33} (5)
6. (a) Define a graph. What are the different representations of a graph? Use a suitable data structure to
represent the following graph. (5)
A B C

D E F

G H I

(b) What are the preconditions to perform binary search on a linear array. Write a recursive function
in C to perform binary search in an array. (5)
7. (a) Write an algorithm to perform DFS on a graph. Find out the path from D to K using DFS. (5)
(b) Write a program in C to sort a list of floating point number using quick sort. Why is the pivot
chosen from the centre of the list rather than from one end? (5)
8. (a) Use linked lists to represent the following polynomial: (5)
P(X, Y, Z) = 2XY 2Z3 + 3X 2YZ 2 + 4XY 3Z + 5X 2Y 2 + 8XY 2Z 5 + 19
(b) Describe the data structure used to represent a general tree. (5)
9. (a) Define circular queue. Sketch to explain the placement of front and rear points when the queue is
full and the queue contains a single element. (5)
(b) Convert the following from infix to postfix using stack: (5)
(C – D) + (E ^ F) + F/(H + W)*A ^ B

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 20 3/3/2012 10:49:47 AM


Solved Question Papers Q.21

Solutions
1. (a) Abstract data types or ADTs are the mathematical specification of a set of data and the set of
operations that can be performed on the data. They are abstract in the sense that the focus is on
the definitions of the constructor that returns an abstract handle that represents the data, and the
various operations with their arguments. The actual implementation is not defined and does not
affect the use of the ADT. For example, rational numbers (numbers that can be written in the form
a/b where a and b are integers) cannot be represented natively in a computer.
(b) The sequence of operations is as follows:
Initial state Push(10) overflow Push(20) Pop() Push(30)

* Pop() * *
6 * 20 * 30
5 5 5 5 5
4 4 4 4 4
# # # # #

(c) A dequeue is a double-ended queue in which insertions and deletions are possible at either end.
There are two forms of dequeue:
• Input restricted dequeue (one insertion end and two deletion ends)
• Output restricted dequeue (one deletion end and two insertion ends)
(d) The loop is executed k times. Since the value of k is decremented each time by one up to the value
of k = 1, the time complexity is O(k).
(e) The minimum height of a binary tree having 16 key values is 4 and the maximum is 15.
(f ) Polynomial expressions allow us to express equations with higher order expressions. In data struc-
tures polynomials are represented by using the concept of linked list where the coefficient part and
exponent part are arranged in the value part of the linked list and the address part refers to the next
node.
For example: The expression 5X3 + 7X2 + 18 = 0 can be represented as follows:

5 3 200 7 2 300 18 0 NULL


100 200 300

(g) The two heap trees are follows:


(i) (ii)
42 42

35 37 35 18

20 14 18 07 20 14 30 10

10

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 21 3/3/2012 10:49:47 AM


Q.22 Solved Question Papers

The first tree is a heap tree (max heap) because all the nodes are smaller or equal to their parent
node. However, in tree (ii), 18 is lesser than 30. So, it is not a tree.
(h) The edge matrix is shown below:

EDGES

1 2 3 4 5 6 7
V
a 1 1 1
E
R b 1 1 1
T c 1 1
E
d 1 1 1 1
X
e 1 1

(i) We can say that a tree is a height balanced tree if:


1. An empty binary tree is an AVL or a height balanced tree.
2. If Bt is a non-empty binary tree with BtL and BtR as its left and right subtrees, then Bt is an
AVL tree only if:
• BtL and BtR are AVL trees and
• BhL – BhR = 1, where hL and hR are the heights of BtL and BtR, respectively.
BhL – BhR is called the balance factor of a node. Its value can be {–1, 0, 1}.
(j) If n is the order of B tree, the minimum number of entries is 1 for root and n/2 for others. The
maximum number of entries is n–1. So, in this case the leaf node contains a minimum of 3 and a
maximum of 5 entries.
2. (a) We have to check the full condition for insertion and the empty condition for deletion. If the stack
is full, it will lead to overflow, i.e. no more elements can be added to the stack. If the stack is empty,
one cannot implement the pop operation. This will lead to underflow, i.e. no elements inside the
stack.

# include<stdio.h>
# include<alloc.h>
static int *s, size, top= -1;
void push (int no)
{
if(top == size-1)
printf(“\n stack overflow”);
else
{
top = top+1;
*(s+top) = no;
}
}
void pop()
{
if(top == -1)
printf(“\n stack underflow”);
else

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 22 3/3/2012 10:49:47 AM


Solved Question Papers Q.23

{
printf(“%d is deleted”, *(s+top));
-top;
}
}
void traverse()
{
int i;
if(top == -1)
printf(“\n stack is empty”);
else
for(i=top; i>=0;i--)
prinf((“%5d”, *(s+i));
}
void main(0
{
int opt;
printf(“\n enter the size of the stack”);
scanf(“%d”,&size);
s=int *) malloc(size * sizeof(int)):
while(1)
{
printf(“\n enter the choice”);
printf(“\n 1. push 2.pop 3.display 0.exit”);
scanf(“%d”, &opt);
if(opt==1)
{
printf(“\n enter the number to insert”);
scanf(“%d”,&opt);
if(opt ==1)
{
printf(“\n enter the number to insert”);
scanf(“%d”, &opt);
push(opt);
}
else
if(opt==2)
pop();
else
if(opt==3)
traverse();
else
if(opt==0)
exit(0);
else
printf(“\n invalid choice”);
}
}

(b) A program to convert a single link list to a circular link list is given below:
#include<stdio.h>
#include<alloc.h>
#include<conio.h>
struct link

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 23 3/3/2012 10:49:47 AM


Q.24 Solved Question Papers

{
int info;
struct link * next;
};
int i; /* represents number of nodes in the list */
int number=0;
struct link start,*node, *new1;
void create()
{
char ch;
node=&start; /* point to the header node in the list */
i=0;
do
{
node→next=(struct link*)malloc (sizeof(struct link));
node=node→next;
printf(“\n input the node %d”, (i+1));
scanf(“%d”, &node→info);
fflush(stdin);
printf(“\n do u want to create more[y/n]”);
ch=getchar();
i++;
} while(ch==’y’ || ch==’y’);
node→next = &start;
start.infor=i; /* assign total number of nodes to the header node */
}
void insertioin()
{
struct link *first;
first=&start;
node=start.next;
int opt;
int count = node→info;
int nod_number=1;
int insert_node;
node=node→next;
printf(“\n input node number your want to insert:”);
printf(“\n value should be less are equal to the”);
printf(“\n number of nodes in the list: “);
scanf(“%d”, &insert_node);
while(count--)
{
if(node_number == insert_node)
{
new1 = (struct link*) malloc(sizeof (struct link));
first→next=new1;
new1→next=node;
printf(“\n input the node value: “);
scanf(“%d”, &new1→info);
opt=1;
break;
}
else
{
node = node→next;

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 24 3/3/2012 10:49:47 AM


Solved Question Papers Q.25

first=first→next;
}
node_number++;
}
if(opt==1)
{
node=&start; /* points to header node */
node→info=node→infor+1;
}
}
/* display the list */
void display()
{
node=&start;
int count=node→info;
do
{
printf(“ \n %5d”, node→info);
node=node→next;
}while(count--);
}
void main()
{
clrscr();
create();
printf(“\n before inserting a node list is as follows:\n”);
display();
insertion():
printf(“\n after inserting a node list is as follows:\n”);
display();
}

The header node is used in a circular list because it aids traversal and enables us to find out the number
of nodes inside the circular list.
3. (a)
#include<stdio.h>
int *q, size, front=-1,rear=-1;
void insert(int n)
{
if(rear==size-1)
printf(“\n queue overflow”);
else
{
rear ++;
*(q+rear)=n;
if (front==-1)
front=0;
}
}
/* function to delete an element from queue*/
void delete()
{
if (front ==-1)
{

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 25 3/3/2012 10:49:47 AM


Q.26 Solved Question Papers

printf(“\n underflow”);
return;
}
printf(“\n element deleted : %d” , *(q+front));
if(front == rear)
{
front=-1;
rear=-1;

}
else
front= front+1;
}

void display()
{
int i ;
if (front = = -1)
printf(“\n empty queue”):
else
{
printf(“\n the queue elements are “);
for(i=front;i<=rear;i++)
printf(“%4d” , * (q+i));
}
}
void main()
{
int opt;
printf(“\n enter the size of the queue”);
scanf(“%d” , &size);
q=(int *)malloc(size * size of (int)):
while(1)
{
printf(“\n enter the choice”);
printf(“\n 1.insert 2. delete 3. display 0 .exit”);
scanf(“%d” , &opt);
if(opt==1)
{
printf(“\n enter the number to insert”);
scanf(“%d”,&opt);
insert(opt);
}
else
if(opt==2)
delete();
else
if(opt==3)
display();
else
if(opt==0)
exit(0);
else
printf(“\n invalid choice”);
}
}

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 26 3/3/2012 10:49:47 AM


Solved Question Papers Q.27

A queue is a linear data structure where elements are entered at one end and deleted from another
end. It follows the principle of first-in-first-out (FIFO). A queue can be implemented with an
array or a linked list.
(b) A binary search tree is a binary tree that is either empty or in which each node possesses a key that
satisfies the following properties:
• The element in the left subtree are smaller than the key in the root
• The element in the right subtree are greater than or equal to the root
• The left and right subtrees are also part of the Binary Search Tree.
Example:

39

24 43

12 26 73

11 13 35

6 29

(i) The tree is not almost complete.


(ii) The tree is not an AVL tree as the balance factor is +2.
(iii) 5
(iv) The preorder traversal is 39, 24, 12, 11 ,6, 13, 26, 35, 29, 43, 73
4. (a) The algorithm is as follows:

Algorithm count (start, node)


Step 1: Node: = next[start]
Step 2: Count: = 1, sum<-0
Step 3: Repeat while (next[node]!=null)
Node: =next[node]
Count: =count+1
sum=sum+info[node]
[end of loop]
Step 4: Write: sum
Step 5: Write: count
Step 6: Return

(b) Inorder: D, B, H, E, A, F, C, I, G
Preoder: A, B, D, E, H, C, F, G, I
Choose the root from the preorder and find the nodes to the left and right from the inorder. This
process will continue until all the elements are chosen from the preorder/inorder.
Step 1: A is the root from the preorder. In the inorder, (D, B, H, E) are to the left of A and (F, C,
I, G) are to the right.

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 27 3/3/2012 10:49:47 AM


Q.28 Solved Question Papers

(D, B, H, E) (F, C, I, G)

Step 2: B will be chosen as the parent from the preorder. D will be to the left of B and (H, E) to
the right.
A (F, C, I, G)

D (H, E)

Step 3: E will be chosen as the parent from the preorder and H is present to the left in the
inorder.
A (F, C, I, G)

D E

Step 4: B will be chosen as the parent from the preorder. We observe from the inorder that (H, E)
are present to the right of B and D to the left.
A

B C
(H, E)

D F G

Step 5: In the postorder, we will choose E from the right as the parent. H which is to the left of E
from the inorder will be used.
A

B C

D E F G

H I

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 28 3/3/2012 10:49:48 AM


Solved Question Papers Q.29

The node structure of the tree is:

struct tree
{
int info;
struct link*left;
struct link *right:
}:

5. (a) Node structure of double link list is the struct link.

{
int info;
struct link*next;
struct link*previous;
};

Algorithm for the deletion of a node at the end:

Dellast (start,node)
Step 1: Node: = next[start]
Step 2: Count: = 1
Step 3: Repeat while (next[node]!=null)
Node: = next [node]
Count: = count+1
End of loop
Step 4: Node: next[start]
Step 5: Repeat while (count!=1)
Node: = next[node]
Count: = count–1
End of loop
Step 6: Write: info[node]
Step 7: Next [prev[node]]: = next[node]
Prev[next[node]]: =prev[node]
Step 8: Free (node)
Step 9: Return

(b) Heaps are based on the concept of a complete tree. Formally, a binary tree is completely full if it is
of height h and has 2h+1–1 nodes. A binary tree of height h is complete if:
1. It is empty, or
2. Its left subtree is completely full and of height h –1 and its right subtree is completely full and
of height h – 2, or
3. Its left subtree is completely full and of height h –1 and its right subtree is completely full and
of height h –1.
A binary tree has the heap property if
1. It is empty, or
2. The key in the root is larger than that of either child, and both subtrees have the heap prop-
erty.
A heap can be used as priority queue. The highest priority item is at the root and is trivially
extracted. But if the root is deleted, we are left with two sub-trees and we must efficiently re-create
a single tree with the heap property. The value of the heap structure is that we can both extract the

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 29 3/3/2012 10:49:48 AM


Q.30 Solved Question Papers

highest priority item and insert a new one in o (log n) time. A heap is an ordered balanced binary
tree (complete binary tree) in which the value of the node at the root of any sub-tree is less than or
equal to the value of either of its children.

Algorithm Max_Heap(A,i)
1. {
2. l←left_child(index)
3. r←right_child(index)
4. if l d ≤ heapsize [A] and A[l] >A[i]
5. then largest ← l
6. else
7. largest ← i
8. if r ≤ d heapsize [A] and A[r] >A[largest]
9. then largest ← r
10. if largest ≠ l then
11. swap(A[i], A[largest])
12. Max_Heap(A, largest)
13. }

In the above function will arrange the elements into a max-heap.


Algorithm Build_Heap(A)
1. {
2. heapsize[A] ←length[A]
3. for i←length[A]/2 to l by -1
4. do Max_Heap(A,i)
5. }

Algorithm Heap_sort(A)
1. {
2. Build_Heap(A)
3. for i←lenghth[A] to 2 by -1
4. do swap(A[1],A[i])
5. heapsize[A] ← heapsize[A]-1
6. Max_Heap(A,1)
7. }

The construction of max heap from the list {21, 6 , 56, 61, 44,7, 9, 76, 75, 32, 34, 4, 49, 33} is shown
below:
Step 1: Step 2: 21
21

Step 3: Interchange 56
21

6 56 6 21

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 30 3/3/2012 10:49:48 AM


Solved Question Papers Q.31

Step 4: 56
Interchange
56 61

6 21 61 21 56 21

61 Interchange 6 6

Step 5: 61
Step 6: 61

56 21 56 21

6 44 6 44 7

Step 7: 61

56 21

6 44 7 9

Step 8: 61 61

56 21 Interchange 56 21

6 44 7 9 76 44 7 9

Interchange
76 6

Step 8: Interchange
61 76

76 21 61 21

56 44 7 9 56 44 7 9

6 6

Step 9:
76 76

61 21 Interchange 61 21

56 44 7 9 75 44 7 9
Interchange
6 75 6 56

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 31 3/3/2012 10:49:48 AM


Q.32 Solved Question Papers

Step 10: 76 76

75 21 75 21

61 44 7 9 61 44 7 9

6 56 6 56 32

Step 11:
76

75 21

61 44 7 9

6 56 32 34

Step 12: 76

75 21

61 44 7 9

6 56 32 34 4

Step 13:
76

75 Interchange 21

61 44 49 9

6 56 32 34 4 7

76

75 21

61 44 7 9
Interchange
6 56 32 34 4 49

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 32 3/3/2012 10:49:49 AM


Solved Question Papers Q.33

76

75 49

61 44 21 9

6 56 32 34 4 7

Step 14: 76

75 49

61 44 21 9
Interchange
6 56 32 34 4 7 33

76

75 49

61 44 21 33

6 56 32 34 4 7 9

6. (a) The major components of a graph are node and edges. Graphs can be represented using array and
linked representation. There are four major approaches to representing graphs:
• Adjacency matrix
• Adjacency lists
• Adjacency multilists
• Incedence matrix
Adjacency matrix: The adjacency matrix is the matrix that keeps the information of adjacent or
nearby nodes. We can say that this matrix keeps the information whether the node is adjacent to
any other node or not. An example of adjacency matrix is shown below:

V1 V2

V3
V4 V5

V6

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 33 3/3/2012 10:49:50 AM


Q.34 Solved Question Papers

The adjacency matrix for the above graph is given below:

V1 V2 V3 V4 V5 V6
V1 0 0 0 0 0 0
V2 1 0 0 0 0 0
V3 0 0 0 0 0 0
V4 1 1 0 0 0 0
V5 0 0 1 1 0 1
V6 0 0 0 0 1 0

If the above is undirected, then the matrix will be:

V1 V2

V3
V4 V5

V6

V1 V2 V3 V4 V5 V6
V1 0 1 0 1 0 0
V2 1 0 0 1 0 0
V3 0 0 0 0 1 0
V4 1 1 0 0 1 0
V5 0 0 1 1 0 1
V6 0 0 0 0 1 0

Adjacency list: Here, we keep a list of all adjacent vertices for each vertex. In the adjacent list rep-
resentation of graphs, we maintain two lists. The first list keeps track of all the nodes in the graph.
In the second list, we maintain a list of adjacent nodes for every node. Each list has a header node,
which will be the corresponding node in the first list. The header nodes are sequential providing
easy random access to the adjacency list for any particular vertex. An example of an adjacency list
is shown below:

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 34 3/3/2012 10:49:50 AM


Solved Question Papers Q.35

V1 V2

V3
V4 V5

V6

V1 V1 N
V2 V1 V3 V5 N
V3 Null
V4 V2 V5 N
V5 V3 V6 N
V6 Null

Incidence matrix: In this type of representation, the major focus is on the edges of the graphs.
The incidence matrix clearly signifies the vertices to which the edges are connected. The vertex
from where the edge starts is represented as 1 and the vertex where it ends is represented by –1. An
example of incidence matrix is shown below:
E1
V1 V2
E2 E4

E3
V6 V5
E6

E5 V3 V4 E8
E7

V1 V2 V3 V4 V5 V6
E1 1 –1 0 0 0 0
E2 –1 0 0 0 0 1
E3 0 –1 0 1 0 0
E4 0 1 0 0 –1 0
E5 0 0 1 0 0 –1
E6 0 0 1 0 -1 0
E7 0 0 1 –1 0 0
E8 0 0 0 –1 1 0

(b) The binary search method is a very fast and efficient method. This method requires the list of ele-
ments to be sorted. We search for an element using this method by comparing it with the element
present at the centre of the list. If it matches, the search is successful. Otherwise, the list is divided
into two halves. The first half is from the 0th position to the centre and the second half is from the

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 35 3/3/2012 10:49:50 AM


Q.36 Solved Question Papers

centre to the last element. As a result, all the elements in the first half are smaller than the centre
element, whereas all the elements in the second half are greater than the centre element.

Algorithm:
Step 1: Low = 0, up = n–1
Step 2: Repeat while low <= up
Mid = int(low + up)/2
If (no = arr[mid])
Print “searched element is found”
Exit
Else
If (no<arr[mid]) then
Up=mid-1
Else
Low=mid+1
Step 3: Print “searched element not found”
Step 4: Exit

Program for binary search:


#include<stdio.h>
#include<conio.h>
void main()
{
int *a,no,up,i,low=0,f=0;
clrscr();
printf(“\n enter how many elements to be stored in the list”);
scanf(“%d”,&up);
a=(int *)malloc(up *sizeof(int));
for(i=0;i<up;i++)
{
printf(“\nenter a number”);
scanf(“%d”,a+i);
prinf(“\n enter the number to search”);
scanf(“%d”, &no);
for(i=(low+up)/2;low<=up;i=(low+up)/2)
{
if(*(a+i)==no)
{
f=1;
break;
}
else
if(*(a+i)>no)
up=i=1;
else
low=i+1;
}
if(f==1)
printf(“\n the searching element is found”);
else
printf(“\n the searching element is not found”);
}

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 36 3/3/2012 10:49:50 AM


Solved Question Papers Q.37

7. (a) The DFS uses stack for the traversal of graph. The procedure is as follows:
1. Push starting node into the stack.
2. Pop an element from the stack. If it has not traversed, then traverse it. If it has already been tra-
versed, then just ignore it. After traversing, make the value of visited array true for this node.
3. Now push all the unvisited adjacent nodes of the popped element on stack. Push the element
even if it is already in the stack.
4. Repeat Step 3 and Step 4 until the stack is empty.

1 2 3

4 5 6

7 8 9

Step 1: Push 1 into stack


Top = 0, stack =1
Step 2: Pop 1 and traverse it and add all the unvisited adjacent nodes as 5, 4, 2
Traverse node = 1
Visited[1]=T
Top = 2 stack = 5, 4, 2
Traversal =1
Step 3: Pop 2 and traverse it and insert 5, 3 into the stack
Traverse node = 2
Visited[2] = T
Top = 3 stack = 5, 4, 5, 3
Traversal =1, 2
Step 4: Pop 3 and traverse it and insert 6 into the stack
Traverse node = 3
Visited[3]=T
Top = 3, stack = 5, 4, 5, 6
Traversal =1, 2, 3
Step 5: Pop 6 and traverse it and push nothing into the stack
Traverse Node = 6
Visited[6] = T
Top = 2 stack = 5, 4, 5
Traversal =1, 2, 3, 6
Step 6: Pop 5 and traverse it and push 8 into the stack. 6 is also adjacent but since it is visited, it
will not push
Traverse node = 5
Visited[5] = T
Top =2 stack = 5, 4, 8
Traversal =1, 2, 3, 6, 5
Step 7: Pop 8 and traverse it and push 9
Traverse node = 8
Visited[8] = T

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 37 3/3/2012 10:49:50 AM


Q.38 Solved Question Papers

Top = 2 stack = 5, 4, 9
Traversal =1, 2, 3, 6, 5, 8
Step 8: Pop 9 and traverse it and push nothing into the stack
Traverse node = 9
Visited[9] = T
Top =1 stack = 5, 4
Traversal =1, 2, 3, 6, 5, 8, 9
Step 9: Pop 4 and traverse it and push 7 into the stack
Traverse node = 4
Visited[4] = T
Top = 1 stack = 5, 7
Traversal =1, 2, 3, 6, 5, 8, 9, 4
Step 10: Pop 7 and traverse it and push nothing into the stack
Traverse node = 7
Visited[7] = T
Top = 0, stack = 5
Traversal =1, 2, 3, 6, 5, 8, 9, 4, 7
Step 11: Pop 5 and traverse it. But since visited[5] = T, just ignore it
Top = 0, stack = empty
(b) A program to sort a list of floating point number using quick sort is given below:

#include<stdio.h>
#include<conio.h>
int split (int *, int, int);
void main()
{
int arr[10]={11,2,9,13,57,25,17,1,90,3};
int i;
void quicksort (int *, int, int);
clrscr();
printf(“\n the given array is\n”);
for(i=0;i<=9;i++)
printf(“%d\t”, arr[i]);
quicksort (arr, 0, 9);
printf(“\nsorted array is \n”);
for(i=0;i<=9;i++)
printf(“%d\t”,arr[i]);
getch();
}
void quicksort( inta[],int lower, int upper)
{
int i;
if(upper >lower)
{
i=split(a,lower,upper);
quicksort(a,lower,i-1);
quicksort(a,i+1,upper);
}
}
int split(int a[], int lower, int upper)
{

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 38 3/3/2012 10:49:50 AM


Solved Question Papers Q.39

int i, p, q, t;
p=lower +1;
q=upper;
i=a[lower];
while(q>=p)
{
while (a[q] < i)
p++;
while (a[q] >i)
q--;
if(q>p)
{
t=a[p];
a[p]=a[q];
a[q]=t;
}
}
t=a[lower];
a[lower]=a[q];
a[q]=t;
return q;
}

8. (a) The polynomial can be represented using linked lists as follows:


2 1 2 3 200 3 2 1 2 300 4 1 3 1 400
200 300
19 0 0 0 NULL 8 1 2 5 600 5 2 2 0 500
600 500 400

Here, 200, 300, 400, 500 and 600 are the respective locations of the nodes.
(b) A binary tree can be represented by using arrays and linked lists. The array and linked representa-
tion of trees are discussed below with an example.
Array representation of a tree: An array can be used to represent a binary tree. The total number
of elements in the array depends on the total number of nodes in the tree. The root node is always
kept as the first element of the array, i.e. the root node will be stored in the 0th index. The left child
and right child are stored in the successive memory locations.
A

B C

D E F G

Array representation:
A
B
C
D
E
F
G

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 39 3/3/2012 10:49:50 AM


Q.40 Solved Question Papers

Linked list representation:


∗ A ∗

∗ B ∗
∗ C ∗

∗ D ∗ ∗ E ∗ ∗ F ∗ ∗ G ∗

Null Null Null Null Null Null Null Null

9. (a) The rear and front end of the queue are interconnected in circular queues. After reaching the
rear end, if the front end is not at zero, the rear end will again be set to zero. The same will be
implemented with the front end.
Overflow: The situation is termed as overflow if one tries to insert an element in a filled queue.
The condition for overflow is:
Rear = Size –1 and front = 0 or Front = Rear +1 (for the queue starting with 0)
Rear = Size and front =1 or front = Rear +1 (for the queue starting with 1)
Underflow: If one tries to delete an element from an empty queue, then the situation is called
underflow. The condition for underflow is:
Front = –1 (for the queue starting with 0)
Front = 0 (for the queue starting with 1)
Examples:
C_Queue(5) Front = −1, rear = −1
0 1 2 3 4
Insert(5) 5 Front = 0, rear = 0
0 1 2 3 4
Insert(25) 5 25 Front = 0, rear = 1
0 1 2 3 4
Insert(53) 5 25 53 Front = 0, rear = 2
0 1 2 3 4
Insert(78) 5 25 53 78 Front = 0, rear = 3
0 1 2 3 4
Insert(99) 5 25 53 78 99 Front = 0, rear = 4
0 1 2 3 4
Insert(145) “Overflow” (rear = size –1 condition for overflow)

Delete 25 53 78 99 Front =1, rear = 4


0 1 2 3 4

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 40 3/3/2012 10:49:51 AM


Solved Question Papers Q.41

Delete 53 78 99 Front = 2, rear = 4


0 1 2 3 4
Delete 78 99 Front = 3, rear = 4
0 1 2 3 4
Insert(87) 87 78 99 Front = 3, rear = 0
0 1 2 3 4
Insert(65) 87 65 78 99 Front = 3, rear = 1
0 1 2 3 4
Insert(5) 87 65 5 78 99 Front = 3, rear = 2
0 1 2 3 4
Insert(89) “Overflow”

Delete 87 65 5 99 Front = 4, rear = 2


0 1 2 3 4
Delete 87 65 5 Front = 0, rear = 2
0 1 2 3 4
Delete 65 5 Front = 1, rear = 2
0 1 2 3 4
Delete 5 Front = 2, rear = 2
0 1 2 3 4
Delete 5 Front = –1, rear = –1
0 1 2 3 4
“Underflow” (front = –1) ( Condition for underflow)
(b) The procedure for conversion from infix to postfix using stack is as follows:
Step 1: Insert an opening parenthesis at the beginning and closing parenthesis at the end of the
expression.
Step 2: Arrange the expression in the array.
Step 3: Scan all the elements in the array. If an operand is encountered, store it in the postfix and
if an operator is encountered then push it into the stack followed by Step 4 and Step 5.
Step 4: If the scanned operator has lesser or equal precedence than the existing operator, then pop
out the operators from the stack till a less precedence operator or opening parenthesis is
found.
Step 5: If the scanned operator is a closing parenthesis, than pop the operators from the stack
up to the opening parenthesis and omit them. The poped operators will be stored in the
postfix.

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 41 3/3/2012 10:49:51 AM


Q.42 Solved Question Papers

Step 6: Repeat Step 3, Step 4 and Step 5 till all the elements are scanned from the array.
Step 7: Print the postfix as the result.
Example: Convert (C – D)+(E^F) + F/(H + W)*A^B into postfix by using stack.
Array Stack Postfix
( (
( ((
C (( C
- ((- C
D ((- CD
) ( CD–
+ (+ CD–
( (+( CD–
E (+( CD–E
^ (+(^ CD–E
F (+(^ CD–EF
) (+ CD–EF^
+ (+ CD–EF^+
F (+ CD–EF^+F
/ (+/ CD–EF^+F
( (+/( CD–EF^+F
H (+/( CD–EF^+FH
+ (+(+ CD–EF^+FH
W (+(+ CD–EF^+FHW
) (+(+ CD–EF^+FHW+
* (+* CD–EF^+FHW+
A (+* CD–EF^+FHW+A
^ (+*^ CD–EF^+FHW+A
B (+*^ CD–EF^+FHW+AB
) CD–EF^+FHW+AB^*+

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 42 3/3/2012 10:49:51 AM


Solved Question Papers Q.43

Biju Patnaik University of Technology


Data Structures Using C
(Common for all Branches of Engineering)
Subject Code: BE-2106
2011

Time: 3 hours Full Marks: 70

Question 1 is compulsory. Answer any five questions from the rest. The figures in the right-hand margin indicate
marks.
1. Answer the following questions. (2 10)
(a) What is a stack? Discuss the pop operation of a stack?
(b) Convert the following infix expression into its equivalent postfix and prefix expressions.
a++ –b++ + – –c/d + e*f
(c) Write at least two disadvantages of linear queues?
(d) How are collisions handled in linear probing? Discuss with a simple example.
(e) For a list L = {8, 99, 3, 4, 6, 10}, find the output list at the end of pass 1 using bubble sorting
method.
(f ) What is the use of a head node in a linked list?
(g) Show that the maximum number of nodes in a binary tree of height h is 2h –1 for h>= 1.
(h) Prove with an example that a tree T with n vertices has n–1 edges.
(i) There are 8, 15, 13, 14 nodes in 4 different trees. Which of them could have formed a full binary
tree? Explain in two sentences.
(j) Distinguish between diagraphs and undirected graphs?
2. (a) Suppose a two-dimensional matrix is represented using a row major order in C programming.
Write the formula and calculate the address of element A [10] [10]. Assume the dimension of the
matrix is 10 × 10 and is of floating type. (5)
(b) What is a circular queue? Why is it better than a normal queue? Give some practical examples of
the usage of circular queues. (5)
3. (a) Write an algorithm and program in C to create five nodes of a linked list. (5)
(b) How are priority queues implemented using a single queue? Discuss with an example. (5)
4. (a) Write an algorithm to find the largest node in a binary search tree (5)
(b) Create a binary search tree using the following data entered as a sequential set:
3, 79, 67, 58, 38, 29, 15, 11, 5 (5)
5. (a) Sort the following elements using heap sorting method:
42, 23, 92, 16, 11, 45, 40, 64, 29, 18 (5)
(b) Create an AVL tree using the following data and show the balance factor in the resulting tree:
14, 23, 7, 10, 33, 56, 80, 75, 90 (5)

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 43 3/3/2012 10:49:51 AM


Q.44 Solved Question Papers

6. (a) Given the following inorder and preorder traversals of a binary tree, construct the binary tree: (5)
Inorder: B, F, G, H, P, R, S, T, W, Y, Z
Preorder: P, F, B, H, G, S, R, Y, T, W, Z
(b) Define a graph. Represent the graph shown below using:
(i) Adjacency matrix
(ii) Adjacency list
(iii) Incidence matrix (5)
e5
A
B
e1 e2 E
e3

C D
e4

7. (a) What is dynamic memory management? Explain the buddy system method of memory manage-
ment with its advantages and disadvantages. (5)
(b) Draw a hash table with open addressing and a size of 9. Use the hash function “k%9.” Insert the
keys: 5, 29, 20, 0, 27 and 18 into your table (in that order). (5)
8. (a) An array contains the elements shown below:
44, 78, 22, 7, 98, 56, 34, 2, 38, 35, 45
Arrange the elements of the array using quick sort. (5)
(b) An array contains the elements shown below. Trace the steps followed to find 20 using the binary
search algorithm.
18, 13, 17, 26, 44, 56, 88, 97 (5)

Solutions
1. (a) A stack is a linear structure in which items may be added or removed at one end, which is called
the top of the stack. This means that the last item to be added to a stack is the first item to be
removed. So, stacks are also called last in first out (LIFO) lists. Pop is one of the basic operations
of stack and is used to delete an element from a stack.
(b) Conversion to postfix:
a ++ –b ++ + – –cd/ + ef*
a ++ –b ++ + – –cd/ ef*+
a ++b ++– –cd/ef*++–

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 44 3/3/2012 10:49:51 AM


Solved Question Papers Q.45

Conversion to prefix:
a ++– b++ / – –cd + *ef
a ++ – b++ ++/– – cd*ef
– a ++ b++++/– – cd*ef
(c) A queue consists of a linear list of elements in which deletion takes place at one end called the front
and insertion takes place at another end called the rear. Queue is also called FIFO. The disadvan-
tages of queues are as follows:
• Whenever an element is deleted from the queue, the value of front is increased by 1. Front =
Front+1.
• Whenever an element is inserted in a queue, the value of the rear is increased by 1. Rear = Rear
+1. When the rear indicates the last location of the queue it means that the rear is full. If there
is space in the queue but the rear indicates the last location, we are unable to insert the element.
If we try to do so, the program will flash the message “Queue Full” though it is empty.
(d) The simplest way to resolve a collision is through closed hashing. Suppose there is a hash table of
size h and the key value of interest is mapped to an address location, i, with a hash function. Closed
hashing can be stated as indicated below:
Start with the hash address where the collision has occurred and let it be i. Then the sequence
below needs to be followed:
i, i +1 , i +2,…,h, 1, 2,…,i – 1
The search will continue until any one of the following cases occurs:
• The key value is found.
• Unoccupied (or empty) location is encountered.
• It reaches the location where the search was started.
Example: Assume there is a hash table of size 10. The hash function uses the division method with the
remainder module 7, namely H(K) = (k%7) + 1.
Let us consider the build up of the hash table (initially, which is empty) with the following set of key
values:
15, 11, 25, 16, 9, 8, 12
The hash table for the values above is shown below.
1 1 1 1 1 1 1 1
2 2 15 2 15 2 15 2 15 2 15 2 15 2 15
3 3 3 3 3 16 3 16 3 16 3 16
4 4 4 4 4 4 9 4 9 4 9
5 5 5 11 5 11 5 11 5 11 5 11 5 11
6 6 6 6 25 6 25 6 25 6 25 6 25
7 7 7 7 7 7 7 8 7 8
8 8 8 8 8 8 8 8 12
9 9 9 9 9 9 9 9
10 10 10 10 10 10 10 10
Initialty the Insertion Insertion Insertion Insertion Insertion Insertion Insertion
hash table of 15 of 11 of 25 of 16 of 9 of 8 of 12
is empty
(Buildings-up hash table)

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 45 3/3/2012 10:49:51 AM


Q.46 Solved Question Papers

(e) The output list can be determined as follows:


Pass 1 8 , 99 , 3 , 4 , 6 , 10
8 , 99 , 3 , 4 , 6 , 10
8 , 3 , 99 , 4 , 6 , 10
8 , 3 , 4 , 99 , 6 , 10
8 , 3 , 4 , 6 , 99 , 10
8 , 3 , 4 , 6 , 10 , 99 (Output list)

(f ) A header linked list is a linked list that always contains a special node, called the header node at
the beginning of the list. Two widely used header lists are:
1. A grounded header list is a header list where the last node contains a null pointer.
Start Header
mode
x
(Grounded header list)

2. A circular header list is a header list in which the last node points back to the header node.
Start

(Circular header list)

(g) The maximum number of nodes = 1+ 2 +…+ 2h – 1


= 2h –1for h >= 1.
Level 0

Level 1

Level 2
Height = 3
(h) If n = 3, then edge = n –1, i.e = 2
An example to prove that a tree T with n vertices has n–1 edges is given below:
Case I:
A

B C

Case II:
A

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 46 3/3/2012 10:49:51 AM


Solved Question Papers Q.47

Case III:
A

Case IV:
A

Case V:
A

Hence, n node contains (n–1) edges.


(i) A complete binary tree of depth d is a binary tree whose leaves are at level d. If a binary tree con-
tains m nodes at level l, most of them are nodes at level a +1. A complete binary tree with 15 nodes
is shown below:

A complete binary tree of 15 nodes

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 47 3/3/2012 10:49:52 AM


Q.48 Solved Question Papers

(j) Diagraph: A diagraph is also called a directed graph. It is a graph G, such that G = <V, E>, where
V is the set of all vertices and E is the set of ordered pairs of elements from V.

V1 V4

V2 V3
Digraph

Undirected graph: In the case of an undirected graph, the pair (Vi, Vj) is unordered, i.e. (Vi, Vj)
and (Vj, Vi) are the same edges. However, in the case of a directed graph, they correspond to two
different edges.
V1 V4

V2 V3
An undirected graph

2. (a) Row major circle:


Address (a[i][j]) = b+ (i*u2 +j)*w
In the question it is given that I = 10 j = 10
Assume base = 1000
W = 4 (floating type)
Hence, a[i][j] = 1000 + (10*10 +10)*4
= 1000 + (110)4
= 1000 + 440
= 1440.
(b) Circular queues: If the queue is represented using arrays then the rear insertion will be denied
even if room is available in the front. One way to remove this is by using ordinary array say, a[n].
But logically this implies that a[0] comes after a[n–1] or after a[n–1], a[0] appears. The following
figure shows the logical and physical representation for a circular array.

n−
2 1 01
n−
2
3
j+1 4
j−1 i−1
Rear Front i+1

Front

0 1 i j n-2 n-1 Rear


(a) Circular queue (physical) (b) Circular queue (logical)

The following figure shows a circular queue with eight elements. Here we need two variables, front
and rear, to keep track of the elements to be deleted and inserted.

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 48 3/3/2012 10:49:52 AM


Solved Question Papers Q.49

9[7] 9[0]

9[6] 9[1]

9[5] 9[2]

9[4] 9[3]

Circular queue: The following assumptions are made for circular queue.
• A front value of –1 indicates that the queue is empty.
• The rear is incremented by 1 each time a new element is inserted into the queue, i.e. rear = rear + 1.
• Each time an element is deleted from the queue the value of front is incremented by 1, i.e.
front = front+1.
• If front = rear, the queue contains only elements (except front = rear = –1)
A roundtable conference is a practical example of a circular queue.
3. (a) A program in C to create 5 nodes of a linked list is given below:

#include<stdio.h>
#include<malloc.h>
Struct link
{
int info:
struct link *next:
}
Void Create List(struct link*);
Void Display(struct link*);
/* Function main*/
Void main()
{
Strcut link *node;
Clrscr();
Node=(struct link*)malloc (sizeof (struct link));
If (node = = NULL)
{
Printf(“input of m/r space)
Exit(0);
}
Createlist(node);
Display(node);
}
/* Create the list*/
Void Create list (struct link* node)
{
Char ch;
int i=1;

print f(“\n Enter the value for %d node: “,i);


scanf(“%d”, &node->info);

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 49 3/3/2012 10:49:53 AM


Q.50 Solved Question Papers

node ->next = NULL;


i++;
printf(“\n press ‘n’ to quit any other key to continue:”);
fflush(stdin);
ch=getchar();
while(ch!=’n’)
{
Node->next = (struct link*) malloc(sizeof(struct link));
If (node->next = = NULL)
{
Printf(“\n out of memory space”);
Exit(0);
}
Node= node->next;
Printf(“\nEnter the value for %d node:”,i);
Scanf(“%d”,&node->info);
Node->next= NULL;
I++;
Printf(“\n press ‘n’ to quit any other key to continue :”);
Fflush(stdin);
Ch=getchar();
}
}

Algorithm to create five nodes of a linked list:


1. Create a new node named as NODE
2. If the NODE = NULL then write “Out of m/r space” and i=1
3. Repeat step 4 and 5,6 while (i<=5)
4. Set info[NODE]=X
5. Set next[NODE]= NULL;
6. i=i+1;
7. Exit.

3. (b) Priority queue is a queue in which it is possible to insert an element or remove an element at
any position depending on the priority in the queue. We can say that a priority queue is a series
of queues representing situations in which the priorities associated with the queue elements are
known.
Example: The telecom department maintains a list of telephone subscribers in alphabetical order.
If the list is very large, it is highly cumbersome to locate the numbers of subscribers with names
that begin with letters that appear in the middle of the alphabet. The remedy is to divide the list
into 26 sub-lists. The processing time will reduce automatically.
4. (a) Algorithm to find the largest node in BSI:
TREE-MAXIMUM(x):
1. while right[x] != NIL
2. do x<- right[x]
3. return x.
We will start from the root. The largest element will always be placed as the right child.

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 50 3/3/2012 10:49:53 AM


Solved Question Papers Q.51

(b) The sequential set of data are:


3, 79, 67, 58, 38, 29, 15, 11, 5
The binary search tree is shown below:

79

67

58

38

29

15

11

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 51 3/3/2012 10:49:53 AM


Q.52 Solved Question Papers

5. (a) The elements are:


42, 23, 92, 16, 11, 45, 40, 64, 29, 18
Using heapsort the elements are as follows:
92 92 92
42 92
23 42 23 45 23 45
23 92 23 42

16 11 15 16 11 42 16 11 42 40

92 92 92

23 45 23 45 64 45

16 11 42 40 64 11 42 40 23 11 42 40

64 16 16 29

92 92 92

64 45 64 45 64 45

29 11 42 40 29 11 42 40 29 18 42 40

16 23 16 23 18 16 23 11

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 52 3/3/2012 10:49:53 AM


Solved Question Papers Q.53

(b) The data given are:


14, 23, 7, 10, 33, 56, 80, 75, 90
The AVL tree is shown below:
14(2) 27(1) 27(0) 7(−1)
R
23(1) 14(1) 23(0) 14(1) 23(−1) 14(1) 23−(−2)
L
7(0) 10(0) 10(0) 33(0) 10(0) 33(−1)

7(0) 56(0)
7(0) 7(−1)

14(1) 33(1) 14(1) 33(−1) 14(1) 33(−2)

10(0) 23(0) 56(−1) 10(0) 23(0) 56(−2)


10(0) 23(0) 56(1) R
80(0) 80(1)
L
7(−2) 75(0)
7(−1)
14(1) 33(2)
R
14(1) 33(−1)
10(0) 23(0) 75(−1)
10(0) 23(0) 75(0) L
56(0) 80(−1)
56(0) 80(0)
90(0)

7 7

14 56(−1) 14 56

10 33(1) 75(−2) 10 33 80
R R
23(0) 80(−1) 23 75 90
R
90(0)

6. (a) Inorder: B, F, G, H, P, R, S, T, W, Y, Z (LNR)


Preorder: P, F, B, H, G, S, R, Y, T, W, Z (NLR)
P

F S

B H R T

G G Y W

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 53 3/3/2012 10:49:53 AM


Q.54 Solved Question Papers

(b) Adjacency list:


Node Adj
A C, E
C A, B, D
D C, B
B C, D
E A

e5
A E
B

e1 e2
e3

C D
e4

A C D B E
A 0 1 0 0 1
C 1 0 1 1 0
D 0 1 0 1 0
Adjacency matrix
B 0 1 1 0 0
E 1 0 0 0 0

Adjacency list
Node Adj

A C, E
C A, B, D
D C, B
B C, D
E A

7. (a) Dynamic memory management: In a single programming operating system, the main memory is
divided into two parts—one is for the operating system and the second is for the user process cur-
rently executed. The main features are as follows:
• In a multiprogramming environment the user space is divided into a number of partitions.
• Each portion is for one process. The task of sub-division is carried out dynamically by the
operating system.
• There are four functions of memory management:
º Keeping track of the parts of memory currently being used and by whom.
º Deciding which processes are to be loaded when memory space becomes available.

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 54 3/3/2012 10:49:53 AM


Solved Question Papers Q.55

º Allocation of memory space.


º De-allocation of memory space.
• There are basically three methods used for effective storage management—first fit, best fit and
worst fit.
Buddy system: Buddy system is another storage management system, which restricts the size of blocks to
some fixed set of sizes. The main features are as follows:
• These blocks of restricted sizes are maintained in a linked list.
• Whenever a request for a block of size n comes, the number m, the smallest of the fixed sizes but
equal to or larger than n is determined and a block of size m is allocated if available on the list.
• If a block of size m is not available, then a larger block if available is split into two sub-blocks
(known as buddies). Each of them are also of fixed sizes. This process is repeated until a block
of size m is produced.
• Buddy system specifies the restricted size as F0, F1, Fmass for blocks according to some pattern.
• The recurrence relation is used for the specification of block sizes.
• Fn = F (n–1) + F (n–k), k < = n< = mass.
(b) K is the element to be entered in a hash table of size (maximum entries) 9. The hash function can
be defined as f(k) = k%9. For example, the element (number) 5 will go to cell number 5 as 5%9=5.
Similarly, the element 27 will go to cell number 0 as 27%9=0, 25 will go to 7 as 25%9=7 within
the hash table.

The element /keys to be inserted are: 0 27 29 20 18 5


5%9 = 5
29%9 = 2
20%9 = 2
0%9 = 0
27%9 = 0
18%9 = 0
8. (a) An array contains the elements:
44, 78, 22, 7, 98, 56, 34, 2, 38, 35, 45 using quick sort:

While(a[i]<key)
i++;
while(a[j]>key)
j--;
if(i<j)
swap(a[i],a[j])
else
swap(a[j],key)

44 45 22 7 98 56 34 2 38 35 78

44 35 22 7 98 56 34 2 38 45 78

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 55 3/3/2012 10:49:53 AM


Q.56 Solved Question Papers

44 35 22 7 38 56 34 2 98 45 78

44 35 22 7 38 2 34 56 98 45 78

34 35 22 7 38 2 44 56 98 45 78

34 2 22 7 38 35 44 56 45 98 78

7 2 22 34 38 35 44 45 56 98 78

2 7 22 34 35 38 44 45 56 78 98
The sorted array is as follows:
27, 22, 34, 35, 38, 44, 45, 56, 78, 98
(b) An array contains the elements:
18, 13, 17, 26, 44, 56, 88, 97
Steps to find 20:
18

13 26

20 44
27
56
88
97

Using binary search algorithm:


After 18 as a root node, 20 must be the right child. However, we have 13 which is lesser than 18, i.e 20
is an unsuccessful search. Hence, 20 is not found.

Z01_ASHOK NAMDEV KAMTHANE5067_01_SE_SOLVED PAPERS.indd 56 3/3/2012 10:49:53 AM

You might also like