Top Banner
CHAPTER 2 LISTS, STACKS, QUEUES AND RECURSION Abstract Data Type (ADT) – Sequences as value definitions - Data types in C - Pointers in C -Data structures and C - Arrays in C - Array as ADT - One dimensional array -Implementing one dimensional array - Array as parameters - Two dimensional array -Structures in C - Implementing structures - Unions in C - Implementation of unions -Structure parameters - Allocation of storage and scope of variables. The List ADT – The Stack ADT – The Queue ADT - Recursion 2.0 INTRODUCTION: BASIC TERMINOLOGY; ELEMENTARY DATA ORGANIZATION Data means simply a value or sets of values. A data item refers to a single unit of value. Data items that are divided into sub-items are called group items; those that are not called elementary items. For example, an employee’s name may be divided into three sub-items namely, first name, middle name and last name - but the Employee security or Identification number would normally be treated as a single item. Collections of data are frequently organized into a hierarchy of fields, records and files. A field is a single elementary unit of information. A record is the collection of field values of a given entity and a file is the collection of records. Records may be classified into two types namely, Fixed Length Record and Variable Length Record. In fixed-length records, all the records contain the same data items with the same amount of space assigned to each data item. In variable-length records, file records may contain different lengths. For example, student records usually have variable lengths, since different students take different numbers of courses. Usually, 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. 2.1 Data Type A data type consists of two parts, namely 1. Set of data 2. The operations that can be performed on the data. For example, an integer type consists of values – whole numbers defined in some range and the operations are add, sub, multiply, divide and any other operations appropriate for the application.
107
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Unit II

CHAPTER 2 LISTS, STACKS, QUEUES AND RECURSION

Abstract Data Type (ADT) – Sequences as value definitions - Data types in C

- Pointers in C -Data structures and C - Arrays in C - Array as ADT - One dimensional array -Implementing one dimensional array - Array as parameters - Two dimensional array -Structures in C - Implementing structures - Unions in C - Implementation of unions -Structure parameters - Allocation of storage and scope of variables.

The List ADT – The Stack ADT – The Queue ADT - Recursion 2.0 INTRODUCTION: BASIC TERMINOLOGY; ELEMENTARY DATA ORGANIZATION

Data means simply a value or sets of values. A data item refers to a single unit of value. Data items that are divided into sub-items are called group items; those that are not called elementary items. For example, an employee’s name may be divided into three sub-items namely, first name, middle name and last name - but the Employee security or Identification number would normally be treated as a single item.

Collections of data are frequently organized into a hierarchy of fields, records and files. A field is a single elementary unit of information. A record is the collection of field values of a given entity and a file is the collection of records.

Records may be classified into two types namely, Fixed Length Record and Variable Length Record.

In fixed-length records, all the records contain the same data items with the same amount of space assigned to each data item.

In variable-length records, file records may contain different lengths. For example, student records usually have variable lengths, since different students take different numbers of courses. Usually, 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. 2.1 Data Type A data type consists of two parts, namely

1. Set of data 2. The operations that can be performed on the data.

For example, an integer type consists of values – whole numbers

defined in some range and the operations are add, sub, multiply, divide and any other operations appropriate for the application.

Page 2: Unit II

2.1.1 Classification of Data type There are two types namely,

1. Atomic or Primitive data type 2. Composite or Structured data type

Atomic (Primitive) Data type

Data may be defined as a set and the elements of the set are called the values of the type. It is a set of atomic data having identical properties. It is defined by a set of values and a set of operations that act on the values. There are four basic (atomic or primitive) data types. These are int, float, char and double. For example, we can define atomic data types are shown below: Integer Values : - ∞, ….., -2, -1, 0,1 ,2, ……….., ∞ Operations : *,+,-,/,%,++,--,……. Real Values : -∞,……….0.0,………… ∞ Operations : *,+,-,/,……. Character Values : \0,……..,’A’,’B’,……..’a’,’b’,…….~ Operations : +, - ,………. Composite data type

It can be broken down out sub fields that have meaning. For example, consider a telephone number. There are actually three different parts to a telephone number. First one is country code, then area code and third is the actual telephone number.

The simple data types built from primitives are arrays, pointers ,strings and records with which we can build new data types called structured or composite types.

The structured data types can be classified into two types. 1. Linear data structure Example: Linked lists, Stacks, and Queues 2. Non-linear data structure Example: Trees and Graphs 2.2 ABSTRACT DATA TYPE (ADT) It is an abstract collection of data elements and accessing functions that are meaningful on the data type, where we are not concerning about how the accessing functions will be implemented is referred as ADT.

Page 3: Unit II

For example, the code to read the keyboard is an ADT. It has a data structure, character and a set of operations that can be used to read that data structure. The rules allow us to not only read the structure but to convert it into different data structures such as integers and strings. With an ADT, users are needed to be concerned only with a. What a data type can do b. Statement of operation that can be performed on elements of the ADT There are four levels of processing for a problem. 1. Abstract Level Here, we recognize the relationships among the data elements and general accessing procedures and functions. But we do not decide any thing about how the data will actually be stored or how the operations will actually implemented. 2. Data Structure Level Here, we can analyze the behavior of the operations and make appropriate choice according to the problem. 3. Implementation Level Here, one can decide the ways to represent the data elements in computer memory and to implement the operations in a programming language. 4. Application Level Here, final details of the particular application are decided.

The first level is called conceptual because at these levels we are more concerned with problem solving than with programming.

The middle two levels can be called algorithmic because they concern precise methods for representing data and operating with it.

The last two levels are specifically concerned with programming.

The accessing functions act as an interface between application and implementation level. To specify communication between these two levels , one can define the certain conditions on the newly defined data type.

1. Precondition : The input specifications and the allowable assumptions to the implementation level are called preconditions.

2. Post condition : The output specifications from the implementation level to the application level are called post conditions.

Page 4: Unit II

2.3 Data Types in C:

The primary data types in C language are: int used to represent integer type data float used to represent a number with a decimal form char used to represent a character type data double used to represent double precision floating point data

type The following table shows the size and range of various data types.

Data type Size(Bytes) Range char or signed char 1 -128 to 127 unsigned char 1 0 to 255 int or short int or signed short int or

2 -32768 to 32767

unsigned short int or unsigned int

2 0 to 65,535

float 4 3.4e-38 to 3.4e+38 long int or signed long int

4 -2,147,483,648 to 2,147,483,647

unsigned long int 4 0 to 4,294,967,295 double 8 7e-308 to 1.7e+308 long double 10 3.4e-4932 to 1.1e+4932

2.3.1 USER DEFINED DATA TYPES It allows the user to define new data types. These data types can be used to declare variable names later in the program. The user defined data type has two types, namely 1. typedef data_type 2. enumerated data_type typedef data__type The typedef can be used to define new data types and also used to define structures. Its syntax is :

typedef data_type identifier; where,

data_type ----> refers to int, float or char identifier ----> refers to the new names given to the data_type.

Example :

typedef int marks; typedef float salary;

Page 5: Unit II

typedef char string;

Here, marks, salary and string represents int, float and char respectively. These can be later used to declare variables names. Example :

marks phy,chem,compu; salary total; string name[20];

Here, phy, chem and compu are declared as integer variables, total is declared as floating point variable and name is declared as character array variable. 2.3.2 Enumerated data_ type : It is a set of named integer constants represented by identifiers that specifies all legal values of same data type. Its syntax is: enum name {enumeration list}; where,

enum ---> is a keyword used to represent enumerated datatype name ---> is an user defined data type name which can be declare

the enumeration list. Example : enum month {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG , SEP, OCT,

NOV, DEC};

It creates a new data type called month in which the enumeration list are automatically set to 0 to 11. That is, JAN as 0 , FEB as 1, MAR as 2 and so on. Suppose, if you want to assign the enumeration list from 1 to 12, the declaration should be,

enum month {JAN=1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};

One can also assign different initializes for the enumeration list. For example,

enum month {JAN=1, FEB, MAR=10, APR, MAY, JUN, JUL=25, AUG, SEP, OCT, NOV=50, DEC};

Then the values of the enumeration constant will be

JAN = 1 FEB = 2 MAR = 10 APR = 11 MAY = 12 JUN = 13 JUL = 25 AUG = 26 SEP = 27 OCT = 28 NOV = 50 DEC = 51

Page 6: Unit II

2.4 ARRAYS IN C Arrays are used to store a large amount of data. The array may be defined as a group of related data items that share a common name and type. The variables which are used to represent the individual data in the memory are called by subscripted variables. For example, assumes the group v = 2.0, 1.2, 3.6, ..... If we want to refer to the second number of the group, we write in C as v[1] where 1 is called the subscript. The subscript is enclosed in parenthesis. There are two types of array . These are : 1. One dimensional array : Which is used for the complete list of item. 2. Two dimensional array : Which is used for all the entries in a given table. The elements in a list (or) table can be either numerical quantity (or) string quantity. NOTE : No two arrays can have the same name (or) An array and an ordinary variable can be assigned the same name. 2.4.1 SUBSCRIPTED VARIABLES : Individual elements within an array is called subscripted variable. It is referred by means of an array name followed by the value of the subscript enclosed in parenthesis. In C, the array subscript must be an integer with range from 0 to n-1. Rules for using subscripted variables : 1. Subscript must be an integer and cannot be negative. 2. The subscript must be in square braces after the array name. 3. If there are more than one subscript each should be given in separate

square braces continuously without any commas. Example :

x[3] ........... an element of the list x contain three characters. t[8][4]......... an element of the table t contains a total of 32 characters.

In C, the array is declared as follows :

datatype var_name [size]; where, datatype ----> may be int or real or long or double or char size ----> maximum number of elements in an array. Example :

int a[10];

Page 7: Unit II

This means that, 10 variables are declared to be integers and they are referred to as a[0],a[1],a[2],.....a[9]. In C, the array elements are started 2.4.2 ARRAY INITIALIZATION

The syntax of initializing an array during declaration is: storage_type datatype array_name[size]={list_of_values};

where, storage_type --> is optional datatype --> Specifies the type of element(int/float/char) size --> optional, which indicates the maximum number of

elements in the array. list_of_values --> values used for initializing the array.

Example:

int marks[5]={50,60,70,80,90}; Here, the values 50,60,70,80 and 90 are assigned to the variable marks[0],marks[1],marks[2],marks[3] and marks[4] respectively.

char xyz[10]={'a','b','c'};

Here, the number of values in the array is less than the size of the array. So, the values 'a', 'b' and 'c' are assigned to the variable xyz[0], xyz[1] and xyz[2] and the remaining variables xyz[4] to xyz[9] will be set to zero automatically.

float a[]={1.1,2.24,3.33,4.44}

Here, the array size is omitted. Hence, the C compiler automatically allocates the memory space for all the elements. Therefore, the size of the array is 4. Note : The character array can be initialized by a string constant. Here, the first element of the array being set to the first character in the string, the second element to the second character and so an. The array also receives the terminating string constant '\0'. For example,

char name[]="RUSHMI"; which is equivalent to char name[]={'R','U','S','H','M','I','\0'};

An array is read or written by loop statements as while, do ... while,

and for loop. Example : for (i=0;i<10;i++) scanf("%d",&a[i]); The above segment can also be written as using while loop as follows:

Page 8: Unit II

int a[10],i=0; while (i<10) {

scanf("%d",&a[i]); i++; }

Arrays can also be represented as more than one subscript value. This is called as multi dimensional array. The arrays of more than one dimension is also called as arrays of arrays. It is mainly used in matrix operations. Its syntax is :

variable_name [size][size];

Here the first size denotes the size of row and the second size denotes the size of column. Example :

int a[5][6]; int b[10][10];

In the above example an array name a has 5 rows and 6 columns and

an array b has 10 rows and 10 columns. 2.5 POINTERS IN C We know that, the variables are stored in memory. The number of bytes occupied by each variable varies with respect to the type of the variable. An integer type variable will occupy two bytes, character occupies one byte and float occupies four bytes of memory. Each memory location has a unique address. C provides the features of data manipulation with the addresses of the variables using pointers. 2.5.1 Pointer - Definition: A pointer is defined as a variable that contains the address of other variable. Advantages of pointer:

1. Execution time is reduced. 2. Reduce the length and complexity of a program. 3. Storage space is reduced. 4. Efficient in handling multidimensional arrays (data tables). 5. It normally returns multiple data items from a function via function

arguments.

Page 9: Unit II

6. It is used to pass information back and forth between a function and its reference point.

2.5.2 Declaring a Pointer Variable : To declare and refer a pointer type variable, two special unary operators such as & and * symbols are used. The ampersand (&) symbol is used to represent an address in which the value will be stored in the variable name. Example : &a --- a is a varilable, and &a is the address in the value of a is stored. The asterisk (*) called as indirection operator which is used to declare pointer variable name and it is followed by any pointer variable name. Its syntax is :

datatype *ptr_var; where,

datatype---> may be int,long,float or double. * ---> tells that the variable ptr_var is a pointer variable. ptr_var ---> is the name of the pointer variable of type datatype. char *a; ---> here a is a pointer variable pointing to a character

type variable. int *a,b; ---> a is a pointer variable which can hold the address of an

integer. Example : A C program contains the following statements. float a = 0.01, b =0.03; float c,*xa,*xb; xa = &a; *xa= 2*a; xb = &b; c = 3*(*xb-*xa); Assume that each floating point number occupies 4 bytes of memory. And the value assigned to A begins at address 1130, the value assigned to B begins at address 1134 and the value assigned to C begins at 1138. Hence, i) The value assigned to &a is 1130 ii) The value assigned to &b is 1134 iii) The value assigned to &c is 1138 iv) The value assigned to xa is 1130 (Since xa = &a) v) The value represented by *xa is 0.02 vi) The value represented by &(*xa) is 1130 (Since &(*xa)=xa)

Page 10: Unit II

vii) The value assigned to xb is 1134 (Since xb = &b) viii) The value represented by *xb is 0.03 ix) The value assigned to c is 0.03 2.5.3 Passing values to a Function : Arguments to a function are usually passed in two ways. They are: 1. Sending the values of the arguments (Call by Value) and 2. Sending the addresses of the arguments (Call by Reference) Call by Value : The process of passing the actual value of variables using in the calling function is copied into the corresponding formal arguments used in the called function. Advantages

1. Expressions can be passed as arguments. 2. Unwanted changes to the variables in the calling function can be avoided.

Example :

Write a program to interchange two values

#include <stdio.h> main() {

int x=5; int y=10; interchange(x,y); printf("\n X = %d",x); printf("\n Y = %d",y);

} interchange(int a,int b) {

int k; k=a; a=b; b=k; printf("\n A = %d",a); printf("\n B = %d",b);

} Example :

#include <stdio.h> void add(int); void main() {

int a = 5; printf("\n The value of A before calling the function is %d",a);

Page 11: Unit II

add(a); printf("\n The value of A after calling the function is %d",a);

} void add(int x) {

x = x + 5; printf("\n The value of A in the called function is %d",x);

} The above program displays the following output :

The value of A before calling the function is 5 The value of A in the called function is 10 The value of A after calling the function is 5

CALL BY REFERENCE Here, the addresses of actual arguments in the calling function are copied into formal arguments of the called function. Example :

Write a program to interchange two values using pointers. #include <stdio.h> main() {

int x=5; int y=10; interchange(&x,&y); printf("\n X = %d",x); printf("\n Y = %d",y);

} interchange(int *a,int *b) {

int k; k=*a; *a=*b; *b=k;

} 2.6 SCOPE AND LIFETIME OF VARIABLES IN FUNCTIONS

In C, all the variables have datatypes and storage classes. Datatype may be int, float or char, that represents the type of variable and storage classes determine the lifetime of the storage, associated with the functions. The various storage classes in C are:

