You are on page 1of 225

DATA STRUCTURES

Lecture 1
Introduction
DATA
• In programming, data represents the input needed for a certain program
to do his work.
VARIABLES
• Variables are memory containers for storing data values.

• Each variable needs an identifier (variable name) that distinguishes it


from the others.

• Variables types must be determined before being used in a program.

• In C++, there are many data types.


DATA TYPES
• The primitive data types are: Type & Description
1 bool
Stores either value true or false.
2 char
Typically a single octet (one byte). This is an integer type.
3 int
The most natural size of integer for the machine.
4 float
A single-precision floating point value.
5 double
A double-precision floating point value.
INTRODUCTION-DATA
STRUCTURES
• Data structure is used to describe the way data is stored.

• It is a representation of logical relationship existing between individual


elements of data.

• It defines a way of organizing all data items that considers not only the
elements stored but also their relationship to each other.
INTRODUCTION-DATA
STRUCTURES

• The term data structure is used to describe the way data is stored.

• The term algorithm is used to describe the way data is processed.

• Data structures and algorithms are interrelated.


WHY WE USE DATA STRUCTURES
• The selection of good data structure will help the programmer to design more efficient
programs.
• The efficiency of a program depends on two measurements :
✓ Space complexity
✓ Time complexity
• Time complexity can be expressed as function of number of operations performed.
OPERATIONS IN DATA
STRUCTURES
Access

Search

Insertion

Deletion
REAL EXAMPLES

A line for a library or a supermarket Queues

In these examples, a policy of


C B A
First-In-First-Out is applied.
D C B

D C That means the first one came is


D the first one served.
Printing the tasks sent to the printer
REAL EXAMPLES
Reading a stack of books
Stacks
Opening many windows or dialog boxes,
then closing them

Good morning my friends


In these examples, a policy of
Good morning my friend Last-In-First-Out is applied.
Good morning my frien
Good morning my frie
Good morning my frien That means the last one came is
Good morning my friend
Good morning my friends the first one served
The undo button in any application
REAL EXAMPLES

• Processing mathematical equations Graphs


Ex: → a + b * c

+ Trees
a *

b c Social network connections


LINEAR AND NON-LINEAR

• Linear Data Structures:

• A data structure is said to be linear if its elements form a sequence or a linear


list.

• Example: arrays, stacks, queues and linked lists organize data in linear order.
LINEAR AND NON-LINEAR

• Non-Linear Data Structures

• A data structure is said to be non-linear if its elements form a hierarchical


classification where, data items appear at various levels.

• Trees and Graphs are widely used non-linear data structures. Tree and graph
structures represents hierarchical relationship between individual data elements.

• Graphs are nothing but trees with certain restrictions removed.


DATA TYPES

Data Types

Primitive Non-primitive

User-Defined Abstract
PRIMITIVE AND NON-PRIMITIVE

• Primitive Data Structures are the basic data structures that directly
operate upon the machine instructions.

• They have different representations on different computers.

• Integers, floating point numbers, character constants, string constants


and pointers come under this category.
PRIMITIVE AND NON-PRIMITIVE

• Non-primitive data structures are more complicated data structures


and are derived from primitive data structures.

• They emphasize on grouping same or different data items with


relationship between each data item.

• Arrays, lists and files come under this category.


CONTIGUOUS AND NON-CONTIGUOUS

• The collection of data you work with in a program have some kind of
structure or organization.
• No matter how complex your data structures are, they can be broken
down into two fundamental types:

✓ Contiguous

✓ Non-Contiguous.
CONTIGUOUS AND NON-CONTIGUOUS
• In contiguous structures, terms of data are kept together in memory
(either RAM or in a file).
• An array is an example of a contiguous structure. Since each element in
the array is located next to one or two other elements.
CONTIGUOUS AND NON-CONTIGUOUS
• In contrast, items in a non-contiguous structure are scattered in memory,
but we linked to each other in some way.
• A linked list is an example of a non-contiguous data structure. Here, the
nodes of the list are linked together using pointers stored in each node.
DATA STRUCTURES
Lecture 2
Pointers
MEMORY ALLOCATION
• Memory allocation is a process by which computer programs and
services are assigned with physical or virtual memory space.
• The memory allocation is done either before or at the time of program
execution.
• There are two types of memory allocations:
✓ Static memory allocation
✓ Dynamic memory allocation
STATIC MEMORY ALLOCATION
• Static Memory is allocated for declared variables by the compiler.
• The address can be found using the address of operator and can be assigned to
a pointer.
• The memory is allocated during compile time.
• It uses stack for managing the static allocation of memory.
• There is no memory re-usability.
• Once the memory is allocated, the memory size can not change.
• The allocated memory remains from the start to the end of the program.
DYNAMIC MEMORY ALLOCATION
• Memory allocation done at the time of execution (run time).
• It uses heap for managing the dynamic allocation of memory.
• Memory can be freed when not required.
• After memory is allocated, the memory size can be changed.
• The allocated memory can be released at any time during the program.
• Execution is slower than static memory allocation.
POINTERS
• Pointers are variables that hold the addresses of another variables.

• They have data type just like variables, for example an integer type pointer
can hold the address of an integer variable and an character type pointer can
hold the address of char variable.

• Pointers declarations
data_type *pointer_name;
• Ex:
int *p;
char *ch;
POINTERS
• Because the value of a pointer is a memory address, a pointer can store
the address of a memory space of the designated type.

• For example, if p is a pointer of type int, p can store the address of any
memory space of type int.

• C++ provides two operators — the address of operator (&) and the
dereferencing operator (*) — to work with pointers.
ADDRESS OF OPERATOR (&)

• In C++, the ampersand, &, called the address of operator, is a unary


operator that returns the address of its operand.

• For example, given the statements:


int x;
int *p;
• And the statement:
p = &x; assigns the address of x to p.
• That is, x and the value of p refer to the same memory location.
DEREFERENCING OPERATOR (*)
• When the * is used as a unary operator, it referred to as the dereferencing
operator or indirection operator, that refers to the object to which its
operand (that is, the pointer) points.
• For example, given the statements:
int x = 25;
int *p;
p = &x; //store the address of x in p
• the statement:
cout << *p << endl; //prints the value stored in the memory space
pointed to by p, which is the value of x.
• Also, the statement:
• *p = 55; //stores 55 in the memory location pointed to by p — that is, in x.
EXPLANATION
After Values of the Variables Explanation
State
1. num = 78; ment
2. p = &num; 1 The statement num = 78; stores 78 into num.
3. *p = 24;
2 The statement p = &num; stores the address of
num, which is 1800, into p.

3 The statement *p = 24; stores 24 into the memory


