18cs32 - Data Structure - Notes
18cs32 - Data Structure - Notes
* Visit https://vtuconnect.in for more info. For any queries or questions wrt our
platform contact us at: [email protected]
VTU Connect Android App Download Now On Google Play Store
LESSON NOTES
Vision
Mission
To keep pace with advancements in knowledge and make the students competitive
and capable at the global level.
To create an environment for the students to acquire the right physical, intellectual,
emotional and moral foundations and shine as torch bearers of tomorrow's society.
To strive to attain ever-higher benchmarks of educational excellence.
1. Demonstrate understanding of the principles and working of the hardware and software
aspects of Embedded Systems.
2. Use professional Engineering practices, strategies and tactics for the development,
implementation and maintenance of software.
3. Provide effective and efficient real time solutions using acquired knowledge in
various domains.
Module – 2
Stacks: Definition, Stack Operations, Array Representation of Stacks, Stacks using 10 Hours
Dynamic Arrays, Stack Applications: Polish notation, Infix to postfix conversion,
evaluation of postfix expression. Recursion - Factorial, GCD, Fibonacci Sequence,
Tower of Hanoi, Ackerman's function. Queues: Definition, Array Representation,
Queue Operations, Circular Queues, Circular queues using Dynamic arrays, Dequeues,
Priority Queues, A Mazing Problem. Multiple Stacks and Queues. Programming
Examples. Textbook 1: Chapter 3: 3.1 -3.7 Textbook 2: Chapter 6: 6.1 -6.3, 6.5, 6.7-6.10,
6.12, 6.13
RBT: L1, L2, L3
Module – 3
Linked Lists: Definition, Representation of linked lists in Memory, Memory allocation; 10 Hours
Garbage Collection. Linked list operations: Traversing, Searching, Insertion, and
Deletion. Doubly Linked lists, Circular linked lists, and header linked lists. Linked
Stacks and Queues. Applications of Linked lists – Polynomials, Sparse matrix
representation. Programming Examples Textbook 1: Ch apter 4: 4.1 – 4.6, 4.8,
Textbook
2: Ch apter 5: 5.1 – 5.10, RBT: L1, L2, L3
Module – 4
Trees: Terminology, Binary Trees, Properties of Binary trees, Array and linked Representation 10 Hours
of Binary Trees, Binary Tree Traversals - Inorder, postorder, preorder; Additional Binary tree
operations. Threaded binary trees, Binary Search Trees – Definition, Insertion, Deletion,
Traversal, Searching, Application of Trees-Evaluation of Expression, Programming Examples
Textbook 1: Chapter 5: 5.1 –5.5, 5.7; Textbook 2: Chapter 7: 7.1 – 7.9 RBT: L1, L2, L3
Module – 5
Graphs: Definitions, Terminologies, Matrix and Adjacency List Representation Of Graphs, 10 Hours
Elementary Graph operations, Traversal methods: Breadth First Search and Depth First
Search. Sorting and Searching: Insertion Sort, Radix sort, Address Calculation Sort. Hashing:
Hash Table organizations, Hashing Functions, Static and Dynamic Hashing. Files and Their
Organization: Data Hierarchy, File Attributes, Text Files and Binary Files, Basic File
Operations, File Organizations and Indexing Textbook 1: Chapter 6 : 6.1 –6.2, Chapter 7:7.2,
Chapter 8 : 8.1-8.3 Textbook 2: Chapter 8 : 8.1 –
8.7, Chapter 9 : 9.1-9.3, 9.7, 9.9 Reference 2: Chapter 16 : 16.1 - 16.7 RBT: L1, L2, L3
Course outcomes: The students should be able to:
1. Use different types of data structures, operations and algorithms
2. Apply searching and sorting operations on files
3. Use stack, Queue, Lists, Trees and Graphs in problem solving
4. Implement all data structures in a high-level language for problem solving.
Question paper pattern:
The question paper will have ten questions.
Each full Question consisting of 20 marks
There will be 2 full questions (with a maximum of four sub questions) from each module.
Each full question will have sub questions covering all the topics under a module.
The students will have to answer 5 full questions, selecting one full question from each
module
TextBooks:
1. Ellis Horowitz and Sartaj Sahni, Fundamentals of Data Structures in C, 2nd Ed, Universities Press, 2014.
2. Seymour Lipschutz, Data Structures Schaum's Outlines, Revised 1st Ed, McGraw Hill, 2014
Reference Books
1. Gilberg & Forouzan, Data Structures: A Pseudo-code approach with C, 2nd Ed,
Cengage Learning,2014.
2. 2. Reema Thareja, Data Structures using C, 3rd Ed, Oxford press, 2012.
3. 3. Jean-Paul Tremblay & Paul G. Sorenson, An Introduction to Data Structures with
Applications, 2 nd Ed, McGraw Hill, 2013
4. 4. A M Tenenbaum, Data Structures using C, PHI, 1989
5. 5. Robert Kruse, Data Structures and Program Design in C, 2nd Ed, PHI, 1996.
DATA STRUCTURES
Data may be organized in many different ways. The logical or mathematical model of a
particular organization of data is called a data structure.
Data items that are divided into sub-items are called Group items. Ex: An Employee Name
may be divided into three subitems- first name, middle name, and last name.
Data items that are not able to divide into sub-items are called Elementary items.
Ex: SSN
Entity: An entity is something that has certain attributes or properties which may be assigned
values. The values may be either numeric or non-numeric.
Ex: Attributes- Names, Age, Sex, SSN
Values- Rohland Gail, 34, F, 134-34-5533
Entities with similar attributes form an entity set. Each attribute of an entity set has a range of
values, the set of all possible values that could be assigned to the particular attribute.
The term “information” is sometimes used for data with given attributes, of, in other words
meaningful or processed data.
Example: Student records have variable lengths, since different students take different numbers
of courses. Variable-length records have a minimum and a maximum length.
The above organization of data into fields, records and files may not be complex enough to maintain
and efficiently process certain collections of data. For this reason, data are also organized into more
complex types of structures.
The study of complex data structures includes the following three steps:
1. Logical or mathematical description of the structure
2. Implementation of the structure on a computer
3. Quantitative analysis of the structure, which includes determining the amount of
memory needed to store the structure and the time required to process the structure.
1. Primitive data Structures: Primitive data structures are the fundamental data types which are
supported by a programming language. Basic data types such as integer, real, character and
Boolean are known as Primitive data Structures. These data types consists of characters that
cannot be divided and hence they also called simple data types.
2. Non- Primitive data Structures: Non-primitive data structures are those data structures which
are created using primitive data structures. Examples of non-primitive data structures is the
processing of complex numbers, linked lists, stacks, trees, and graphs.
Based on the structure and arrangement of data, non-primitive data structures is further
classified into
1. Linear Data Structure
2. Non-linear Data Structure
The common examples of linear data structure are Arrays, Queues, Stacks, Linked lists
Arrays:
The simplest type of data structure is a linear (or one dimensional) array. A list of a finite
number n of similar data referenced respectively by a set of n consecutive numbers, usually 1,
2, 3 . . . . . . . n. if A is chosen the name for the array, then the elements of A are denoted by
subscript notation a1, a2, a3….. an
or
by the parenthesis notation A (1), A (2), A (3)............ A (n)
or
by the bracket notation A [1], A [2], A [3]............. A [n]
Example 1: A linear array STUDENT consisting of the names of six students is pictured in
below figure. Here STUDENT [1] denotes John Brown, STUDENT [2] denotes Sandra
Gold, and so on.
Linear arrays are called one-dimensional arrays because each element in such an array is referenced
by one subscript. A two-dimensional array is a collection of similar data elements where each
element is referenced by two subscripts.
Example 2: A chain of 28 stores, each store having 4 departments, may list its weekly sales as in
below fig. Such data can be stored in the computer using a two-dimensional array in which the
first subscript denotes the store and the second subscript the department. If SALES is the name
given to the array, then
SALES [1, 1] = 2872, SALES [1, 2] - 805, SALES [1, 3] = 3211,…., SALES [28, 4] = 982
Trees
Data frequently contain a hierarchical relationship between various elements. The data structure
which reflects this relationship is called a rooted tree graph or a tree.
Some of the basic properties of tree are explained by means of examples
However, Name may be a group item with the sub-items Last, First and MI (middle initial). Also
Address may be a group item with the subitems Street address and Area address, where Area itself
may be a group item having subitems City, State and ZIP code number.
This hierarchical structure is pictured below
Another way of picturing such a tree structure is in terms of levels, as shown below
1. Stack: A stack, also called a fast-in first-out (LIFO) system, is a linear list in which insertions
and deletions can take place only at one end, called the top. This structure is similar in its operation
to a stack of dishes on a spring system as shown in fig.
Note that new 4 dishes are inserted only at the top of the stack and dishes can be deleted only from
the top of the Stack.
2. Queue: A queue, also called a first-in first-out (FIFO) system, is a linear list in which deletions
can take place only at one end of the list, the "from'' of the list, and insertions can take place only at
the other end of the list, the “rear” of the list.
This structure operates in much the same way as a line of people waiting at a bus stop, as pictured
in Fig. the first person in line is the first person to board the bus. Another analogy is with
automobiles waiting to pass through an intersection the first car in line is the first car through.
3. Graph: Data sometimes contain a relationship between pairs of elements which is not
necessarily hierarchical in nature. For example, suppose an airline flies only between the cities
connected by lines in Fig. The data structure which reflects this type of relationship is called a graph.
ARRAYS
• An Array is defined as, an ordered set of similar data items. All the data items of an
array are stored in consecutive memory locations.
• The data items of an array are of same type and each data items can be accessed using
the same name but different index value.
• An array is a set of pairs, <index, value >, such that each index has a value associated
with it. It can be called as corresponding or a mapping
Ex: <index, value>
< 0 , 25 > list[0]=25
< 1 , 15 > list[1]=15
< 2 , 20 > list[2]=20
< 3 , 17 > list[3]=17
< 4 , 35 > list[4]=35
Here, list is the name of array. By using, list [0] to list [4] the data items in list can be
accessed.
Array in C
Declaration: A one dimensional array in C is declared by adding brackets to the name of a
variable.
Ex: int list[5], *plist[5];
• The array list[5], defines 5 integers and in C array start at index 0, so list[0], list[1],
list[2], list[3], list[4] are the names of five array elements which contains an integer
value.
• The array *plist[5], defines an array of 5 pointers to integers. Where, plist[0], plist[1],
plist[2], plist[3], plist[4] are the five array elements which contains a pointer to an
integer.
Implementation:
• When the complier encounters an array declaration, list[5], it allocates five consecutive
memory locations. Each memory is enough large to hold a single integer.
• The address of first element of an array is called Base Address. Ex: For list[5] the
address of list[0] is called the base address.
• If the memory address of list[i] need to compute by the compiler, then the size of the
int would get by sizeof (int), then memory address of list[i] is as follows:
Note: In C the offset i do not multiply with the size of the type to get to the appropriate
element of the array. Hence (list2+i) is equal &list2[i] and *(list2+i) is equal to list2[i].
When sum is invoked, input=&input[0] is copied into a temporary location and associated
with the formal parameter list
A function that prints out both the address of the ith element of the array and the value found
at that address can written as shown in below program.
Output:
Address Content
12244868 0
12344872 1
12344876 2
12344880 3
12344884 4
STRUCTURES
Ex: struct {
char name[10];
int age;
float salary;
} Person;
The above example creates a structure and variable name is Person and that has three fields:
name = a name that is a character array
age = an integer value representing the age of the person
salary = a float value representing the salary of the individual
Ex: strcpy(Person.name,“james”);
Person.age = 10;
Person.salary = 35000;
Type-Defined Structure
The structure definition associated with keyword typedef is called Type-Defined Structure.
Syntax 1: typedef struct
{
data_type member 1;
data_type member 2;
………………………
………………………
data_type member n;
}Type_name;
Where,
• typedef is the keyword used at the beginning of the definition and by using typedef
user defined data type can be obtained.
• struct is the keyword which tells structure is defined to the complier
• The members are declare with their data_type
• Type_name is not a variable, it is user defined data_type.
In above example, humanBeing is the name of the type and it is a user defined data type.
This statement declares the variable person1 and person2 are of type humanBeing.
Structure Operation
The various operations can be performed on structures and structure members.
1. The structures are defined separately and a variable of structure type is declared inside the
definition of another structure. The accessing of the variable of a structure type that are nested
inside another structure in the same way as accessing other member of that structure
Example: The following example shows two structures, where both the structure are defined
separately.
typedef struct {
int month;
int day;
int year;
}date;
typedef struct {
char name[10];
int age;
float salary;
date dob;
} humanBeing;
humanBeing person1;
A person born on February 11, 1944, would have the values for the date struct set as:
person1.dob.month = 2;
person1.dob.day = 11;
person1.dob.year = 1944;
2. The complete definition of a structure is placed inside the definition of another structure.
Example:
typedef struct {
char name[10];
int age;
float salary;
struct {
int month;
int day;
int year;
} date;
} humanBeing;
SELF-REFERENTIAL STRUCTURES
A self-referential structure is one in which one or more of its components is a pointer to itself. Self-
referential structures usually require dynamic storage management routines (malloc and free) to
explicitly obtain and release memory.
Consider as an example:
typedef struct {
char data;
struct list *link ;
} list;
Each instance of the structure list will have two components data and link.
• Data: is a single character,
• Link: link is a pointer to a list structure. The value of link is either the address in
memory of an instance of list or the null pointer.
Consider these statements, which create three structures and assign values to their respective fields:
Structures item1, item2 and item3 each contain the data item a, b, and c respectively, and the null
pointer. These structures can be attached together by replacing the null link field in item 2 with
one that points to item 3 and by replacing the null link field in item 1 with one that points to item
2.
item1.link = &item2;
item2.1ink = &item3;
Unions:
A union is similar to a structure, it is collection of data similar data type or dissimilar.
Syntax: union{
data_type member 1;
data_type member 2;
………………………
………………………
data_type member n;
}variable_name;
Example:
union{
int children;
int beard;
} u;
Union Declaration:
A union declaration is similar to a structure, but the fields of a union must share their memory
space. This means that only one field of the union is "active" at any given time.
union{
char name;
int age;
float salary;
}u;
The major difference between a union and a structure is that unlike structure members which are
stored in separate memory locations, all the members of union must share the same memory space.
This means that only one field of the union is "active" at any given time.
Example:
#include <stdio.h>
union job {
char name[32];
float salary;
int worker_no;
}u;
int main( ){
printf("Enter name:\n");
scanf("%s", &u.name);
printf("Enter salary: \n");
scanf("%f", &u.salary);
printf("Displaying\n Name :%s\n",u.name);
printf("Salary: %.1f",u.salary);
return 0;
}
Output:
Enter name: Albert
Enter salary: 45678.90
Displaying
Name: f%gupad (Garbage Value)
Salary: 45678.90
POINTERS
A pointer is a variable which contains the address in memory of another variable.
The two most important operator used with the pointer type are
& - The unary operator & which gives the address of a variable
* - The indirection or dereference operator * gives the content of the object pointed to
by a pointer.
Declaration
int i, *pi;
pi = &i;
Here, &i returns the address of i and assigns it as the value of pi
Null Pointer
The null pointer points to no object or function.
The null pointer is represented by the integer 0.
The null pointer can be used in relational expression, where it is interpreted as false.
3. Pointer is dangerous when use of explicit type casts in converting between pointer types
Ex: pi = malloc (sizeof (int));
pf = (float*) pi;
4. In some system, pointers have the same size as type int, since int is the default type specifier,
some programmers omit the return type when defining a function. The return type defaults to int
which can later be interpreted as a pointer. This has proven to be a dangerous practice on some
computer and the programmer is made to define explicit types for functions.
Pointers to Pointers
A variable which contains address of a pointer variable is called pointer-to-pointer.
1. malloc( ):
The function malloc allocates a user- specified amount of memory and a pointer to the start of
the allocated memory is returned.
If there is insufficient memory to make the allocation, the returned value is NULL.
Syntax:
data_type *x;
x= (data_type *) malloc(size);
Where,
2. calloc( ):
The function calloc allocates a user- specified amount of memory and initializes the allocated
memory to 0 and a pointer to the start of the allocated memory is returned.
If there is insufficient memory to make the allocation, the returned value is NULL.
Syntax:
data_type *x;
x= (data_type *) calloc(n, size);
Where,
Ex: int *x
x= calloc (10, sizeof(int));
The above example is used to define a one-dimensional array of integers. The capacity of this
array is n=10 and x [0: n-1] (x [0, 9]) are initially 0
Macro CALLOC
#define CALLOC (p, n, s)\
if ( ! ((p) = calloc (n, s)))\
{\
fprintf(stderr, “Insuffiient memory”);\
exit(EXIT_FAILURE);\
}\
3. realloc( ):
• Before using the realloc( ) function, the memory should have been allocated using malloc(
) or calloc( ) functions.
• The function relloc( ) resizes memory previously allocated by either mallor or calloc, which
means, the size of the memory changes by extending or deleting the allocated memory.
• If the existing allocated memory need to extend, the pointer value will not change.
• If the existing allocated memory cannot be extended, the function allocates a new block and
copies the contents of existing memory block into new memory block and then deletes the
old memory block.
• When realloc is able to do the resizing, it returns a pointer to the start of the new block and
when it is unable to do the resizing, the old block is unchanged and the function returns the
value NULL
Syntax:
data_type *x;
x= (data_type *) realloc(p, s );
The size of the memory block pointed at by p changes to S. When s > p the additional s-p
memory block have been extended and when s < p, then p-s bytes of the old block are freed.
Macro REALLOC
#define REALLOC(p,S)\
if (!((p) = realloc(p,s))) \
{\
fprintf(stderr, "Insufficient memory");\
exit(EXIT_FAILURE);\
}\
4. free( )
Dynamically allocated memory with either malloc( ) or calloc ( ) does not return on its own.
The programmer must use free( ) explicitly to release space.
Syntax:
free(ptr);
This statement cause the space in memory pointer by ptr to be deallocated
Linear Array
A linear array is a list of a finite number ‘n’ of homogeneous data element such that
a. The elements of the array are reference respectively by an index set consisting of n
consecutive numbers.
b. The element of the array are respectively in successive memory locations.
The number n of elements is called the length or size of the array. The length or the numbers
of elements of the array can be obtained from the index set by the formula
When LB = 0,
Length = UB – LB + 1
When LB = 1,
Length = UB
Where,
Let LA be a linear array in the memory of the computer. The memory of the computer is
simply a sequence of address location as shown below,
1000
1001
1002
1003
1004
Using the base address of LA, the computer calculates the address of any element of LA by
the formula
Where, w is the number of words per memory cell for the array LA.
While writing computer programs, if finds ourselves in a situation where we cannot determine
how large an array to use, then a good solution to this problem is to defer this decision to run
time and allocate the array when we have a good estimate of the required array size.
Example:
int i, n, *list;
printf(“Enter the number of numbers to generate:”);
scanf(“%d”, &n);
if(n<1)
{
fprintf (stderr, “Improper value of n \n”);
exit(EXIT_FAILURE);
}
MALLOC (list, n*sizeof(int));
The programs fails only when n<1 or insufficient memory to hold the list of numbers that are
to be sorted.
Array-of-arrays representation
int **myArray;
myArray = make2dArray(5,10);
myArray[2][4]=6;
The second line allocates memory for a 5 by 10 two-dimensional array of integers and the
third line assigns the value 6 to the [2][4] element of this array.
ARRAY OPERATIONS
1. Traversing
• Let A be a collection of data elements stored in the memory of the computer. Suppose
if the contents of the each elements of array A needs to be printed or to count the
numbers of elements of A with a given property can be accomplished by Traversing.
• Traversing is a accessing and processing each element in the array exactly once.
Hear LA is a linear array with the lower bound LB and upper bound UB. This algorithm
traverses LA applying an operation PROCESS to each element of LA using while loop.
1. [Initialize Counter] set K:= LB
2. Repeat step 3 and 4 while K ≤ UB
3. [Visit element] Apply PROCESS to LA [K]
4. [Increase counter] Set K:= K + 1
[End of step 2 loop]
5. Exit
Hear LA is a linear array with the lower bound LB and upper bound UB. This algorithm
traverses LA applying an operation PROCESS to each element of LA using repeat – for loop.
1. Repeat for K = LB to UB
Apply PROCESS to LA [K]
[End of loop]
2. Exit.
Example:
Consider the array AUTO which records the number of automobiles sold each year from 1932
through 1984.
To find the number NUM of years during which more than 300 automobiles were sold,
involves traversing AUTO.
1. [Initialization step.] Set NUM := 0
2. Repeat for K = 1932 to 1984:
If AUTO [K] > 300, then: Set NUM: = NUM + 1.
[End of loop.]
3. Return.
2. Inserting
• Let A be a collection of data elements stored in the memory of the computer.
Inserting refers to the operation of adding another element to the collection A.
• Inserting an element at the “end” of the linear array can be easily done provided the memory
space allocated for the array is large enough to accommodate the additional element.
• Inserting an element in the middle of the array, then on average, half of the elements must
be moved downwards to new locations to accommodate the new element and keep the order
of the other elements.
Algorithm:
INSERT (LA, N, K, ITEM)
Here LA is a linear array with N elements and K is a positive integer such that K ≤ N. This
algorithm inserts an element ITEM into the Kth position in LA.
3. Deleting
• Deleting refers to the operation of removing one element to the collection A.
• Deleting an element at the “end” of the linear array can be easily done with difficulties.
• If element at the middle of the array needs to be deleted, then each subsequent
elements be moved one location upward to fill up the array.
Algorithm
DELETE (LA, N, K, ITEM)
Here LA is a linear array with N elements and K is a positive integer such that K ≤ N. this
algorithm deletes the Kth element from LA
4. Sorting
Sorting refers to the operation of rearranging the elements of a list. Here list be a set of n
elements. The elements are arranged in increasing or decreasing order.
Ex: suppose A is the list of n numbers. Sorting A refers to the operation of rearranging the
elements of A so they are in increasing order, i.e., so that,
A[I] < A[2] < A[3] < ... < A[N]
Bubble Sort
Suppose the list of numbers A[l], A[2], ... , A[N] is in memory. The bubble sort algorithm
works as follows:
Example:
Linear Search
Suppose DATA is a linear array with n elements. Given no other information about DATA, The
way to search for a given ITEM in DATA is to compare ITEM with each element of DATA one by
one. That is, first test whether DATA [l] = ITEM, and then test whether DATA[2] = ITEM, and so
on. This method, which traverses DATA sequentially to locate ITEM, is called linear search or
sequential search.
Average Case: The average number of comparisons required to find the location of ITEM is
approximately equal to half the number of elements in the array.
(𝑛+1)
f(n)=
2
Binary Search
Suppose DATA is an array which is sorted in increasing numerical order or, equivalently,
alphabetically. Then there is an extremely efficient searching algorithm, called binary search,
which can be used to find the location LOC of a given ITEM of information in DATA.
That is, the running time for the worst case is approximately equal to log2 n. One can also
show that the running time for the average case is approximately equal to the running time for
the worst case.
MULTIDIMENSIONAL ARRAY
Two-Dimensional Arrays
The element of A with first subscript j and second subscript k will be denoted by
AJ,K or A[J, K]
The computer uses the formula to find the address of LA[K] in time independent of K.
LOC (LA[K]) = Base(LA) + w(K - 1)
The computer keeps track of Base(A)-the address of the first element A[1, 1] of A-and
computes the address LOC(A[J, K]) of A[J, K] using the formula
The element of B with subscripts K1 K2 ... , Kn will be denoted by B[K1 K2 ... , Kn]
The programming language will store the array B either in row-major order or in column-
major order.
Let C be such an n-dimensional array. The index set for each dimension of C consists of the
consecutive integers from the lower bound to the upper bound of the dimension. The length Li
of dimension i of C is the number of elements in the index set, and Li can be calculated, as
Li = upper bound - lower bound + 1
For a given subscript Ki, the effective index Ei of Li is the number of indices preceding Ki in
the index set, and Ei can be calculated from
Ei = Ki - lower bound
Then the address LOC(C[K1 K2 ... , Kn] of an arbitrary element of C can be obtained from the
formula
Base(C) + w[((( ... (ENLN-1 ] + E N-1])LN-2) + ... + E3))L2 + E2)L1 + E1]
or from the formula
Base(C) + w[( ... ((E1L2 + E2)L3 + E3)L4 + ... + EN-1 )LN + EN]
POLYNOMIALS
What is a polynomial?
“A polynomial is a sum of terms, where each term has a form axe , where x is the variable, a is
the coefficient and e is the exponent.”
The largest (or leading) exponent of a polynomial is called its degree. Coefficients that are
zero are not displayed. The term with exponent equal to zero does not show the variable since
x raised to a power of zero is 1.
Polynomial Representation
One way to represent polynomials in C is to use typedef to create the type polynomial as
below:
Now if a is a variable and is of type polynomial and n < MAX_DEGREE, the polynomial
A(x) = Σai xi would be represented as:
a.degree = n
a.coef[i] = an-i , 0 ≤ i ≤ n
In this representation, the coefficients is stored in order of decreasing exponents, such that
a.coef [i] is the coefficient of xn-i provided a term with exponent n-i exists;
Otherwise, a.coef [i] =0. This representation leads to very simple algorithms for most of the
operations, it wastes a lot of space.
To preserve space an alternate representation that uses only one global array, terms to store
all polynomials.
The C declarations needed are:
• The above figure shows how these polynomials are stored in the array terms. The index
of the first term of A and B is given by startA and startB, while finishA and finishB
give the index of the last term of A and B.
• The index of the next free location in the array is given by avail.
• For above example, startA=0, finishA=1, startB=2, finishB=5, & avail=6.
Polynomial Addition
• C function is written that adds two polynomials, A and B to obtain D =A + B.
• To produce D (x), padd( ) is used to add A (x) and B (x) term by term. Starting at
position avail, attach( ) which places the terms of D into the array, terms.
• If there is not enough space in terms to accommodate D, an error message is printed to
the standard error device & exits the program with an error condition
void padd(int startA, int finishA, int startB, int finishB, int *startD,int *finishD)
{ /* add A(x) and B(x) to obtain D(x) */
float coefficient;
*startD = avail;
while (startA <= finishA && startB <= finishB)
switch(COMPARE(terms[startA].expon, terms[startB].expon))
{
case -1: /* a expon < b expon */
attach (terms [startB].coef, terms[startB].expon);
startB++;
break;
if (coefficient)
attach (coefficient, terms[startA].expon);
startA++;
startB++;
break;
Department of CSE, ATMECE, Mysuru 35
VTU Connect Android App Download Now On Google Play Store
VTU Connect Android
Data Structures App
& Applications [18CS32] Download Now On Google Play Store
Analysis of padd( ):
The number of non-zero terms in A and B is the most important factors in analyzing the time
complexity.
Let m and n be the number of non-zero terms in A and B, If m >0 and n > 0, the while loop is
entered. Each iteration of the loop requires O(1) time. At each iteration, the value of startA or
startB or both is incremented. The iteration terminates when either startA or startB exceeds
finishA or finishB.
𝑛 𝑛
A(x) = ∑ 𝑖=0 𝑥2𝑖 and B(x) = ∑ 𝑥2𝑖+1
𝑖=0
The time for the remaining two for loops is bounded by O(n + m) because we cannot iterate
the first loop more than m times and the second more than n times. So, the asymptotic
computing time of this algorithm is O(n +m).
SPARSE MATRICES
A matrix contains m rows and n columns of elements as illustrated in below figures. In this figure,
the elements are numbers. The first matrix has five rows and three columns and the second has six
rows and six columns. We write m x n (read "m by n") to designate a matrix with m rows and n
columns. The total number of elements in such a matrix is mn. If m equals n, the matrix is
square.
Important Note:
A sparse matrix can be represented in 1-Dimension, 2- Dimension and 3- Dimensional array.
When a sparse matrix is represented as a two-dimensional array as shown in
Figure B, more space is wasted.
Example: consider the space requirements necessary to store a 1000 x 1000 matrix that has only
2000 non-zero elements. The corresponding two-dimensional array requires space for 1,000,000
elements. The better choice is by using a representation in which only the nonzero elements are
stored.
• The below figure shows the representation of matrix in the array “a” a[0].row contains the
number of rows, a[0].col contains the number of columns and a[0].value contains the total
number of nonzero entries.
• Positions 1 through 8 store the triples representing the nonzero entries. The row index is in
the field row, the column index is in the field col, and the value is in the field value. The
triples are ordered by row and within rows by columns.
a[0] 6 6 8 b[0] 6 6 8
[1] 0 0 15 [1] 0 0 15
[2] 0 3 22 [2] 0 4 91
[3] 0 5 -15 [3] 1 1 11
[4] 1 1 11 [4] 2 1 3
[5] 1 2 3 [5] 2 5 28
[6] 2 3 -6 [6] 3 0 22
[7] 4 0 91 [7] 3 2 -6
[8] 5 2 28 [8] 5 0 -15
Fig (a): Sparse matrix stored as triple Fig (b): Transpose matrix stored as triple
Transposing a Matrix
To transpose a matrix, interchange the rows and columns. This means that each element
a[i][j] in the original matrix becomes element a[j][i] in the transpose matrix.
If we process the original matrix by the row indices it is difficult to know exactly where to
place element <j, i, value> in the transpose matrix until we processed all the elements that
precede it.
This can be avoided by using the column indices to determine the placement of elements in
the transpose matrix. This suggests the following algorithm:
The columns within each row of the transpose matrix will be arranged in ascending order. void
transpose (term a[], term b[])
{ /* b is set to the transpose of a */
int n, i, j, currentb;
n = a[0].value; /* total number of elements */
b[0].row = a[0].col; /* rows in b = columns in a */
b[0].col = a[0].row; /* columns in b = rows in a */
b[0].value = n;
if (n > 0)
{ currentb = 1;
for (i = 0; i < a[O].col; i++)
for (j= 1; j<=n; j++)
if (a[j].col == i)
{
b[currentb].row = a[j].col;
b[currentb].col = a[j].row;
b[currentb].value = a[j].value;
currentb++;
}
}
}
Transpose of a sparse matrix
STRING
BASIC TERMINOLOGY:
Each programming languages contains a character set that is used to communicate with the
computer. The character set include the following:
Alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Digits: 012345678 9
Special characters: + - / * ( ) , . $ = ‘ _ (Blank space)
Concatenation: Let S1 and S2 be the strings. The string consisting of the characters of S1
followed by the character S2 is called Concatenation of S1 and S2.
Ex: ‘THE’ // ‘END’ = ‘THEEND’
‘THE’ // ‘ ’ // ‘END’ = ‘THE END’
Substring: A string Y is called substring of a string S if there exist string X and Z such that
S = X // Y // Z
If X is an empty string, then Y is called an Initial substring of S, and Z is an empty string then
Y is called a terminal substring of S.
Ex: ‘BE OR NOT’ is a substring of ‘TO BE OR NOT TO BE’
‘THE’ is an initial substring of ‘THE END’
STRINGS IN C
In C, the strings are represented as character arrays terminated with the null character \0.
Declaration 1:
#define MAX_SIZE 100 /* maximum size of string */
char s[MAX_SIZE] = {“dog”};
char t[MAX_SIZE] = {“house”};
s[0] s[1] s[2] s[3] t[0] t[1] t[2] t[3] t[4] t[4]
d o g \0 h o u s e \0
The above figure shows how these strings would be represented internally in memory.
Declaration 2:
char s[ ] = {“dog”};
char t[ ] = {“house”};
Using these declarations, the C compiler will allocate just enough space to hold each word
including the null character.
STORING STRINGS
Example: Suppose the input consists of the program. Using a record oriented, fixed length
storage medium, the input data will appear in memory as pictured below.
That is, one can use a linear array POINT which gives the address of successive record, so
that the records need not be stored in consecutive locations in memory. Inserting a new record
will require only an updating of the array POINT.
The other method to store strings one after another by using some separation marker, such as
the two dollar sign ($$) or by using a pointer giving the location of the string.
These ways of storing strings will save space and are sometimes used in secondary memory
when records are relatively permanent and require little changes.
These types of methods of storage are usually inefficient when the strings and their lengths
are frequently being changed.
Linked Storage
• Most extensive word processing applications, strings are stored by means of linked
lists.
• In a one way linked list, a linearly ordered sequence of memory cells called nodes,
where each node contains an item called a link, which points to the next node in the
list, i.e., which consists the address of the next node.
Ex: TO BE OR NOT TO BE
Constants
Many programming languages denotes string constants by placing the string in either single
or double quotation marks.
Ex: ‘THE END’
“THE BEGINNING”
The string constants of length 7 and 13 characters respectively.
Variables
Each programming languages has its own rules for forming character variables. These
variables fall into one of three categories
1. Static: In static character variable, whose length is defined before the program is
executed and cannot change throughout the program
2. Semi-static: The length of the variable may vary during the execution of the program
as long as the length does not exceed a maximum value determined by the program
before the program is executed.
3. Dynamic: The length of the variable can change during the execution of the program.
STRING OPERATION
Substring
Accessing a substring from a given string requires three pieces of information:
(1) The name of the string or the string itself
(2) The position of the first character of the substring in the given string
(3) The length of the substring or the position of the last character of the substring.
The syntax denote the substring of a string S beginning in a position K and having a length L.
Indexing
Indexing also called pattern matching, refers to finding the position where a string pattern P
first appears in a given string text T. This operation is called INDEX
If the pattern P does not appears in the text T, then INDEX is assigned the value 0.
The arguments “text” and “pattern” can be either string constant or string variable.
Concatenation
Let S1 and S2 be string. The concatenation of S1 and S2 which is denoted by S1 // S2, is the string
consisting of the characters of S1 followed by the character of S2.
Ex:
(a) Suppose S1 = 'MARK' and S2= ‘TWAIN' then
S1 // S2 = ‘MARKTWAIN’
Length
The number of characters in a string is called its length.
Syntax: LENGTH (string)
String length is determined in C language using the strlen( ) function, as shown below:
X = strlen ("sunrise");
strlen function returns an integer value 7 and assigns it to the variable X
Similar to strcat, strlen is also a part of string.h, hence the header file must be included at the
time of pre-processing.
Pattern matching is the problem of deciding whether or not a given string pattern P appears in a
string text T. The length of P does not exceed the length of T.
Observation of algorithms
• P is an r-character string and T is an s-character string
• Algorithm contains two loops, one inside the other. The outer loop runs through each
successive R-character substring WK = T[K] T[K + 1] ... T[K+R-l] of T.
• The inner loop compares P with WK, character by character. If any character does not match,
then control transfers to Step 5, which increases K and then leads to the next substring of T.
• If all the R characters of P do match those of some WK then P appears in T and K is the
INDEX of P in T.
• If the outer loop completes all of its cycles, then P does not appear in T and so INDEX
= 0.
Complexity
The complexity of this pattern matching algorithm is equal to O(n 2)
This algorithm contains the table that is used for the pattern P = aaba.
The table is obtained as follows.
• Let Qi denote the initial substring of P of length i, hence Q0 = A, Q1 = a, Q2 = a2, Q3
= aab, Q4 = aaba = P (Here Q0 = A is the empty string.)
• The rows of the table are labeled by these initial substrings of P, excluding P itself.
• The columns of the table are labeled a, b and x, where x represents any character that doesn't
appear in the pattern P.
• Let f be the function determined by the table; i.e., let f(Qi, t) denote the entry in the table in
row Qi and column t (where t is any character). This entry f(Qi, t) is defined to be the largest
Q that appears as a terminal substring in the string (Qi t) the concatenation of Qi and t.
For example,
a2 is the largest Q that is a terminal substring of Q2a = a3, so f(Q2, a) = Q2 A
is the largest Q that is a terminal substring of Q1b = ab, so f(Q1, b) = Q0 a is
the largest Q that is a terminal substring of Q0a = a, so f(Q0, a) = Q1
A is the largest Q that is a terminal substring of Q3a = a3bx, so f(Q3, x) = Q0
STACKS
DEFINITION
“A stack is an ordered list in which insertions (pushes) and deletions (pops) are made at one
end called the top.”
Given a stack S= (a0, ... ,an-1), where a0 is the bottom element, an-1 is the top element, and ai is
on top of element ai-1, 0 < i < n.
As shown in above figure, the elements are added in the stack in the order A, B, C, D, E, then
E is the first element that is deleted from the stack and the last element is deleted from stack
is A. Figure illustrates this sequence of operations.
Since the last element inserted into a stack is the first element removed, a stack is also known
as a Last-In-First-Out (LIFO) list.
STACK OPERATIONS
Implementation of the stack operations as follows.
1. Stack Create
Stack CreateS(maxStackSize )::=
#define MAX_STACK_ SIZE 100 /* maximum stack size*/
typedef struct
{
int key;
/* other fields */
} element;
element stack[MAX_STACK_SIZE];
int top = -1;
The element which is used to insert or delete is specified as a structure that consists of only a
key field.
The IsEmpty and IsFull operations are simple, and is implemented directly in the program
push and pop functions. Each of these functions assumes that the variables stack and top are
global.
4. Push( )
Function push checks whether stack is full. If it is, it calls stackFull( ), which prints an error
message and terminates execution. When the stack is not full, increment top and assign item to
stack [top].
5. Pop( )
Deleting an element from the stack is called pop operation. The element is deleted only from
the top of the stack and only one element is deleted at a time.
element pop ( )
{ /*delete and return the top element from the stack */
if (top == -1)
return stackEmpty(); /*returns an error key */
return stack[top--];
}
6. stackFull( )
The stackFull which prints an error message and terminates execution.
void stackFull()
{
fprintf(stderr, "Stack is full, cannot add element");
exit(EXIT_FAILURE);
}
The array is used to implement stack, but the bound (MAX_STACK_ SIZE) should be known
during compile time. The size of bound is impossible to alter during compilation hence this
can be overcome by using dynamically allocated array for the elements and then increasing
the size of array as needed.
4. push()
Here the MAX_STACK_SIZE is replaced with capacity
5. pop( )
In this function, no changes are made.
element pop ( )
{ /* delete and return the top element from the stack */
if (top == -1)
return stackEmpty(); /* returns an error key */
return stack[top--];
}
6. stackFull( )
The new code shown below, attempts to increase the capacity of the array stack so that new
element can be added into the stack. Before increasing the capacity of an array, decide what
the new capacity should be.
In array doubling, array capacity is doubled whenever it becomes necessary to increase the
capacity of an array.
void stackFull()
{
REALLOC (stack, 2*capacity*sizeof(*stack));
capacity *= 2;
}
Stack full with array doubling
Analysis
In the worst case, the realloc function needs to allocate 2*capacity*sizeof (*stack) bytes of
memory and copy capacity *sizeof (*stack)) bytes of memory from the old array into the
new one. Under the assumptions that memory may be allocated in O(1) time and that a stack
element can be copied in O(1) time, the time required by array doubling is O(capacity).
Initially, capacity is 1.
Suppose that, if all elements are pushed in stack and the capacity is 2k for some k, k>O, then
the total time spent over all array doublings is O ( ∑𝑘 𝑖=1 2𝑖 ) = O(2k+l) = O(2k).
Since the total number of pushes is more than 2k-1, the total time spend in array doubling is
O(n), where n is the total number of pushes. Hence, even with the time spent on array
doubling added in, the total run time of push over all n pushes is O(n).
Expressions: It is sequence of operators and operands that reduces to a single value after
evaluation is called an expression.
X=a/b–c+d*e–a*c
In above expression contains operators (+, –, /, *) operands (a, b, c, d, e).
Infix Expression: In this expression, the binary operator is placed in-between the operand.
The expression can be parenthesized or un- parenthesized.
Example: A + B
Here, A & B are operands and + is operand
Prefix or Polish Expression: In this expression, the operator appears before its operand.
Example: + A B
Here, A & B are operands and + is operand
Postfix or Reverse Polish Expression: In this expression, the operator appears after its
operand.
Example: A B +
Here, A & B are operands and + is operand
The first answer is picked most because division is carried out before subtraction, and
multiplication before addition. If we wanted the second answer, write expression differently
using parentheses to change the order of evaluation
X= ((a / ( b – c + d ) ) * ( e – a ) * c
In C, there is a precedence hierarchy that determines the order in which operators are
evaluated. Below figure contains the precedence hierarchy for C.
• The operators are arranged from highest precedence to lowest. Operators with highest
precedence are evaluated first.
• The associativity column indicates how to evaluate operators with the same precedence. For
example, the multiplicative operators have left-to-right associativity. This means that the
expression a * b / c % d / e is equivalent to ( ( ( ( a * b ) / c ) % d ) / e )
• Parentheses are used to override precedence, and expressions are always evaluated from the
innermost parenthesized expression first
• The analysis of the examples suggests a precedence-based scheme for stacking and
unstacking operators.
• The left parenthesis complicates matters because it behaves like a low-precedence operator
when it is on the stack and a high-precedence one when it is not. It is placed in the stack
whenever it is found in the expression, but it is unstacked only when its matching right
parenthesis is found.
• There are two types of precedence, in-stack precedence (isp) and incoming precedence
(icp).
void postfix(void)
{
char symbol;
precedence token;
int n = 0,top = 0; /* place eos on stack */
stack[0] = eos;
for (token = getToken(&symbol, &n); token != eos; token =
getToken(&symbol,& n ))
{
if (token == operand)
printf("%c", symbol);
else if (token == rparen)
{
while (stack[top] != lparen)
printToken(pop( ));
pop( );
}
else{
while(isp[stack[top]] >= icp[token])
printToken(pop());
push(token);
}
}
while((token = pop ())!= eos)
printToken(token);
printf("\n");
}
Analysis of postfix: Let n be the number of tokens in the expression. Ө (n) time is spent extracting
tokens and outputting them. Time is spent in the two while loops, is Ө (n) as the number of tokens
that get stacked and unstacked is linear in n. So, the complexity of function postfix is Ө (n).
int eval(void)
{
precedence token;
char symbol;
int opl,op2, n=0;
int top= -1;
token = getToken(&symbol, &n);
while(token! = eos)
{
if (token == operand)
push(symbol-'0'); /* stack insert */
else {
op2 = pop(); /* stack delete */
opl = pop();
switch(token) {
case plus: push(opl+op2);
break;
case minus: push(opl-op2);
break;
case times: push(opl*op2);
break;
case divide: push(opl/op2);
break;
case mod: push(opl%op2);
}
}
token = getToken(&symbol, &n);
}
return pop(); /* return result */
}
RECURSION
A recursive procedure
Suppose P is a procedure containing either a Call statement to itself or a Call statement to a
second procedure that may eventually result in a Call statement back to the original procedure
P. Then P is called a recursive procedure. So that the program will not continue to run
indefinitely, a recursive procedure must have the following two properties:
1. There must be certain criteria, called base criteria, for which the procedure does not call
itself.
2. Each time the procedure does call itself (directly or indirectly), it must be closer to the
base criteria.
A recursive function
A function is said to be recursively defined if the function definition refers to itself. A recursive
function must have the following two properties:
1. There must be certain arguments, called base values, for which the function does not
refer to itself.
2. Each time the function does refer to itself, the argument of the function must be closer
to a base value
A recursive function with these two properties is also said to be well-defined.
Factorial Function
“The product of the positive integers from 1 to n, is called "n factorial" and is denoted by n!”
n! = 1*2 * 3 ... (n - 2)*(n - 1)*n
It is also convenient to define 0! = 1, so that the function is defined for all nonnegative integers.
Observe that this definition of n! is recursive, since it refers to itself when it uses (n - 1)!
(a) The value of n! is explicitly given when n = 0 (thus 0 is the base value )
(b) The value of n! for arbitrary n is defined in terms of a smaller value of n which is closer to
the base value 0.
1. Using for loop: This procedure evaluates N! using an iterative loop process
2. Using recursive function: This is a recursive procedure, since it contains a call to itself
GCD
The greatest common divisor (GCD) of two integers m and n is the greatest integer that divides
both m and n with no remainder.
Fibonacci Sequence
That is, F0 = 0 and F1 = 1 and each succeeding term is the sum of the two preceding terms.
Here
(a) The base values are 0 and 1
(b) The value of Fn is defined in terms of smaller values of n which are closer to the base values.
A procedure for finding the nth term Fn of the Fibonacci sequence follows.
Tower of Hanoi
Problem description
Suppose three pegs, labeled A, Band C, are given, and suppose on peg A a finite number n of
disks with decreasing size are placed.
The objective of the game is to move the disks from peg A to peg C using peg B as an auxiliary.
We write A→B to denote the instruction "Move top disk from peg A to peg B"
In other words,
n=3: A→C, A→B, C→B, A→C, B→A, B→C, A→C
For completeness, the solution to the Towers of Hanoi problem for n = 1 and n = 2
n=l: A→C
n=2: A→B, A→C, B→C
The Towers of Hanoi problem for n > 1 disks may be reduced to the following sub-problems:
(1) Move the top n - 1 disks from peg A to peg B
(2) Move the top disk from peg A to peg C: A→C.
(3) Move the top n - 1 disks from peg B to peg C.
• When n > 1, the solution may be reduced to the solution of the following three sub-
problems:
(a) TOWER (N - I, BEG, END, AUX)
(b) TOWER (l, BEG, AUX, END) or BEG → END
(c) TOWER (N - I, AUX, BEG, END)
Ackermann function
The Ackermann function is a function with two arguments each of which can be assigned any
nonnegative integer: 0, 1, 2, ....
QUEUES
DEFINITION
• “A queue is an ordered list in which insertions (additions, pushes) and deletions
(removals and pops) take place at different ends.”
• The end at which new elements are added is called the rear, and that from which old
elements are deleted is called the front.
If the elements are inserted A, B, C, D and E in this order, then A is the first element deleted
from the queue. Since the first element inserted into a queue is the first element removed,
queues are also known as First-In-First-Out (FIFO) lists.
Figure indicates the way elements will be deleted from the queue and the way new elements
will be added to the queue.
• Whenever an element is deleted from the queue, the value of FRONT is increased by 1;
this can be implemented by the assignment FRONT := FRONT + 1
• When an element is added to the queue, the value of REAR is increased by 1; this can
be implemented by the assignment REAR := REAR + 1
QUEUE OPERATIONS
Implementation of the queue operations as follows.
1. Queue Create
Queue CreateQ(maxQueueSize) ::=
#define MAX_QUEUE_ SIZE 100 /* maximum queue size */
typedef struct
{
int key; /* other fields */
} element;
element queue[MAX_QUEUE_ SIZE];
int rear = -1;
int front = -1;
In the queue, two variables are used which are front and rear. The queue increments rear in
addq( ) and front in delete( ). The function calls would be
addq (item); and item =delete( );
4. addq(item)
void addq(element item)
{ /* add an item to the queue */
if (rear == MAX_QUEUE_SIZE-1)
queueFull();
queue [++rear] = item;
}
5. deleteq( )
element deleteq()
{ /* remove element at the front of the queue */
if (front == rear)
return queueEmpty( ); /* return an error key */
return queue[++front];
}
Program: Delete from a queue
6. queueFull( )
The queueFull function which prints an error message and terminates execution
void queueFull()
{
fprintf(stderr, "Queue is full, cannot add element");
exit(EXIT_FAILURE);
}
Drawback of Queue
When item enters and deleted from the queue, the queue gradually shifts to the right as shown
in figure.
In this above situation, when we try to insert another item, which shows that the queue is full .
This means that the rear index equals to MAX_QUEUE_SIZE -1. But even if the space is
available at the front end, rear insertion cannot be done.
Method 1:
• When an item is deleted from the queue, move the entire queue to the left so that the first
element is again at queue[0] and front is at -1. It should also recalculate rear so that it is
correctly positioned.
• Shifting an array is very time-consuming when there are many elements in queue &
queueFull has worst case complexity of O(MAX_QUEUE_ SIZE)
Method 2:
Circular Queue
• It is “The queue which wrap around the end of the array.” The array positions are arranged
in a circle.
• In this convention the variable front is changed. front variable points one position
counterclockwise from the location of the front element in the queue. The convention for
rear is unchanged.
CIRCULAR QUEUES
• It is “The queue which wrap around the end of the array.” The array positions are arranged
in a circle as shown in figure.
• In this convention the variable front is changed. front variable points one position
counterclockwise from the location of the front element in the queue. The convention for
rear is unchanged.
• When the array is viewed as a circle, each array position has a next and a previous position.
The position next to MAX-QUEUE-SIZE -1 is 0, and the position that precedes 0 is MAX-
QUEUE-SIZE -1.
• When the queue rear is at MAX_QUEUE_SIZE-1, the next element is inserted at position
0.
• In circular queue, the variables front and rear are moved from their current position to the
next position in clockwise direction. This may be done using code
if (rear = = MAX_QUEUE_SIZE-1)
rear = 0;
else rear++;
element deleteq()
{ /* remove front element from the queue */
element item;
if (front == rear)
return queueEmpty( ); /* return an error key */
front = (front+1)% MAX_QUEUE_SIZE;
return queue[front];
}
Program: Delete from a circular queue
Note:
• When queue becomes empty, then front =rear. When the queue becomes full and
front =rear. It is difficult to distinguish between an empty and a full queue.
• To avoid the resulting confusion, increase the capacity of a queue just before it
becomes full.
Consider the full queue of figure (a). This figure shows a queue with seven elements in an
array whose capacity is 8. A circular queue is flatten out the array as in Figure (b).
To get a proper circular queue configuration, slide the elements in the right segment (i.e.,
elements A and B) to the right end of the array as in figure (d)
Below program gives the code to add to a circular queue using a dynamically allocated array.
Below program obtains the configuration of figure (e) and gives the code for queueFull. The
function copy (a,b,c) copies elements from locations a through b-1 to locations beginning at c.
void queueFull( )
{ /* allocate an array with twice the capacity */
element *newQueue;
MALLOC ( newQueue, 2 * capacity * sizeof(* queue));
/* copy from queue to newQueue */
/* switch to newQueue*/
front = 2*capacity – 1;
rear = capacity – 2;
capacity * =2;
free(queue);
queue= newQueue;
}
Program: queueFull
DEQUEUES OR DEQUE
A deque (double ended queue) is a linear list in which elements can be added or removed at
either end but not in the middle.
Representation
• Deque is maintained by a circular array DEQUE with pointers LEFT and RIGHT, which
point to the two ends of the deque.
• Figure shows deque with 4 elements maintained in an array with N = 8 memory
locations.
• The condition LEFT = NULL will be used to indicate that a deque is empty.
DEQUE
AAA BBB CCC DDD
1 2 3 4 5 6 7 8
LEFT: 4 RIGHT: 7
PRIORITY QUEUES
A priority queue is a collection of elements such that each element has been assigned a priority and
such that the order in which elements are deleted and processed comes from the following rules:
(1) An element of higher priority is processed before any element of lower priority.
(2) Two elements with the same priority are processed according to the order in which they were
added to the queue.
A prototype of a priority queue is a timesharing system: programs of high priority are processed
first, and programs with the same priority form a standard queue.
One way to maintain a priority queue in memory is by means of a one-way list, as follows:
1. Each node in the list will contain three items of information: an information field INFO,
a priority number PRN and a link number LINK.
2. A node X precedes a node Y in the list
a. When X has higher priority than Y
b. When both have the same priority but X was added to the list before Y. This means
that the order in the one-way list corresponds to the order of the priority queue.
Example:
• Below Figure shows the way the priority queue may appear in memory using linear arrays
INFO, PRN and LINK with 7 elements.
• The diagram does not tell us whether BBB was added to the list before or after DDD. On the
other hand, the diagram does tell us that BBB was inserted before CCC, because BBB and
CCC have the same priority number and BBB appears before CCC in the list.
The main property of the one-way list representation of a priority queue is that the element in
the queue that should be processed first always appears at the beginning of the one-way list.
Accordingly, it is a very simple matter to delete and process an element from our priority
queue.
Algorithm: This algorithm deletes and processes the first element in a priority queue which
appears in memory as a one-way list.
1. Set ITEM:= INFO[START] [This saves the data in the first node.]
2. Delete first node from the list.
3. Process ITEM.
4. Exit.
Algorithm: This algorithm adds an ITEM with priority number N to a priority queue which is
maintained in memory as a one-way list.
1. Traverse the one-way list until finding a node X whose priority number exceeds N. Insert
ITEM in front of node X.
2. If no such node is found, insert ITEM as the last element of the list.
The main difficulty in the algorithm comes from the fact that ITEM is inserted before node X. This
means that, while traversing the list, one must also keep track of the address of the node preceding
the node being accessed.
Example:
Consider the priority queue in Fig (a). Suppose an item XXX with priority number 2 is to be
inserted into the queue. We traverse the list, comparing priority numbers.
Fig (a)
Fig(b)
Observe that DDD is the first element in the list whose priority number exceeds that of XXX.
Hence XXX is inserted in the list in front of DDD, as pictured in Fig(b).
Observe that XXX comes after BBB and CCC, which have the same priority as XXX. Suppose now
that an element is to be deleted from the queue. It will be AAA, the first element in the List.
Assuming no other insertions, the next element to be deleted will be BBB, then CCC, then XXX,
and so on.
• Another way to maintain a priority queue in memory is to use a separate queue for each
level of priority (or for each priority number).
• Each such queue will appear in its own circular array and must have its own pair of
pointers, FRONT and REA R.
• If each queue is allocated the same amount of space, a two-dimensional array QUEUE
can be used instead of the linear arrays.
Observe that FRONT[K] and REAR[K] contain, respectively, the front and rear elements of
row K of QUEUE, the row that maintains the queue of elements with priority number K.
The following are outlines or algorithms for deleting and inserting elements in a priority
queue
Algorithm: This algorithm deletes and processes the first element in a priority queue
maintained by a two-dimensional array QUEUE.
1. [Find the first non-empty queue.]
Find the smallest K such that FRONT[K] ≠ NULL.
2. Delete and process the front element in row K of QUEUE.
3. Exit.
Algorithm: This algorithm adds an ITEM with priority number M to a priority queue
maintained by a two-dimensional array QUEUE.
1. Insert ITEM as the rear element in row M of QUEUE.
2. Exit.
In the figure, n is the number of stacks entered by the user, n < MAX_STACKS, and
m =MEMORY_SIZE. Stack i grow from boundary[i] + 1 to boundary [i + 1] before it is full.
A boundary for the last stack is needed, so set boundary [n] to MEMORY_SIZE-1.
element pop(int i)
{ /* remove top element from the ith stack */
if (top[i] == boundary[i])
return stackEmpty(i);
return memory[top[i]--];
}
Program: Delete an item from the ith stack
The top[i] == boundary[i+1] condition in push implies only that a particular stack ran out of
memory, not that the entire memory is full. But still there may be a lot of unused space between
other stacks in array memory as shown in Figure.
Therefore, create an error recovery function called stackFull , which determines if there is any free
space in memory. If there is space available, it should shift the stacks so that space is allocated to
the full stack.