Page 12: Unit II

1.Automatic storage class 2. External storage classes 3. Static storage classes 4. Register storage classes Automatic storage classes These variables are declared inside a function. These type of variables are also called as local variables. They are created when the function is called and destroyed when the function is existed. Its value cannot be accessed by any other function. The general form of automatic variables is :

auto datatype v1,v2,.... where,

auto ----> is the keyword used only if the variables are declared explicitly as an automatic variable.

datatype --> may be int, float or char v1,v2,... ---> variable lists

Example:

#include <stdio.h> main() {

auto int n; is equivalent to ..... }

Example :

#include <stdio.h> main() {

int n=10; fun(); printf("\n n = %d in function main",n); } fun1() {

int n=5; n=n*5; /* compound statement with another n */ {

int n; n=1; printf("\nn = %d in inner most block ",n); } printf("\n n= %d (parameter of function fun) ",n);

Page 13: Unit II

}

The output of the above program is n = 1 in inner most block n = 25 (parameter of function fun) n = 10 in function main.

External storage classes :

These are declared out of the main function. They are also known as global variables. These variables can be accessed by any function in the program. The general form of external variables is :

extern datatype v1,v2,.... where,

extern ----> is the keyword used only to define the storage class as external variables.

datatype ---> may be int, float or char v1,v2,... ---> variable lists

Example :

#include <stdio.h> int x; main() {

x=5; run1(); run2(); run3(); printf("%d \t",x); } run1() {

x=x+10; printf("%d\t",x); } run2() {

x=10; printf("%d\t",x); } run3() {

x+=100; printf("%d\t",x); }

The program displays the following output;

Page 14: Unit II

15 10 110 110 In the above program, the keyword extern is not used, since the variable is declared above all functions. If you want to declare a variable inside a function as global, we have to use the keyword extern before the definition of the variable. static storage classes : These variables are defined within a function. It has two types internal static and external static variables. Internal static variable is same as automatic variables except that the contents of the variables is retained throughout the program. The External static variable is declared outside of all functions and is available to all the functions in that program. The general form of external variables is :

static datatype v1,v2,.... where,

extern ----> is the keyword used to define the storage class as static variables.

datatype ---> may be int, float or char v1,v2,... ---> variable lists

Example :

#include <stdio.h> main() {

int i; for (i=0;i<5;i++) state(); } state()/*static variable */ state() /* automatic variable*/ { { static int x=5; int x=5; x=x+1; x=x+1; printf("\nx = %d",x); printf("\nx = %d",x); } } It displays the following output.

x = 6 x = 7 x = 8 In the above program static variable is initialized only once. During the first call to state, x is incremented to 1. Because x is static, this value persists and therefore, next call adds another 1 to x giving it a value of 7. The value of x becomes 8 when the third call is made.

Suppose if x is declared as auto, then the output will be: x = 6 x = 6 x = 6

Page 15: Unit II

This is because, each time state() is called, the auto variable x is set to 6.

Register storage classes : It is similar to the automatic storage classes. Here, variables defined inside a function are local to the block in which it is defined. It can be accessed by the function in which it is defined and its value cannot be accessed by any other function. Normally, the register variables are stored in the CPU registers. CPU registers are faster than memory access and hence in a program, a variable is used to read or repeat again and again, it is better to declare its storage class as register. The general form of register variables is :

register datatype v1,v2,.... where,

register ---> is the keyword used to define the storage class of variables as a register type. datatype ---> may be int, float or char v1,v2,... ---> variable lists

Example :

Write a program to display a number and its square from 0 to 5 using register variables.

#include <stdio.h> main() {

register int i,x,y,z; x=0; y=0; while (x<=10) {

z=f(x,y); printf("%d\t%d\n",x,z); ++x; ++y;

} } f(x,y) register int x,y; {

register int temp; temp = x*y; return(temp); }

Note:

Page 16: Unit II

The CPU registers in the microcomputers are usually 16 or 32 bit registers and therefore it is impossible to declare float or double as register type. When you use float or double as register type, then C compiler will automatically ignore the register data type and it keeps them in the memory and compiler will be treated as an automatic variables. 2.7 MEMORY ALLOCATION It is used to allocate memory space to all the variables in the program. The memory space can be allocated in two ways. They are: 1. Static Memory Allocation 2. Dynamic Memory Allocation. Static Memory Allocation Here, memory space that is allocated for all variables used in the program remains unchanged before run time, as long as the program stops execution. Example : char class[25];

It reserves 25 memory locations for the array named class as type char. In static memory allocation, the address of a variable is assigned to a pointer variable which is declared as the same data type. The compiler allocates the required memory space for a variable declared. For Example,

int a,b,*c; *c = &b;

It initializes the pointer variable c with the address of b.

Dynamic Memory Allocation It is used to allocate additional memory space or to release the unwanted memory space at run time. Using this technique, the programmer can allocate memory whenever one decides and releases it after using the memory. In C, the following functions are used to implement the Dynamic Memory Allocation technique. 1. The malloc() function 2. The calloc() function 3. The realloc() function 4. The free() function malloc() statement:

Page 17: Unit II

It is used to assign sufficient blocks of memory for a given variable in bytes. The syntax is : var = malloc(parameter); where,

var ---> must be a pointer variable and parameter ---> must be an integer value. Example :

ptr = malloc(10);

In this example 10 bytes of memory are allocated to the pointer variable ptr. calloc() statement: It is used to allocate a sufficient multiple blocks of memory in bytes. The syntax is : var = calloc(a1,a2); where, a1 -----> total number of blocks of memory required. a2 -----> total number of bytes in each block of memory location. Example :

ptr = calloc(3,2)

In this 3 blocks of memory, 2 bytes of memory are allocated in each and the starting address is stored in ptr. realloc( ) statement : It is used to increase or decrease the size of memory previously allocated in each by using malloc( ) or calloc( ) function. Its syntax is :

var = realloc(old_pointer_variable, new_size) where,

old_pointer_variable ---> is the variable used in malloc( ) or calloc( ) function.

new_size ---> size of the new memory area needed. Example:

ptr = malloc(10) x = realloc(ptr,20)

The first statement allocates memory space of size 10 bytes and returns

the starting address of the memory through the pointer ptr. The second statement reallocates (increases) the already allocated space to 20 bytes. free() statement : It is used to free (release or deallocate) the block of unused or already used memory. Its syntax is:

Page 18: Unit II

free(pointer_variable); where,

pointer_variable ---> is a pointer to the memory block which has been already created by malloc() or calloc() function. Example:

ptr = malloc(10) free(ptr);

The first statement allocates memory space of 10 bytes and returns the

starting address of the allocated memory. The second statement frees the allocated memory. 2.8 STRUCTURES and UNIONS Definition : C provides a compound data type called a structure. It is defined as a collection of one or more variables of different data types grouped together under a single name. For example, if we consider the student details, we may refer student roll number(integer), his/her name(character), his/her marks(integer), his/her total mark(integer) and an average(float). These data are of different types organized together under a single name called as a structure. The general form of the structure is :

struct <tag_name> {

data type declarations; };

where struct ---> is a keyword. tag_name ---> It is used to identify the structure and it is optional.

Here, the datatype declarations are called as members.

One can declare structure variable using the tag name anywhere in the program. For example : A book has name, author's name, contents, index and year of publication. It is defined as follows : struct book {

char book_name[20]; char auth_name[20]; char contents[10]; char index[5];

Page 19: Unit II

int year; }; From the above declarations , the name of the structure is book. The members of the structure are book_name, auth_name, contents, index and year. One can also declare structure variable using the tag name anywhere in the program. Its syntax is :

struct <tag_name> {

data type declarations; }structure_name;

where, struct ---> is a keyword. tag_name ---> It is used to identify the structure and it is optional. structure_name ---> Name of the structure.

Here, the datatype declarations are called as members.

For example, the following statement

struct book b1,b2,b3; declares b1,b2 and b3 as variables of type struct book. Therefore, the

complete declaration might be: struct book {

char book_name[20]; char auth_name[20]; char contents[10]; char index[5]; int year;

}; struct book b1,b2,b3; OR One can also written as : struct book struct { { char book_name[20]; char book_name[20]; char auth_name[20]; char auth_name[20]; char contents[10]; OR char contents[10]; char index[5]; char index[5]; int year; int year; }b1,b2,b3; }b1,b2,b3;

Page 20: Unit II

In the second example, the tag_name book is omitted and it does not include later use in declaration. The above structure declares b1, b2 and b3 as structure variables representing three b's. 2.8.1 ACCESSING A STRUCTURE : For accessing the member of a structure, the syntax is:

structure_name.member_name Example : To assign a value to the structure variable,

book.book_name="digital electronics" This assigns the name "digital electronics" to the structure member book_name. Similarly, to display the book_name on the screen, type

puts(book.book_name); displays the name contained in the book_name, member structure variable book. 2.8.2 STRUCTURE INITIALIZATION : The syntax is: main ( ) {

static struct structure_name {

data_type_declarations; ...... } struct_name = {initialization_values}

} Example:

main( ) { static struct student

{ int height; float weight;

} student = {170,90} }

In the above example, 170 assigns to student.height and 90 assigns to student.weight. Note that, the assigning values must be in same order as that in which the members are specified. That is, there must be one-to-one correspondence between the members and their initialization values.

Page 21: Unit II

NESTING OF STRUCTURES : It is nothing but a structure containing one or more structures. The syntax is:

struct struct_name {

data_type_declarations; struct another_structure_name {

data_type_declarations; } }

Example: struct student {

int rollno; char name[20]; struct stud_addr {

int no; char street[15]; char place[15]; char city[10]; long pincode;

}address; char deptname[15]; char year[5];

}stud1,stud2;

In the above declaration struct student is the main structure. It gets additional information about the student address from the struct stud_addr.

The member of a nested structure is accessed as main_strcture_variable.sub_structure_variable.sub_structure_member Example :

stud1.address.no

refers to the member of the sub structure, address is the structure variable of the inner structure and stud1 is the structure variable of the main structure. 2.8.3 ARRAY OF STRUCTURES It is defined as a group of different data types stored in consecutive memory locations with a common variable name. Its syntax is:

struct structure_name {

Page 22: Unit II

data_type_declarations; }array_name[size];

Example : struct student {

int rollno; char name[20]; char dept[10]; char year[5];

}stud[5]; The above declaration declares an array of structures, which allocates memory for five structures of type struct student. 2.8.4 STRUCTURES AND POINTERS A structure containing a member that is a pointer to the same structure type is called a self referential structure. One can declare a pointer variable for the structure by placing an asterisk (*) infront of the structure pointer variable. Its syntax is:

struct <tag_name> {

data type declarations; }*structure_name;

Here, structure_name is a pointer, pointing to the structure specified in

<tag_name>. When pointers are pointing to a structure, then the structure elements can be referenced by using the symbol -> (Hyphen followed by greater than symbol). This symbol -> is called as structure pointer symbol.

DIFFERENCE BETWEEN ARRAYS and STRUCTURES ARRAYS STRUCTURES

It is a single name that represents a collection of data items of same data type

It is a single name that represents collection of data items of different data types

Individual entries in an array are called elements.

Individual entries in a structure are called members.

It reserves enough memory space for its elements.

It reserves enough memory space for its members.

There is no keyword to represent arrays, but the square braces[ ] preceding the variable name tells us that we are dealing with arrays.

The keyword struct tells us that we are dealing with structures.

Initialization of elements done only during structure declarations.

Initialization of members can be definition.

The elements of an array are stored in sequence of memory locations.

The members of a structure are not stored in sequence of memory locations.

Page 23: Unit II

The array elements are accessed by its name followed by square brackets [] within which the subscript value is placed.

The members of a structure are accessed by the dot operator.

Its syntax is: datatype var_name[size];

Its syntax is: struct structure_name { datatype_declarations; } structure_variable;

2.8.5 UNIONS : It is another compound data type that may hold objects of different types and sizes. Union provides different kinds of data in a single area of storage. Its syntax is:

union union_name {

datatype_declarations; }union_variables;

Example :

union stud {

char name[20]; int rollno; float mark1,mark2,mark3;

};

In the above example, union stud has 5 members. The first member is a character name having 20 characters. The second member is a integer type rollno having 2 bytes. All the other members mark1, mark2 and mark3 are of type float which requires 4 bytes each.

In the union all the 5 members are allocated in a common place of memory. All the members share the same memory locations. Rules :

1. Any number of union members can be present in the union. But union type variables will take the largest memory occupied by its members.

2. At any time only one value can be stored. 3. The data can be retrieved with the type of the largest storage. 4. Unions can also appear in an array and structures. 5. Pointers to union is also possible and the members of the pointer to

union are referred using the symbol ->

DIFFERENCE BETWEEN STRUCTURES and UNIONS

Page 24: Unit II

STRUCTURES UNIONS

It occupies its own memory space It uses the same memory space. The keyword struct tells us that we are dealing with structures.

The keyword union tells us that we are dealing with structures.

All the members of a structure can be initialized

Only the first member of an union can be initialized.

The members of a structure are not stored in sequence of memory locations.

The members of a union are stored in sequence of memory locations.

Here, each member is stored in a separate memory location. Therefore, more memory space is required.

Here, all members are stored in the same memory locations. Hence, less memory space is required.

Its syntax is: struct structure_name { datatype_declarations; }structure_variable;

Its syntax is: union union_name { datatype_declarations; }union_variable;

2.9 Data structure Definition: It is an aggregation of atomic and composite data types into a set with defined relationships. In this definition, the structure means a set of rules that hold the data together. The data structures can be nested. We can have a data structure that consists of other data structures.

2.9.1 OPERATION OF DATA STRUCTURES

There are different operations are performed in data structures. The following four operations play a major role.

1. Traversing: Accessing each record exactly once so that certain items in the record may be processed.

2. Searching: Finding the location of the record with a given key value, or finding the locations of all records which satisfy one or more conditions.

3. Inserting: Adding a new record to the data structure. 4. Deleting: Removing a record from the data structure.

The following two operations, which are used in special situations:

1. Sorting: Arranging the records in some logical order (e.g., alphabetically according to NAME key, or in numerical order according to some NUMBER key, such as register number or account number)

2. Merging: Combining the records in two different sorted files into a single sorted file.

Page 25: Unit II

2. 10 Arrays

Array is a structured data type. It may be defined as a finite ordered set of elements all of which are of the same data type. The simplest type of data structure is a linear (or one-dimensional) array.

By a linear array, we mean a list of a finite number n of similar data elements referenced by a set of n consecutive numbers, usually 1,2,3, . . . , n. If we choose the name A for the array, then the elements of A are denoted by subscript notation A1, A2, A 3,..., 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]

Regardless of the notation, the number K in A[K] is called a subscript and A[K] is called a subscripted variable.

The number n of elements are called length or size of the array. It is usually defined by

Length = UB - LB +1

where, UB = Upper Bound (Largest Index)

LB = Lower Bound (Smallest Index)

Example:

Let A be an array having 5 elements such that A(1) = 23 A(2) = 45

A(3) = 37 A(4) = 56 A(5) = 97

We denote the array as follows:

A : 23,45,37,56,97

The array A is pictured as follows:

A

23 45 37 56 97

OR

A

23

45

37

56

97

Example

Page 26: Unit II

An automobile company uses an array Auto to record the number of automobiles sold each year from 1945 to 2004. Find the number of automobiles sold?

Solution

Length = UB - LB + 1

= 2004 - 1945 + 1

= 60

2.10.1 Representation of Linear Array in memory

Let A be an array in the memory of the computer. The memory of the computer is simply a sequence of addressed locations, which can be defined as follows:

LOC(A[k]) = Address of the element A[k] of the array A