location to which p points. Because the value of p
is 1800, statement 3 stores 24 into
memory location 1800. Note that the value of num
is also changed.
EXPLANATION
1. A declaration such as int *p; allocates memory for p only, not for *p.
2. The content of p points only to a memory location of type int.
3. &p, p, and *p all have different meanings.
4. &p means the address of p—that is, 1200.
5. p means the content of p, which is 1800, after the statement p = &num;
executes.
6. *p means the content of the memory location to which p points.

• Note that after the statement p = &num; executes, the value of *p is 78; after
the statement *p = 24; executes, the value of *p is 24.
POINTERS EXAMPLE 1
#include <iostream>
using namespace std;
int main(){
int *p, var=101; //Pointer declaration
p = &var; //Assignment
cout << "Address of var: " << &var << endl;
cout << "Address of var: " << p << endl;
cout << "Address of p: " << &p <<endl;
cout << "Value of var: " << *p <<endl;
return 0;
}
POINTERS EXAMPLE 1
• Output

Address of var: 0x7fff5dfffc0c


Address of var: 0x7fff5dfffc0c
Address of p: 0x7fff5dfffc10
Value of var: 101
POINTERS EXAMPLE 2
#include <iostream>
using namespace std;
int main() {
int int_var = 5;
float f_var = 10.5;
cout << "int_var:\t" << int_var;
cout << "\nAddress of int_var:\t" << &int_var << "\n";
cout << "f_var:\t" << f_var;
cout << "\nAddress of f_var:\t" << &f_var << "\n";
return 0;
}
POINTERS EXAMPLE 2
• Output

int_var: 5
Address of int_var: 0x7fff6d7b1d58

f_var: 10.5
Address of f_var: 0x7fff6d7b1d5c
DYNAMIC VARIABLES
• Since a pointer can be used to refer to a variable, your program can
manipulate variables even if the variables have no identifiers to name them.

• The operator new can be used to create variables that have no identifiers to
serve as their names.

• These nameless variables are referred to via pointers.

• Ex: p1 = new int;


DYNAMIC VARIABLES
• This new, nameless variable can be referred to as *p1 (that is, as the
variable pointed to by p1).
• You can do anything with this nameless variable that you can do with
any other variable of type int.
• Ex:
cin >> *p1;
*p1 = *p1 + 7;
cout << *p1;
OUTPUT
USES OF THE ASSIGNMENT
OPERATOR
POINTERS AND ARRAYS
• Array names alone represent the base address of array.

• So while assigning the address of array to pointer don’t use ampersand


sign(&).

• Do it like this:
p = arr;

Correct: Because arr represent the address of array.


POINTERS AND ARRAYS
#include <iostream>
using namespace std;
int main(){
int *p; //Pointer declaration
int arr[]={1, 2, 3, 4, 5, 6}; //Array declaration
p = arr; //Assignment
for(int i=0; i < 6; i++){
cout << *p << endl;
p++; //++ moves the pointer to next int position
}
return 0; }
POINTERS AND ARRAYS
• Output

1
2
3
4
5
6
DELETE DYNAMIC VARIABLES
• A special area of memory, called the freestore (called heap) is reserved
for dynamic variables.
• Any new dynamic variable created by a program consumes some of the
memory in the freestore.
• If your program creates too many dynamic variables, it will consume all
of the memory in the freestore.
• If this happens, any additional calls to new will fail. The size of the
freestore varies from one implementation of C++ to another.
DELETE DYNAMIC VARIABLES
• It is typically large, and a modest program is not likely to use all the
memory in the freestore.
• It is a good practice to recycle any freestore memory that is no longer
needed.
• The delete operator eliminates a dynamic variable and returns the
memory that the dynamic variable occupied to the freestore so that the
memory can be reused.
delete p;
• After the above call to delete, the value of p is undefined and p should be
treated like an uninitialized variable.
DANGLING POINTERS
• When you apply delete to a pointer variable, the dynamic variable it is
pointing to is destroyed.
• At that point, the value of the pointer variable is undefined, which means
that you do not know where it is pointing, nor what the value is where it
is pointing.
• These undefined pointer variables are called dangling pointers.
• To produce the expression *p, the result is unpredictable and usually
disastrous.
• Before you apply the dereferencing operator * to a pointer variable, you
should be certain that the pointer variable points to some variable.
TYPE DEFINITION
• You can assign a name to a type definition and then use the type name to declare variables,
using the keyword typedef.
• These type definitions are normally placed outside of the body of the main part of your
program (and outside the body of other functions) in the same place as struct definitions.
• We will use type definitions to define names for pointer types.
• Syntax: typedef Known_Type_Definition New_Type_Name;
• Example: typedef int* IntPtr;
• The type name IntPtr can then be used to declare pointers to dynamic variables of
type int, as in the following:
IntPtr pointer1, pointer2;
DYNAMIC ARRAYS
• One problem with the kinds of arrays you have used thus far is that you must
specify the size of the array when you write the program.

• A dynamic array is an array whose size is determined when the program is


running.

• But for dynamic arrays, the size of the array can be entered as input to the
program and the dynamic array can be created to be exactly that size.

• Dynamic arrays are created using the new operator.


DYNAMIC ARRAYS
• The following will define a new type for a pointer to double.
typedef double* DoubleArrayPtr;
• This will create a pointer.
DoubleArrayPtr a;
• This will create an array with size = array_size that can be taken from
the user, during execution.
a = new double[array_size];
• This is used at the end of using the array to eliminate the dynamic array.
delete [] a;
DYNAMIC ARRAYS

int size= 10;


int *a;
a = new int[size];
int *p = a;
for (int i = 0; i < size; i++)
a[i] = i;
p[0] = 10;
for (i = 0; i < size; i++)
cout << a[i] << " ";
cout << endl;
DATA STRUCTURES
Lecture3
Linked lists
LINKED LISTS
• The linked list structure can be used as the basis for the implementation
of other data structures.

• Linked lists and arrays are similar since they both store collections of
data.

• Linked lists have their own strengths and weaknesses, but they happen
to be strong where arrays are weak.
ARRAYS DISADVANTAGES
• Arrays disadvantages are:

• The size of the array is fixed. Most often this size is specified at compile
time. This makes the programmers to allocate arrays, which seems "large
enough" than required.

• Inserting new elements at the front is potentially expensive because


existing elements need to be shifted over to make room.

• Deleting an element from an array is not possible.


ARRAYS AND LINKED LISTS

• Generally arrays allocates the memory for all its elements in one block

• Whereas linked lists use an entirely different strategy.


• Linked lists allocate memory for each element separately and only when
necessary.
LINKED LISTS
• A linked list is a non-sequential collection of data items.

• It is a dynamic data structure.

• For every data item in a linked list, there is an associated pointer that
would give the memory location of the next data item in the linked list.

