Data Structures
Data Structures
Data Structures
Primitive Non-primitive
Linear Non-linear
in float cha
t r
arrays lists trees graph
s
List ADT:
Component:
Item
Operations:
Insertion
Deletion
Search
Traverse
Here Item is the component of abstract data type. List can contain no.of items. Operations on these items can
be insertion, deletion, search, and traverse.
Thus ADT is a tool for specifying the logical problems of a data type. It is a mathematical concept not
concerned with space and time efficiency. ADT has two parts for definition.
i. value definition
ii. operator definition
RATIONAL: i.e., represent a rational with two integers second of which is not equal to 0.
/* value definition */
abstract typedef <integer, integer> RATIONAL,
condition RATIONAL[1] !=0
/* Operator definition */
abstract RATIONAL make rational(a,b)
int a,b;
Pre Condition b!=0;
Post Condition makerational[0] = = a;
makerational[1] = = b;
2
Abstract RATIONAL add(a,b)
RATIONAL a,b;
Post Condition add[1] = = a[1].b[1];
add[0] = = a[0] .b[1] + b[0] . a[1];
So post condition specifies what the operator does & precondition specifies the compulsory condition.
ALGORITHMS:
Difinition: An algorithm is a finite sequence of instructions each of which has a clear meaning and can be
performed with a finite amount of effort in a finite length of time.
Features of an algorithm:
1. Finiteness: The algorithm must terminate after a finite no.of steps.
2. Definiteness: Each step of an algorithm must be precisely definied i.e. the actions to be performed
rigorously and unambiguously specified for ease i.e. there should not be any action such as x 10.
3. Input: Zero or more inputs taken from specified set of objects, which is undetermined.
4. Output: Quantities to be specified related to inputs.
5. Effectiveness: All of the operations be performed in the algorithm in a finite length of time by a man
using pencil and paper.
ARRAYS
Linear Arrays (One dimensional arrays):
One dimensional array may be defined abstractly as a finite ordered set of homogeneous elements. By
finite we mean that there is a specific no.of elements in the array. This number may be large or small, but
it must exist. By ordered we mean that the elements of the array are arranged so that there is a zeroth
element, first element, second element, third element, and so forth . By homogenous we mean that all the
elements in the array must be of the same type. For example, an array may contain all integers or all
characters but may not contain both.
The C declaration of an array:
Syntax:
<storage class> <datatype> <array name> [<size>] ;
Example:
static int A[10] ;
auto int B[10] ;
or
int B[10];
The elements of an array A may be denoted by the subscript notation
A[0], A[1], A[2], . . . , A[N-1] where N is the size of the array.
Regardless of the notation, the number I in A[I] is called a subscript or an index and A[I] is called a
subscripted variable. Note that subscripts allow any element of A to be referenced by its relative position in
A.
In general, the length or the no.of data elements of the array, called its range can be obtained from the index
set by the formula
Length or size = UB LB + 1
Where UB is the largest index, called the Upper Bound, and LB is the smallest index, called the Lower
Bound of the array.
3
Computer Memory
As we know, the elements of A are stored in successive memory cells. Accordingly,the computer does not
need to 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)
and called the base address of A. Using this address, the computer calculates the address of any element of A
by the following formula:
LOC(A[I]) = Base (A) + ESIZE * (I- LB)
Where, ESIZE is the amount of memory space occupied by an individual element (single element) of the
array A.
The time to calculate LOC(A[I]) is essentially the same for any value of I. Further more, given any subscript
I, one can locate and access the content of A[I] without scanning any other element of A.
Example:
Memory representation of
int A[5] ={10,20,30,40,50};
Operations on Array:
The two basic operations that access an array are extraction and storing. The extraction operation is a
function that accepts an array A and an index i and returns an element of the array. In C, the result of this
operation is denoted by the expression A[i]. The storing operation accepts an array A , an index i and an
element x. In C this operation is denoted by the assignment statement A[i]= x. The operations are defined
by the rule that after the foregoing assignment statement has been executed, the value of A[i] is x. Before a
value has been assigned to an element of the array, its value is undefined and a reference to it in an
expression is illegal.
Various operations can be performed on Arrays:
i. Traversing
ii. Inserting
iii. Deleting,
iv. Searching
v. Sorting
vi. Merging
4
Two Dimensional Arrays
A two-dimensional m x n array A is a collection of m . n data elements such that each element is specified
by a pair of integers (such as I, J), called subscripts, with the property that
0 < I < m and 0 < J < n
The element of A with first subscript I and second subscript J will be denoted by
A[I][J]
Two-dimensional arrays are called matrices in mathematics and tables in business applications; hence two-
dimensional arrays are sometimes called matrix arrays.
There is a standard way of drawing a tow-dimensional m x n array A where the elements of A form a
rectangular array with m rows and n columns and where the element A[I][J] appears in row I and column J.
(A row is a horizontal list of elements, and a column is a vertical list of elements.)
COLUMNS
0 1 2 3
0 A[ 0 ][ 0 ] A[ 0][1] A[ 0 ][ 2] A[0][3]
ROWS 1 A[1][0] A[1][1] A[1][2] A[1][3]
2 A[2][0] A[2][1] A[2][2] A[ 2][3]
Two-Dimensional 3 X 4 Array A
Suppose A is a two-dimensional m x n array. The first dimension of A contains the index set 0, 1, 2, . . . , m,
with lower bound 0 and upper bound m; and the second dimension of A contains the index set 0, 1, 2, . . ., n,
with lower bound 0 and upper bound n. The length of a dimension is the number of integers in its index set.
The pair of lengths m x n (read m by n) is called the size of the array.
The length of a given dimension can be obtained from the formula
Length = upper bound - lower bound + 1
Representation of Two-Dimensional Arrays in Memory
Let A be a two-dimensional m x n array. Although A is pictured as a rectangular array of elements with m
rows and n columns, the array will be represented in memory by a block of m . n sequential memory
locations. Specifically, the programming language will store the array A either
1. row by row, called row-major order or
2. column by column, called column-major order
Ex:
0,0 0,1 0,2 0,3 1,0 1,1 1,2 1,3 2,0 2,1 2,2 2,3
0,0 1,0 2,0 0,1 1,1 2,1 0,2 1,2 2,2 0,3 1,3 2,3
Or the formula
5
Column major order LOC(A[I][J]) = Base(A) + ESIZE [ m ( J CLB ) + ( I RLB)]
Where,
ESIZE- denotes the size of each element i.e number of words per memory location for the array A.
RLB - denotes the Row Lower Bound
CLB - denotes the Column Lower Bound
m - is the no.of rows and
n - is the no.of columns of the array A.
Matrix Operations
1. Addition
2. Transpose
3. Multiplication, etc
Sparse Matrices:
Matrices with a relatively high proportion of zero entries are called sparse matrices. Two general types of n-
square sparse matrices, which occur in various applications, are given below. The first matrix, where all
entries above the main diagonal are zero or, equivalently, where nonzero entries can only occur on or below
the main diagonal, is called a (lower) triangular matrix. The second matrix, where nonzero entries can only
occur on the diagonal or on elements immediately above or below the diagonal, is called a tridiagonal
matrix.
2 7 5
3 5 3 2 1
1 -7 6 8 -2 4
-1 0 -5 7 6 -1 1
4 -2 9 0 8 9 0 -1
-5 3 6
4 -3
The natural method of representing matrices in memory as two-dimensional arrays may not be suitable for
sparse matrices. That is, one may save space by storing only those entries which may be nonzero.
3-tuple Method:
As the name implies, every nonzero entry of sparse matrix represented by three tuples. First tuple represents
row, second for column and third for value. Here all the elements of matrix will come sequentially. It can be
row major or column major 3-tuple presentation of sparse matrix. First row will represent the number of
rows, number of columns and number of nonzero elements of matrix. After that each row will represent non
zero entries of matrix.
0 -7 0 0 5
9 0 0 0 0
0 0 0 0 0
0 0 8 6 0
6
0 0 0 0 0
-1 0 0 0 2
Now we have to represent this matrix in 3-tuple representation of sparse matrix. Here total no.of rows is 6,
number of columns are 5 and nonzero entries are 7. So sparse matrix will be-
Here its a row major 3-tuple presentation. So elements are coming sequentially on the basis of row. Suppose
we want to represent column major 3-tuple sparse matrix then it will be as-
This 3-tuple method can be implemented in programming by using array or linked list.
7
STACK
A Stack is a linear list in which an element may be inserted or deleted only at one end, called the top of the
stack. This means, elements are removed from a stack in the reverse order, that in which they were inserted
into the stack. Thus a stack is referred to as a Last In First Out (LIFO) data structure. It is a linear data
structure.
Examples of Stack are:
1) Stack of trays
2) Stack of books kept one above the other.
Here is a stack of trays:
Characteristics:
1) Deletion of an element can be done only from top of the stack.
2) Insertion of an element can be done only on top of the stack.
Memory Representation:
There are two ways to represent the stack in memory. They are
1. Using array(static memory)
2. Using linked list(dynamic memory)
Stack declaration using an array:
Suppose elements of the stack are of type int and the stack can store a maximum of 10 elements.
#define MAX 10
typedef struct
{
int top;
int elements[MAX];
}stack;
stack s;
0 1 2 3 4 5 6 7 8 9
Operations on Stack
initstack(s) to initialize s as an empty stack
push(s,i) to push element i onto stack s.
pop(s) to access and remove the top element of the stack s
peek(s) to access the top element of the stack without removing it from the stack s.
isfull(s) to check whether the stack s is full
isempty to check whether the stack s is empty
Stack initialization
Before we can use a stack, it needs to be initialized.
As the index of array elements can take any value in the range 0 to MAX-1, the purpose of
initializing the stack is served by assigning value -1 to the top of variable.
This simple task can be accomplished by the following function.
void initstack( stack *ps)
{
ps->top = -1;}
Testing if stack is empty
8
int isempty(stack *ps)
{
if(ps->top==-1)
return 1;
else
return 0;
}
or
int isempty(stack *ps)
{
return ((ps->top==-1)?1:0);
}
or even
int isempty (stack *ps)
{
return ps->top==-1;
}
Push operation
Adding a new element on to the top of the stack is known as push operation. While inserting a new element
into the stack, we must test whether there is a room in the stack or not. If room is available then the element
can be pushed i.e. the TOP identifies the next available room in the stack and the element is stored in the
room.
Overflow: This situation occurs when TOP identifies the last available room of the stack (i.e. stack is full),
and one performs the PUSH operation.
Condition for Overflow:
When TOP = MAX -1(where MAX is the maximum number of elements that can be hold by the array that
represents the stack in memory), where PUSH operation is performed.
The following figures illustrate operations on a stack, which can accommodate maximum of 10 elements.
top
0 1 2 3 4 5 6 7 8 9
8 10 12 -5 6
top
0 1 2 3 4 5 6 7 8 9
8 10 12 -5 6 9 55
10
Applications of Stack:
1. Keeping track of function calls.
2. Used to implement recursive procedures i.e. in recursion.
3. To reverse a list of elements or a string
4. Parsing data
5. Conversion and evaluation of Arithmetic expressions
Postfix
The sum of X and Y is written as X+Y where + is the operator while X and Y are the operands. We have
always learnt to write the sum of two numbers as X + Y; this notation is know as infix. Here, well be talking
about the postfix notation of representing arithmetic operations.
XY+ // postfix
The relative position of the operator with respect to the operands tells whether the expression is written in
postfix or infix notation. As the above expression shows, when the position of the operator is after the two
operands then the expression is said to be in postfix notation and if the position of the operator is between
the two operands the expression is in infix notation.
1. If the expression contains any parentheses, then they should be converted first.
2. Conversion should be done according to the DMAS rule with precedence given first to division (/),
then multiplication (*), then addition (+) and finally subtraction (-). That is, in an expression
containing /, *, + and - first the division (/) sign should be evaluated followed by multiplication (*),
addition (+) and subtraction (-). Also, the exponentiation operator has a precedence higher than
these four common operators.
3. If there are two operators of the same precedence, then conversion should be done left to right.
Examples
Let us now consider some additional examples. The expression given below has a combination of
parentheses and division, multiplication and addition operators. In the first step according to rule number 1
the expression inside the parentheses is evaluated and converted into postfix notation, after this according to
rule number 2 first division is evaluated followed by multiplication and then addition.
The main thing that should be remembered during the conversion process is that the operator with highest
precedence is converted first and that the portion of expression already converted is treated as one single
operand.
11
Heres another example.
Note: In this example, the parentheses have deliberately been added to reverse the precedence.
(A + B) * C infix form
(AB +) * C convert the addition
(AB +) C * convert the multiplication
AB + C* postfix form
In the above example, addition is converted before the multiplication, this is because the parentheses around
A+B gives + more precedence than *. After the conversion of A+ B, AB+ is treated as one single operand
and not a combination of operands and operator. The rules for converting infix to postfix are simple,
providing that the order of precedence is known.
According to rule number 3, when unparenthesized operators of the same precedence are scanned, the order
of conversion is left to right except in the case of exponentiation, where the order is assumed to be from
right to left. Thus A + B + C means (A + B) + C, whereas A $ B $ C means A $ (B $ C). By using parentheses
we can override the default precedence.
The following are some more examples of infix expressions and their postfix equivalents.
Infix Postfix
A+B AB+
A+B-C+D AB+CD+-
(A + B) * (C - D) AB+ CD -*
A$B*C-D+E/F/(G + H) AB$C*DEF/GH+/+-
A - B/(C*D$E) ABCDE$*/-
12
QUEUES
A queue is a line of persons waiting for their turn at some service counter. The service counter can be a
ticketing window of a cinema hall, a railway station, etc. Depending on the type of service provided by the
service counter and number of persons interested in service, there could be queues of varying lengths. The
service at the service counter is on the first come first serve (FCFS) basis, i.e., in order of their arrival in the
queue.
Queues in Programming
As far as programming is concerned, a queue is a linear list in which insertion can take place at one end of
the list, called the rear of the list, and deletion can take place at the other end called the front of the list. This
is how a simple FCFS queue works.
In programming jargon, insert and delete operations are known as enqueue and dequeue operations.
Memory Representation:
There are two ways to represent the stack in memory. They are
1. Using array(static memory)
2. Using linked list(dynamic memory)
Array Representation
We use the following declarations in order to represent the queue:
/*Define a queue of MAX 10*/
#define MAX 10
typedef struct
{
int front;
int rear;
int elements[MAX];
} queue;
queue q;
Using this declaration, we can perform the various queue operations.
Types of Queue:
1. Linear Queue
2. Circular Queue
3. Double Ended Queue or DEQUE
4. Priority Queue
Operations on Queues
The following are typical operations performed on queues:
1. initqueue(q) to initialize a queue as an empty queue.
2. enqueue(q,i) to insert element i in a q.
3. dequeue(q) to access and remove an element of queue q.
4. peek(q) to access the first element of the queue q without removing it.
5. isfull(q) to check whether the queue q is full.
6. isempty(q) to check whether the queue q is empty.
Linear Queue:
Queue Initialization
Before we can use a queue, it must be created. The purpose of initializing the queue is served by assigning
-1 (as a sentinel value) to the front and rear variables. Note that the valid range of an index for the array is 0
to MAX1.
void createqueue(queue *q)
{
q->front=q->rear=-1;
}
13
Testing if the Queue is empty
bool isempty(queue q)
{
if(q.front==-1)
return true;
else
return false;
}
Testing if the Queue is Full
bool isfull(queue q)
{
if ((q.front==0) && (q.rear==MAX-1))
return true;
else
return false;
}
Note: bool can be defined as
typedef enum {false, true} bool;
The following figures illustrate operations on a linear queue, which can accommodate maximum of 10
elements.
Circular Queue
The difficulty of managing front and rear in an array-based non-circular queue can be overcome if we treat
the queue position with index 0 as if it comes after the last position (in our case, index 9), i.e., we treat the
queue as circular. Note that we use the same array declaration of the queue.
Implementation of operations on a circular queue:
Testing a circular queue for full
There are two conditions:
(front=0) and (rear=MAX-1)
front=rear+1
If any of these two conditions is satisfied, it means that circular queue is full.
bool isfull(queue *q)
{
if (((q->front==0)&&( q->rear==MAX-1))||( q->front==q->rear+1))
return true;
else
return false;}
15
Note: bool can be defined as typedef enum {false, true} bool;
The following figures illustrate operations on a circular queue, which can accommodate maximum of 10
elements.
16
Empty queue:
Non-empty queues:
DEQUE
A deque (pronounced ether deck or dequeue) is a linear list in which elements can be added or removed
at either end but not in the middle. The term deque is a contraction of the name double ended queue.
deletion deletion
insertion insertion
17
1. Input restricted deque: This is a deque which allows insertions at only one end of the list but
allows deletions at both ends of the list.
2. Output restricted deque: This is a deque which allows deletions at only one end of the list but
allows insertions at both ends of the list.
PRIORITY QUEUES
A priority queue is a collection of elements such that each element has been assigned a priority and such that
the order in which elements are deleted and processed comes from the following rules:
1. An element of higher priority is processed before any element of lower priority.
2. Two elements with the same priority are processed according to the order in which they were added
to the queue.
There are two types of priority queues
1. Ascending priority queue ( or Minimum priority queue) : This is a priority queue where lower
number has higher priority.
2. Descending priority queue ( or Maximum priority queue): This is a priority queue where higher
number has higher priority.
Applications of Queue:
1. Many computers have only a single processor, so only one user at a time may be serviced. Entries for
the other users are placed in a queue. Each entry gradually advanced to the front of the queue as users
receive service. The entry at the front of the queue is the next to receive service.
2. Queues are also used to support print spooling.
3. Information packets also wait in queues in computer network.
18
Dynamic Storage Management
1. Static Memory allocation: Static memory allocation is the one in which the required memory is
allocated at compile time.
Example: arrays are the best examples of static memory allocation.
Drawbacks :
a. Size is fixed before execution.
b. Insertion and deletion is a time taking process as the elements need to be shifted towards left or
right.
c. There may be a possibility that memory may get wasted or memory is deficit.
2. Dynamic memory allocation: Dynamic memory allocation is the one in which the required memory
is allocated at the run time.
Example: linked lists are the best examples of dynamic memory allocation.
Advantages:
a. The allocated size can be increased or decreased as per the requirement at run time.
b. Memory can be utilized efficiently as the programmer can choose exact amount of memory
needed.
c. The operations like insertion and deletion are less time-consuming as compared to arrays.
Disadvantages:
a. It takes more memory space because each node contains the link or address part.
b. Moving to a specific node directly like array is not possible.
START
100
INFO LINK
Suppose we want to store a list of ints, then the linear linked list can be declared as:
19
The above declaration defines a new data type, struct nodetype, with a typedef of node.
The main operations that are performed on a linked list are the following:
Overflow condition:
When AVAIL = NULL
It indicates that no free memory block exist in the memory, at this point of time if we try to create a new
node overflow situation occurs.
Underflow condition:
When START = NULL
It indicates that linked list has no nodes or linked list does not exist, at this point of time if we try to delete a
node from linked list to underflow situation.
Sample Program
/*
* Linear Linked List of strings
* http://www.tech-faq.com
*/
#include <stdio.h>
#include <stdlib.h>
struct llnode
{
char *data;
struct llnode *next;
};
20
void displayrev(struct llnode *, int );
/*
* Driver functions -- main() and menu()
*/
int menu(struct llnode *);
int main()
{
struct llnode *start = NULL;
int pos;
char temp[80];
while (1)
{
switch(menu(start))
{
case 1:
puts("Enter strings to add at end, blank line to stop: ");
while (gets(temp)[0])
addAtPos(&start, temp, INT_MAX);
break;
case 2:
puts("Enter strings to add at beginning, blank line to stop: ");
while (gets(temp)[0])
addAtPos(&start, temp, 1);
break;
case 3:
printf("Enter position: ");
scanf("%d", &pos);
gets(temp); /*Clear buffer*/
printf("Enter the string to add: ");
addAtPos(&start, gets(temp), pos);
break;
case 4:
printf("Enter string to search: ");
search(start, gets(temp));
break;
case 5:
printf("Enter string to delete: ");
deleteByElement(&start, gets(temp));
break;
case 6:
printf("Enter position: ");
scanf("%d", &pos);
gets(temp);
deleteByPosition(&start, pos);
break;
case 7:
delete_list(&start);
puts("List deleted successfully");
break;
case 8:
display(start);
getchar();
break;
case 9:
printf("Enter position: ");
scanf("%d", &pos);
gets(temp);
displaynth(start, pos);
break;
case 10:
displayrev(start, 1);
getchar();
break;
21
case 11:
exit(0);
}
}
}
if (p!=NULL)
22
printf("%s found at position %d\n", tosearch, pos);
else
printf("%s not found in list\n", tosearch);
}
void deleteByElement(struct llnode **start, char *todelete)
{
struct llnode *prev, *curr, *temp;
prev = NULL;
curr = *start;
23
}
}
void display(struct llnode *p)
{
int cnt;
for (cnt=1; p; cnt++)
{
printf("%d: %s\n",cnt,p->data);
p = p->next;
}
}
if (p && cnt==pos)
printf("The %dth node is %s\n", pos, p->data);
else
printf("Invalid position\n");
getchar();
}
Disadvantages:
1. It may enter into an infinite loop.
2. Head node is required to indicate the START or END of the circular linked list.
3. Backward traversing is not possible.
24
1. The first part, called the previous pointer field, contains the address of the preceding element in the
list.
2. The second part contains the information of the list.
3. The third part, called the next pointer field, contains the address of the succeeding element in the list.
In addition, two pointer variables, named head and tail, are used that contain the address of first element and
the address of last element of the list.
Suppose we want to store list of integers. Then, we define the following self-referential structure:
The above declaration defines a new data type called struct nodetype with a typedef of node. Two node
pointers are also declared: head and tail.
A call to the above function will need to pass the addresses of head and tail (as double pointers) as follows:
createemptylist(&head, &tail);
25
Operations on Doubly Linked Lists
Inserting an element
Deleting an element
Traversing and Searching
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
/*Insert: Insert new data in the list at position specified by pos, beginning from 1
pos is invalid if < 1. If pos>length of list, insert at end*/
void Insert(int pos, int data, Node **start)
{
if (pos<1)
{
puts("Invalid position");
return;
}
if (*start == NULL)
{
*start = MakeNode(data);
(*start)->prev = NULL;
(*start)->next = NULL;
}
else
{
Node *curr=*start;
for (;curr->next && pos>1; pos--)
curr = curr->next;
if (pos > 1 ) /*insert at end*/
{
Node *newnode = MakeNode(data);
newnode->prev = curr;
newnode->next = curr->next;
curr->next = newnode;
}
else if (curr==*start) /*insert at beginning*/
26
{
Node *newnode = MakeNode(data);
newnode->prev = curr->prev;
newnode->next = curr;
curr->prev = newnode;
*start = newnode;
}
else
{
Node *newnode = MakeNode(data);
newnode->prev = curr->prev;
newnode->next = curr;
curr->prev->next = newnode;
curr->prev = newnode;
}
}
}
27
}
}
}
int menu(void)
{
int choice;
puts("1-Insert data at end");
puts("2-Insert at beginning");
puts("3-Insert at position");
puts("4-Delete by position");
puts("5-Delete by element");
puts("6-Display");
puts("7-Display in reverse");
puts("8-Exit");
printf("Enter choice: ");
scanf("%d", &choice);
while (getchar()!='\n')
;
return choice;
}
/* Test driver. Note: gets() is unsafe and
* should not be used in production environments.
* Its use here is only for illustration.
*/
int main(void)
{
28
Insert(INT_MAX, atoi(input), &start);
break;
case 2:
printf("Enter number: ");
Insert(1, atoi(gets(input)), &start);
break;
case 3:
printf("Enter position: ");
pos = atoi(gets(input));
printf("Enter number: ");
Insert(pos, atoi(gets(input)), &start);
break;
case 4:
printf("Enter position: ");
DeleteByPosition(atoi(gets(input)), &start);
break;
case 5:
printf("Enter value: ");
DeleteByValue(atoi(gets(input)), &start);
break;
case 6:
Traverse(start);
break;
case 7:
TraverseInReverse(start);
break;
case 8:
exit(0);
}
}
}
A hard disk can be compared to a large, square piece of graphing paper composed of squares a thousand
long and a thousand wide. Each individual square can accommodate one kilobyte of data and thus a 'strip'
having a thousand squares can store one megabyte of data. In such a case, the disk head will 'fill' in the
upper leftmost square first then continue down the line one square at a time until all the appropriate
squares are filled.
A second key concept to remember is that data storage follows a simple rule data is stored (or 'written') on
the first available space, wherever this may be.
Imagine that you are saving a 1-Mb Word document on the hard disk. Saving a 1 MB file means the disk
will systematically 'fill in' a thousand squares.
After saving the Word document, let us assume that you saved to your hard disk a 3 MB photo. Following
the key concepts of data storage, the disk writer head will go through the disk and then look for the first
available space which in our example, happens to be the square following the last kilobyte of the Word
document. Thus, the 3 MB photo will be saved at the space next to the Word document.
Afterwards, you go back to your Word document and trim it down, ending up with a file 700 KB in size,
which you then save to your hard disk. Given the smaller file size, the 1 MB space requirement was reduced
to 700 KB, leaving 300 KB free or (using the analogy above) 300 blank squares immediately after the Word
document. There's now available space between the Word Document and the 3 MB photo.
When you save yet another file, say a 2 MB Excel file, the hard disk will follow its rule of saving data on the
first available space. Thus, the Excel file will be split into two portions: 300 KB would be written on the 300
KB free space and the rest will be placed in the next available space after the image file.
The Problem
Data storage, while designed to be logical and systematic, leads to file fragmentation. Imagine adding,
deleting files and editing files for days, weeks and months. After a few months, the hard disk will become so
fragmented that it would take the disk a lot of time to find fragments of a single file.
It is easy to see from this that data retrieval would be easy if the file components are in a single, contiguous
location on the hard disk. De-fragmentation is the process wherein the different file fragments in a data
storage system are located, 'gathered' and consolidated into specific areas of the storage device, thus making
30
it easier to retrieve data allowing for speedier processing as well as reduced wear and tear on data retrieval
mechanisms.
Trees
Arrays, linked lists, stacks and queues are used to represent linear and tabular data. These structures are not
suitable for representing hierarchical data.
ancestors, descendants
superiors, subordinates, etc
Family Structure
31
Federal Government Structure
Introduction to Trees
Fundamental data storage structures used in programming
Combine advantages of ordered arrays and linked lists
Searching can be made as fast as in ordered arrays
Insertion and deletion as fast as in linked lists
Tree characteristics
Consists of nodes connected by edges
Nodes often represent entities (complex objects) such as people, car parts etc.
Edges between the nodes represent the way the nodes are related.
Its easy for a program to get from one node to another if there is a line connecting them.
The only way to get from node to node is to follow a path along the edges.
Tree Terminology
Root: node without parent (A)
Internal node: node with at least one child (A, B, C, F)
External node: (a.k.a. leaf) node without children (E, I, J, K, G, H, D)
Ancestors of a node: parent, grandparent, grand-grandparent, etc
Depth of a node: number of ancestors
Height of a tree: maximum depth of any node (3)
Descendant of a node: child, grandchild, grand-grandchild, etc
Degree of an element: no. of children it has
Subtree: tree consisting of a node and its descendants
32
Path: traversal from node to node along the edges that results in a sequence
Root: node at the top of the tree
Parent: any node, except root has exactly one edge running upward to another node. The node above
it is called parent.
Child: any node may have one or more lines running downward to other nodes. Nodes below are
children.
Leaf: a node that has no children
Subtree: any node can be considered to be the root of a subtree, which consists of its children and its
childrens children and so on.
Visiting: a node is visited when program control arrives at the node, usually for processing.
Traversing: to traverse a tree means to visit all the nodes in some specified order.
Levels: the level of a particular node refers to how many generations the node is from the root. Root
is assumed to be level 0.
Keys: key value is used to search for the item or perform other operations on it.
Binary Trees
Every node in a binary tree can have at most two children.
The two children of each node are called the left child and right child corresponding to their
positions.
A node can have only a left child or only a right child or it can have no children at all.
33
Arithmetic Expression Tree
Binary tree associated with an arithmetic expression
o internal nodes: operators
o external nodes: operands
Example: arithmetic expression tree for the expression (2 * (a - 1) + (3 * b))
(A + B) * (C + D) * 2 X / Y
as a binary tree, in which the leaves are constants or variables and the nodes are operations:
Notation
n number of nodes
e number of external nodes
34
i number of internal nodes
h height
Properties
e = i +1
n =2e -1
h <= i
h <= (n -1)/2
e <= 2h
Searching
Searching is the process of finding the location of a given element in a set of elements. The search is said to
be successful if the given element is found i.e., the element does exist in the collection (such as an array);
otherwise it is unsuccessful.
Linear search: This method traverses a list sequentially to locate the search key.
Binary search: This method works on sorted lists by progressively making better guesses to find the
location of a search key.
Linear Search
This method traverses a list sequentially to locate the search key.
The algorithm that one chooses generally depends on the organization of the array elements. If the elements
are in random order, then one should choose the linear search technique.
Algorithm
linearsearch (a,n,item,loc)
Here a is an array of the size n. This algorithm finds the location of the element item in the array a. If
search item is found, it sets loc to the index of the element; otherwise, it sets loc to -1
Begin
for i=0 to (n-1) by 1 do
if (a[i] = item) then
set loc=I
exit
endif
endfor
set loc -1
end
In the best possible case, the item may be found at the first position. In that case, the search operation
terminates in success with just one comparison.
The worst case occurs when the item is present at the last position or it is missing from the array. In the
former case, the search terminates in success with n comparisons. In the latter case, the search terminates in
failure with n comparisons. Thus, we find that in the worst case, linear search carries out n operations.
Complete Program
/**
* Program that illustrates the working of Linear Search
* http://www.tech-faq.com
*/
#include <stdio.h>
/**
* Parameters:
* a: array to search in
* n: number of elements in the array
* key: search key
*
* Return Value: index of the first occurence
* of key in a[], or -1 if not found
*/
int linearsearch (int a[], int n, int key)
{
int i;
for(i=0;i<n;i++)
{
if(a[i]==key)
return i;
}
return -1;
}
int main()
{
int array[50], num, index, element, key;
36
if ( (index=linearsearch(array, num, key)) != -1)
printf("The element was found at index: %d\n", index);
else
printf("Could not find %d\n", key);
return 0;
}
Binary Search
This method works on sorted lists by progressively making better guesses to find the location of a search
key.
Illustration
3 10 15 20 35 40 60
1. We take beg = 0, end = 6 and compute the location of the middle element as
2. We then compare the search key with mid i.e. a[mid]=a[3] is not equal to 15. Since beg<end, we start
the next iteration.
3. As a[mid]=20>15, therefore, we take end = mid-1 = 3-1 = 2 whereas beg remains the same.. Thus
4. Since a[mid] i.e. a[1]=10<15, therefore, we take beg=mid+1=1+1=2, while end remains the same.
5. Now beg=end. Compute the mid element:
Algorithm
Binarysearch(a,n,item,loc)
Begin
set beg=0
set end=n-1
set mid=(beg+end)/2
while((beg<=end) and(a[mid]!=item) do
if(item<a[mid]) then
set end=mid-1
else
set beg=mid+1
endif
set mid=(beg+end)/2
endwhile
if(beg>end) then
set loc=-1
37
else
set loc=mid
endif
end
C/C++ Implementation
int binarysearch(int a[], int n, int key)
{
int beg,end,mid;
beg=0; end=n-1;
mid=(beg+end)/2;
while((beg<=end)&&(a[mid]!=key))
{
if(key<a[mid])
end=mid-1;
else
beg=mid+1;
mid=(beg+end)/2;
}
if(beg>end)
return -1;
else
return mid;
}
In each iteration, the search is reduced to one-half of the array. For n elements in the array, there will be a
maximum of log2 n iterations.
#include <stdio.h>
int main()
{
int arr[50], n, key, index;
38
printf("How many elements do you want to create the array with?(max 50): ");
fflush(stdout);
scanf("%d", &n);
scanf("%d", &key);
if (index == -1)
puts("Sorry, the given key was not found");
else
printf("The given key was found at index: %d\n", index);
return 0;
}
Sorting
Sorting is the process of arranging elements in some logical order.
External sorting: This deals with sorting of data stored in external files. This method is used when
the volume of data is very large and cannot be held in a computers RAM.
Internal sorting: This deals with sorting of data held in the RAM of a computer.
Sorting Methods
The following are links to tutorials on some of the most popular sorting methods:
Bubble sort
Bucket sort
Insertion sort
Merge sort
Quick sort
Selection sort
Shell sort
Bubble Sort
It requires n-1 passes to sort an array.
In each pass every element a[i] is compared with a[i+1], for i=0 to (n-k-1), where k is the pass
number and if they are out of order i.e. if a[i]>a[i+1], they are swapped.
This will cause the largest element to move up or bubble up.
39
Thus after the end of the first pass the largest element in the array will be placed in the last or nth
position and on the next pass, the next largest element will be placed at position (n-1). This continues
for each successive pass until the last or (n-1)th pass when the second smallest element will be
placed at the second position.
Pass1.
Step 1. if a[0]>a[1] then swap a[0] and a[1].
Step 2. if a[1]>a[2] then swap a[1] and a[2].
Pass k.
Step 1. if a[0]>a[1] then swap a[0] and a[1].
Step 2. if a[1]>a[2] then swap a[1] and a[2].
Pass n-1
Step 1. if a[0]>a[1] then swap a[0] and a[1].
40
Analysis of bubble sort
First pass requires n-1 comparison
Second pass requires n-2 comparison
kth pass requires n-k comparisons
Last pass requires only one comparison
41
Algorithm
Bubblesort(a,n)
Begin
for k=1 to (n-1) by 1 do
for j=0 to (n-k-1) by 1 do
if(a[j]>a[j+1]) then
set temp=[j]
set a[j]=a[j+1]
set a[j]=temp
endif
endfor
endfor
end
Complete Program
/**
* Bubble sort
* http://www.tech-faq.com
*/
#include <stdio.h>
int main()
{
int a[50], n, i;
printf("How many elements in the array(max 50)?: ");
fflush(stdout);
scanf("%d", &n);
puts("Enter array elements");
for (i=0; i<n; i++)
scanf("%d", &a[i]);
bubblesort(a, n);
printf("\n");
return 0;
}
Bucket/Radix Sort
Most people use the bucket sort method when sorting a list of names in alphabetical order. The procedure is:
42
First, the names are grouped according to the first letter, thus the names are arranged in 26 classes,
one for each letter of the alphabet. The first class consists of those names that begin with letter A, the
second class consists of those names that begin with letter B, and so on.
Next, the names are grouped according to the second letter. After this step, the list of names will be
sorted on the first two letters.
This process is continued for a number of times equal to the length of the name with maximum
letters.
Since there are 26 letters in the alphabet, we make use of 26 buckets, one for each letter of the alphabet.
After grouping these names according to their specific letter, we collect them according to the order of the
buckets. This new list becomes the input for the next pass when we consider the next letter.
To sort decimal numbers where the base (or radix) is 10, we need 10 buckets, numbered from 0-9. Unlike
sorting names, decimal numbers are sorted from right to left i.e. first on unit digits, then on ten digits and so
on.
Example
Here is an illustration of how bucket sorting works. Consider the following unsorted array:
43
44
After pass three, when the numbers are collected, they are in the following order:
Algorithm
Bucketsort(a,n)
Here a is a linear array of integers with n elements, the variable digitcount is used to store the number of
digits in the largest number in order to control the number of passes to be performed.
Begin
find the largest number of the array
set digitcount=no. of digits of the largest no.
for pass=1 to digitcount by 1 do
initialize buckets
for i=1 to n-1 by 1 do
set digit=obtain digit no. pass of a[i]
put a[i] in bucket no. digit
increment bucket count for bucket no. digit
endfor
collect all the numbers from buckets in order
endfor
end
45
Analysis of Bucket Sort
Suppose that the number of digits in the largest number of the given array is s and the number of passes to
be performed is n. Then, the number of comparisons, f(n), needed to sort the given array are:
f(n)=n*s*10, where 10 is the decimal number base.
From the above discussion, we conclude that bucket sort performs well only when the number of digits in
the elements are very small.
Insertion Sort
This algorithm is very popular with bridge players when they sort their cards. In this procedure, we pick up a
particular value and then insert it at the appropriate place in the sorted sub list.
Pass1: a[1] is inserted either before or after a[0] so that a[0] and a[1] are sorted.
Pass2: a[2] is inserted either before a[0] or between a[0] and a[1] or after a[1] so that the elements a[0], a[1],
a[2] are sorted.
Pass3: a[3] is inserted either before a[0] or between a[0] and a[1] or between a[1] and a[2] or after a[2] so
that the elements a[0], a[1], a[2], a[3] are sorted.
Pass k: a[k] is inserted in its proper place in the sorted sub array a[0], a[1], a[2],a[k-1] so that the
elements a[0], a[1], a[2],a[k-1],a[k] are sorted.
Pass n-1:a[n-1] is inserted in its proper place in the sorted sub array a[0], a[1], a[2],a[n-2] so that the
elements a[0], a[1], a[2],a[n-1] are sorted.
46
47
Analysis of Insertion Sort
The worst-case performance occurs when the elements of the input array are in descending order.
In the worst-case, the first pass will require one comparison, the second pass will require 2 comparisons, and
so on until the last pass which will require (n-1) comparisons. In general, the kth pass will require k-1
comparisons.
Algorithm
insertionsort(a,n)
Here a is a linear array with n elements. This algorithm sorts the elements in ascending order. It uses a
temporary variable temp to facilitate the exchange of two values and variables j and k are used as loop
control variables.
begin
for k=1 to (n-1) by 1 do
set temp=a[k]
set a[j]=k-1
while((temp<a[j]) and j>=0) do
set a[j+1]=a[j]
set j=j-1
endwhile
48
set a[j+1]=temp
endfor
end
Complete Program
/**
* Insertion sort
* http://www.tech-faq.com
*/
#include <stdio.h>
int main()
{
int a[50], n, i;
printf("How many elements do you want to create the array with?"
"max(50): ");
scanf("%d", &n);
fflush(stdout);
puts("Enter the array elements");
for (i=0; i<n; i++)
scanf("%d", &a[i]);
insertionsort(a, n);
puts("--------Sorted Array--------");
for (i=0; i<n; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
Output
How many elements do you want to create the array with?(max 50): 6
Enter the array elements
3
67
85
89
56
44
--------Sorted Array--------
3
44
56
67
85
89
49
Merge Sort
Merging means combining elements of two arrays to form a new array. The simplest way of merging two
arrays is to first copy all the elements of one array into a new array and then append all the elements of the
second array to the new array. If you want the resultant array to be sorted, you can sort it by any of the
sorting techniques.
If the arrays are originally in sorted order, they can be merged in such a way as to ensure that the combined
array is also sorted. This technique is known as merge sort.
The technique of merge sort (i.e., sorting during merging) is much more efficient than sorting after merging
for arrays that are already sorted.
STEP 1: Let us consider two arrays say, A[7] and B[5] to be merged to form a new array. The new array say
C will be having 7+5=12 elements.
STEP 2: Compare A[0] and B[0]; if A[0]<B[0] (say); move A[0] to C[0]. Increment the pointers of array A
and array C (the pointer of that array is incremented whose element is moved in the third array).
STEP 3: Now compare the elements of A and B where the pointers are pointing. That is, compare A[1] and
B[0].
Suppose that we find B[0]<A[1], so we move B[0] to C[1] and increment Bs pointer to point to the next
element in array B.
C++ Implementation
/**
* A and B are the input arrays which contain
* elements in ascending order. Their respective
* sizes are m and n. C is the output array
* that will contain the elements from the
* two arrays combined and in sorted order.
*/
void mergesort(int A[], int B[], int C[], int m, int n)
{
int a=0, b=0, c=0;
for (a=0, b=0, c=0; a<m && b<n;)
{
if (A[a]<B[b])
C[c++] = A[a++];
else
C[c++] = B[b++];
}
if (a<m)
while (a<m)
C[c++] = A[a++];
else
while (b<n)
C[c++] = B[b++];
}
Complete Program
/**
* Merge Sort
* http://www.tech-faq.com
*/
#include <stdio.h>
return 0;
}
/**
* A and B are the input arrays which contain
* elements in ascending order. Their respective
* sizes are m and n. C is the output array
* that will contain the elements from the
* two arrays combined and in sorted order.
*/
Output
How many elements do you want to create the first arraywith? (max 50): 3
Enter the array elements in ascending order:
4
8
10
How many elements do you want to create the second arraywith? (max 50):
4
Enter the array elements in ascending order:
51
3
5
7
9
Quick Sort
Quick sort is a divide-and-conquer sorting algorithm. To understand quick-sort, let us look at a high-level
description of the algorithm.
1. Divide: If the sequence S has 2 or more elements, select an element x from S to be your pivot. Any
arbitrary element, like the last, will do. Remove all the elements of S and divide them into 3
sequences:
a. L, which holds Ss elements less than x
b. E, which holds Ss elements equal to x
c. G, which holds Ss elements greater than x
2. Recurse: Recursively sort L and G
3. Conquer: Finally, to put elements back into S in order, first insert the elements of L, then those of E,
and then those of G.
Let us choose the last element of the array, 50, as the pivot element. Our aim is to place this element in its
final position. In other words, all elements less than or equal to the pivot will be to its left and all elements
greater than or equal to the pivot will be to its right.
We will take the help of two variables: l and r. l scans the sequence from the left, and r from the right.
l is successively incremented until it reaches an element greater than or equal to the pivot.
r is successively decremented until it reaches an element that is less than the pivot.
Now, l and r both point to elements on the wrong sides, so a swap is performed. The swap is performed only
if l < r.
52
These steps are repeated until l >= r. Now, we swap the pivot element with the element at position l. This
concludes the partitioning procedure.
Algorithm
quicksort(a, l, r)
Begin
if(l<r) then
splitarray(a,l,r,loc) //partition the array
quicksort(a,l,loc-1) //recursively sort left sub array
quicksort(a,loc+1,r) //recursively sort right sub array
endif
end
Finding the location of the element that splits the array into two sections is an O(n) operation, because every
element in the array is compared to the pivot element.
If the array is split approximately in half (an optimistic assumption), then there will be log2n splits.
53
Therefore, the total comparisons will be:
f(n) = n*log2n = O(nlog2n)
Complete Program
/**
* Quick Sort
* http://www.tech-faq.com
*/
#include <stdio.h>
int main()
{
int a[50], n, i;
printf("How many elements do you want to create the array with?"
"(max 50): ");
scanf("%d", &n);
fflush(stdout);
puts("Enter the array elements");
for (i=0; i<n; i++)
scanf("%d", &a[i]);
quicksort(a, n);
puts("--------Sorted Array--------");
for (i=0; i<n; i++)
printf("%d\n", a[i]);
printf("\n");
return 0;
}
Output
How many elements do you want to create the array with?(max 50): 6
Enter the array elements
3
67
85
89
56
44
--------Sorted Array--------
3
44
56
67
85
89
Selection Sort
Selection sort requires (n-1) passes to sort an array.
In the first pass, we find the smallest element from a[0], a[1], a[2], a[n-1] and swap it with the first
element, i.e. a[0]. In the second pass, we find the smallest element from a[1], a[2], a[3].a[n-1] and swap it
with a[1] and so on.
Pass1.
1. Find the location loc of the smallest element in the entire array, i.e. a[0],[1],a[2]a[n-1].
2. Interchange a[0] & a[loc]. Then, a[0] is trivially sorted.
Pass2.
1. Find the location loc of the smallest element in the entire array, i.e. a[1],a[2]a[n-1].
2. Interchange a[1] & a[loc]. Then a[0], a[1] are sorted.
Pass k.
1. Find the location loc of the smallest element in the entire array, i.e. a[k],a[k+1],a[k+2]a[n-1].
2. Interchange a[k] & a[loc]. Then a[0],a[1],a[2],a[k] are sorted.
Pass n-1.
56
57
Analysis of Selection Sort
The first pass requires n-1 comparisons to find the location of the smallest element.
The second pass requires n-2 comparisons.
The kth pass requires n-k comparisons.
The last pass requires only one comparison.
Smallestelement(a,n,k,loc)
Here a is linear array of size n. This sub algorithm finds the location loc of smallest element among a[k-
1],a[k+1],a[k+2]a[n-1]. A temporary variable small is used to hold the current smallest element and j is
used as the loop control variable.
Begin
set small=a[k-1]
set loc=k-1
for j=k to (n-1) by 1 do
if(a[j]<small) then
set small = a[j]
set loc=j
endif
endfor
end
58
Selection Sort Algorithm
Selectionsort(a,n)
Here a is the linear array with n elements. This algorithm sorts elements into ascending order. It uses a
temporary variable temp to facilitate the exchange of two values and variable i is used as a loop control
variable
Begin
for i=1 to (n-1) by 1 do
call Smallestelement(a,n,I,loc)
set temp=a[i-1]
set a[i-1]=a[loc]
set a[loc]=temp
endfor
end
Complete Program
/**
* Selection Sort
* http://www.tech-faq.com
*/
#include <stdio.h>
int main()
{
int a[50], n, i;
printf("How many elements do you want to create the array with?"
"(max 50): ");
scanf("%d", &n);
fflush(stdout);
puts("Enter the array elements");
for (i=0; i<n; i++)
scanf("%d", &a[i]);
selectionsort(a, n);
puts("--------Sorted Array--------");
for (i=0; i<n; i++)
printf("%d\n", a[i]);
printf("\n");
return 0;
}
Output
How many elements do you want to create the array with?(max 50): 6
Enter the array elements
3
67
85
89
56
44
--------Sorted Array--------
3
44
56
67
85
89
Shell Sort
Invented by Donald Shell in 1959, Shell sort is the most efficient of the O(n2) class of sorting algorithms. It
is also the most complex of the O(n2) algorithms. This algorithm is similar to bubble sort in the sense that it
also moves elements by exchanges.
Shell sort begins by comparing elements that are at distance d. With this, the elements that are quite away
from their place will move more rapidly than the simple bubble sort.
In each pass, each element is compared with the element that is located d indexes away from it, and an
exchange is made if required. The next iteration starts with a new value of d.
Example:
12 9 -10 22 2 35 40
60
61
Analysis of Shell Sort
1. It is difficult to predict the complexity of Shell sort, as it is very difficult to show the effect of one
pass on another pass.
2. One thing is very clear that if the new distance d is computed using the above formula, then the
number of passes will approximately be log2d since d=1 will complete the sort.
3. Empirical studies have shown that the worst case complexity of Shell sort is O(n2).
C/C++ Implementation
void shellsort(int a[], int n)
{
int d, temp, i;
d=n/2;
while (d>=1)
{
for (i=0;i<n-d;i++)
{
if (a[i]>a[i+d])
{
temp=a[i];
a[i]=a[i+d];
a[i+d]=temp;
}
}
if(d==1)
return;
d=d/2.0+0.5;
}
}
Complete Program
/**
* Shell Sort
* http://www.tech-faq.com
*/
#include <stdio.h>
62
void shellsort(int [], int );
int main()
{
int a[50], n, i;
printf("How many elements do you want to create the array with?"
"(max 50): ");
scanf("%d", &n);
fflush(stdout);
puts("Enter the array elements");
for (i=0; i<n; i++)
scanf("%d", &a[i]);
shellsort(a, n);
puts("--------Sorted Array--------");
for (i=0; i<n; i++)
printf("%d\n", a[i]);
printf("\n");
return 0;
}
Output
How many elements do you want to create the array with?(max 50): 6
Enter the array elements
3
67
85
89
56
44
--------Sorted Array--------
3
44
56
67
85
89
63
Heaps
A heap is a binary tree that satisfies the following properties:
Shape property
Order property
By the shape property, we mean that a heap must be a complete binary tree. A complete binary tree has all its
levels filled, except possibly for the last, where the leaves must be located as far to the left as possible.
By the order property, we mean that for every node in the heap, the value stored in that node is greater than
or equal to the value in each of its children. A heap that satisfies this property is known as max heap.
Alternatively, every node in the heap can have a value less than or equal to the value in each of its children.
In this case, we have a min heap.
Heap Implementation
A heap is efficiently implemented using a linear array i.e. by sequential representation.
Since a heap is a complete binary tree, a heap of size n is represented in memory using a linear array
of size n.
A node at index i has its left child at 2i, right child at 2i+1 and parent at index i/2.
64
Operations on Heaps
Insertion
Deletion
65
Algorithm
ReheapifyUpward(heap,start)
Here heap is a linear array and start is the index of the element from where the reheapifyupward
operation is to start. It uses parent as the index of the parent node in the heap.
Begin
if heap[start] is not root node then
if (heap[parent]<heap[start]) then
swap heap[parent] and heap[start]
call ReheapifyUpward(heap,parent)
66
endif
endif
end
C/C++ implementation
void reheapifyUpward(int heap[],int start)
{
int temp, parent;
if(start>1)
{
parent=start/2;
if(heap[parent]<heap[start])
{
temp = heap[start];
heap[start] = heap[parent];
heap[parent] = temp;
reheapifyUpward(heap,parent);
}
}
}
67
Algorithm
ReheapifyDownward(heap,start,finish)
Here heap is a linear array, start is the index of the element from where the reheapify downward
operation is to start, and finish is the index of the last element of the heap. The variable index is used
to keep track of the index of the largest child.
Begin
if heap[start] is not leaf node then
set index=index of the child with largest value
if(heap[start]<heap[index]) than
swap heap[start] and heap[index]
call ReheapifyDownward(heap,index,finish)
endif
endif
end
C/C++ Implementation
void reheapifyDownward(int heap[],int start,int finish)
{
int index,lchild,rchild,maximum,temp;
lchild=2*start; /*index of the left child*/
rchild=lchild+1; /*index of the right child*/
if(lchild<=finish)
{
maximum=heap[lchild];
index=lchild;
if(rchild<=finish)
{
if(heap[rchild]>maximum)
68
{
maximum=heap[rchild];
index=rchild;
}
}
if(heap[start<heap[index])
{
temp=heap[start];
heap[start]=heap[index];
heap[index]=temp;
reheapifyDownward(heap,index,finish)
}
}
}
Assign the value of the root to a temporary variable, which can be returned from the function for
further processing.
Bring the last element of the heap to the root node position.
Reduce the size of the heap by one.
Apply the reheapify downward operation from the root node.
DeleteElement(heap,n,item)
Here heap is a linear array representing a heap with n elements. This algorithm deletes the element from the
root of the heap and assigns it to item (an output parameter). Note that the code assumes that the array index
begins from 1 and ends at n.
Begin
set item=heap[1]
set heap[1]=heap[n]
set n=n-1;
call reheapifyDownward(heap,1,n)
End
C/C++ Implementation
int deleteElement(int heap[],int *n)
{
int temp;
temp=heap[1];
heap[1]=heap[*n];
--*n;
reheapifydownward(heap,1,n);
return temp;
}
69