The elements of A are stored in successive memory cells. We know that, the computer does not keep track of the address of every element of A, but needs to keep track only of the address of the first element of A, denoted by Base(A) is called the base address of A. Using this base address, the computer calculates the address of any element of A by the following formula:

LOC(A[K]) = Base (A) + w(K - Lower Bound)

Where, w = Number of words per memory cell of array A.

Example:

Consider the arrays A(5:50), B(-5:10) and C(18)

a. Find the number of elements in each array

b. Suppose Base (A)=300, w = 4 words per memory cell for A. Find the address of A[15], A[35] and A[55].

Solution:

a. The number of elements is equal to the length.

Length = UB - LB + 1

Therefore, Length (A) = 50 - 5 + 1 = 46

Length (B) = 10 - (-5) + 1 = 16

Length(C) = 18 - 1 + 1 = 18

Note: Length (C) = UB, Since LB = 1

b. Use the formula LOC (A[K]) = Base (A) + w(K - LB)

Hence, LOC(A[15]) = 300 + 4 (15 - 5) = 340

LOC(A[35])= 300 + 4 (35 - 5) = 420

A[55] is not an element of A, since 55 exceeds UB = 50.

Page 27: Unit II

2.10.2 Representation of Two-Dimensional Array A two-dimensional array m x n array A is a collection of mxn elements such that each element is specified by a pair of integers (such as J,K) called subscripts, with the property that,

1 <= J <= m and 1 <= K <= n

The element of A with subscripts J and K will be denoted by AJ,K or A[J, K] .

The two-dimensional arrays are called matrices in mathematics and tables in business applications. Hence two-dimensional arrays are sometimes called matrix arrays.

The length of the array = Pair of lengths J x K.

Li = Upper Bound - Lower Bound - 1

Representation of Two Dimensional Arrays in Memory

Let A be a two-dimensional m x n array. The array A will be represented in memory by a block of mxn sequential memory locations. The data may store the array A either

1. Column – major order (Column by Column) 2. Row – major order (Row by Row).

A A A(1,1) A(1,1) A(2,1) A(1,2) A(1,2) A(1,3) A(2,2) A(2,1) A(1,3) A(2,2) A(2,3) A(2,3)

Column Major Order Row-major order For two-dimensional array, the computer also 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: Column major Order

LOC(A[J, K]) = Base (A) + w[M(K - 1) + (J - 1)]

Row major Order

LOC (A[J, K] = Base (A) + w[N(J - 1) + (K - 1)] Where,

w = Number of words per memory location of the array A

Page 28: Unit II

Using the above formula, one can find the address LOC(A[J, K]) in time independent of J and K. 2.10.3 Multi- Dimensional Array For a multi-dimensional array,

Length 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,K3,........,KN] of an arbitrary element of C can be obtained from the following formula: Column major Order

Base(C) + w[(((...(ENLN-1 + EN-1)LN-2) + .....+ E3)L2 + E2)L1+E1] Row Major Order

Base(C) + w[(......(E1L2 + E2)L3 + E3)L4 + ........+ EN-1)LN+EN] Where w = Number of words per memory location. Example: Consider the 25 x 4 matrix array A. Suppose Base (A) = 200 and there are w = 4 words per memory cell. Find the address of A[12,3] using row-major order. Solution

LOC(A[12, 3]) = 200 + 4[4(12 - 1) + (3 - 1)] = 200 + 4[46] = 384 Example: Suppose a three dimensional array A is declared as A(2:8, -4:1, 6:10). Find the length of A. Also find A[5, -1, 8]. Assume Base(A)=200 and w = 4 words per memory cell. Solution

L1 = 8 - 2 + 1 = 7 L2 = 1 - (-4) + 1 = 6 L3 = 10 - 6 + 1 = 5 The total elements of A = L1.L2.L3 = 7.6.5 = 210 elements. Suppose, the programming language stores A in memory in row-major order. The effective indices of the subscripts are: E1 = 5 - 2 = 3

Page 29: Unit II

E2 = -1 - (-4) = 3 E3 = 8 - 6 = 2 For row-major order, we have: E1L2 = 3.6 = 18 E1L2 + E2 = 18 + 3 = 21 (E1L2 + E2)L3 = 21.5 = 105 (E1L2 + E3)L3 + E3 = 105 + 2 = 107

Therefore, LOC(A[5, -1, 8]) = 200 + 4(107) = 200 + 428 = 628. Example: Suppose multi-dimensional arrays A and B are declared using A(-2:2, 2:22) and B(1:8, -5:5, -10:5)

a. Find the length of each dimension and the number of elements in A and B.

b. Consider the element B[3,3,3] in B. Find the effective indices E1,E2,E3 and the address of the element, assuming Base(B) = 300 and there are w = 4 words per memory location.

Solution: (a). The Length = Upper bound - Lower bound + 1 Hence the length Li of the dimensions of A are: L1 = 2 - (-2) + 1 = 5 L2 = 22 - 2 + 1 = 21 Therefore, A has 5.21 = 105 elements. Similarly, the length Li of the dimensions of B are: L1 = 8 - 1 + 1 = 8 L2 = 5 - (-5) + 1 = 11 L3 = 5 - (-10) + 1 = 16 Therefore, B has 8.11.16 = 1408 elements. (b). The effective indes Ei is obtained from Ei = Ki - LB where, Ki = Given Index and LB = Lower Bound E1 = 3 - 1 = 2 E2 = 3 - (-5) = 8 E3 = 3 - (-10) = 13 The address depends on whether the programming language stores B in row-major order or column major order. Assuming B is stored in column major order, we use the following equation:

Page 30: Unit II

Base(C) + w[(((...(ENLN-1 + EN-1)LN-2) + .....+ E3)L2 + E2)L1+E1] E3L2 = 13.11 = 143 E2L2 + E2 = 143 + 8 = 151 (E3L2 + E2)L1 = 151.8 = 1208 (E3L2 + E2)L1 + E1 = 1208 + 2 = 1210 Therefore, LOC(B[3,3,3]) = 300 + 4(1210) = 300 + 4840 = 5140 2.10.4 Triangular Array It may be either upper-triangular (all elements below the diagonal are zero) or lower-triangular (all elements above the diagonal elements are zero. An array is called strictly triangular (upper or lower) if the elements of the diagonal are also zero.

x x x x x0 x x x x0 0 x x x0 0 0 x x0 0 0 0 x

x 0 0 0 0x x 0 0 0x x x 0 0x x x x 0x x x x x

a. Upper Triangular Array b. Lower Triangular Array

The total number of non-zero elements is not more than, ∑=

+=

n

1i 2)1n(n

i

2.10.5 Sparse Array An array is called sparse if it has a relatively high density of zero elements. For example, the array has 10 non-zero elements out of 50, is a sparse array.

0 0 2 0 0 5 0 0 0 00 0 1 0 0 0 0 1 0 0

0 0 0 0 1 2 0 0 0 00 0 0 0 0 1 6 2 0 00 0 0 0 1 0 0 0 0 0

2.11 LIST The term “list” refers to a linear collection of data items. Example: Shopping list; it contains a first element, a second element… and a last element.

Page 31: Unit II

We know that, data processing function involves storing and processing data organized into lists. One way to store such data is by means of arrays. There are some advantages and disadvantages using arrays. These are: 2.11.1 Advantages or list

1. It is easy to create a list and print the elements 2. Finding the kth element consumes less time 3. The data are stored in contiguous memory locations.

2.11.2 Disadvantages 1. It is expensive to insert and delete elements in an array. 2. Also, since an array usually occupies a block of memory space, one

cannot simply double or triple the size of an array when additional space is required. (For this reason, arrays are called dense lists and are said to be static data structure.

3. Performance is very slow 4. When the program starts up, it must determine the maximum number of

items. An another way of storing a list in memory is called a link or pointer,

which contains the address of the next element in the list. Thus successive elements in the list need not occupy adjacent space in memory. This will make it easier to insert and delete elements in the list. This type of data structure is called a linked list. 2.11.3 Linked List (One-way List) or Single Linked List It is a linear collection of data elements called nodes, where the linear order is given by means of pointers. The node is divided into two parts: the first part contains the information of the element, and the second part, called the link field or nextpointer field, contains the address of the next node in the list. The node of the linked list is represented as follows: The Next address field of the last node contains a special value, known as null value. This is not a valid address. This is only tells us that we have reached the end of the list. Figure shows a schematic diagram of a linked list with 3 nodes.

Page 32: Unit II

Figure : Linked List wity 5 nodes Each node is pictured with two parts. The left part represents the information part of the node, which may contain an entire record of data items(e.g., NAME, ADDRESS, . . .). The right part represents the nextpointer field of the node, and there is an arrow drawn from it to the next node in the list. The nodes in the linked list are called self-referential structures. In a self-referential structure each instance of the structure contains a pointer to another instance of the same structural type. 2.11.4 Operations on Linked List There are five basic types of operations associated with linked list.

1. To determine if the list is empty or not. It returns true if the list contains no elements.

2. Create a list. 3. Add new elements anywhere in the list 4. To check if the particular element is present in the list or not. 5. To delete a particular element from the list placed any where in the list. 6. Find the size of the list 7. To print all the elements of the list.

Before describing the algorithms w will introduce some notations to be

used in algorithms.

If p is a pointer to a node, then node(p) = Node pointed to by p

Page 33: Unit II

info(p) = Data part of that node next(p) = Address part of that node info(next(p)) = Data part of the next node which follows node (p) in the list if next(p) is not null. We can initialize the list by making the external pointer null.

list = null Also, we can check whether the list is empty by checking whether the external pointer is null. if list = null then

return (true) else return(false) This routine will return true if the list is empty, otherwise it will return false. 2.11.5 Traversing a Linked list To traverse or to print the elements of a linked list, we need to use a temporary pointer p, known as a traversal pointer. 1. p = list 2. Repeat steps 3 and 4 while list <> null 3. print info(p) 4. p=next(p) [Updates pointer] [End of Step 2 loop] 5. Return If we do not use the traversal pointer and instead change the value of the external pointer list, we will not be able to access that node anymore. The following procedure finds the number of elements in the linked list. 1. Set N : = 0 . [Initializes counter.] 2. Set p := LIST. [Initializes pointer.] 3. Repeat Steps 4 and 5 whik P <> NULL. 4. Set N : = N + 1. [Increases NUM by 1.] 5. Set p : = next(p). [Updates pointer.]

[End of Step 3 loop.] 6. Return.

Page 34: Unit II

2.11.6 INSERTION INTO A LINKED LIST Let List be a linked list. Now let us consider the linked list containing two elements as shown in figure:

To add a new node containing data value x in the beginning of the list we need to follow the step.

a. To get a new node which is not in use getnode(p) The operation getnode(p) obtains an empty node and sets

the contents of a variable named p to the address of that node. b. To set the data field of the new node to x. info(p) = x c. To set the next field of the new node to point to list.

next(p) = list d. To set pointer list point to the new node list = p.

To understand the above steps, pictorially, we can represent as follows:

The above algorithm works even if the list is initially empty. Using these steps iteratively, we can create a linked list. 2.11.7 INSERTION INTO A ORDERED LINKED LIST To insert a node into the list, which consists of three steps.

1. Allocate memory for the new node and insert data 2. Point the new node to its successor 3. Point the new node’s predecessor to it.

Page 35: Unit II

Let us consider the steps to insert data element 10 in the following ordered list:

(2,7,12,15)

a. Get a new node which is currently unused b. To set the data field of this node to 10 or x in general c. To set the next field of the new node to the node containing 12. d. To set the next field of the node containing 7 to the new node.

Figure shows these illustrations.

Figure (a)

In order to carry out step c and d, we must find the correct place for

inserting x.

p = list while x >= info(p) p = next(p) The above steps are used to find the correct place for insertion, p will point the node that should follow the new node. This enables us to carry step (c). But, there is no way to access the node which should precede the new node to carry out step (d). To overcome this problem, we must check the data field of the next node, rather than the node itself.

p=list while x>= info(next(p)) p=next(p)

Therefore, we can insert the node by using the following algorithm: getnode(new) info(new)=x p=list while x>=info(next(p))

Page 36: Unit II

p=next(p) next(new)=next(p) next(p)=new

Working through these steps, we can insert data 10 correctly.

Suppose we want to insert 1 in this list. Working thorugh the steps, we notice that we skip the first node in the comparison. Also, if x < info(list) (data field of the first node) we must treat it as a special case as we will need to change the external pointer. So, we can modify our algorithm to include the following steps. p = list if x < info(p) then next(new) = list /* To insert new node as first node */ list = new else while .... The insertion of 1 using above steps in the list of above figure(a) is shown in figure (b).

Figure: b Now suppose, we have to insert 20 to the above figure a, which is greater than all the values in the list. Now, the term info(next(p)) will give us an error, as we try to move p pass null. To avoid this, we can use the following loop control. while (next(p) <> null) and (x >= info(next(p))) Please note that, the compiler stops checking the second condition if the first one fails. Another special condition is to insert when the list is empty. In this case we must check if the list is empty, we can make the list pointer point to the new node if list = null list = new

Page 37: Unit II

Hence putting all the above conditions together our algorithm to insert anywhere in the ordered list becomes as follows: getnode(new) info(new) = x next (new) = null if list = null then list = new else { p = list if x < info(p) then next(new) = list list = new else { while (next(p)<>null) and (x >= info (next(p)))

p = next(p) next(new) = next(p) next(p) = new } } 2.11.8 Deleting from a linked list

Let LIST be a linked list with a node N between nodes A and B. Suppose Node N is to be deleted from the linked list.

For example, if the node to be deleted is the first one in the list, we are

simply required to make the external pointer list equal to the next field of the first node in the list.

Consider the following figure:

Page 38: Unit II

The dashed arrows in the figure shows that list now point to the next field of the first node in the list.

The first node (data field containing 2) is still connected to the node containing 7 but there is no way to access that node as it is not pointed to by any pointer. Therefore, this is a logical deletion. Also, the node that was first on the list is currently useless because it is no longer on the list. Therefore, there should be a mechanism for making this node available for reuse. To do this, we need to access the node. This means, before we change pointer list to point to next node, we must assign a new pointer to this node which we can use t access it later. Also we need to store the value of the data item of this node. Therefore, to delete the first node, the algorithm is as follows: p = list x = info(p) list = next (list) Let us assume that, there exists an operation FREENODE that takes a temporary pointer to an unrequired node and puts that node back into the pool of available nodes that can be reused. Using this operation, we can free the node pointed to by pointer p in our algorithm and include the following statement freenode(p) Once this operation is performed, it becomes illegal to reference node(p). To understand this algorithm to remove the first node, pictorially as shown in figure.

Page 39: Unit II

Now let us remove a node which may be placed anywhere in the list. Let the node to be deleted has data value x. For simplicity, we assume that x appears only once in the list. The deletion operation can be broken down into three simple sub operations.

a. Find the node containing the value x b. Modify the pointers to delete the node c. Free the node

To find the node containing value x we have to traverse the list till we find the node or till we reach the end of the list (the node with value x is not present in the list). p = list while (p <> null) and (info (p) <> x) p = next(p) When we reach the node containing x, that is info (p) =x, p is pointing to the node, we wish to delete. But, to delete a node, we must know the address of the previous node. Deleting the node means, changing the next pointer of the previous node to point to the node following the node, which is to be deleted. To solve this problem, we have to check the contents of the next node. Another way is to keep two pointers PREV and CURRENT to traverse the list. So that, when current points to the node to deleted, prev points to the preceding node. We can do the following steps: prev = null current = list while (current <> null) and (info (current) <> x) { prev = current current = next(current) } At this stage, current points to the node which is to be deleted and prev points to the preceding node. To delete the current node, we simply say next(prev) = next(current)

Page 40: Unit II

freenode(current) Please note that, if the node to be deleted is the last one in the list, which mean next of current points to null, the above two statement will work. As in that case next(prev) will point to null, as we desire. Suppose we want to delete the first node, we will not enter into the search loop and therefore prev will remain null. We can add the following steps to our algorithm. if prev = null

then list = next(list) freenode (urrent) If x doesn’t exit in the list when we dropout of the loop, current will be null. We can check that and print a message. Finally, we can put together these steps to make a complete algorithm to delete a node which is as follows:

current = list prev=null while (current <> null) and (info(current)<>x) do { prev=current current=next(current) } if current not null then if prev=null then list=next(list) else next(prev)=next(current) freenode(current) else print(“Node with a given value doesn’t exist in the list”) In order to understand this algorithm, let us work through some examples: Let us consider a linked list as shown in figure (a).

Figure (a)

Now, let us try to delete 2.

Page 41: Unit II

Since, it is the first node, prev will be null. The pointer adjustment to delete 2 is shown in figure b.

Figure (b)

Similarly, we can delete node 7.

Now, let us try to delete 10. Since this node is not present in the list, it

will print a message Node with the given value doesn’t exist in the list” and a pointer positions will be shown in figure (c).

Figure (c)

Next, we delete node 12. It is in the middle of the list. Neither current nor prev is null. So, pointer adjustment is as shown in figure (d).

Figure (d)

Lastly, we can delete node 15 which is the last node of the list. The next

(prev) will point to next (current) which is null as shown in figure (e).

Page 42: Unit II

Figure (e)

2.12 Garbage Collection Suppose some memory space becomes reusable because a node is deleted from a list or an entire list is deleted from a program. Clearly, we want the space to be available for future use. The operating system of a computer may periodically collect all the deleted space onto the free-storage list. Any technique which does this collection is called garbage collection. It is usually takes place in two steps:

1. The computer runs through all lists, tagging those cells which are currently in use.

2. Then the computer runs through the memory, collecting all untagged space onto the free-storage list.

The garbage collection may takes place when there is only some

minimum amount of space or no space at all left in the free storage list or when the CPU is idle and has time to do the collection. Please note that, the garbage collection is invisible to the programmer. 2.12.1 OVERFLOW AND UNDERFLOW Sometimes new data are to be entered into a data structure but there is no available space, then such situation is called Overflow. Similarly, when one wants to delete data from a data structure, that is empty, then it is called Underflow. AVAIL List The maintenance of linked lists in memory assumes the possibility of inserting new nodes into the lists and hence requires some mechanisms which provides unused memory space for the new nodes. We know that, the getnode operation uses our delete-first-node algorithm and removes the first node from this list and makes it available for use. The freenode operation uses our insert-first-algorithm and adds the

Page 43: Unit II

unused nodes to the front of the list, making it available for reuse by the next getnode. This list of available nodes is called AVAIL List and it is pointed by an external pointer called AVAIL, as shown in figure a.

Figure (a)

We can write the algorithm for getnode(p) as follows: if (avail=null) then print “Overflow” else { p=avail avail=next(avail) } The available list will only be empty when all nodes are currently in use and it is not possible to allocate any more. Figure(b) shows how getnode(p) works pictorially.

Figure (b)

Similarly, we can implement freenode(p) as

next(p)=avail avail=p

Figure (c) shows how freenode(p) works pictorially in two steps.

Page 44: Unit II

2.13 Linked List Algorithms 2.13.1 Traversing Algorithm Let LIST be a linked list in memory. This algorithm traverses applying an operation PROCESS to each element of LIST. The variable P points to the node currently being processed.

1. [Initialize pointer P] set P:= START

2. Repeat steps 3 and 4 while P<> Null 3. Apply PROCESS to INFO[P] 4. Set P=Link[P] [P now points to the next node]

[End of Step 2 loop] 5. Exit

2.13.2 Printing Information about Each node of a linked list

1. Set P=START 2. Repeat steps 3 and 4 while P<>Null 3. Write:INFO[P] 4. Set P:=LINK[P] [Update pointer]

[End of Step 2 loop] 5. Return

2.13.3 Find the number of elements in a linked list

1. [Initialize counter] Set Num=0

Page 45: Unit II

2. [Initialize pointer] Set P=START

3. Repeat steps 3 and 4 while P<> Null 4. Set Num=Num+1 [Increment Num by 1] 5. Set P=LINK[P] [Update pointer]

[End of Step 3 loop] 6. Return

2.13.4 Searching Let LIST is a linked list in memory. This algorithm finds the location LOC of the node where ITEM first appears in LIST or sets LOC=NULL.

1. Set P=START 2. Repeat steps 3 while P<>NULL 3. If ITEM=INFO[P], then

Set LOC=P and Exit Else: Set P=LINK[P] [Pointer now points to the next node] [End of IF structure] [End of Step 2 loop]

4. [Search is unsuccessful?] Set LOC=NULL

5. Exit 2.13.5 Inserting item as the first node in the list

1. [Overflow?] If Avail=Null, then: Write: Overflow and Exit

2. [Remove first node from Avail list] Set New=Avail and Avail=Link[Avail]

3. [Copies new data into new node] Set INFO[New]=ITEM

4. [New node now points to original first node] Set LINK[New]=START

5. [Changes START so it points to the new node] Set START=NEW

6. Exit 2.13.6 Inserting after a given node This algorithm inserts ITEM so that ITEM follows the node with location LOC or inserts ITEM as the first node when LOC=NULL.

Page 46: Unit II

1. [Overflow?] If Avail= NULL, then:

Write: Overflow and Exit 2. [Remove First node from Avail list]

Set New=Avail and Avail=LINK[Avail] 3. [Copies new data into new node]

Set INFO[New]=ITEM 4. [Inset as first node]

If LOC=Null, then: Set LINK[New]=START and START=New Else: [Insert after node with location LOC] Set LINK[New]=LINK[Loc] and LINK[LOC]=NEW [End of IF structure]

5. Exit

2.13.7 Deleting the node following a given node

This algorithm deletes the node N with location LOC. LOCP is the location of the node which precedes N or, when N is the first node, LOCP = NULL.

1. If LOCP = NULL, then: Set START:= LINK[START]. [Deletes first node.] Else: Set LINK[LOCP] : = LINK[LOC]. [Deletes node N.] [End of If structure.] 2. [Return deleted node to the AVAIL list.] Set LINK [LOC}: = AVAIL and AVAIL = LOC. 3. Exit. 2.13.8 Implementation of Linked List

There are two ways of implementing linked lists in C namely arrays and dynamic memory allocation. 2.13.8.1 Implementation of Linked List using Arrays Assume, we allocate 100 nodes to the program and place them all on the available list as all nodes are initially unused. We link these nodes initially in their natural order so that each node point to the next node in the array.

Node [0] is the first node and node [99] is the last one.

Page 47: Unit II

Let the link list be defined as follows: # define maxnodes 100 struct nodetype {

int info, next; }; struct nodetype node[maxnodes];

Here the index of array represents a pointer to a node which ranges between 0 to maxnodes -1. The two fields of the node can be accessed as node[p].info and node [p].next respectively. Null is represented by –l.

Using this declaration we can organize our avail list as; initialize() {

int k; avail = 0; for(k=0;k<maxnodes - 1 ; k++) node[k].next=k+l; node[maxnodes-l].next = - 1 ;

} Now all the 100 nodes are on the avail list. Here we have

assumed avail to be global variable. Whenever an individual list for a particular model requires a node, a getnode function may be called. Let us now write getnode, which removes a node from the available list and returns a pointer to it. If there are no more nodes available, avail contains value null that is -1 and in that case, it prints an error message. getnode () {

int p; if (avail == -1) {

printf ("no more nodes available \n"); exit(l);

} p = avail; avail = node [avail] .next ; return (p);

}

Similarly, we can write another function free node, which

Page 48: Unit II

accepts a pointer to a node and adds that node at the front of the avail list.

freenode(int p) { node[p] .next =avail;

avail = p; return; }

Using the avail list, we can create four lists, one for each model. We initialize the external pointer of all the four lists to null.

We can write a routine in C, which accepts address p of a node and item x which is to be inserted as parameter. p is the starting address of the list in which item x is to be inserted.

inserted (p,x) int p, x; {

int r,q; /* put x into a new node */ q = getnode(); node[q] .info = x; node[q] .next= -1; /* insert the new node into the list */ if (p == -1) {

p = q; return;

} / * insert into empty list */ if (x < node[p] .info) {

node[q].next = p;. p = q;

return; } /* insert before first node*/ r = p; while (node[r] .next <> -1) && (x >= node[r] .info) {

r = node[r] .next; } / * find insertion place */ node[q] .next = node[r] .next; node[r] .next = q; return;

Page 49: Unit II

/* connect the pointers */ }

The routine delete (p, x), called by the statement delete (list, val) deletes the node containing x.)