• The data items in the linked list are not in consecutive memory locations.
They may be anywhere, but the accessing of these data items is easier as
each data item contains the address of the next data item.
LINKED LISTS ADVANTAGES
• Linked lists advantages:
• They are dynamic data structures. i.e., they can grow or shrink during the
execution of a program.

• They have efficient memory utilization. Memory is allocated whenever it


is required, and it is de-allocated (removed) when it is no longer needed.

• Insertion and Deletions are easier and efficient.

• Many complex applications can be easily carried out with linked lists.
LINKED LISTS DISADVANTAGES

• Linked lists disadvantages are:

• It consumes more space because every node requires an additional pointer


to store address of the next node.

• Searching a particular element in list is difficult and time consuming.


LINKED LISTS TYPES
• Basically we can put linked lists into the following four items:

1. Single Linked List.

2. Double Linked List.

3. Circular Linked List.

4. Circular Double Linked List.


LINKED LISTS TYPES

• A single linked list is one in which all nodes are linked together in some
sequential manner. Hence, it is also called as linear linked list.
LINKED LISTS TYPES
• A double linked list is one in which all nodes are linked together by
multiple links which helps in accessing both the successor node (next
node) and predecessor node (previous node) from any arbitrary node
within the list.
• Each node in a double linked list has two link fields (pointers) to point
to the left node (previous) and the right node (next).
• This helps to traverse in forward direction and backward direction.
LINKED LISTS TYPES
• A circular linked list is one, which has no beginning and no end.
• A single linked list can be made a circular linked list by simply storing
address of the very first node in the link field of the last node.
LINKED LISTS TYPES
• A circular double linked list is one, which has both the successor
pointer and predecessor pointer in the circular manner.
ARRAYS VS. LINKED LIST
Arrays Linked Lists
Size of an array is fixed Size of a list is not fixed
Memory is allocated from stack Memory is allocated from heap
It is necessary to specify the number of elements It is not necessary to specify the number of elements
during declaration (i.e., during compile time). during declaration (i.e., memory is allocated during
run time).
It occupies less memory than a linked list for the It occupies more memory.
same number of elements.
Inserting new elements at the front is potentially Inserting a new element at any position can be carried
expensive because existing elements need to be out easily.
shifted over to make room.
Deleting an element from an array is not possible. Deleting an element is possible.
LINKED LIST
• Linked List is called a dynamic data structure because each of the boxes
in the following figure is a variable of a struct or class type that has
been dynamically created with the new operator.
• In a dynamic data structure, these boxes, known as nodes, contain
pointers, diagrammed as arrows, that point to other nodes.
LINKED LIST
• We have pointers inside structs and have these pointers pointing to
structs that contain pointers.
• If you want to change the number in the first node from 17 to 12 .
• One way to accomplish this is with the following statement:
(*head).info = 12;
• The parentheses around *head are not optional.
• You want the dereferencing operation, * , to be performed before the dot
operation, and the dot operator has higher precedence than the
dereferencing one.
LINKED LIST
• C++ has an operator that can be used with a pointer to simplify the notation
for specifying the members of a struct or a class.
• The arrow operator -> combines the actions of a dereferencing operator, * ,
and a dot operator.
• For example, the previous assignment statement can be written more simply
as
head->info = 12;
THE ARROW OPERATOR, ->
• The arrow operator, ->, specifies a member of a struct or a member of a
class object that is pointed to by a pointer variable.
• The syntax is
Pointer_Variable->Member_Name
• This refers to a member of the struct or class object pointed to by the
Pointer_ Variable.
• Which member it refers to is given by the Member_Name.
• For example, Node *p;
p = new Node;
p->info = 30;
CONSTANT NULL
• In C++ programs we use the constant NULL as a marker to signal the end of a
linked list (or the end of any other kind of linked data structure).
• NULL is typically used for two purposes.
• First, it is used to give a value to a pointer variable that otherwise would not
have any value (this prevents an inadvertent reference to memory, since
NULL is not the address of any memory location.)
• The second category of use is that of an end marker (i.e. end of the list).
• It is actually the number 0.
• The definition of the identifier NULL is in a number of the standard libraries,
such as <iostream>.
• It can be assigned to a pointer variable of any pointer type.
LINKED LIST
First, build the node as a separate class:
class Node
{
int info;
Node* link;
};

Then, build the List class which contains the head pointer and the List
methods:
class List {
Node* head;
List() {
head = NULL;
}
};
OPERATIONS ON LINKED LISTS
• Linked list is a very important data structure, used as an abstract data structure ADT
• The basic operations on linked lists are as follows:
1. Display the list items.
2. Insert a node (first , last , certain position).
3. Delete a node.
4. Find the length of the list.
5. Search the list for a given item.
6. Check if the list is empty.
7. Destroy the list.
8. Make a copy of the linked list.
TRAVERSING A LINKED LIST
• We always want head to point to the first node.
• It now follows that we must traverse the list using another pointer of the same type.
• Suppose that current is a pointer of the same type as head. The following code
traverses the list:
Node* ptr;
ptr = head;
while (ptr != NULL) { //Process the current node
ptr = ptr>link; }

ptr
DISPLAYING LINKED LIST ITEMS
• The following code outputs the data stored in each node:
void print() {
if (head==NULL)
{ cout<<"The list is empty";
return; }
Node* ptr=head;
cout<<endl;
cout<<"List items : ";
while(ptr != NULL)
{ cout<<ptr->info<<" ";
ptr=ptr->link; }
}
NODE INSERTION
• Consider the following linked list, suppose we want to insert a node at the beginning
of the list:

5 10 15 20
info link

2
NODE INSERTION
• Consider the following linked list, suppose we want to insert a node at the beginning
of the list:

void insert_first(int item)


{
Node* newnode = new Node;
newnode -> info = item;
Newnode -> link = head;
head = newnode;
}
NODE INSERTION
• Consider the following linked list, suppose we want to insert a node at the end of the list:

5 10 15 20
info link
ptr
25
NODE INSERTION
• Consider the following linked list, suppose we want to insert a node at the end of the list:

void append(int item) {


Node* newnode = new Node;
newnode -> info = item;
newnode -> link = NULL;
Node* ptr = head;
while(ptr -> link != NULL)
ptr = ptr -> link; //traversing the linked list to reach the last node
ptr -> link = newnode; //append the new node to the list
}
NODE INSERTION
• Consider the following linked list, suppose we want to insert a node in an ordered list:

5 10 15 20