delete (p, x) int p, x; {

int q, current, trail; current = p; trail = -1; while (current != -1) && (node [current] .info !=x) {

trail = current; current = node [current] .next;

} /* search the node with value x */ if (current == -1) {

printf ("void deletion \n"); return;

} /* the node with value x is not present */ if (trail == -1) {

q = p; p = node[p] .next; freenode (q) ;

return; } /* delete the first node */ q = current; node [trail] .next = node [current] .next; freenode (q) ; return;

} Advantages of Array implementation:

1. Less time consuming. 2. We have to keep an extra node at the front of the list. This

node does not represent an item in the list, but may contain some global information about an entire list. Example: Number of nodes in the list, such a node is called a header node.

Page 50: Unit II

In the above program, a fixed number of nodes represented by an array is established at the start of execution. Therefore the main disadvantages are:

1. We have to predict the number of nodes when a program is written which is not always possible.

2. We have to allocate the declared number of nodes throughout the execution of the program whereas the program may not be actually using those many numbers of nodes.

To overcome the above drawback, we have to use dynamic memory

allocation. That is, storage must be allocated to a program only when it is required, and it must be released, when it is no longer in use. Now, we will implement the list using dynamic memory allocation.

2.13.8.2 Implementation of Link List Using Dynamic Allocation

We can implement a link list using the concept of pointers in C. A node of a link list can be defined as follows. struct node {

int info; struct node *next;

} ; typedef struct node *nodeptr;

Here, a node consists of an information field and a pointer to the next node in the list rather than an integer as in the case of array implementation.

Here, there is no need to check for overflow as it will be detected by the malloc function. We can, therefore, write the function getnode as follows. nodeptr getnode() {

nodeptr p; p = (nodeptr) malloc(size of(struct node)); return (p);

} If we call this function as p = getnode();

It should place the address of an available node into p. Similarly we can write the freenode function as

Page 51: Unit II

freenode (p) nodeptr p; {

free (p); }

If we call this function as freenode (p); it should return the node whose address is at p to the available storage. We can now write a C routine insert(p, x) using the dynamic implementation of a linked list. insert (p,x) nodeptr p; int x; {

nodeptr r, q; q = getnode(); q → info = x; q → next = null; /* insert the new node into the list */

if (p == null) { p = q; return;

} if (x < p →info) {

q → next = p; p = q; return;

} r = p; /* find the insertion place */ while (r → next != null) && (x >= r → info)

r = r → next; q → next = r → next; r → next = q; return; /* connect the pointers */

}

Now we present the delete (p, x) routine using dynamic implementation of a linked list.

Page 52: Unit II

delete (p, x) nodeptr p; int *x; {

nodeptr q, current, back; current = p; trail = null; while (current != null) && (current → info != x) {

trail = current; current = current → next;

} /* end of searching the node with values */

if (current == null) {

printf ("void deletion \n"); return;

} /* the node with value x is not present */ if (trail == null) {

q = p; p = p →next; *x = p → info; freenode (q) ;

return; } /* delete the first, node */ q = current; trail → next = current → next; *x = q → info; freenode (q); return;

}

The major advantage of dynamic implementation are:

1. A set of nodes is not required to be reserved in advance. Even if a program uses different types of lists (say, one list of integers and one list of characters).

2. No storage is allocated for variable until needed. Any storage not used for one type of node may be used for another.

3. No overflow occurs as long as sufficient storage is available unlike the array implementation where two arrays of fixed size would be allocated immediately and if one group of lists overflow its array, the program cannot continue.

Page 53: Unit II

4. No address calculation is required to reference *p as it is given directly by the contents of p unlike reference to node[p] whose address must be computed by adding the contents of p to the base address of the array.

Let us now write a complete C program to add, delete, search, display and count the number of nodes using linked list. . #include <stdio.h> #include <conio.h> #include <alloc.h> struct node {

int data; struct node *link;

}; void append (struct node **); void delete (struct node **); void display (struct node *); int count (struct node *); void search (struct node *); main ( ) {

int ch; struct node *list=NULL; while (1) {

clrscr(); printf(“\n1. ADD A NODE\n”); printf(“2. DELETE A NODE\n”); printf(“3. SEARCH \n”); printf(“4. VIEW THE LIST \n”); printf(“5. COUNT THE LIST \n”); printf(“6. QUIT\n”); printf(“\nENTER YOUR CHOICE:”); scanf (“%d”, &ch) ; switch (ch) { case 1: append (&list); break; case 2: delete (&list); break; case 3: search (&list); break; case 4: display (&list); break; case 5: printf(“ Number of nodes in the list = %d”,i);

Page 54: Unit II

getch; break; case 6: exit(); default: printf(“Invalid choice ….. Try again……\n”); }

} } void append (struct node **q) {

struct node *temp; int x: printf(“nter the values you want to add & terminate by –l \n”);

while (x!= -l) {

scanf (“%d” , &x) ; if (x != -1) {

if (*q==NULL) {

*q=(struct node*) malloc (size of (struct node)); (*q) →data=x; (*q) →link=NULL;

} else {

temp=*q; while (temp→link !=null)

temp=temp→link; temp→link=(struct node *) malloc (size of (struct

node)); temp=temp→link; temp→data=x; temp→link=NULL;

} } } } void display (struct node *q) {

while (q!=NULL) {

printf (“%d\n”, q→data); q=q→link;

Page 55: Unit II

} printf(“ Press any key to continue”); getch();

} int count (struct node *q) {

int i = 0; while (q! =NULL) {

i++; q=q→link;

} return i;

} void delete (struct node **q) {

struct node *temp, *temp1, *temp2; int x; printf (“enter the value of node you want to delete:”) ; scanf (“%d”, &x); if (q==NULL) {

printf (“no node to delete\n”); getch ( ) ;

} else

{ temp=*q; if (x==(*q)→data)

*q=(*q) →link; else

{ while ((temp!=NULL)&&((temp→link) →data!=x) ) temp=temp→link;

if (temp==NULL) {

printf (“node not found\n”); getch ( );

} else {

temp1=temp→link; temp2=temp1→link;

Page 56: Unit II

free (temp1) ; temp→link=temp2;

} } } } void search(struct node *q) {

int x; if (q==NULL) {

printf (“no node to search\n”); getch ( );

} else {

printf(“enter the value of node you want to search \n”); scanf (“%d”, &x); while ((q!=NULL) && (q→data!=x))

q=q→link; if (q==NULL) {

printf (“node not found\n”); getch();

} else {

printf (“node found\n”); getch ( );

} }

} 2.14 HEADER LINKED LISTS A header-linked list is a linked list, which always contains a special node, called the header node, at the beginning of the fist. There are two types of header lists:

1. A grounded header list is a header list where the last node contains the null pointer.

Page 57: Unit II

Figure (a). Grounded Header List

2. A circular header list is a header list where the last node points back to the header node.

Figure (b). Circular Header List