info link
ptr
12
NODE INSERTION
• Consider the following linked list, suppose we want to insert a node in an ordered list:
if (head->info > item) //item will be the first node
{ newnode->link=head;
head=newnode; }
else
{
While (ptr->link != NULL && ptr->link->info < item)
//traversing the list to find the order of the item
ptr=ptr->link;
newnode->link = ptr->link;
ptr->link = newnode;
}
FIND THE LENGTH OF THE LIST
• The following code outputs the count of list items:
int count()
{
Node* ptr = head;
int counter=0;
while (ptr != NULL)
{
counter++;
ptr = ptr -> link;
}
return counter;
}
SEARCH THE LIST
• The following method searches the list for a given item and retrieves its location,
outputs -1 if the item was not found:
int search(int item){
Node* ptr = head;
int loc=1;
while (ptr != NULL)
{ if (ptr->info==item)
return loc;
ptr=ptr->link;
loc++;
}
if (ptr == NULL)
return -1; }
CHECK IF THE LIST IS EMPTY
• The following method outputs true if the list is empty, otherwise it
outputs false:
bool is_empty()
{
return head==NULL;
}
NODE DELETION
• Consider the following linked list,
prev ptr

5 10 15 20

info link

• Suppose that the node with info 15 is to be deleted from the list. We need to do the
following steps:

1) Find the previous node of the node to be deleted.


2) Change the next of the previous node.
3) Free memory for the node to be deleted.
NODE DELETION
• To delete the first node in the list:
void delete_first()
{
if (head==NULL)
{ cout<<"The list is empty";
return;
}
Node* ptr = head;
head = head -> link;
delete ptr;
}
NODE DELETION
• To delete the last node in the list, we must have access to the previous node:
void delete_last() {
if (head==NULL)
{ cout<<"The list is empty";
return; }
Node* ptr = head;
Node* prev = NULL;
while (ptr -> link != NULL)
{ prev = ptr;
ptr = ptr -> link; }
prev -> link = NULL;
delete ptr; }
NODE DELETION
• To delete a specific item:
Node* ptr = head;
Node* prev = NULL;
while (ptr != NULL && ptr -> info != item)
{ prev = ptr;
ptr = ptr -> link; }
if (ptr==head) //the item is the first item in the list
head = head -> link;
else
if (ptr == NULL) //the list ends and the item was not found
cout<<endl<<"Sorry!! item is not found in the list";
else
prev -> link = ptr -> link; //the item is in the middle of the list
delete ptr;
DESTROY THE LIST
• The following function destroy deallocates the memory occupied by each node.
void destroy()
{
Node* ptr=NULL;
while (head!=NULL)
{
ptr = head;
head = head -> link;
delete ptr;
}
}
DATA STRUCTURES
Lecture 5
ABSTRACT DATA TYPES (ADTS)
• An abstract data type (ADT) is a set of objects together with a set of operations.
• Objects such as lists, sets, and graphs, along with their operations, can be viewed as
ADTs, just as integers, reals, and booleans are data types. Integers, reals, and
booleans have operations associated with them, and so do ADTs.
• For the set ADT, we might have such operations as add, remove, size, and contains.
• The C++ class allows for the implementation of ADTs, with appropriate hiding of
implementation details.
• If for some reason, implementation details need to be changed, it should be easy to
do so by merely changing the routines that perform the ADT operations. This
change, in a perfect world, would be completely transparent to the rest of the
program.
STACKS
• A stack is a list of homogenous elements.
• The addition and deletion of elements in a stack occurs only at one end, called the
top of the stack.
• The elements at the bottom of the stack have been in the stack the longest.
• The top element of the stack is the last element added. Because the elements are
added and removed from one end (that is, the top), it follows that the item that is
added last will be removed first.
STACKS
• A Stack is a data structure in which the elements are added and removed from one
end only; a Last In First Out (LIFO) data structure.

• Because new items can be added to the stack, we can perform the add operation,
called push, to add an element onto the stack.

• Similarly, because the top item can be retrieved and/or removed from the stack, we
can perform the operation top to retrieve the top element of the stack.

• And the operation pop to remove the top element from the stack.
STACKS
• The push, top, and pop operations work as follows:
• Suppose there are boxes lying on the floor that need to be stacked on a table.
• Initially, all the boxes are on the floor and the stack is empty.

• We push box A onto the stack, then B, C, D then E.


STACKS
• Because all the elements of a stack are of the same type, a stack can be
implemented as either an array or a linked structure.

Stacks

Linked
Arrays
Lists
STACKS USING ARRAYS
• Implementation of Stacks as Arrays
• The first element of the stack can be put in the first array slot, the second
element of the stack in the second array slot, and so on.
• The top of the stack is the index of the last element added to the stack.
• An element can be removed from the stack only if there is something in the
stack.
• An element can be added to the stack only if there is room.
• Array is a random-access data structure. Thus, a stack element is accessed
only through the top, not through the bottom or middle. This feature of a stack
is extremely important and must be recognized in the beginning.
STACKS USING ARRAYS
• The push, top, and pop operations work as follows:
STACKS USING ARRAYS

Stack operations
isEmptyStack Determines whether the stack is empty. If it is empty, it returns the value true; otherwise, it
returns the value false.
isFullStack Determines whether the stack is full. If it is full, it returns the value true; otherwise, it returns
the value false.
push Adds a new element to the top of the stack. The input to this operation consists of the stack
and the new element. Prior to this operation, the stack must exist and must not be full.
top Returns the top element of the stack. Prior to this operation, the stack must exist and must
not be empty.
pop Removes the top element of the stack. Prior to this operation, the stack must exist and must
not be empty.
STACKS USING ARRAYS
• Taking into considerations the following global variables, for the stack
implementation to initialize the array.

const int SIZE = 10;


int stack[SIZE], top=-1;

• Global variables are defined outside of all functions, usually on top of the
program.
• They will hold their value throughout the lifetime of your program and can be
accessed by any function.
PUSH FUNCTION
• The following is the push function.

void push(int val) {


if (top >= n-1)
cout << "Stack is FULL" << endl;
else {
top++;
stack [top] = val;
}
}
PUSH FUNCTION
• If we try to add a new item to a full stack, the resulting condition is called an
overflow.
• Error checking for an overflow can be handled in different ways.
• We can check for an overflow before calling the function push.

if (!isFullStack ())// calling the isFullStack function from the main


// function
push (newItem); // calling the push function from the main function
POP FUNCTION
• The following is the pop function.

void pop() {
if (top <= -1)
cout << "Stack is EMPTY" << endl;
else {
cout << "The popped element is " << stack [top] << endl;
top--;
}
}
POP FUNCTION
• If we try to remove an item from an empty stack, the resulting condition is
called an underflow.
• Error checking for an underflow can be handled in different ways.
• One way is as shown previously, or,
• We can check for an underflow before calling the function pop

if (!isEmptyStack ()) // calling the isFullStack function from the main


// function
pop (); // calling the push function from the main function
DISPLAY STACK ELEMENTS
• The display() function displays all the elements in the stack.
• It uses a for loop to do so.
• If there are no elements in the stack, then Stack is empty is printed.
void display() {
if (top >= 0) {
cout << "Stack elements are:";
for (int i = top; i >= 0; i--)
cout << stack [i] << " ";
cout << endl;
} else
cout << "Stack is empty";
}
STACKS USING LINKED LIST
• We can represent a stack as a linked list.
• We can perform pop and push operations at one end of list using top pointer.
Info link
PUSH FUNCTION
• The following is the push function.

void push(int item) {


Node* newnode = new Node;
newnode->info = item;
newnode->link = top;
top = newnode;
}
POP FUNCTION
• The following is the pop function

void pop () {
if (top == NULL)
cout << "Stack is EMPTY"<< endl;
else {
cout << "The popped element is "<< top->info<< endl;
top = top-> link;
}
}
DISPLAY STACK ELEMENTS
• The following is a function to display all elements in the stack.
void display() {
Node* ptr;
if (top == NULL)
cout << "stack is empty";
else {
ptr = top;
cout << "Stack elements are: ";
while (ptr != NULL) {
cout << ptr->info << " ";
ptr = ptr->link;
}
}
cout<<endl;
}
STACKS APPLICATIONS

➢ Runtime Stack
➢ Balanced Symbol checking
➢ Evaluating a postfix expression
➢ Infix to postfix conversion
STACKS APPLICATIONS
STACKS APPLICATIONS
➢ Balanced Symbol checking
CASE STUDY: BALANCED PARENTHESIS
CHECKING
POSTFIX EXPRESSIONS

• The usual notation for writing arithmetic expressions is called infix notation, in
which the operator is written between the operands. For example: a + b
• In infix notation, the operators have precedence. That is, we must evaluate
expressions from left to right, and multiplication and division have higher
precedence than addition and subtraction.
• If we want to evaluate the expression in a different order, we must include
parentheses. For example: a + b * c, we first evaluate * using the operands b and c,
and then we evaluate + using the operand a and the result of b * c.
• A discovered scheme, the postfix notation was used, in which the operators follow
the operands (postfix operators). This has the advantage that the operators appear in
the order required for computation.
POSTFIX EXPRESSIONS
• For example, the expression:
2*3–8/4
• A corresponding postfix expression is:
23*84/-
• The following example shows various infix expressions and their equivalent postfix
expressions.
EVALUATING POSTFIX EXPRESSIONS

• Stacks are used to evaluate postfix expressions:


Algorithm
Scan the postfix string
i. If you find a number , push
ii. If you find an operator,
➢pop top two operands, op2 then op1,
➢Perform operation, push result
EVALUATING POSTFIX EXPRESSIONS
EVALUATING POSTFIX EXPRESSIONS
INFIX TO POSTFIX CONVERSION
Algorithm :

1. Scan the infix expression from left to right.