Observe that the list pointer START always points to the header node. Accordingly, LINK[START] = NULL indicates that a grounded header list is empty, and LINK[START] = START indicates that a circular header list is empty.

2.14.1 Properties of Circular Header List

1. The null pointer is not used, and hence all pointers contain valid addresses.

2. Every (ordinary) node has a predecessor, so the first node may not require a special case.

2.14.2 Algorithm (Traversing a Circular Header List)

Let LIST be a circular header list in memory. This algorithm traverses LIST, applying an operation PROCESS to each node of LIST.

1. Set PTR:= LINK[START]. [Initializes the pointer PTR.] 2. Repeat Steps 3 and 4 while PTR <> START: 3. Apply PROCESS to INFO[PTR]. 4. Set PTR: = LINK[PTR]. [PTR now points to the next node.]

[End of Step 2 loop.] 5. Exit.

Page 58: Unit II

2.14.3 Algorithm find the Location of ITEM in a Circular linked list

Suppose LIST is a linked list in memory, and suppose a specific ITEM of information is given. This algorithm finds the location LOC of the first node in LIST, which contains ITEM when LIST is an ordinary linked list. The following is such an algorithm when LIST is a circular header list.

1. Set PTR:= LINK[START]. 2. Repeat while INFO[PTR] <> ITEM and PTR <> START:

Set PTR:= LINK[PTR]. [PTR now points to the next node.] [End of loop.]

3. If INFO[PTR] = ITEM, then: Set LOC: = PTR.

Else: Set LOC: = NULL. [End of If structure.]

4. Exit. 2.14.4 Circular Linked List

A linked list whose last node points back to the first node instead of containing the null pointer, called a circular list.

2.14.5 Circular Linked List with Header and Trailer Nodes

A linked list which contains both a special header node at the beginning of the list and a special trailer node at the end of the list.

Page 59: Unit II

Figure: Linked List with header and trailer nodes

2.15 Double Linked List or Two-way List

A double linked list or a two-way list, which can be traversed in two directions:

1. In the usual forward direction from the beginning of the list to the end.

2. In the backward direction from the end of the list to the beginning.

The double linked list or a two-way list, is a linear collection of data elements, called nodes, where each node N is divided into three parts:

1. An information field INFO which contains the data of node 2. A pointer field NEXT which contains the location of the next node in

the list 3. A pointer field BACK which contains the location of the previous node

in the list

The list also requires two list pointer variables:

1. FIRST, which points to the first node in the list 2. LAST, which points to the last node in the list.

Figure shows the schematic diagram of such a list.

Page 60: Unit II

Figure: Two-way list or Double linked list

Observe that the null pointer appears in the NEXT field of the last node in the list and also in the BACK field of the first node in the list. Advantages:

1. It is more efficient.

Disadvantages of Two-way list over one way list

1. The location of the preceding node is needed. The two-way list contains this information, whereas with a one-way list we must traverse the list.

2. A two-way list is not much more useful than a one-way list except in special circumstances.

2.15.1 Two-Way Header Lists

The advantages of a two-way list and a circular header list may be

combined into a two-way circular header list. This is shown in figure. The list is circular because the two end nodes point back to the header node. Observe that such a two-way list requires only one list pointer variable START, which points to the header node. This is because the two pointers in the header node point to the two ends of the list.

Figure: Two-way circular header list.

2.16 Application of Linked Lists

Page 61: Unit II

Linked lists are used in many applications. One application of linked lists is to maintain directory of names. This type of problem occurs in compiler construction to store the list of identifiers appearing in a program for maintaining symbol table. Another application is polynomial manipulation. For maintaining the polynomials in memory, header linked lists are frequently used. The hardware of most computers allows integers of only a maximum specific length. But using linear lists we can perform arithmetic operations on long integers. Linked lists are also used to implement sparse matrices. These can also be used to implement a line editor, where we can keep a linked list of line nodes, each containing a line number, a line of text and a pointer to the next line node. It would be an appropriate application to implement with dynamically created nodes since you can not predict the number of lines needed. 2.17 Polynomials Manipulation Here, we can represent any number of different polynomials as long as their combined size doesn’t exceed our block of memory. Here, we will represent each term by a node. A node will be of fixed size having three fields; one representing the coefficient, second representing exponent and a third is a pointer to the next term. A node will look like this:

Coefficient Exponent Link For example, consider the polynomial in one variable:

P(x)=2x8 – 3 x4 – 2x2 + 4x + 5 The polynomial would look shown below:

Page 62: Unit II

Observe that the list pointer variable POLY points to the header node, whose exponent field is assigned a negative number, in this case –1. 2.18 PROBLEMS 1. Let LIST be a linked list in memory. Write a procedure which

a. Finds the number NUM of times a given ITEM occurs in LIST b. Finds the number NUM of nonzero elements in LIST c. Adds a given value K to each element in LIST

Solution: a.

1. [Initialize Counter] Set NUM=0

2. [Initialize pointer P] Set P:= START 3. Repeat steps 4 and 5 while P<> Null 4. Apply PROCESS to INFO[P] 5. If INFO[P]=ITEM, then: set NUM=NUM+1

[End of Step 3 loop] 6. Exit

b.

a. [Initialize Counter] Set NUM=0

b. [Initialize pointer P] Set P:= START 3. Repeat steps 4 and 5 while P<> Null 4. Apply PROCESS to INFO[P] 5. If INFO[P] <> ITEM, then: set NUM=NUM+1

[End of Step 3 loop] 6. Exit

c.

1. [Initialize Counter] Set NUM=0

2. [Initialize pointer P] Set P:= START 3. Repeat steps 4 and 5 while P<> Null 4. Apply PROCESS to INFO[P] 5. Set INFO[P] =INFO[P]+1

[End of Step 3 loop] 6. Exit

2. Suppose LIST is in memory. Write an algorithm which deletes the last

Page 63: Unit II

node from list. Solution

The last node can be deleted only when one also knows the location of the next-to-last Accordingly, traverse the list using a pointer variable P, and keep track of the preceding node using pointer variable SAVE. P points to the last node when LINK[P] = NULL, and in such a case, SAVE points to the next to last node. The case that LIST has only one node is treated separately, since SAVE can be defined only when the list has 2 or more elements. The algorithm follows.

1. [List empty?]

If START = NULL, then Write: UNDERFLOW, and Exit.

2. [List contains only one element?] If LINK[START] = NULL, then:

a. Set START:= NULL. [Removes only node from list] b. Set LINK[START]:= AVAIL and AVAIL:= START.

[Returns node to AVAIL list.] c. Exit

[End of If structure.] 3. Set P:= LINK[START] and SAVE:= START. [Initializes pointers] 4. Repeat while LINK[P] <> NULL. [Traverses list, seeking last node.] Set SAVE:= P and P:= LINK[P]. [Updates SAVE and P]. [End of loop.] 5. Set LINK[SAVE]:= LINK[P]. [Removes last node.] 6. Set LINK[P]:= AVAIL and AVAIL:= P. [Returns node to AVAIL List] 7. Exit.

3. Suppose NAME1 is a list in memory. Write an algorithm which copies

NAME1 into a list NAME2.

First set NAME2:= NULL to form an empty list. Then traverse NAME1 using a pointer variable P, and while visiting each node of NAME1, copy its contents INFO[P] into a new node, which is then inserted at the end of NAME2. Use LOC to keep track of the last node of NAME2 during the traversal. Inserting the first node into NAME2 must be treated separately, since LOC is not defined until NAME2 has at least one node. The algorithm follows:

This algorithm makes a copy of a list NAME1 using NAME2 as the list

pointer variable of the new list.

1. Set NAME2 : = NULL. [Forms empty list.] 2. [NAME1 empty?] If NAME1 = NULL, then: Exit.

Page 64: Unit II

3. [Insert first node of NAME1 into NAME2.] a. If AVAIL = NULL, then: Write: OVERFLOW, and Exit. b. Set NEW: = AVAIL and AVAIL: = LINK[AVAIL].

[Removes first node from AVAIL list.] c. Set INFO[NEW]:= INFO[NAME1]. [Copies data into new node.] d. [Insert new node as first node in NAME2.]

Set LINK[NEW]:= NAME2 and NAME2:= NEW. 4. [Initializes pointers P and LOC.]

Set P:= LINK[NAME1] and LOC:= NAME2. 5. Repeat Steps 6 and 7 while PTR <> NULL: 6.

a. If AVAIL = NULL, then: Write: OVERFLOW, and Exit. b. Set NEW:= AVAIL and AVAIL:= LINK[AVAIL]. c. Set INFO[NEW]:= INFO[PTR]. [Copies data into new node.] d. [Insert new node into NAME2 after the node with location LOC]

Set LINK[NEW]:= LINK[LOC], and LINK[LOC]:= NEW.

7. Set P:= LINK[P] and LOC:= LINK[LOC]. [Updates P and LOC.] [End of Step 5 loop.]

8. Exit. 4. Suppose LIST is a header (circular) list in memory. Write an algorithm

which deletes the last node from LIST.

The algorithm for deleting the last node from the header list.

1. [List empty?] If LINK[START] = NULL, then: Write: UNDERFLOW. 2. Set P:= LINK[START] and SAVE:= START. [Initializes pointers.] 3. Repeat while LINK[P] <> START: [Traverses list seeking last node.]

Set SAVE = P and P:= LINK[P]. [Updates SAVE and P] [End of loop.]

4. Set LINK[SAVE]:= LINK[P]. [Removes last node.] 5. Set LINK[P]:= AVAIL and AVAIL:= P. [Returns node to AVAIL list] 6. Exit.

6. Imagine we have the two linked lists shown below. What would happen

if we apply the following statement to these two lists? list1=list2

Page 65: Unit II

Solution: list1 no longer points to the head of the first list, rather it points to the head of the second list in the figure shown below.

7. Imagine we have the linked list shown in figure.

Show what would happen if we apply the following statements to this list?

1. temp=pList 2. loop (temp->link not null)

i. temp=temp->link 3. temp->link=pList

Solution: This will create a circularly linked list.

8. Imagine we have a liked list as shown below:

Page 66: Unit II

Show what happens if we use the following statement in a search of the linked list: header = header → link What is the problem with using this kind of statement?

Solution:

Header is a unique pointer that is used to keep track of the head or the first node of the list. Executing statements like header = header → link modifies header which no longer points to the first node of the list, an effect that may be devastating for the whole program.

2.19 STACK

A stack is a linear structure in which items may be added or removed only at one end called top of the stack. This means that, last item to be added to a stack is the first item to be removed. Therefore, the stacks are also called Last-In First-Out (LIFO) or First-In-Last-Out (FILO) lists. Other names used for stacks are: piles and push-down lists.

The various operations performed over stacks are:

1. Create the stack, leaving it empty 2. Determine whether the stack is empty or not 3. Determine whether the stack is full or not. 4. Find the size of the stack. 5. Push a new entry onto the top of the stack, provided the stack is not

full. 6. Retrieve the top entry in the stack, provided the stack is not empty. 7. Pop the entry off the top of the stack, provided the stack is not empty. 8. Clear the stack to make it empty. 9. Traverse the stack, performing a given operation with each entry.

Examples: A stack of books, stack of folded towels, stack of discs, stack of coins, computer stack 2.19.1 Stack Operations:

The basic operations with stack are:

a. Push

Page 67: Unit II

It is used to insert an element into the stack.

b. Pop It is used to remove an element from the stack.

c. Stack Top

It copies the item at the top of the stack. That is, it returns the data in the top element to the user but does not delete it. It can also result in underflow if the stack is empty.

Figure: PUSH stack operation

Page 68: Unit II

Figure: POP stack operation

Example: Suppose the following 6 elements are pushed, in order, onto an empty stack:

AA, BB, CC, DD, EE, FF

Figure shows three ways of picturing such a stack. For notational convenience, we will frequently designate the stack by writing:

STACK: AA, BB, CC, DD, EE, FF

Page 69: Unit II

Figure: Diagram of stacks

Please note that, EEE cannot be deleted before FFF is deleted, DDD cannot be deleted before EEE and FFF are deleted, and so all.

2.19.2 ARRAY REPRESENTATION OF STACKS

Stacks may be represented in the computer in various ways, usually by means of a one-way list or a linear array. A pointer variable TOP, which contains the location of the top element of the stack; and a variable MAXSTACK which gives the maximum number of elements that can be held by the stack. The condition TOP = 0 or TOP = NULL will indicate that the stack is empty.

Figure shows an array representation of a stack.

Since TOP = 6, the stack has six elements, AA, BB, CC, DD, EE and FF.

and since MAXSTACK = 12, there is room for 6 more items in the stack.

The operation of adding (pushing) an item onto a stack and the operation of removing (popping) an item from a stack may be implemented, respectively, by the following procedures, called PUSH and POP.

In executing the procedure PUSH, one must first test whether there is room in the stack for the new item; if not, then we have the condition known as overflow.

Similarly, in executing the procedure POP, one must first test whether there is an element in the stack to be deleted; if not, then we have the condition known as underflow.

2.19.3 Algorithm : PUSH Operation

This procedure pushes an ITEM onto a stack.

1. [Stack already filled?] If TOP = MAXSTACK, then: Print: OVERFLOW, and Return.

2. Set TOP: = TOP + 1. [Increases TOP by 1.] 3. Set STACK[TOP] : = ITEM. [Inserts ITEM in new TOP position.] 4. Return.

Page 70: Unit II

2.19.4 Algorithm : POP Operation

This procedure deletes the top element of STACK and assigns it to the variable ITEM.

1. [Stack has an item to be removed?] If TOP = 0, then: Print: UNDERFLOW, and Return.

2. Set ITEM: = STACK[TOP]. [Assigns TOP element to ITEM.] 3. Set TOP:= TOP - 1. [Decreases TOP by 1.] 4. Return.

2.19.5 Applications of Stack 1. Reversing a data 2. Parsing 3. Postponement

It is used to convert infix to postfix notation and also to evaluate a postfix notation.

4. Backtracking It is used to make decisions between two or more paths. Backtracking

is found in applications such as computer gaming, decision analysis and expert systems.

2.19.5.1 Reversing a data

This means a given set of data to be reordered so that the first and last elements are exchanged, with all of the positions between the first and last being relatively exchanged also. For example, {1 2 3 4} becomes {4 3 2 1}.

Example: Reversing a list, converting decimal to binary number

2.19.5.2 Parsing Parsing is a logic that breaks data into independent pieces for further processing. For example, to translate a source program into machine language, a compiler must parse the program into individual parts such as keywords, names and tokens.

The common problem you have faced is unmatched parenthesis in an algebraic expression. When parenthesis are unmatched, two types of error can occur:

1. The opening parenthesis can be missing

Example: ((A+B)/C 2. The closing parenthesis can be missing

Example: (A+B)/C)

2.19.5.3 Postponement

Page 71: Unit II

It is used to convert infix to postfix notation and also to evaluate a postfix notation.

An arithmetic expression can be represented in three different formats: infix, prefix and postfix. Infix Notation

In an infix expression, the operator is placed between two operands. Example: a + b

Disadvantage: 1. We need to use parenthesis to control the evaluation of the

operators.

Prefix Notation In a prefix expression, the operator is placed before the two operands. Example: + a b

Postfix Notation

In a postfix expression, the operator is placed after the two operands. Example: a b +

2.19.5.3.1 Rules for converting infix to postfix expression

1. Evaluate parenthesis 2. Evaluate power 3. Evaluate multiplication and division; the operations are done from left

to right. 4. Evaluate addition and subtraction; the operations are done from left to

right. 5. Change all infix notations in each parenthesis to postfix notation

starting from the innermost expressions. 6. Remove all parenthesis.

Example:

Page 72: Unit II

Infix Notation Postfix Notation

A+B*C A B C * +