2. If the scanned character is an operand, output it.
3. If the precedence of the scanned operator is greater than the precedence of the operator in the top of the
stack (or the stack is empty or the stack contains a ‘(‘ ), push it.
Else, Pop all the operators from the stack which are greater than or equal to in precedence than that of
the scanned operator. After doing that Push the scanned operator to the stack. (If you encounter parenthesis
while popping then stop there and push the scanned operator in the stack.)
4. If the scanned character is an ‘(‘, push it to the stack.
5. If the scanned character is an ‘)’, pop the stack and output it until a ‘(‘ is encountered, and discard both
the parenthesis.
6. Repeat steps 2-5 until infix expression is scanned.
7. Pop and output from the stack until it is not empty.
INFIX TO POSTFIX CONVERSION
INFIX TO POSTFIX CONVERSION
INFIX TO POSTFIX CONVERSION
INFIX TO POSTFIX CONVERSION

Convert the following expressions from infix to postfix notation.


a. X * Y + W * Z + V * U
b. W * X + W * (U * V + Z)
c. (W * (X + Y * (U * V)))/(U * (X + Y))
DATA STRUCTURES
Lecture 5
QUEUES
• A queue is another special kind of lists, where items are inserted at one end called the
back or rear and deleted at the other end called the front.

• Another name for a queue is a “FIFO” or “First-in-first-out” list.

• The operations for a queue are analogues to those for a stack, the difference is that
the insertions go at the end of the list, rather than the beginning.

• We shall use the following operations on queues:


• enqueue (addQueue) : which inserts an element at the end of the queue.
• dequeue (deleteQueue) : which deletes an element at the start of the queue.

• The rear of the queue is accessed whenever a new element is added to the queue, and
the front of the queue is accessed whenever an element is deleted from the queue.
QUEUE
STACKS VS. QUEUES
Stacks Queues
Uses LIFO (Last in, First out) approach. Uses FIFO (First in, First out) approach.
Items are added or deleted from only one end called Items are added from “Rear” end of the queue and are
“Top” of the stack. removed from the “front” of the queue.
The basic operations for the stack are “push” and The basic operations for a queue are “enqueue” and
“Pop”. “dequeue”.
We can do all operations on the stack by maintaining In queues, we need to maintain two pointers, one to
only one pointer to access the top of the stack. access the front of the queue and the second one to
access the rear of the queue.
The stack is mostly used to solve recursive problems. Queues are used to solve problems related to ordered
processing.
QUEUE APPLICATIONS
• The queue data structure is used in various CPU and disk scheduling. Here we have
multiple tasks requiring CPU or disk at the same time. The CPU or disk time is
scheduled for each task using a queue.

• The queue can also be used for print spooling wherein the number of print jobs is
placed in a queue.

• Call center phone systems use queues to hold the calls until they are answered by the
service representatives.
QUEUE OPERATIONS
• As in a stack, the middle elements of the queue are inaccessible, even if the queue
elements are stored in an array.
• The two key operations are add and delete. We call the add operation addQueue (or
enqueue) and the delete operation deleteQueue (or dequeue).
• Because elements can be neither deleted from an empty queue nor added to a full
queue, we need two more operations:
• isEmptyQueue (checks whether the queue is empty) and
• isFullQueue (checks whether a queue is full).
• We also need an operation, initializeQueue, to initialize the queue to an empty state.
• Moreover, to retrieve the first and last elements of the queue, we include the
operations front and back.
QUEUE OPERATIONS
isEmpty Determines whether the queue is empty. If the queue is empty, it returns the value true;
otherwise, it returns the value false.
isFull Determines whether the queue is full. If the queue is full, it returns the value true;
otherwise, it returns the value false.
front Returns the front, that is, the first element of the queue. Prior to this operation, the queue
must exist and must not be empty.
back Returns the last element of the queue. Prior to this operation, the queue must exist and must
not be empty.
enqueue Adds a new element to the rear of the queue. Prior to this operation, the queue must exist
and must not be full.
dequeue Removes the front element from the queue. Prior to this operation, the queue must exist and
must not be empty.
QUEUES
• As stacks, queues can be implemented as either an array or a linked structure.

Queues

Linked
Arrays
Lists
QUEUES USING ARRAYS
• We need to decide how many variables are needed to implement the queue
using arrays.
• Of course, we need
• an array to store the queue elements,
• the variable front and
• the variable rear
to keep track of the first and last elements of the queue,
and
• the variable MAX to specify the maximum size of the queue.
• Thus, we need at least four member variables.
QUEUES USING ARRAYS

• The following are the four variables needed for the implementation of the queue using an
array.
• Those variables will be either declared as global, or as member variables if we implement a
queue class.

const int MAX = 10;


int myqueue [MAX];
int front = -1;
int rear = -1;
QUEUES USING ARRAYS
• Let us see what happens when front changes after a deleteQueue operation and rear changes
after an addQueue operation.
• Assume that the array to hold the queue elements is of size 100.
• Initially, the queue is empty (that means front = rear = -1).
• After the operation:
• addQueue(Queue,'A’);
rear++;
queue [rear] = item;
• addQueue(Queue,'B');
• addQueue(Queue,'C');
QUEUES USING ARRAYS
• Now consider the deleteQueue operation:
• deleteQueue();

front ++;

• Whenever an addQueue function is executed, the rear variable will be


incremented by one; and whenever a deleteQueue (deQueue) function is
executed, the front variable will be incremented by one.
QUEUES USING ARRAYS
• Now consider the following situation :

3 0

3 1

10 3
QUEUES USING ARRAYS
• One solution is to shift all elements after each dequeue operation but this solution too cost.
• A better solution is the CIRCULAR queue.
• The first array position immediately follows the last array position.
• A new variable queue_size is needed to keep track of the actual size
of the queue (the number of actual elements) and will be initialized by
0.

enqueue : rear = (rear +1) % MAX;


queue [rear] = item;
queue_size++;
dequeue :
front = (front +1) % MAX;
queue_size --;
QUEUES USING ARRAYS
• The following is the isFull function
bool isFull ()
{
return (queue_size == MAX)
}

• The following is the isEmpty function


bool isEmpty ()
{
return (queue_size == 0)
}
QUEUES USING ARRAYS
• The following is the enqueue function
void enqueue(int item)
{
if (isFull())
cout<<"\n Queue is full";
else
{ if (front == -1)
front = rear = 0;
else
rear = (rear +1) % MAX;
queue[rear]=item;
queue_size++;
}
}
QUEUES USING ARRAYS
• The following is the dequeue function

void dequeue()
{
if (isEmpty())
cout<<"queue is empty";
else
{
cout<<"item = "<< queue[front];
front = (front +1) % MAX;
queue_size --;
}
QUEUES USING ARRAYS
• The following is the print function to display the queue elements.
void printQueue()
{
if (isEmpty())
cout<<"Queue is empty";
else
{ cout<<“Queue elements : ";
int ptr=front;
while (ptr!=rear)
{ cout<<queue[ptr]<<" ";
ptr=(ptr + 1) % MAX;
}
cout<<queue[ptr]<<" ";
}
}
QUEUES USING LINKED LISTS
class Queue
{
public:
Node* front;
Node* rear;
Queue()
{
front = rear = NULL;
}
bool isEmpty()
{
return (front==NULL);
}
};
QUEUES USING LINKED LISTS
• The following is the enqueue (add in Queue) function
void enqueue(int item)
{
Node* newnode = new Node();
newnode->info = item;
newnode->link = NULL;
if (isEmpty())
front = rear = newnode;
else
{
rear -> link = newnode;
rear = newnode;
}
}
QUEUES USING LINKED LISTS
• The following is the dequeue (delete from Queue) function
void dequeue()
{
if (isEmpty())
cout<<"Queue is empty";
else if (front==rear)
{ delete front;
front = rear = NULL; }
else {
Node* ptr=front;
front = front->link;
delete ptr;
}
}
QUEUES USING LINKED LISTS
• The following is the print:
void printQueue()
{
if (isEmpty())
cout<<"Queue is empty";
else {
Node* ptr=front;
cout<<"Queue elements : ";
while (ptr!=NULL) {
cout<<ptr->info<<" ";
ptr=ptr->link;
}
}
}
DATA STRUCTURES
Lecture 8
TREES
• A data structure is said to be linear if its elements form a sequence or a linear
list. Previous linear data structures that we have studied like an array, stacks,
queues and linked lists organize data in linear order.
• A data structure is said to be nonlinear if its elements form a hierarchical
classification where, data items appear at various levels.
• Trees and Graphs are widely used non-linear data structures.
• Graphs are nothing but trees with certain restrictions removed.
TREES
TREES
• Tree and graph structures represents hierarchical
relationship that organizes data elements called nodes
by connecting them using links called edges.

• A tree consists of:


✓ A node called Root.
✓ zero or more nonempty subtrees T1, T2, ...., Tk, each of whose subtrees are
connected by an edge from Root.
TREE APPLICATIONS

a *

+ d

b c

Folders and files Expression parse tree


TREE APPLICATIONS

Binary Search Tree Decision trees


TREE TERMINOLOGIES
• The root, is at the top of the hierarchy.
• Each node can have at most one link coming into it.
• The node where the link originates is called the parent node.
• The root node has no parent.
• The links leaving a node point to child nodes.
• Trees are recursive structures. Each child node is itself the root of a subtree.
• At the bottom of the tree are leaf nodes, which have no children.
• The internal node is a node which is neither a root nor a leaf
• Sibling : a node with a common parent node.
TREE TERMINOLOGIES
• Check the following tree:

• (a) is the root,


• (a) has no parents
• (a) is the parent of (b) and (c)
• (b) and (c) are the children of (a)
• (b) is the parent of (d)
• (d) is the child of (b)
• (c) is the parent of (e) and (f)
• (e) and (f) are the children of (c)
• (b) and (c) are internal nodes
• (d), (e) and (f) are leaf nodes
• (e) and (f) are siblings
TREE TERMINOLOGIES
• Path : a sequence of edges.
Path from A to O is : A - C - G - O
• Size : The number of nodes in a tree.
• Subtree : a smaller tree of nodes,
which is one of the current node children.
TREE TERMINOLOGIES
• Height : The number of edges on the longest path from the node to a leaf.
➢ The height of this tree is 3.
➢ The height of (B) is 2.

• Depth : The number of edges from the node to the tree’s root node.
➢ Node C has a depth of 1.

• Degree : The maximum number of subtrees.


TREE TERMINOLOGIES
•Level :
➢The level of the node refers to its distance from the root.
➢The root of the tree has level 0, and the level of any other node in the tree is one more
than the level of its parent.
➢Node F is at level 2 and node H is at level 3.
➢The maximum number of nodes at any level is 2^n.
BINARY TREES
• In general, tree nodes can have any number of children.
• In a binary tree, each node can have at most two children and one parent.
• A binary tree is either empty or consists of a node called the root together
with two binary trees called the left subtree and the right subtree.
• A tree with no nodes is called as a null tree.
BINARY TREE EXAMPLES
BINARY TREE TRAVERSALS

• Traversal: An examination of the elements of a tree.

• Common orderings for traversals:


– pre-order: process root node, then its left/right subtrees (VLR)
– in-order: process left subtree, then root node, then right (LVR)
– post-order: process left/right subtrees, then root node (LRV)
TRAVERSAL EXAMPLE
Root

• in-order (LVR):
17
41
6
41 9
17
81
9
6 81
TRAVERSAL EXAMPLE
Root

• pre-order (VLR): 17
17
41 41 9
6
9
6 81
81
TRAVERSAL EXAMPLE
Root
• post-order (LRV):
6 17
41
81 41 9
9
17 6 81
EXERCISE 1
– Pre-order: Root
42 15 27 48 9 86 12 5 3 39
42

– In-order:
15 9
15 48 27 42 86 5 12 9 3 39
27 86 3
– Post-order:
48 27 15 5 12 86 39 3 9 42 48 12 39

5
EXERCISE 2
EXAMPLE: EXPRESSION TREES

• It is a binary tree contains an arithmetic


expression with some operators and operands.

• Leaves are operands (constants or variables) *


a b
• The internal nodes contain operators
a* b
• For each node contains an operator, its left subtree
gives the left operand, and its right subtree gives
the right operand.
EXAMPLE: EXPRESSION TREES

• Building Expression Trees has great importance in syntactical analysis


and parsing, along with the validity of expressions
EXAMPLE: EXPRESSION TREES
(d * e + f ) *g -
b
-b

+
* +
a
a b
a++
a* b
EXAMPLE: C TREES
TREE IMPLEMENTATION
root

left A right

left B right left C right

left D right left E right left F right

left G right left H right

Tree Node Model


TREE IMPLEMENTATION

class Node
{
public:
int info;
Node* left;
Node* right;
};
TREE IMPLEMENTATION

class Tree
{
public:
Node* root;

Tree()
{
root=NULL;
}
};
TREE IMPLEMENTATION

• The following function is to implement the pre-order traversal.


void preorder(Node* node)
{
if (node == NULL)
return;
cout << node->info << " ";
preorder(node->left);
preorder(node->right);
}
TREE IMPLEMENTATION

• The following function is to implement the in-order traversal.


void inorder(Node* node)
{
if (node == NULL)
return;
inorder(node->left);
cout << node->info << " ";
inorder(node->right);
}
TREE IMPLEMENTATION

• The following function is to implement the post-order traversal.


void postorder(Node* node)
{
if (node == NULL)
return;
postorder(node->left);
postorder(node->right);
cout << node->info << " ";
}
TREE IMPLEMENTATION

• The following function is to return the size of a tree.


int size(Node* node)
{
if (node == NULL)
return 0;
return (1 + size(node->left)+ size(node->right));
}
BINARY SEARCH TREE
BINARY SEARCH TREE

Binary Search Tree is a node-based binary tree data structure which


has the following properties:
1. The left subtree of a node contains only nodes with keys less than
the node’s key.
2. The right subtree of a node contains only nodes with keys greater
than the node’s key.
3. The left and right subtree each must also be a binary search tree.
BINARY SEARCH TREE

A binary search tree Not a binary search tree


BINARY SEARCH TREE
• Is this a binary search tree?
BINARY SEARCH TREE

• Is this a binary search tree?


BINARY SEARCH TREE

• Find 6

➔After 3 steps 6 is found


➔Search path : 8 - 3 - 6
BINARY SEARCH TREE

• Find 9

➔After 2 steps we can


conclude that 9
is not found
BINARY SEARCH TREE

• Find 12

➔After 4 steps we can


conclude that 12
is not found
BINARY SEARCH TREE

• Find the smallest value

➔At most left


BINARY SEARCH TREE

• Find the largest value

➔At most right


BINARY SEARCH TREE

• Insert 9

9
BINARY SEARCH TREE

• Draw the binary tree which would be


50
created by inserting the following numbers 30
75
in the order given: 25
63
50 30 25 75 63 28 70
28 70
BINARY SEARCH TREE

• Delete 4
(leaf node)
BINARY SEARCH TREE

• Delete 10
(node with one child)
BINARY SEARCH TREE

• Delete 14
(node with one child)
BINARY SEARCH TREE
• Delete 8
7
(node with two children)

Find the
maximum
node in the left
subtree
BINARY SEARCH TREE
• Delete 8
10
(node with two children)

OR find the
minimum node
in the right
subtree
DELETING FROM A BINARY SEARCH TREE
• Item not present: do nothing
• Item present in leaf: remove leaf (change to null)
• Item is non-leaf with one child:
Replace current node with that child
• Item is non-leaf with two children:
• Find largest item in the left subtree
• Remove it
• Use it as the parent of the two subtrees
• (Could use smallest item in right subtree)
BINARY SEARCH TREE EXAMPLE
Given the following binary search tree:
• Delete 10
• Delete 22
• Delete 30
• Delete 25
BINARY SEARCH TREE INSERTION
void insert(int item)
{
Node* newnode = new Node;
newnode -> info = item;
newnode -> left = newnode -> right = NULL;
Node* ptr=root;
Node* prev=NULL;
if (root == NULL)
root = newnode;
// continued
BINARY SEARCH TREE INSERTION
else
{
while(ptr != NULL)
{
prev=ptr;
if(item<ptr->info)
ptr=ptr->left;
else
ptr=ptr->right;
}
//continued
BINARY SEARCH TREE INSERTION
if (item <prev->info)
prev->left= newnode;
else
prev->right=newnode;
}
}
BINARY SEARCH TREE
int tree_min()
{
Node* ptr=root;
If (ptr == NULL)
cout<<“The tree is empty”;
while(ptr->left!=NULL)
ptr = ptr->left;
return ptr->info;
}
BINARY SEARCH TREE
int tree_max()
{
Node* ptr=root;
If (ptr == NULL)
cout<<“The tree is empty”;
while(ptr->right!=NULL)
ptr = ptr->right;
return ptr->info;
}
BINARY SEARCH TREE
int Search(int item) {
int depth = -1;
Node* ptr = root;
while(ptr != NULL) {
depth++;
if(ptr->info == item)
return depth;
else if(item < ptr -> info)
ptr = ptr -> left;
else
ptr = ptr -> right; }
return depth;
}
DATA STRUCTURES
Lecture 7
LINEAR SEARCH

int linear_search(int arr[],int n,int item)


{
for (int i = 0 ; i < n ; i++)
if (arr[i] == item)
return i;
return -1;
}
BINARY SEARCH

• Also known as half-interval search,and logarithmic search.


• Can be implemented only on a sorted array.
• Time complexity less than linear search.
• Binary search is faster than linear search except for small arrays. However, the array must be
sorted first to be able to apply binary search.
• Linear search complexity O(n) while binary search complexity is O(log n)
BINARY SEARCH

• Compares the target value to the middle element of the array.


• If they are not equal, the half in which the target cannot lie is eliminated and the search continues
with the remaining half.
• Again, taking the middle element to compare to the target value, and repeating this until the target
value is found.
• If the search ends with the remaining half being empty, the target is not in the array.
BINARY SEARCH

• Suppose we want to search for the item 60.


• Low = 0 , High = 11
BINARY SEARCH
BINARY SEARCH

• 60 is bigger than 22 (element at index m)


• So, we will continue the search in the right half only.
• The elements from index 0 to index 5 (the left half) are eliminated.
BINARY SEARCH
BINARY SEARCH
BINARY SEARCH
BINARY SEARCH
int binary_search(int arr[],int n,int item)
{
int l=0, h=n-1 , m;
while (l <= h)
{ m = ( l + h ) / 2;
if (arr[m] == item)
return m;
if (item < arr[m])
h = m - 1;
else
l = m + 1;
}
return -1; }
SORTING ALGORITHMS
• Selection sort
• Bubble sort
• Insertion sort
• Merge sort
• Quick sort
SELECTION SORT
• The selection sort algorithm sorts an array by repeatedly finding the minimum element
(considering ascending order) from the unsorted part and putting it at the beginning.
• The algorithm maintains two subarrays in a given array.
➢The subarray which already sorted.
➢The remaining subarray was unsorted.
• In every iteration of the selection sort, the minimum element (considering ascending order) from
the unsorted subarray is picked and moved to the sorted subarray.
SELECTION SORT
• Lets consider the following array as an example: arr[] = {64, 25, 12, 22, 11}
• First pass:
• For the first position where 64 is presented, the whole array is traversed from index 1 to 4
sequentially to find the minimum value.

• After traversing the whole array, it is clear that 11 is the lowest value.
• Thus, replace 64 with 11. After one iteration 11, which happens to be the least value in the
array, tends to appear in the first position of the sorted list.
SELECTION SORT
• Second Pass:
• For the second position, where 25 is present, again traverse the rest of the array from index 2 to
index 4 in a sequential manner.

• After traversing, we found that 12 is the second lowest value in the array and it should appear
at the second place in the array, thus swap these values.
SELECTION SORT
• Third Pass:
• Now, for third place, where 25 is present again traverse the rest of the array and find the third
least value present in the array.

• While traversing, 22 came out to be the third least value and it should appear at the third place
in the array, thus swap 22 with element present at third position.
SELECTION SORT
• Fourth pass:
• Similarly, for fourth position traverse the rest of the array and find the fourth least element in
the array
• As 25 is the 4th lowest value hence, it will place at the fourth position.

• The largest value present in the array automatically get placed at the last position in the array
• The resulted array is the sorted array.
SELECTION SORT
void selection(int arr[], int n) //array and size of array
{
int min;
for (int i=0;i<n-1;i++)
{
min = i;
for (int j=i+1;j<n;j++)
if (arr[j]<arr[min])
min=j;
swap(arr[i],arr[min]);
}
}
BUBBLE SORT
• Bubble Sort is the simplest sorting algorithm that works by repeatedly swapping the adjacent
elements if they are in the wrong order.
• These passes through the list are repeated until no swaps had to be performed during a pass,
meaning that the list has become fully sorted.
• The algorithm is named for the way the larger elements "bubble" up to the top of the list.
• This algorithm is not suitable for large data sets as its average and worst-case time complexity is
quite high.
BUBBLE SORT
• Lets consider the following array as an example: arr[] = {5 , 1 , 4 , 2 , 8}
First pass:
BUBBLE SORT
Second pass:

Third pass:
BUBBLE SORT
Third pass:
BUBBLE SORT
void bubble_sort(int arr[],int n)
{
int temp;
for(int i=0;i<n-1;i++)
for (int j=0;j<n-i-1;j++)
if (arr[j]>arr[j+1])
swap(arr[j],arr[j+1]);
}
REFERENCES
• LECTURE NOTES ON DATA STRUCTURES USING C, L. V. NARASIMHA
PRASAD, E. KRISHNA RAO PATRO, INSTITUTE OF AERONAUTICAL
ENGINEERING DUNDIGAL – 500 043, HYDERABAD 2014-2015
• Tree Data Structure (programiz.com)
• DATA STRUCTURES USING C++, D.S. MALIK, SECOND EDITION

• Data Structures and Algorithm Analysis in C++, Mark Allen Weiss, Florida International
University, Fourth Edition
REFERENCES
• LECTURE NOTES ON DATA STRUCTURES USING C, L. V. NARASIMHA
PRASAD, E. KRISHNA RAO PATRO, INSTITUTE OF AERONAUTICAL
ENGINEERING DUNDIGAL – 500 043, HYDERABAD 2014-2015
• DATA STRUCTURES USING C++, D.S. MALIK, SECOND EDITION
• Queue Data Structure In C++ With Illustration (softwaretestinghelp.com)
REFERENCES
• Lecture Notes On Data Structures Using C, L. V. Narasimha Prasad, E.
Krishna Rao Patro, Institute of Aeronautical Engineering, 2014-2015
• C++ Programming: From Problem Analysis To Program Design, Fifth Edition,
D.S. Malik
• C++ Data Structures, Third Edition, N. Dale, University of Texas.
REFERENCES
• Lecture Notes On Data Structures Using C, L. V. Narasimha Prasad, E.
Krishna Rao Patro, Institute of Aeronautical Engineering, 2014-2015
• C++ Programming: From Problem Analysis To Program Design, Fifth
Edition, D.S. Malik
• https://beginnersbook.com/2017/08/cpp-pointers/
• Chapter 17: Linked Data Structures
REFERENCES
• Lecture Notes On Data Structures Using C, L. V. Narasimha Prasad, E.
Krishna Rao Patro, Institute Of Aeronautical Engineering, 2014-2015
• C++ Programming: From Problem Analysis To Program Design, Fifth
Edition, D.S. Malik
• https://beginnersbook.com/2017/08/cpp-pointers/
• Chapter 12: Pointers and Dynamic Arrays
REFERENCES
• LECTURE NOTES ON DATA STRUCTURES USING C, L. V. NARASIMHA PRASAD,
E. KRISHNA RAO PATRO, INSTITUTE OF AERONAUTICAL ENGINEERING, 2014-
2015
• https://www.w3schools.com/cpp/cpp_variables.asp

You might also like