(A+B)*C+D+E*F-G A B + C * D + E F * +G -

A*B+C A B * C +

A+B*C-D/E A B C * D E / - +

A*B-(C+D)+E A B * C D + - E +

A+B – C A B + C -

(A+B)*(C-D) AB+CD-*

A*(B+C)*D ABC+*D*

B*C-D+E/F/(G+H) BC*D-EF/GH+/+

A+(B*C-(D/E↑F)*G)*H ABC*DEF↑/G*-H*H

A-B*(D/E) AB-DE/*

(A+B↑D)/(E-F)+G ABD↑+EF-/G+

A*(B+D)/E-F*(G+H/K) ABD+*E/FGHK/+*-

((A+B)*D) ↑(E-F) AB+D*EF-↑

Postfix notation to Infix notation Example:

Postfix Notation Infix Notation

A B C + * A * B+C

12 7 3 - / 2 1 5 + * + 12/(7-3)+2*(1+5)

2.19.5.4 Backtracking It is used to make decisions between two or more paths. It is found in application such as computer gaming, decision analysis and expert systems. Examples of backtracking are: Goal seeking and Eight-queens problem.

Evaluation of a Postfix Expression

Suppose P is an arithmetic expression written in postfix notation. The following algorithm, which uses a STACK to hold operands, evaluates P.

Algorithm This algorithm finds the VALUE of an arithmetic expression P

Page 73: Unit II

written in postfix notation.

1. Add a right parenthesis “)” at the end of P. [This acts as a sentinel.] 2. Scan P from left to right and repeat Steps 3 and 4 for each element of P

until the sentinel “)” is encountered. 3. If an operand is encountered, put it on STACK. 4. If an operator ⊗ is encountered, then:

i. Remove the two top elements of STACK, where A is the top element and B is the next-to-top element.

ii. Evaluate B ⊗ A. iii. Place the result of (b) back on STACK.

[End of If structure.] [End of Step 2 loop.]

5. Set VALUE equal to the top element on STACK. 6. Exit.

Please note that, when Step 5 is executed, there should be only one

number on STACK.

2.19.6 Algorithm for Infix Expressions into Postfix Expressions

Let Q be an arithmetic expression written in infix notation. Besides operands and operators, Q may also contain left and right parentheses.

The operators in Q consist only of exponentiations (↑), multiplications (*), divisions (/), additions (+) and subtractions (-).

We also assume that operators on the same level, including exponentiations, are performed from left to right.

The following algorithm converts the infix expression Q into its equivalent postfix expression P. The algorithm uses a stack to temporarily hold operators and left parentheses. The postfix expression P will be constructed from left to right using the operands from Q and the operators, which are removed from STACK. We begin by pushing a left parenthesis onto STACK and adding a right parenthesis at the end of Q. The algorithm is completed when STACK is empty.

Algorithm

Suppose Q is an arithmetic expression written in infix notation. This

algorithm finds the equivalent postfix expression P.

1. Push “(“ onto STACK, and add “)” to the end of Q.

2. Scan Q from left to right and repeat Steps 3 to 6 for each element of Q until the STACK is empty:

3. If an operand is encountered, add it to P. 4. If a left parenthesis is encountered, push it onto STACK. 5. If an operator ⊗ is encountered, then:

Page 74: Unit II

i. Repeatedly pop from STACK and add to P each operator (on the top of STACK) which has the same precedence as or higher precedence than ⊗.

ii. Add ⊗ to STACK. [End of If structure.]

6. If a right parenthesis is encountered, then: i. Repeatedly pop from STACK and add to P each operator

(on the top of STACK) until a left parenthesis is encountered.

ii. Remove the left parenthesis. [Do not add the left parenthesis to P.]

[End of If structure.] [End of Step 2 loop.]

7. Exit

2.19.7 Check for Balanced Parenthesis An another application of stacks, we will try to determine whether parenthesis and brackets are balanced properly in algebraic expressions. To indicate the boundaries of a sub-expression, we used parenthesis, brackets and braces. To determine, whether the pair is matching or not we must check that a right counter part ‘)’ or ‘]’ or ‘}’ exist for each left parenthesis ‘(‘ or ‘[‘ or ‘{‘ in the proper order. To do this, we must use a stack. Whenever we encounter a left parenthesis, we push it onto the stack. Whenever we encounter a right parenthesis, we pop the top symbol off the stack and check to see whether its type matches the type of right parenthesis, bracket or brace encountered. The expression has properly balanced parenthesis, if the stack is empty by the time we get to the end of an expression and all pairs of matched parenthesis were of the same type. Otherwise, the parenthesis are not balanced properly. For example, the stack will vary as shown below for the algebraic expression. We may note that all pairs of parenthesis are matching and the stack is empty at the end of expression string. Therefore, the expression string has balanced parenthesis.

Page 75: Unit II

Figure: An example of checking balanced parenthesis

An algorithm for checking balanced parenthesis may be written as follows:

1. [Initialize] match=True; stack=empty;

2. Read symbol from input string 3. While not end of input string and matching

{ If symbol =’(‘ or ‘{‘ or ‘[‘ Push(symbol,stack); Else If symbol =’)’ or ‘}’ or ‘]’ or if stack is empty then match=false Write (“More right parenthesis than left parenthesis”) Else C=pop(stack) Match c and the input symbol; If not matched { match=false; write(“Mismatched parenthesis”); } read the next input symbol; } if stack is empty then write (“Parenthesis are balanced properly”) else write (“More left parenthesis than write parenthesis”)

Page 76: Unit II

2.19.8 Eight Queens Problem (using stack and backtracking logic)

A classic chess problem requires that you place eight queens on the chessboard in such a way that no queen can capture another queen. A queen can attack another queen if it is in the same row, same column or on a diagonal. There are actually several solutions to this problem. The computer solution to this problem requires that we place a queen on the board and then analyze all of the attack positions to see if there is a queen that could capture the new queen. If there is, then we try another queen.

Now, let us first demonstrate four queen’s on a four-by-four chessboard. The queens capture rule and one solution are shown in figure.

Figure: Four Queens Solution We can solve this problem using a stack and backtracking logic. Because only one queen can be placed in any row, we begin by placing the first queen in row 1 and column 1. This location is then pushed into a stack, giving the position as shown below.

After placing a queen in the first row, we look for a position in the second row. Position 2, 1 is not possible because the queen in the first row is guarding this solution on the vertical. Likewise, position 2, 2 is guarded on the diagonal. We therefore place a queen in the third column in row 2 and push this location into the stack. This is shown below.

Page 77: Unit II

We now begin to locate a position in row 3. It is noted that, none of the positions in row 3 are possible. The first column is guarded by the queen in row one, and the other three positions are guarded by the queen in row two. At this point we must backtrack the second row by popping the stack and continue looking for a position for the second row queen. Because column four is not guarded, we place a queen there and push its location into the stack. This is shown below:

Looking again at row three, we see that the first column is still guarded by the queen in row one, but that we can place a queen in the second column. We do so and push this location into the stack. This is shown below.

When we try to place a queen in row four, however we find that all positions are guarded. Column one is guarded by the queen in row one and the queen in row three.

Page 78: Unit II

Column two is guarded by the queen in row two and the queen in row three. Column three is guarded by the queen in row three and the column four is guarded by both the queen in row one and the queen in row two. We therefore backtrack to the queen in row three and try to find another place for her. Because the queen in row two is guarding both column three and column four, there is no position for a queen in row three. Once again backtrack by popping the stack and find that the queen in row two has nowhere else to go, so we backtrack to the queen in row one and move her to column two. This is shown below.

Analyzing row two, we see that the only possible solution for a queen is column four because the queen in row one is guarding the first three positions. We therefore place the queen in this location and push the location into the stack. This is shown below.

Column one in the third row is unguarded so we place a queen ther. This is shown below.

Page 79: Unit II

Moving to row four, we find that the first two positions are guarded, the first by the queen in row three and the second by all three queens. The third column is unguarded, however, so we can place the fourth queen in this column for a solution to this problem. Generalizing the solution, we see that we place a queen in a position in a row and then examine all positions I the next row to see if a queen can be placed there. If we can’t place a queen and try to position her in the next column. If there is no room in the next column, then we fall back again. Given that there is a solution, this trial and error method works well. Please note that, there is no solution for boards for boards less than 4 x 4 positions. All boards from 4 x 4 to 8 x 8 have at least one solution.

2.19.9 PROBLEMS

1. Consider the following stack of characters, where STACK is allocated N = 8 memory cells: STACK : A,C,D,F,K, - , - , - Describe the stack as the following operations take place:

a. POP(STACK, ITEM) b. POP(STACK, ITEM) c. PUSH(STACK, L) d. PUSH(STACK, P) e. POP(STACK, ITEM) f. PUSH(STACK, R) g. PUSH(STACK, S) h. POP(STACK, ITEM)

Solution:

The POP procedure always deletes the top element from the stack, and the PUSH procedure always adds the new element to the top of the stack. Accordingly:

a. STACK: A,C,D,F,_,_,_, b. STACK: A, C, D, -, -, -, -, - c. STACK: A, C, D, L, -, -, -, -

Page 80: Unit II

d. STACK: A, C, D, L, P, -, -, - e. STACK: A, C, D, L, -, -, -, - f. STACK: A, C, D, L, R, -, -, - g. STACK: A, C, D, L, R, S, -, - h. STACK: A, C, D, L, R, -, -, -

2. Consider the data in above problem. (a) When will overflow occur?

(b) When will C be deleted before D?

Solution: a. Since STACK has been allocated N = 8 memory cells, overflow

will occur when STACK contains 8 elements and there is a PUSH operation to add another element to STACK.

b. Since STACK is implemented as a stack, C will never be deleted before D.

3. Consider the following stack, where STACK is allocated N = 6 memory cells:

STACK: AA, DD, EE, FF, GG, - Describe the stack as the following operations take place: a. PUSH(STACK,KK) b. POP(STACK, ITEM) c. PUSH(STACK,LL) d. PUSH(STACK,SS) e. POP(STACK, ITEM) f. PUSH(STACK, TT).

Solutions:

a. KK is added to the top of STACK, yielding STACK: AA,DD,EE,FF,GG,KK

b. The top element is removed from STACK, yielding STACK: AA, DD, EE, FF, GG,-

c. LL is added to the top of STACK, yielding STACK: AA, DD, EE, FF, GG, LL

d. Overflow occurs, since STACK is full and another element SS is to be added to STACK.

e. The top element is removed from STACK, yielding STACK: AA, DD, EE, FF, GG,-

f. TT is added to the top of STACK, yielding STACK: AA, DD, EE, FF, GG, TT

4. Suppose STACK is allocated N = 6 memory cells and initially

STACK is empty, or, in other words, TOP = 0. Find the output of the following module:

1. Set AA:= 2 and BB :=5. 2. Call PUSH(STACK, AA).

Call PUSH(STACK, 4). Call PUSH(STACK, BB + 2).

Page 81: Unit II

Call PUSH(STACK, 9). Call PUSH(STACK, AA + BB).

3. Repeat while TOP <> 0 Call POP(STACK, ITEM). Write: ITEM.

[End of loop.] 4. Return.

Solution: Step 1. Sets AA = 2 and BB = 5. Step 2. Pushes AA = 2, 4, BB + 2 = 7, 9 and AA + BB = 7 onto STACK, yielding

STACK: 2,4,7,9,7, - Step 3. Pops and prints the elements of STACK until STACK is empty. Since

the top element is always popped, the output consists of the following sequence: 7,9,7,4,2, -

Observe that, this is the reverse of the order in which the elements

were added to stack. 5. Consider the following arithmetic expression P, written in postfix

notation: P: 12, 7, 3, -, /, 2, 1, 5, +, *, +

a. Translate P, into its equivalent infix expression. b. Evaluate the infix expression.

Solution:

a. Scanning from left to right, translate each operator from postfix to infix notation. (We use brackets [ ] to denote a partial translation.)

P = 12, [7 - 3], /, 2, 1, 5, +, *, +

= [12/(7 - 3)], 2, 1, 5, +, *, +

= [12/(7 - 3)], 2, [1 + 5], *, +

= [12/(7 - 3)], [2 * (1 + 5)], +

= 12/(7 - 3) + 2* (1 + 5)

b. Using the infix expression, we obtain: P = 12/(7 - 3) + 2 * (1 + 5) = 12/4 + 2 * 6 = 3 + 12 = 15

5. Imagine we have two empty stacks of integers s1 and s2. Draw a

Page 82: Unit II

picture of each stack after the following operations: Pushstack (s1,3); Pushstack (s1,5); Pushstack (s1,7); Pushstack (s1,9); Pushstack (s1,11); Pushstack (s1,13); While (!emptystack (s1)) { popstack(s1,x); Pushstack (s2,x); }

Solution:

6. Using the manual transformation, write the following infix expressions in their postfix and prefix forms:

a. D – B + C b. A * B + C * D c. (A + B) * C – D * F + C d. (A – 2 * (B + C) – D * E) * F

SOLUTION:

INFIX PREFIX POSTFIX D – B + C + - D B C D B – C + A * B + C * D + * A B * C D A B * C D * + (A + B) * C – D * F + C + - * * A B C * D F C A B + C * D F * - C + (A – 2 * (B + C) – D * E) * F * - - A * 2 + B C * D E F A 2 B C + * - D E * - F *

7. If the value of A,B, C and D are 2, 3, 4 and 5 respectively, manually calculate the value of the following prefix expressions:

a. A B * C – D + b. A B C + * D – Solution: a. 7 b. 9

Page 83: Unit II

8. Change the following infix expressions to postfix expressions using

the algorithmic method (a stack). a. D – B + C b. A * B + C * D c. (A + B) * C – D * F + C d. (A – 2 * (B + C) – D * E) * F

Solution: a. b.

c. d. 2.20 QUEUE

A queue is a linear list of elements in which items may be added only at one end called rear and items may be deleted only at the other end called front. Thus a queue is also called First-In-First-Out (FIFO) lists, since the first element in a queue will be first element out of the queue.

Original Stack Output D - B + C D

D D B -

C +

- B + C B + C - - B

B –

Original Stack Output A * B + C * D * B + C * D A

A A B A B * A B * C

* A B * C * A B * C D

A B * C D * A B * C D * +

+ C D C +

+ B + C * D * + C * D *

Original Stack Output (A + B) * C – D * F + C A + B ) * C – D * F + C (

+ + B

B + +

+ C + C * D

C * D * D * D F

D F * - * - C

- C +

D C * D + * D + D + + +

+ B ) * C – D * F + C ( A B ) * C – D * F + C ( A ) * C – D * F + C ( A * C – D * F + C A C – D * F + C * A B - D * F + C * A B D * F + C - A B * F + C - A B + F + C - * A B + C + C - * A B + C C + A B + C * + A B + C * D F A B + C * D F *

Original Stack Output (A – 2 * (B + C) – D * E) * F A – 2 * (B + C) – D * E) * F ( - 2 * (B + C) – D * E) * F ( A 2 * (B + C) – D * E) * F ( - A * (B + C) – D * E) * F ( - A 2 (B + C) – D * E) * F ( - * A 2 B + C) – D * E) * F ( - * ( A 2 + C) – D * E) * F ( - * ( A 2 B C) – D * E) * F ( - * ( + A 2 B ) – D * E) * F ( - * ( + A 2 B C - D * E) * F ( - * A 2 B C + D * E) * F ( - A 2 B C + * - * E) * F ( - A 2 B C + * - D E) * F ( - * A 2 B C + * - D ) * F ( - * A 2 B C + * - D E * F A 2 B C + * - D E * - F * A 2 B C + * - D E * - * A 2 B C + * - D E * - F A 2 B C + * - D E * - F *

Queues abound in everyday life. The automobiles waiting to pass through an intersection for queue, in which the first car in line is the first car through; the people waiting in line at a bank or milk booth forms a queue, where the first person in line is the first person to be waited on; and so on.

An important example of a queue in computer science occurs in a timesharing system, in which programs with same priority form a queue while waiting to be executed.

Page 84: Unit II

The operations performed over queue are:

1. Create the queue, leaving it empty 2. Determine whether the queue is empty or not 3. Determine whether the queue is full or not. 4. Find the size of the queue. 5. Append a new entry onto the rear of the stack, provided the queue is

not full. 6. Retrieve the front entry in the queue, provided the queue is not empty. 7. Serve (and Remove) the entry from the front of the queue, provided the

queue is not empty. 8. Clear the queue to make it empty. 9. Traverse the queue, performing a given operation with each entry.

2.20.1 Representation of Queue Queues may be represented in the computer in various ways, usually by means of one-way lists or arrays. The queues will be maintained by a linear array QUEUE and two pointer variables: FRONT, containing the location of the front element of the queue; and REAR, containing the location of the rear element of the queue. The condition FRONT=NULL will indicate that the queue is empty.

Figure shows the representation of queue stored in memory using an array and Linked list. Using Linked List

Figure: Representation of a queue using linked list

Figure shows a schematic diagram of a queue with 4 elements, where

AA is the front element and DD rear element. Observe that the front and rear elements of the queue are also, respectively, the first and last elements of the list.

Suppose an element is deleted from the queue. Then it must be AA. This yields the queue in figure (b), where BB is now the front element. Next, suppose EE is added to the queue and then FF is added to the queue. Then

Page 85: Unit II

they must be added at the rear of the queue, as shown in figure (c). Note that FF is the rear element. Now suppose another element is

deleted from the queue; then it must be BB, to yield the queue in figure (d). And so on. Observe that in such a data structure, EE will be deleted before FF because it has been placed in the queue before FF. However, EE will have to wait until CC and DD are deleted.

Representation of queues using Arrays

Figure: Array Representation of Queue

Figure also indicates the way elements will be deleted from the queue

and the way the new elements will be added to the queue. Observe that 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

Similarly, whenever 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

This, means that after N insertions, the rear element of the queue will occupy QUEUE[N] or, in other words, the queue will occupy the last part of the array. This occurs even though the queue may not contain many elements.

Suppose we want to insert an element ITEM into a queue at the time

Page 86: Unit II

the queue does occupy the part of the array, i.e., when REAR = N. One way to do this is to simply move the entire queue to beginning of the array, changing FRONT and REAR accordingly, and then inserting ITEM as above. The procedure we adopt is to assume that the array QUEUE is circular, that is, that QUEUE[l] comes after QUEUE[N] in the array. With this assumption, we insert ITEM into the queue by assigning ITEM to QUEUE[l]. Specifically, instead increasing REAR to N + 1, we reset REAR = 1 and then assign QUEUE[REAR]:= ITEM

Similarly, if FRONT = N and an element of QUEUE is deleted, we reset FRONT = 1 instead of increasing FRONT to N+1.

Suppose that our queue contains only one element, i.e., suppose that FRONT = REAR <> NULL and suppose that the element is deleted. Then we assign FRONT: = NULL and REAR: = NULL to indicate that the queue is empty.

2.20.2 Algorithm for Queue Insert This algorithm will insert a data ITEM into a queue. QINSERT(QUEUE, N, FRONT, REAR, ITEM)

1. [Queue already filled?] If FRONT = 1 and REAR = N, or if FRONT = REAR + 1, then: Write: OVERFLOW, and Return.

2. [Find new value of REAR.] If FRONT:= NULL, then: [Queue initially empty.] Set FRONT:= 1 and REAR:= 1. Else if REAR = N, then: Set REAR:= 1 Else: Set REAR:= REAR + 1.

[End of If structure.] 3. Set QUEUE[REAR] : = ITEM.

[This inserts new element] 4. Return.

Page 87: Unit II

2.20.3 Algorithm for Queue Delete This algorithm will delete the first element from a queue. QDELETE(QUEUE, N, FRONT, REAR, ITEM)

1. [Queue already empty?] If FRONT: = NULL, then:

Write: UNDERFLOW, and Return. 2. Set ITEM:= QUEUE[FRONT]. 3. [Find new value of FRONT.]

If FRONT = REAR, then: [Queue has only one element to start.! Set FRONT: = NULL and REAR: = NULL. Else if FRONT = N, then: Set FRONT: = 1. Else: Set FRONT: = FRONT + 1. [End of If structure.]

4. Return. 2.20.4 DEQUES

A deque is a linear list in which elements can be added or removed at either end but not in the middle.

There are various ways of representing a deque in a computer. The deque is maintained by a circular array DEQUE with pointers LEFT and RIGHT, which point to the two ends of the deque. We assume that the elements extend from the left end to the right end in the array. The term "circular" comes from the fact that we assume that DEQUE[1] comes after DEQUE[N] in the array.

There are two variations of a deque-namely, an input -restricted deque and an output-restricted deque-which are intermediate between a deque and a queue.

An input-restricted deque is a deque which allows insertions at only one end of the list but allows deletions at both ends of the list.

An output-restricted deque is a deque which allows deletions at only one end of the list but allows insertions at both ends of the list. 2.20.5 PRIORITY QUEUES

A priority queue is a collection of elements such that each element has been assigned a priority. The following rules are used to delete and process the elements from a priority queue.

Page 88: Unit II

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.

There are various ways of maintaining a priority queue in memory. These are:

1. One -way list 2. Multiple queues.

2.20.5.1 One-Way List Representation of a Priority Queue

Here,

1. Each node in the list will contain three items of information: a. An information field INFO b. A priority number PRNUM c. A link number LINK.

2. A node X precedes a node Y in the list a. When X has higher priority than Y or 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: Consider the following figure:

Figure shows a diagram of a priority queue with 7 elements. The

diagram does not tell us whether BB was added to the list before or after DD. On the other hand, the diagram does tell us that BB was inserted before

CC, because BB and CC have the same priority number and BB appears before CC in the list.

Page 89: Unit II

The main property of the one-way list representation of a priority queue is as follows:

The element in the queue that should be processed first always appears at the beginning of the one-way list. The outline of the algorithm follows.

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.

Adding an element to the priority queue is much more complicated than deleting an element from the queue, because we need to find the correct place to insert the element. An outline of the algorithm follows.

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 is 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 as shown in figure.

Suppose an item XXX with priority number 2 is to be inserted into the queue. We traverse the list, comparing priority numbers. Observe that DDD is

Page 90: Unit II

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 shown in figure. 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. 2.20.5.2 Array Representation of a Priority Queue

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 REAR.

If each queue is allocated the same amount of space, a two-dimensional array QUEUE can be used instead of the linear arrays.

Figure shows this representation for the priority queue in the above figure. 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. FRONT REAR 1 2 3 4 5 6 1 2 2 1 AAA 2 1 3 2 BBB CCC XXX 3 0 0 3 4 5 1 4 FFF DDD EEE 5 4 4 5 GGG

The following are outlines of algorithms for deleting and inserting

elements in a priority queue that is maintained in memory by a two-dimensional array QUEUE, as above. 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.

Page 91: Unit II

1. Insert ITEM as the rear element in row M of QUEUE. 2. Exit.

2.20.6 Applications of Queues

1. Simulation of a real world situation so that it is possible to understand what happens in a real world in a particular situation without actually observing its occurrence.

2. It is also useful in a time-sharing computer system, where many users share the system simultaneously.

3. It is also used for finding a path using breadth-first search of graphs. 4. Queues are also used in business such as processing customer requests,

jobs and orders.

2.20.7 PROBLEMS

1. Consider the following queue of characters, where QUEUE is a circular array which is allocated six memory cells:

FRONT = 2, REAR=4 QUEUE: -, A, C, D, -, - Describe the queue as the following operations take place:

a. F is added to the queue. b. Two letters are deleted. c. K, L and M are added to the queue. d. Two letters are deleted. e. R is added to the queue. f. Two letters are deleted g. S is added to the queue h. Two letters are deleted i. One letter is deleted j. One letter is deleted.

Solution:

a. F is added to the rear of the queue, yielding FRONT = 2, REAR = 5

Queue : -, A, C, D, F, -

Note that REAR is increased by 1.

b. The two letters, A and C, are deleted, leaving FRONT = 4, REAR = 5 QUEUE: -, -, -, D, F,

Note that FRONT is increased by 2. c. K, L and M are added to the rear of the queue. Since K is placed

in the last memory cell of QUEUE, L and M are placed in the first two memory cells. This yields FRONT = 4, REAR = 2

QUEUE: L, M, _ , D, F, K

Page 92: Unit II

Note that REAR is increased by 3 but the arithmetic is modulo 6: REAR = 5 + 3 = 8 = 2 (mod 6)

d. The two front letters, D and F are deleted, leaving FRONT = 6, REAR = 2 QUEUE: L, M, -, -, -, K

e. R is added to the rear of the queue, yielding FRONT = 6, REAR = 3, QUEUE: L, M, R, -, -, K

f. The two front letters, K and L, are deleted, leaving FRONT=2, REAR=3, QUEUE: -, M, R, -, -,

Note that FRONT is increased by 2 but the arithmetic is modulo 6:

FRONT=6+2=8=2(mod 6) g. S is added to the rear of the queue, yielding FRONT = 2, REAR = 4 QUEUE: -, M, R, S, -, - h. The two front letters, M and R, are deleted, leaving FRONT = 4,

REAR = 4 QUEUE: -, -, -, S, -,

i. The front letter S is deleted. Since FRONT = REAR, this means that the queue is empty; hence assign NULL to FRONT and REAR. Thus

FRONT = 0, REAR = 0 QUEUE: -, -, -, -, -, - j. Since FRONT= NULL, no deletion can take place. That is,

underflow has occurred.

2. Suppose each data structure is stored in a circular array with N memory cells.

a. Find the number NUM of elements in a queue in terms of FRONT and REAR.

b. Find the number NUM of elements in a deque in terms of LEFT and RIGHT.

c. When will the array be filled? Solution:

(a) If FRONT <=REAR, then NUM = REAR - FRONT + 1.

For example, consider the following queue with N = 12: FRONT = 3, REAR=9 QUEUE: -,-,*,*,*,*,*,*,*,-,-,- Then NUM = 9 - 3 + 1 = 7, as pictured. If REAR < FRONT, then FRONT - REAR - 1 is the number of empty cells, so NUM = N - (FRONT - REAR - 1) = N + REAR - FRONT + 1 For example, consider the following queue with N = 12: FRONT = 9, REAR = 4, QUEUE: *,*,*,*,-,-,-,-,*,*,*,* Then NUM = 12 + 4 - 9 + 1 = 8, as pictured. Using arithmetic modulo N, we need only one formula,

Page 93: Unit II

as follows: NUM = REAR - FRONT + 1 (mod N) (b) The same result holds for deques except that FRONT is replaced by

RIGHT. That is, NUM = RIGHT - LEFT + 1 (mod N) (c). With a queue, the array is full when

(i) FRONT = 1 and REAR=N OR (ii) FRONT = REAR + 1

Similarly, with a deque, the array is full when (i) LEFT = 1 and RIGHT = N

OR (ii) LEFT = RIGHT + 1

Each of these conditions implies NUM = N.

3. Consider the following deque of characters where DEQUE is a circular array which is allocated six memory cells: LEFT = 2, RIGHT = 4 DEQUE: -, A, C, D, -, - Describe the deque while the following operations take place. a. F is added to the right of the deque. b. Two letters on the right are deleted. c. K, L and M are added to the left of the deque. d. One letter on the left is deleted. e. R is added to the left of the deque. f. S is added to the right of the deque. g. T is added to the right of the deque.

Solution:

a. F is added on the right, yielding LEFT = 2, RIGHT = 5 DEQUE: -, A, C, D, F, - Note that, RIGHT is increased by 1.

b. The two right letters, F and D, are deleted, yielding LEFT = 2, RIGHT = 3 DEQUE: -, A, C, -, -, -

Note that RIGHT is decreased by 2. c. K, L and M are added on the left. Since K is placed in the first memory

cell, L is placed in the last memory cell and M is placed in the next-to-last memory cell. This yields LEFT = 5, RIGHT=3

DEQUE: K, A, C, -, M, L Note that LEFT is decreased by 3 but the arithmetic is modulo 6: LEFT = 2 - 3 = -1 = 5 (mod 6)

d. The left letter, M, is deleted, leaving LEFT = 6, RIGHT = 3 DEQUE: K, A, C, -, -, L Note that LEFT is increased by 1.

Page 94: Unit II

e. R is added on the left, yielding LEFT = 5, RIGHT = 3 DEQUE: K, A, C, -, R, L Note that LEFT is decreased by 1. f. S is added on the right, yielding LEFT = 5, RIGHT=4 DEQUE: K,A,C,S,R,L g. Since LEFT = RIGHT + 1, the array is full, and hence T cannot be added

to the deque. That is, overflow has occurred. 4. Consider a deque maintained by a circular array with N memory cells.

a. Suppose an element is added to the deque. How is LEFT or RIGHT changed?

b. Suppose an element is deleted. How is LEFfTor RIGHT changed? Solution:

a. If the element is added on the left, then LEFT is decreased by 1 (mod N). On the other hand, if the element is added on the right, then RIGHT is increased by 1 (mod N).

b. If the element is deleted from the left, then LEFT is increased by 1 (mod N). However if the element is deleted from the right, then RIGHT is decreased by 1 (mod N). In the case that LEFT = RIGHT before the deletion (that is, when the deque has only one element), then LEFT and RIGHT are both assigned NULL to indicate that the deque is empty.

4. Consider a queue as shown below. Queue

FRONT REAR 1 2 3 4 5 6 1 2 2 1 AAA 2 1 3 2 BBB CCC XXX 3 0 0 3 4 5 1 4 FFF DDD EEE 5 4 4 5 GGG

The above queue is maintained by a two-dimensional array QUEUE. a. Describe the structure after (PP,3), (RR,4), (SS,1), (MM,1), (II,4) and

(NN, 2) are added to the queue. b. Describe the structure if, after the preceding insertions, four

elements are deleted. Solution:

a. Insert each elements in its priority row. That is PP as the rear element in row 3, and RR as the rear element in row 4, and SS as the

Page 95: Unit II

rear element in row 1 and add MM as the rear element in row 1, II as the rear element in row 4 and NN as the rear element in row 2. This yields the structure as shown below.

1 2 3 4 5 6

1 AAA SS MM 2 BBB CCC XXX NN 3 PP 4 FFF RR II DDD EEE 5 GGG

b. First delete the elements with the highest priority in row 1. Since row 1 contains three elements AAA, SS and MM, then the front element in row 2, BBB is also deleted. The resulting structure is as shown below.

1 2 3 4 5 6

1 2 BBB CCC XXX NN 3 PP 4 FFF RR II DDD EEE 5 GGG

Please note that, in both cases the FRONT and REAR elements

are changed accordingly.

5. What would be the contents of queue Q after the following code is executed and the following data are entered? Q = createqueue Loop (not end of file) Read number If (number not 0) Enqueue(Q,number) Else Queuerear(Q,x) Enqueue(Q,x) The data are: 5, 7, 12, 4, 0, 4, 6, 8, 67, 34, 23, 5, 0, 44, 33, 22, 6, 0

Solution: 5, 7, 12, 4, 4, 4, 6, 8, 67, 34, 23, 5, 5, 44, 33, 22, 6, 6

6. What would be the contents of queue Q after the following code is executed and the following data are entered?

Page 96: Unit II

Q=createqueue S=createstack Loop (not end of file) Read number If (number not 0) Pushstack(S,number) Else Popstack(S,x) Popstack(S,x) Loop (not empty S) Popstack(S,x) Enqueue(Q,x) The data are: 5, 7, 12, 4, 0, 4, 6, 8, 67, 34, 23, 5, 0, 44, 33, 22, 6, 0. Solution

7, 5, 34, 67, 8, 6, 4, 33, 44

2.21 Recursion

A recursion is an important programming tool which can simplify the design and coding of an operation. A subprogram invokes itself or invokes a series of other subprograms that eventually invokes the first subprogram again is called recursion.

Every recursive call must either solve a part of the problem or reduce the size of the problem.

A general rule for designing a recursive algorithm is as follows: 1. First determine the base case 2. Then determine the general case 3. Combine the base case and general case into an algorithm.

For example, in mathematics, the factorial function of a non-negative integer is usually defined by the following formula n! = n x (n – 1) x (n – 2) x …….x 2 x 1 For more precise definition, we can also write

{ 0n if 1)!-(n xn 0n if 1 !n >

==

Now, let us consider the case of 4! , since n>0, we use the second clause of the definition 4! = 4 x 3! = 4 x (3 x 2!) = 4 x (3 x (2 x 1!)) = 4 x (3 x (2 x (1 x 0!))) = 4 x (3 x (2 x (1 x 1)))

Page 97: Unit II

= 4 x (3 x (2 x 1)) = 4 x (3 x 2) = 4 x (6) = 24. Such definition is called iterative because it calls for the explicit relation of some process until a certain condition is met. The C language routine for calculating factorial of n is as follows: factorial(n) int n; { int x; if (n==0) return 1; else x=n-1; return(n*factorial(x)); } Note that, the second return statement factorial calls itself. This is essential for recursive routine. Therefore, a procedure call to itself or a procedure call to a second procedure, which eventually causes the first procedure to be called, is known as recursive procedure. The general algorithm for recursive procedure is as follows:

1. Save the parameters, local variables and return address 2. If the base criterian has been reached, then perform the final computation

and go to step 3, otherwise perform the partial computation and go to step 1 with reduced parameter values (initiate a recursive call)

3. Restore the most recently saved parameters, local variables and return address. Go to this return address.

Note: One should not use recursion if the answer to any of the following questions is no.

1. Is the algorithm or data structure naturally suited to recursion? 2. Is the recursion solution shorter and more understandable? 3. Does the recursive solution run in acceptable time and space limits?

2.21.1 Some more recursive algorithms

1. Multiplication of Natural numbers 2. Fibonacci Sequence 3. Greatest Common Divisor(GCD) 4. Towers of Hanoi problem 5. Ackermann function

Page 98: Unit II

2.21.1.1 Multiplication of Natural numbers Here, the product a*b, where a and b are positive numbers, may be written as a added to itself b times. This definition is iterative. We can write this definition in a recursive way as:

{ 1 b if a1)-(b * a 1b if a b*a >+

==

To evaluate 5 *3, we first evaluate 5 * 2 and add 5. To evaluate 5*2, we first evaluate 5 * 1 and add 5. 5*1 is equal to 5 due to first part of the definition. Therefore, 5 * 3 = 5 * 2 + 5 = 5 * 1 + 5 +5 = 5 + 5 + 5 = 15 We can convert this recursive definition of multiplication of natural numbers to C routine is as follows: multiplication (a,b) int a,b; { int c; if (b==1) return(a); c=b-1; return(multiplication (a,c)+a); } 2.21.1.2 Fibonacci Sequence The fibonacci sequence is the sequence of integers 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ……. Each element is the sum of the previous two numbers. We may define the fibonacci sequence by letting fib(0)=0 and fib(1)=1, as follows:

{ 2 n if 1)-fib(n 2)-fib(n1 0, n if n )n(fib ≥+

==

This definition can be written in C as follows: fib(n) int n; { int a,b; if (n<=1) return n; a=fib(n – 1); b=fib(n – 2); return(a+b); } 2.21.1.3 Finding Greatest Common Divisor (GCD) The greatest common divisor of two integers is defined as follows:

Page 99: Unit II

=>

=Otherwise n))mod(m,(n, GCD

0 n if mm n if m)(n, GCD

)n,m(GCD

Here, mod(m,n) is the remainder on dividing m by n. The base case is when the second argument is zero. In this case, the greatest common divisor is equal to the first argument. If the second argument is greater than the first, the order of argument is interchanged. Finally, the GCD is defined in terms of itself. Note that, the size of the argument is getting smaller as mod(m,n) will eventually reduce to zero in a finite number of steps. A C routine for computing GCD can be written as follows: gcd(m,n) int m,n; { int x; if (n>m) return (gcd(n,m)); if n=0 return(m); x=m mod n; return(gcd(n,x)); } 2.21.1.4 Towers of Hanoi Problem Another complex recursive procedure is that towers of Hanoi problem. The problem is as follows: There are n disks of different sizes and there are three needles A, B and C. All the n disks are placed on a needle (A) in such a way that a larger disk is always placed below a smaller disk, which is shown below.

The other two needles are initially empty. The aim is to move the n disks to the second needle (C) using he third needle (B) as a temporary storage. The rules for the movement of disks as follows:

1. Only the top disk may be moved at a time 2. A disk may be moved from any needle to any other needle 3. A larger disk may never be placed upon a smaller disk

Now, let us see how to solve this problem.

Page 100: Unit II

CASE 1: If there is only one disk, we can directly move from A to C. CASE 2: If there are two disks, we move the top disk to B and move the second disk to C and finally move the disk from B to C.

In general, we can move n –1 disks from A to B and then move the nth disk from A to C, finally we can move n – 1 disks from B to C.

Now, let us consider n= 4 disks. We first move three disks from needle A to B using C as temporary. This is

shown below:

Then we move the fourth disk from A to C. This is shown below.

Finally we move the three disks from needle B to C using A as

temporary. This is shown below.

Therefore, a recursive solution can be formulated to solve the problem of

Hanoi to move n disks from A to C using C as temporary as follows:

1. If n=1, move the single disk from A to C and return 2. If n>1,

a. move the top n – 1 disks from A to B using C as temporary

Page 101: Unit II

b. Move the remaining disk from A to C c. Move the n – 1 disks from B to C, using A as temporary

Now, let us convert this algorithm to C program. For that let us decide about

the input and output to the program. As an input to the program, we must give n, the number of disks. Apart from number of disks, we must also specify the needles which are to act as the initial needle from which we are moving disks, the final needle to which we are moving disks and temporary needle.

We must also decide about the names of the disks. Let the numbering itself represents the names of the disks. The smallest disk, which is on the top of the needle is numbered 1, the next disk is 2 and so on. Such that the largest disk is represented by number n.

The output from the program could be a list statements as: Move disk nn from needle x to needle y. The solution of the problem then would be to perform action according to

the output of the statement in exactly the same order that they appear in the output.

The C program for the problem of towers of Hanoi can be written as follows: #include <stdio.h> void hanoi (int n, char initial, char final, char temp) { if (n==1) { printf(“Move disk 1 from needle %c to %c\n”,initial,final); return; } honai(n – 1, initial, temp, final); printf(“Move disk %d from %c to %c\n”, n, initial, final); hanoid(n – 1, temp, final, initial); } void main() { int n; printf(“Enter number of disks to be moved\n”); scanf(“%d”,&n); hanoi (n,’A’,’B’,’C’); } The output produced by the above problem when n=3 as follows: 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

Page 102: Unit II

Move disk 2 from needle B to needle C Move disk 1 from needle A to needle C

2.21.1.5 Ackermann Function The Ackermann function is a function with two arguments each of which can be assigned any non-negative integers: 0, 1, 2,. …. This function is defined as follows:

a. If m=0, then A(m, n) = n + 1. b. If m ≠ 0 but n = 0, then A(m, n) = A(m – 1, 1) c. If m ≠ 0 and n ≠ 0, then A(m , n) = A(m – 1, A(m, n – 1))

2.21.1.6 PROBLEMS:

1. Let a and b denote positive integers. Suppose a function Q is recursively defined as follows:

{ a b if 1b) b,-Q(ab a if 0 )b,a(Q ≤+

<=

a. Find the value of Q(2, 3) and Q(14, 3) b. What does this function do? Q(5861, 7).

Solution:

a. Q(2,3) = 0, since 2 < 3. Q(14, 3) = Q(11, 3) + 1

= [Q(8, 3) + 1] + 1 = Q(8, 3) + 2 = [Q(5, 3) + 1] + 2 = Q(5, 3) + 3 = [Q(2, 3) + 1] + 3 = Q(2, 3) + 4 = 0 + 4 = 4

b. Each time b is subtracted from a, the values of Q is increased by 1. Hence

Q(a,b) finds the quotient when a is divided by b. Thus, Q(5871, 7) = 837

2. Use the definition of Ackermann function, find A(1,3) Solution:

a. If m=0, then A(m, n) = n + 1. b. If m ≠ 0 but n = 0, then A(m, n) = A(m – 1, 1) c. If m ≠ 0 and n ≠ 0, then A(m , n) = A(m – 1, A(m, n – 1))

Here, m = 1 and n = 3 A(1, 3) = A(0, A(1, 2)) A(1, 2) = A(0, A(1, 1)) A(1, 1) = A(0, A(1, 0)) A(1, 0) = A(0, 1) A(0, 1) = 1 + 1 = 2

Page 103: Unit II

A(1, 0) = 2 A(1, 1) = A(0, 2) = 2 + 1 = 3 A(1, 2) = A(0, A(1, 1)) = A(0, 3) = 3 + 1 = 4 A(1, 3) = A(0, A(1, 2)) = A(0, 4) = 4 + 1 = 5

3. Consider the following algorithm. Algorithm fun1 (int x) If (x < 5) Return(3 *x) Else Return(2*fun1(x – 5)+7) End fun1. What would be returned if fun1 is called as

a. fun1(4)? b. fun1(10)? c. Fun1(12)?

Solution: a.

3*4 = 12

b. (2*fun1(5) + 7) = (2 * (2 *fun1(0) +7) + 7) = (2 * (2*(3 * 0) +7) + 7) = 21 c. (2* fun1(7)+7) = (2* (2* fun1(2)+7) + 7) = (2* (2* (3*2) + 7) + 7 = 45

4. Consider the following algorithm. Algorithm fun2 ( int x, y) If (x > y) Return –1 Else if (x==y) Return 1 else Return(x*fun2(x+1, y)) End fun2.

Page 104: Unit II

What would be returned if fun2 is called as a. fun2(10, 4)? b. fun2(4, 3)? c. fun2(4, 7)? d. fun2(0, 0)?

Solution: a. - 1 b. - 1 c. (4 * fun2(5, 7)) = (4 * (5 * fun2(6, 7))) = 4 * (5 * (6* fun2(7, 7))) = 4 * 5 * 6 * 1 = 120 d. 1

Review Questions

1. How is a 2 dimensional array represented in row major order? 2. What is meant by the terms ‘row-major order and column-major

order’? 3. The array DATA [10,15] is stored in memory in row-major order. If

base address is 200 and element size is 1. Calculate the address of element DATA[07,12].

4. What is an empty linked list? How do you check, whether a given linked list is empty?

5. Write the applications of doubly linked list. 6. What are the basic operations on a data structure? 7. What is called multilinked structure? Explain. 8. Write an algorithm to insert an item at the beginning of the linked

list. 9. Define data structure. 10. What are the advantages of linked lists over arrays? 11. Give the differences between a queue and a circular queue. 12. What are the advantages of linked list over linear list. 13. Compare a list and an array. 14. Discuss in detail the algorithmic notations with example. 15. Formulate an algorithm that searches for an item in a linked list that

is unsorted. 16. Explain any one control structure in PSEUDO linked list.

Page 105: Unit II

17. Write an algorithm to insert, delete and search an item in a doubly linked list.

18. Give the implementation of circular linked list. 19. Give the implementation of stack using linked list. 20. Describe the process of evaluation of postfix expression using stack.

Illustrate with an example. 21. Give the recursive algorithms for preorder, postorder and inorder

traversals. 22. Perform the three traversals on the expression (a-b+c*e/f) and

explain. 23. What are the basic operations performed on a list? 24. What are associative lists? 25. Explain with an example how arrays can be used to represent a

linked list? What are its limitations? 26. What is a header node in linked list? What are its uses? Give an

algorithm to add an element to a circularly linked (singly) list with a header node.

27. What are the primitive data structures used in a computer? 28. What do you mean by garbage collection? 29. What are the uses of priority queues? 30. What is an array? 31. Convert the following expression to postfix expression:

A+B*C/D+E 32. What is the purpose of stack in implementing a recursive

procedure? 33. Explain how arrays are useful in storing sparse matrices. Give an

algorithm to transpose a sparse matrix stored in three tuple form. 34. Explain how a linked list can be used to represent sparse

polynomials? 35. What is external fragmentation? 36. Write procedures to add and delete an element from the stack. 37. Explain the various methods of implementation of lists. 38. Write algorithms to insert and delete a node into and from circular

list. 39. Write procedures for implementing queue operations using linked

list. 40. Write and explain the procedure for evaluating a postfix expression

using stack with an example. 41. Differentiate between list and array. 42. What is a linear list? 43. Write an algorithm to delete and insert an element in the doubly

linked linear list. 44. Write the advantages of circular list with example. 45. What do you mean by multi-dimensional arrays? 46. Give the structure of a circular linked list. 47. List any two applications of stack.

Page 106: Unit II

48. Write the pseudo code to delete an element from a queue. 49. Write procedures for implementing stack operations peep and

change. 50. Write an algorithm to insert an element in a circular queue. 51. Write a recursive procedure for finding the greatest common

divisor (GCD) of any two numbers. 52. What is priority queue. 53. Discuss the operations that can be performed on a queue. 54. Describe the implementation of a priority queues with an

illustrative example. 55. What is a stack? 56. Explain the use of stacks in a recursive procedure to solve the

“Tower of Hanoi” problem. 57. Give an algorithm that can be used to evaluate an expression given

in the postfix form. 58. Explain non-recursive method for implementing tower of Hanoi. 59. Convert the expression a+3(b-2)/(5c+76/2) into postfix notation. 60. Define recursion. 61. Define ‘prefix’ and ‘infix’ notation. 62. What is backtracking? 63. Explain how the following infix expression is evaluated with the

help of stack: 5*(6+2)-12/4. 64. Explain the procedure to delete a node with a given item of

information in a singly linked list. 65. What is sparse matrix? 66. Consider the following stack of characters, where STACK is

allocated N=8 memory cells. STACK : A,C,D,F,K,-,-,-. ‘-‘ DENOTES ON EMPTY MEMORY CELL. Describe the stack as the following operations takes place:

i. POP(STACK,ITEM) ii. POP(STACK,ITEM)

iii. POP(STACK,ITEM) iv. PUSH(STACK,L) v. PUSH(STACK,P)

vi. PUSH(STACK,R) vii. POP(STACK,ITEM)

viii. POP(STACK,ITEM) ix. PUSH(STACK,S) x. POP(STACK,ITEM)

67. Discuss different data types? 68. Discuss: Evaluation of arithmetic expression using stack. 69. With example, show how a linked list can be used to represent

sparse polynomials. 70. Why are parenthesis needed to specify the order of operations in

infix expressions but not in postfix expressions?

Page 107: Unit II

71. Why are queues that are housed in arrays are represented in circular rather than linear fashion?

72. Convert the following infix expression to postfix expression. ((A+B)-((C+D)*E)/F)*G

73. What is the value of the following postfix expression? 5 4 6 + * 4 9 3 / + *

74. Write short notes on: a. Linked list implementation of a stack b. Circular implementation of queue.