0% found this document useful (0 votes)
35 views119 pages

Ds All Units (1) Rajakumari

The document discusses various search and sorting algorithms, including Linear Search, Binary Search, Fibonacci Search, and several sorting methods like Insertion Sort, Quick Sort, and Merge Sort. It explains their time complexities, operational principles, and when to use each method. Additionally, it covers hashing, its applications, and collision resolution techniques such as Separate Chaining.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
35 views119 pages

Ds All Units (1) Rajakumari

The document discusses various search and sorting algorithms, including Linear Search, Binary Search, Fibonacci Search, and several sorting methods like Insertion Sort, Quick Sort, and Merge Sort. It explains their time complexities, operational principles, and when to use each method. Additionally, it covers hashing, its applications, and collision resolution techniques such as Separate Chaining.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

UNIT-II

What is Search?

Search is a process of finding a value in a list of values. In other words,


searching is the process of locating given value position in a list of values.

Linear Search Algorithm (Sequential Search Algorithm)

Linear search algorithm finds a given element in a list of elements with O(n) time complexity
where n is total number of elements in the list. This search process starts comparing search
element with the first element in the list. If both are matched then result is element found
otherwise search element is compared with the next element in the list. Repeat the same until
search element is compared with the last element in the list, if that last element also doesn't
match, then the result is "Element not found in the list". That means, the search element is
compared with element by element in the list.

1
2
Binary Search

Binary search algorithm finds a given element in a list of elements with O(log n) time complexity
where n is total number of elements in the list. The binary search algorithm can be used with
only a sorted list of elements. That means the binary search is used only with a list of elements
that are already arranged in an order. The binary search cannot be used for a list of elements
arranged in random order. This search process starts comparing the search element with the
middle element in the list. If both are matched, then the result is "element found". Otherwise, we
check whether the search element is smaller or larger than the middle element in the list. If the
search element is smaller, then we repeat the same process for the left sub list of the middle
element. If the search element is larger, then we repeat the same process for the right sub list of
the middle element. We repeat this process until we find the search element in the list or until we
left with a sub list of only one element. And if that element also doesn't match with the search
element, then the result is "Element not found in the list".

Example
Consider the following list of elements and the element to be searched...

3
4
Fibonacci Search: It is a comparison- based technique that uses Fibonacci numbers tosearch an element
in a sorted array.
Similarities with Binary Search:
1. Works for sorted arrays
2. A Divide and Conquer Algorithm.
3. Has Log n time complexity.
Differences with Binary Search:
1. Fibonacci Search divides given array in unequal parts
2. Binary Search uses division operator to divide range. Fibonacci Search doesn’tuse /,
but uses + and - . The division operator may be costly on some CPUs.
3. Fibonacci Search examines relatively closer elements in subsequent steps. So when input
array is big that cannot fit in CPU cache or even in RAM, FibonacciSearch can be
useful.

Fibonacci Numbers are recursively defined as F(n) = F(n- 1) + F(n- 2), F(0) = 0, F(1) = 1.First
few Fibonacci Numbers are 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …

6
Sorting Techniques: Basic Concepts, Sorting by: Insertion (Insertion Sort), Selection (heap sort),
Exchange (Bubble sort, Quick Sort), distribution (Radix sort) and merging (Merge sort) Algorithms.
Stacks: Basic Stack operations, Representation of a stack using arrays, Stack Applications: Reversing list,
Infix to postfix transformation.

Sorting refers to the operation or technique of arranging and rearranging sets of data in some specific
order. A collection of records called a list where every record has one or more fields. The fields which
contain a unique value for each record is termed as the keyfield. For example, a phone number directory
can be thought of as a list where each record has three fields - 'name' of the person, 'address' of that
person, and their 'phone numbers'. Being unique phone number can work as a key to locate any record in
the list.
Sorting is the operation performed to arrange the records of a table or list in some order according
to some specific ordering criterion. Sorting is performed according to some keyvalue of each record.
The records are either sorted either numerically or alphanumerically. The records are then arranged
in ascending or descending order depending on the numerical value of the key.

Categories of Sorting
The techniques of sorting can be divided into two categories. These are:
• Internal Sorting
• External Sorting
Internal Sorting: If all the data that is to be sorted can be adjusted at a time in the main memory, the
internal sorting method is being performed.
External Sorting: When the data that is to be sorted cannot be accommodated in the memory at the same
time and some has to be kept in auxiliary memory such as hard disk, floppy disk, magnetic tapes etc, then
external sorting methods are performed.

The complexity of sorting algorithm

The complexity of sorting algorithm calculates the running time of a function in which 'n' number of items
are to be sorted. The choice for which sorting method is suitable for a problem depends on several
dependency configurations for different problems. The most noteworthy of these considerations are:

• The length of time spent by the programmer in programming a specific sorting program

• Amount of machine time necessary for running the program

1
• The amount of memory necessary for running the program

The Efficiency of Sorting Techniques

To get the amount of time required to sort an array of 'n' elements by a particular method, the normal
approach is to analyze the method to find the number of comparisons (or exchanges) required by it. Most
of the sorting techniques are data sensitive, and so the metrics for them depends on the order in which
they appear in an input array.

Various sorting techniques are analyzed in various cases and named these cases as follows:

• Best case

• Worst case

• Average case

Hence, the result of these cases is often a formula giving the average time required for a particular sort of
size 'n.' Most of the sort methods have time requirements that range from O(nlog n) to O(n2).

Types of Sorting Techniques


• Sorting by: Insertion (Insertion Sort), Selection (heap sort)
• Exchange (Bubble sort, Quick Sort)
• Distribution (Radix sort)
• Merging (Merge sort)

Insertion (Insertion Sort Algorithm)


Insertion sort algorithm arranges a list of elements in a particular order. In insertion sort algorithm,
every iteration moves an element from unsorted portion to sorted portion until allthe elements are
sorted in the list.
Example

2
3
Complexity of the Insertion Sort Algorithm

To sort an unsorted list with 'n' number of elements, we need to make (1+2+3+ ................. +n- 1) = (n (n-
1))/2 number of comparisons in the worst case. If the list is already sorted then itrequires 'n'
number of comparisons.

Worst- Case: O(n2)


Best- Case: Ω(n)
Average- Case :
Θ(n2)

4
Selection (heap sort):

Heap sort is one of the sorting algorithms used to arrange a list of elements in order. Heap sort
algorithm uses one of the tree concepts called Heap Tree. In this sorting algorithm, we use Max Heap to
arrange list of elements in Descending order and Min Heap to arrange list elements in ascending order.

5
6
Exchange (Bubble sort, Quick Sort)
Bubble sort
Bubble sort is a simple sorting algorithm. This sorting algorithm is comparison- based algorithm in
which each pair of adjacent elements is compared and the elements are swapped if they are not in order.
This algorithm is not suitable for large data sets as its average and worst case complexity are of Ο(n2)
where n is the number of items.

Algorithm: Following We assume list is an array of n elements. We further assume that swap function
swaps the values of the given array elements.

Step - 1: Starting with the first element (index = 0), compare the current element with the next element
of the array.
Step - 2: If the current element is greater than the next element of the array, swap them.
Step - 3: If the current element is less than the next element, move to the next element. Repeat Step 1.
Example:We take an unsorted array for our example. Bubble sort takes Ο(n2) time so we'rekeeping it
short and precise.

Bubble sort starts with very first two elements, comparing them to check which one is greater.

In this case, value 33 is greater than 14, so it is already in sorted locations. Next, we compare33 with
27.

We find that 27 is smaller than 33 and these two values must be swapped.

The new array should look like this −

Next we compare 33 and 35. We find that both are in already sorted positions.

Then we move to the next two values, 35 and 10.

We know then that 10 is smaller 35. Hence they are not sorted.

9
We swap these values. We find that we have reached the end of the array. After one iteration,the array
should look like this −

To be precise, we are now showing how an array should look like after each iteration. After thesecond
iteration, it should look like this −

Notice that after each iteration, at least one value moves at the end.

And when there's no swap required, bubble sorts learns that an array is completely sorted.

10
Quick Sort algorithm

Quick sort is a fast sorting algorithm used to sort a list of elements. Quick sort algorithm isinvented by
C. A. R. Hoare.

The quick sort algorithm attempts to separate the list of elements into two parts and then sort each part
recursively. That means it use divide and conquer strategy. In quick sort, the partition of the list is
performed based on the element called pivot. Here pivot element is one of the elements in the list.The
list is divided into two partitions such that "all elements to the left of pivot are smaller than the
pivot and all elements to the right of pivot are greater than or equal to the pivot".

Algorithm:

In Quick sort algorithm, partitioning of the list is performed using following steps...

• Step 1 - Consider the first element of the list as pivot (i.e., Element at first position inthe
list).
• Step 2 - Define two variables i and j. Set i and j to first and last elements of the list
respectively.
• Step 3 - Increment i until list[ i] > pivot then stop.
• Step 4 - Decrement j until list[ j] < pivot then stop.
• Step 5 - If i < j then exchange list[ i] and list[ j] .
• Step 6 - Repeat steps 3,4 & 5 until i > j.
• Step 7 - Exchange the pivot element with list[ j] element.

Following is the sample code for Quick sort...


Example

11
12
Distribution (Radix sort) :
Radix sort is one of the sorting algorithms used to sort a list of integer numbers in order. In radix sort
algorithm, a list of integer numbers will be sorted based on the digits of individual numbers. Sorting is
performed from least significant digit to the most significant digit.
Radix sort algorithm requires the number of passes which are equal to the number of digits present in the
largest number among the list of numbers. For example, if the largest number is a 3 digit number then
that list is sorted with 3 passes.
Example:

13
14
Merging (Merge sort)

Merge sort algorithm:

Like Quick Sort, Merge Sort is a Divide and Conquer algorithm. It divides input array in two halves, calls
itself for the two halves and then merges the two sorted halves. The merge() function is used for merging
two halves. The merge(arr, l, m, r) is key process that assumes that arr[ l..m] and arr[ m+1..r] are sorted
and merges the two sorted sub- arrays into one.

15
Step 2 − divide the list recursively into two halves until it can no more be divided.Step 3 −
merge the smaller lists into new list in sorted order.

Example 1:

To understand merge sort, we take an unsorted array as the following −

We know that merge sort first divides the whole array iteratively into equal halves unless the atomic
values are achieved. We see here that an array of 8 items is divided into two arrays of size 4.

This does not change the sequence of appearance of items in the original. Now we divide these two
arrays into halves.

We further divide these arrays and we achieve atomic value which can no more be divided.

Now, we combine them in exactly the same manner as they were broken down. Please note the color
codes given to these lists.

We first compare the element for each list and then combine them into another list in a sorted manner.
We see that 14 and 33 are in sorted positions. We compare 27 and 10 and in the target list of 2 values we
put 10 first, followed by 27. We change the order of 19 and 35 whereas 42 and 44 are placed
sequentially.

In the next iteration of the combining phase, we compare lists of two data values, and merge them into a
list of found data values placing all in a sorted order.

After the final merging, the list should look like this −

16
Now we should learn some programming aspects of merge sorting.

Example 2:

17
Comparison of Sorting Methods

The comparison of sorting methods is performed based on the Time complexity and Space complexity of
sorting methods. The following table provides the time and space complexities of sorting methods. These
Time and Space complexities are defined for 'n' number of elements.

Time
Sorting Time Complexity Time Complexity Complexity Best Space Complexity
Method Worst Case Average Case Case

Bubble Sort n(n- 1)/2 = O(n2) n(n- 1)/2 = O(n2) n(n- 1)/2 = O(n2) Constant

Insertion Sort n(n- 1)/2 = O(n2) n(n- 1)/4 = O(n2) O(n) Constant

Selection Sort n(n- 1)/2 = O(n2) n(n- 1)/2 = O(n2) n(n- 1)/2 = O(n2) Constant

Quick Sort n(n+3)/2 = O(n2) O(n log n) O(n log n) Constant

Heap Sort O(n log n) O(n log n) O(n log n) Constant

Merge Sort O(n log n) O(n log n) O(n log n) Depends

HASHING: Hashing is the process of converting a given key into another value. A hash function is used to
generate the new value according to a mathematical algorithm. The result of a hash function is known as a hash
value or simply, a hash.

A good hash function uses a one-way hashing algorithm, or in other words, the hash cannot be converted back
into the original key.

Collisions

Keep in mind that two keys can generate the same hash. This phenomenon is known as a collision. There are
several ways to handle collisions, but that’s a topic for another time.

18
HASHING Applications
Hashing is most commonly used to implement hash tables. A hash table stores key/value pairs in the form of a
list where any element can be accessed using its index.

Since there is no limit to the number of key/value pairs, we can use a hash function to map the keys to the size of
the table; the hash value becomes the index for a given element.

A simple hashing approach would be to take the modular of the key (assuming it’s numerical) against the table’s
size:

index = key \text{ } MOD \text{ } tableSizeindex=key MOD tableSize


This will ensure that the hash is always within the limits of the table size. Here is the code for such a hash
function:

def hashModular(key, size):


return key % size
list_ = [None] * 10 # List of size 10
key = 35
index = hashModular(key, len(list_)) # Fit the key into the list size
print("The index for key " + str(key) + " is " + str(index))

Hashing is also used in data encryption. Passwords can be stored in the form of their hashes so that even if a
database is breached, plaintext passwords are not accessible. MD5, SHA-1 and SHA-2 are popular cryptographic
hashes.

What is Separate Chaining?

Separate Chaining is the collision resolution technique that is implemented using linked list. When two or more
elements are hash to the same location, these elements are represented into a singly-linked list like a chain. Since this
method uses extra memory to resolve the collision, therefore, it is also known as open hashing.

Separate Chaining Hash Table

In separate chaining, each slot of the hash table is a linked list. We will insert the element into a specific linked list to
store it in the hash table. If there is any collision i.e. if more than one element after calculating the hashed value
mapped to the same key then we will store those elements in the same linked list. Given below is the representation of
the separate chaining hash table

EXAMPLE

Let's use "key mod 7" as our simple hash function with the following key values: 50, 700, 76, 85, 92, 73, 101.

19
Advantages:
o easy to implement
o We can always add more elements to the chain, thus the hash table never runs out of space.
o less susceptible to load factors or the hash function.
o When it is unclear how many or how frequently keys might be added or removed, it is typically used.

Disadvantages:
o Chaining's cache performance is poor since keys are kept in a linked list. Since everything is stored in the same table, open
addressing improves cache speed.
o Space wastage (Some Parts of hash table are never used)
o In the worst situation, search time can become O(n) as the chain lengthens.
o additional space is used for connections.

Collision Resolution Separate Chaining : Separate Chaining is the collision resolution technique
that is implemented using linked list. When two or more elements are hash to the same location, these elements are
represented into a singly-linked list like a chain

Collision: when two keys map to the same location in the hash table. Two ways to resolve collisions:

20
1. Separate Chaining

2. Open Addressing (linear probing, quadratic probing, double hashing)

Collision resolution techniques are classified as-

1. Separate Chaining
2. Open Addressing

In this article, we will discuss about separate chaining.

Separate Chaining-

To handle the collision,

 This technique creates a linked list to the slot for which collision occurs.
 The new key is then inserted in the linked list.
 These linked lists to the slots appear like chains.
 That is why, this technique is called as separate chaining.

Time Complexity-

21
For Searching-

 In worst case, all the keys might map to the same bucket of the hash table.
 In such a case, all the keys will be present in a single linked list.
 Sequential search will have to be performed on the linked list to perform the search.
 So, time taken for searching in worst case is O(n).

For Deletion-

 In worst case, the key might have to be searched first and then deleted.
 In worst case, time taken for searching is O(n).
 So, time taken for deletion in worst case is O(n).

Load Factor (α)-

Load factor (α) is defined as-

PRACTICE PROBLEM BASED ON SEPARATE CHAINING-

Problem-

Using the hash function ‘key mod 7’, insert the following sequence of keys in the hash table-
50, 700, 76, 85, 92, 73 and 101

Use separate chaining technique for collision resolution.

Solution-
Step-01:

 Draw an empty hash table.


 For the given hash function, the possible range of hash values is [0, 6].
 So, draw an empty hash table consisting of 7 buckets as-

22
Step-02:

 Insert the given keys in the hash table one by one.


 The first key to be inserted in the hash table = 50.
 Bucket of the hash table to which key 50 maps = 50 mod 7 = 1.
 So, key 50 will be inserted in bucket-1 of the hash table as-

Step-03:

 The next key to be inserted in the hash table = 700.


 Bucket of the hash table to which key 700 maps = 700 mod 7 = 0.
 So, key 700 will be inserted in bucket-0 of the hash table as-

23
Step-04:

 The next key to be inserted in the hash table = 76.


 Bucket of the hash table to which key 76 maps = 76 mod 7 = 6.
 So, key 76 will be inserted in bucket-6 of the hash table as-

Step-05:

 The next key to be inserted in the hash table = 85.


 Bucket of the hash table to which key 85 maps = 85 mod 7 = 1.
 Since bucket-1 is already occupied, so collision occurs.
 Separate chaining handles the collision by creating a linked list to bucket-1.
 So, key 85 will be inserted in bucket-1 of the hash table as-

24
Step-06:

 The next key to be inserted in the hash table = 92.


 Bucket of the hash table to which key 92 maps = 92 mod 7 = 1.
 Since bucket-1 is already occupied, so collision occurs.
 Separate chaining handles the collision by creating a linked list to bucket-1.
 So, key 92 will be inserted in bucket-1 of the hash table as-

Step-07:

 The next key to be inserted in the hash table = 73.


 Bucket of the hash table to which key 73 maps = 73 mod 7 = 3.
 So, key 73 will be inserted in bucket-3 of the hash table as-

25
Step-08:

 The next key to be inserted in the hash table = 101.


 Bucket of the hash table to which key 101 maps = 101 mod 7 = 3.
 Since bucket-3 is already occupied, so collision occurs.
 Separate chaining handles the collision by creating a linked list to bucket-3.
 So, key 101 will be inserted in bucket-3 of the hash table as-

26
UNIT-1
DATA STRUCTURE:
A data structure is a storage that is used to store and organize data. It is a way of arranging data on a computer so that it
can be accessed and updated efficiently. A data structure is not only used for organizing the data. It is also used for
processing, retrieving, and storing data

data structure is a specialized format for organizing, processing, retrieving and storing data. There are
several basic and advanced types of data structures, all designed to arrange data to suit a specific
purpose. Data structures make it easy for users to access and work with the data they need in
appropriate ways. Most importantly, data structures frame the organization of information so that
machines and humans can better understand it.

What is abstract data type?

An abstract data type is an abstraction of a data structure that provides only the interface to which the data structure must

adhere. The interface does not give any specific details about something should be implemented or in what

programming language.

For example, a List is an abstract data type that is implemented using a dynamic array and linked list. A queue is

implemented using linked list-based queue, array-based queue, and stack-based queue. A Map is implemented using Tree

27
map, hash map, or hash table.

Abstract data type model

Before knowing about the abstract data type model, we should know about abstraction and encapsulation.

Abstraction: It is a technique of hiding the internal details from the user and only showing the necessary details to the user.

Encapsulation: It is a technique of combining the data and the member function in a single unit is known as encapsulation.

The above figure shows the ADT model. There are two types of models in the ADT model, i.e., the public function and

the private function. The ADT model also contains the data structures that we are using in a program. In this model,

first encapsulation is performed, i.e., all the data is wrapped in a single unit, i.e., ADT. Then, the abstraction is performed

means showing the operations that can be performed on the data structure and what are the data structures that we are

using in a program.

Lists (ADT)
A list is an abstract data type that describes a linear collection of data items in some order, in that each element occupies a
specific position in the list. The order could be alphabetic or numeric or it could just be the order in which the list elements have
been added. Unlike a set, the elements of a list do not need to be unique.

Lists are used in a wide variety of situations. Many of us use to-do lists to keep ourselves organised. You may use a shopping
list to make sure you don’t forget to buy something when you visit the supermarket. If you use a streamed music service, you
probably have several playlists.

The main list operations are:

create create a new list


28
add add a new element to the list
delete delete an element from the list
traverse visit the elements in the list one at a time

Array Implementation of list:


Array: A set of data elements of same data type is called array. Array is a static data structure i.e., the memory
should be allocated in advance and the size is fixed. This will waste the memory space when used space is less
than the allocated space. An array implementation allows the following operations.
The basic operations are: a. Creation of a List.
b. Insertion of a data in the List
c. Deletion of a data from the List
d. Searching of a data in the list
Stack

Stack is a linear data structure in which the insertion and deletion operations are performed at only one
end. In a stack, adding and removing of elements are performed at a single position which is known as
"top". That means, a new element is added at top of the stack and an element is removed from the top of
the stack. In stack, the insertion and deletion operations are performed based on LIFO (Last In First
Out) principle.

In a stack, the insertion operation is performed using a function called "push" and deletion operation is
performed using a function called "pop".

In the figure, PUSH and POP operations are performed at a top position in the stack. That means, both
the insertion and deletion operations are performed at one end (i.e., at Top)

A stack data structure can be defined as follows...

Stack is a linear data structure in which the operations are performed based on LIFO principle.

Stack can also be defined as

"A Collection of similar data items in which both insertion and deletion operations are performed based
29
on LIFO principle".

Example: If we want to create a stack by inserting 10,45,12,16,35 and 50. Then 10 becomes the bottom-
most element and 50 is the topmost element. The last inserted element 50 is at Top of the stack as shown in
the image below...

30
Operations on a Stack

The following operations are performed on the stack...

• Push (To insert an element on to the stack)

• Pop (To delete an element from the stack)

• Display (To display elements of the stack)

Stack data structure can be implemented in two ways. They are as follows...

• Using Array

• Using Linked List

When a stack is implemented using an array, that stack can organize an only limited number of elements.
When a stack is implemented using a linked list, that stack can organize an unlimited number of elements.

Stack Using Array

A stack data structure can be implemented using a one- dimensional array. But stack implemented using
array stores only a fixed number of data values. This implementation is very simple. Just define a one
dimensional array of specific size and insert or delete the values into that array by using LIFO principle
with the help of a variable called 'top'. Initially, the top is set to - 1. Whenever we want to insert a value
into the stack, increment the top value by one and then insert. Whenever we want to delete a value from
the stack, then delete the top value and decrement the top value by one.

Stack Operations using Array

A stack can be implemented using array as follows...

Before implementing actual operations, first follow the below steps to create an empty stack. Step 1 -

Include all the header files which are used in the program and define a

31
constant 'SIZE' with specific value.

Step 2 - Declare all the functions used in stack implementation.

tep 3 - Create a one dimensional array with fixed size (int stack[ SIZE] )

Step 4 - Define a integer variable 'top' and initialize with '- 1'. (int top = - 1)

Step 5 - In main method, display menu with list of operations and make suitable function calls to perform
operation selected by the user on the stack.

push(value) - Inserting value into the stack

In a stack, push() is a function used to insert an element into the stack. In a stack, the new element is
always inserted at top position. Push function takes one integer value as parameter and inserts that value
into the stack. We can use the following steps to push an element on to the stack...

Step 1 - Check whether stack is FULL. (top == SIZE- 1)

Step 2 - If it is FULL, then display "Stack is FULL!!! Insertion is not possible!!!" and terminate the
function.

Step 3 - If it is NOT FULL, then increment top value by one (top++) and set stack[ top] to value (stack[ top] =
value).

pop() - Delete a value from the Stack

In a stack, pop() is a function used to delete an element from the stack. In a stack, the element is always
deleted from top position. Pop function does not take any value as parameter. We can use the following
steps to pop an element from the stack...

Step 1 - Check whether stack is EMPTY. (top == - 1)

Step 2 - If it is EMPTY, then display "Stack is EMPTY!!! Deletion is not possible!!!" and terminatethe
function.

Step 3 - If it is NOT EMPTY, then delete stack[ top] and decrement top value by one (top- - ).display() -

Displays the elements of a Stack

We can use the following steps to display the elements of a stack... Step 1 -

Check whether stack is EMPTY. (top == - 1)

Step 2 - If it is EMPTY, then display "Stack is EMPTY!!!" and terminate the function.

Step 3 - If it is NOT EMPTY, then define a variable 'i' and initialize with top.
Display stack[ i] value and decrement i value by one (i- - ).

32
Step 3 - Repeat above step until i value becomes '0'.

Stack Using Linked List

The major problem with the stack implemented using an array is, it works only for a fixed number of data
values. That means the amount of data must be specified at the beginning of the implementation itself.
Stack implemented using an array is not suitable, when we don't know the size of data which we are going
to use. A stack data structure can be implemented by using a linked list data structure. The stack
implemented using linked list can work for an unlimited number of values. That means, stack implemented
using linked list works for the variable size of data. So, there is no need to fix the size at the beginning of
the implementation. The Stack implemented using linked list can organize as many data values as we want.

In linked list implementation of a stack, every new element is inserted as 'top' element. That means every
newly inserted element is pointed by 'top'. Whenever we want to remove an element from the stack, simply
remove the node which is pointed by 'top' by moving 'top' to its previous node in the list. The next field of
the first element must be always NULL.

Example

In the above example, the last inserted node is 99 and the first inserted node is 25. The orderof elements
inserted is 25, 32,50 and 99.

33
Stack Operations using Linked List

To implement a stack using a linked list, we need to set the following things before
implementing actual operations.

Step 1 - Include all the header files which are used in the program. And declare all the userdefined
functions.

Step 2 - Define a 'Node' structure with two members data and next.Step 3 -

Define a Node pointer 'top' and set it to NULL.

Step 4 - Implement the main method by displaying Menu with list of operations and makesuitable
function calls in the main method.

push(value) - Inserting an element into the Stack

We can use the following steps to insert a new node into the stack...Step 1 -

Create a newNode with given value.

Step 2 - Check whether stack is Empty (top == NULL)

Step 3 - If it is Empty, then set newNode → next = NULL. Step 4 -

If it is Not Empty, then set newNode → next = top.Step 5 -

Finally, set top = newNode.

pop() - Deleting an Element from a Stack

We can use the following steps to delete a node from the stack... Step 1 -

Check whether stack is Empty (top == NULL).

Step 2 - If it is Empty, then display "Stack is Empty!!! Deletion is not possible!!!" and terminate the
function

Step 3 - If it is Not Empty, then define a Node pointer 'temp' and set it to 'top'.Step 4 -

Then set 'top = top → next'.

Step 5 - Finally, delete 'temp'. (free(temp)).

display() - Displaying stack of elements

We can use the following steps to display the elements (nodes) of a stack... Step 1 -

Check whether stack is Empty (top == NULL).

Step 2 - If it is Empty, then display 'Stack is Empty!!!' and terminate the function.

Step 3 - If it is Not Empty, then define a Node pointer 'temp' and initialize with top.

34
Step 4 - Display 'temp → data - - - >' and move it to the next node. Repeat the sameuntil temp
reaches to the first node in the stack. (temp → next != NULL).

Step 5 - Finally! Display 'temp → data - - - > NULL'.

1) Expression Evaluation
In any programming language, if we want to perform any calculation or to frame a condition etc., we use
a set of symbols to perform the task. These set of symbols makes an expression.An expression can be
defined as follows...

An expression is a collection of operators and operands that represents a specific value.

In above definition, operator is a symbol which performs a particular task like arithmetic operation or
logical operation or conditional operation etc.,

Operands are the values on which the operators can perform the task. Here operand can be a direct value
or variable or address of memory location.

Stack is used to evaluate prefix, postfix and infix expressions.

2) Expression Conversion
An expression can be represented in prefix, postfix or infix notation. Stack can be used to convert one
form of expression to another.
Based on the operator position, expressions are divided into THREE types. They are as follows...

35
1. Infix Expression
2. Postfix Expression
3. Prefix Expression

Infix A+B Operator between operands.

Prefix + AB Operator before operands.

Postfix AB + Operator after operands.

Conversions:
i. Infix to Postfix
ii. Infix to Prefix
iii. Postfix to Infix
iv. Prefix to Infix

1. Conversion of Infix to Postfix

Algorithm for Infix to Postfix

Step 1: Consider the next element in the input.Step 2:


If it is operand, display it.
Step 3: If it is opening parenthesis, insert it on stack. Step
4: If it is an operator, then
If stack is empty, insert operator on stack.
If the top of stack is opening parenthesis, insert the operator on stack
If it has higher priority than the top of stack, insert the operator on stack.Else, delete
the operator from the stack and display it, repeat Step 4.
Step 5: If it is a closing parenthesis, delete the operator from stack and display them until an opening
parenthesis is encountered. Delete and discard the opening parenthesis.
Step 6: If there is more input, go to Step 1.
Step 7: If there is no more input, delete the remaining operators to output. Example:

Suppose we are converting 3* 3/(4- 1)+6* 2 expression into postfix form.Following table

shows the evaluation of Infix to Postfix:

Expression Stack Output

3 Empty 3

* * 3

3 * 33

36
/ / 33*

( /( 33*

4 /( 33* 4

- /(- 33* 4

1 /(- 33* 41

) - 33* 41-

+ + 33* 41- /

6 + 33* 41- /6

* +* 33* 41- /62

2 +* 33* 41- /62

Empty 33* 41- /62* +

So, the Postfix Expression is 33* 41- /62* +

Example 2:
Consider the following Infix Expression...
(A+B)*(C- D)

The given infix expression can be converted into postfix expression using Stack data StructureThen the final
Postfix Expression is as follows...
AB+CD-*

Postfix Expression Evaluation

Postfix Expression Evaluation using Stack Data Structure


A postfix expression can be evaluated using the Stack data structure. To evaluate a postfixexpression
using Stack data structure we can use the following steps...

• Read all the symbols one by one from left to right in the given Postfix Expression
• If the reading symbol is operand, then push it on to the Stack.
• If the reading symbol is operator (+ , - , * , / etc.,), then perform TWO pop operationsand
store the two popped oparands in two different variables (operand1 and operand2).

37
Then perform reading symbol operation using operand1 and operand2 and push resultback on to
the Stack.
• Finally! perform a pop operation and display the popped value as final result.

Example
Consider the following Expression...

38
33
3) Syntax Parsing
Many compilers use a stack for parsing the syntax of expressions, program blocks etc. before translating
into low level code.

4) Backtracking
Suppose we are finding a path for solving maze problem. We choose a path and after following it we
realize that it is wrong. Now we need to go back to the beginning of the path to start with new path. This
can be done with the help of stack.

5) Parenthesis Checking
Stack is used to check the proper opening and closing of parenthesis.

6) String Reversal
Stack is used to reverse a string. We push the characters of string one by one into stack and then pop
character from stack.

Reversing string is an operation of Stack by using Stack we can reverse any string, here we
implemented a program in C - this will reverse given string using Stack.

The logic behind to implement this program:

1. Read a string.
2. Push all characters until NULL is not found - Characters will be stored in stack variable.
3. Pop all characters until NULL is not found - As we know stack is a LIFO technique, so
last character will be pushed first and finally we will get reversed string in a variable in which
we store inputted string.

Example:

Input a string: Hello World!


Reversed String is: !dlroW olleH

7) Function Call
Stack is used to keep information about the active functions or subroutines.8)Memory

Management

Any modern computer environment uses a stack as the primary memory management model for a running
program. Whether it's native code (x86, Sun, VAX) or JVM, a stack is at the center of the run- time
environment for Java, C++, Ada, FORTRAN, etc.

34
Queues: Introduction, Representation of a Queue using arrays, Queue Operations, Applications
of queues- Round Robin Algorithm, Circular Queues, Priority Queues.
Queues: Introduction

Queue is a linear data structure in which the insertion and deletion operations are performed at
two different ends. In a queue data structure, adding and removing elements are performed at
two different positions. The insertion is performed at one end and deletion is performed at
another end. In a queue data structure, the insertion operation is performed at a position which
is known as 'rear' and the deletion operation is performed at a position which is known as
'front'. In queue data structure, the insertion and deletion operations are performed based on
FIFO (First In First Out) principle.

In a queue data structure, the insertion operation is performed using a function called
"enQueue()" and deletion operation is performed using a function called "deQueue()".

Queue data structure can be defined as follows...

Queue data structure is a linear data structure in which the operations are performed based on
FIFO principle.

A queue data structure can also be defined as

"Queue data structure is a collection of similar data items in which insertion and deletion
operations are performed based on FIFO principle".

Example

Queue after inserting 25, 30, 51, 60 and 85.

Operations on a Queue

The following operations are performed on a queue data structure...


• enQueue(value) - (To insert an element into the queue)
• deQueue() - (To delete an element from the queue)
• display() - (To display the elements of the queue)
Queue data structure can be implemented in two ways. They are as follows...

1. Using Array
2. Using Linked List

When a queue is implemented using an array, that queue can organize an only limited number of
elements. When a queue is implemented using a linked list, that queue can organize an unlimited
number of elements.
Implementation of Queue Data structure Using Array:

A queue data structure can be implemented using one dimensional array. The queue
implemented using array stores only fixed number of data values. The implementation of queue
data structure using array is very simple. Just define a one dimensional array of specific size and
insert or delete the values into that array by using FIFO (First In First Out) principle with
the help of variables 'front' and 'rear'. Initially both 'front' and 'rear' are set to - 1. Whenever,
we want to insert a new value into the queue, increment 'rear' value by one and then insert at that
position. Whenever we want to delete a value from the queue, then delete the element which is at
'front' position and increment 'front' value by one.

Queue Operations using Array


Queue data structure using array can be implemented as follows...
Before we implement actual operations, first follow the below steps to create an empty queue.

• Step 1 - Include all the header files which are used in the program and define a
constant 'SIZE' with specific value.
• Step 2 - Declare all the user defined functions which are used in queue
implementation.

• Step 3 - Create a one dimensional array with above defined SIZE (int queue[
SIZE] )
• Step 4 - Define two integer variables 'front' and 'rear' and initialize both with '- 1'.
(int front = - 1, rear = - 1)
• Step 5 - Then implement main method by displaying menu of operations list and make
suitable function calls to perform operation selected by the user on queue.

enQueue(value) - Inserting value into the queue


In a queue data structure, enQueue() is a function used to insert a new element into the queue.
In a queue, the new element is always inserted at rear position. The enQueue() function takes
one integer value as a parameter and inserts that value into the queue. We can use the following
steps to insert an element into the queue...
• Step 1 - Check whether queue is FULL. (rear == SIZE- 1)
• Step 2 - If it is FULL, then display "Queue is FULL!!! Insertion is not
possible!!!" and terminate the function.
• Step 3 - If it is NOT FULL, then increment rear value by one (rear++) and set
queue[ rear] = value.

deQueue() - Deleting a value from the Queue


In a queue data structure, deQueue() is a function used to delete an element from the queue. In a
queue, the element is always deleted from front position. The deQueue() function does not take
any value as parameter. We can use the following steps to delete an element from the queue...

• Step 1 - Check whether queue is EMPTY. (front == rear)


• Step 2 - If it is EMPTY, then display "Queue is EMPTY!!! Deletion is not
possible!!!" and terminate the function.
• Step 3 - If it is NOT EMPTY, then increment the front value by one (front ++). Then
display queue[ front] as deleted element. Then check whether both front and
rear are equal (front == rear), if it TRUE, then set both front and
rear to '- 1' (front = rear = - 1).

display() - Displays the elements of a Queue


We can use the following steps to display the elements of a queue...

• Step 1 - Check whether queue is EMPTY. (front == rear)


• Step 2 - If it is EMPTY, then display "Queue is EMPTY!!!" and terminate the
function.
• Step 3 - If it is NOT EMPTY, then define an integer variable 'i' and set'i
= front+1'.
• Step 4 - Display 'queue[ i] ' value and increment 'i' value by one (i++). Repeat the
same until 'i' value reaches to rear (i <= rear)
}

Implementation of Queue Data structure Using Linked List:

The major problem with the queue implemented using an array is, It will work for an only fixed
number of data values. That means, the amount of data must be specified at the beginning itself.
Queue using an array is not suitable when we don't know the size of data which we are going to
use. A queue data structure can be implemented using a linked list data structure. The queue
which is implemented using a linked list can work for an unlimited number of values. That
means, queue using linked list can work for the variable size of data (No need to fix the size at
the beginning of the implementation). The Queue implemented using linked list can organize as
many data values as we want.

In linked list implementation of a queue, the last inserted node is always pointed by 'rear' and the
first node is always pointed by 'front'.

Example

In above example, the last inserted node is 50 and it is pointed by 'rear' and the first inserted
node is 10 and it is pointed by 'front'. The order of elements inserted is 10, 15, 22 and 50.

Operations

To implement queue using linked list, we need to set the following things
before implementing actual operations.

Step 1 - Include all the header files which are used in the program. And declare allthe user
defined functions.

Step 2 - Define a 'Node' structure with two members data and next.

Step 3 - Define two Node pointers 'front' and 'rear' and set both to NULL.

Step 4 - Implement the main method by displaying Menu of list of operations and make suitable
function calls in the main method to perform user selected operation.

enQueue(value) - Inserting an element into the Queue

We can use the following steps to insert a new node into the queue...
Step 1 - Create a newNode with given value and set 'newNode → next' to NULL.Step 2 -

Check whether queue is Empty (rear == NULL)

Step 3 - If it is Empty then, set front = newNode and rear = newNode.

Step 4 - If it is Not Empty then, set rear → next = newNode and rear = newNode.deQueue() -

Deleting an Element from Queue

We can use the following steps to delete a node from the queue... Step 1 -

Check whether queue is Empty (front == NULL).

Step 2 - If it is Empty, then display "Queue is Empty!!! Deletion is not possible!!!" andterminate
from the function

Step 3 - If it is Not Empty then, define a Node pointer 'temp' and set it to 'front'.Step 4 -

Then set 'front = front → next' and delete 'temp' (free(temp)).

display() - Displaying the elements of Queue

We can use the following steps to display the elements (nodes) of a queue... Step 1 -

Check whether queue is Empty (front == NULL).

Step 2 - If it is Empty then, display 'Queue is Empty!!!' and terminate the function.

Step 3 - If it is Not Empty then, define a Node pointer 'temp' and initialize with front.

Step 4 - Display 'temp → data - - - >' and move it to the next node. Repeat the sameuntil
'temp' reaches to 'rear' (temp → next != NULL).

Step 5 - Finally! Display 'temp → data - - - > NULL'.


Circular Queue Datastructure

In a normal Queue Data Structure, we can insert elements until queue becomes full. But once
the queue becomes full, we can not insert the next element until all the elements are deleted from
the queue. For example, consider the queue below...

The queue after inserting all the elements into it is as follows...

Now consider the following situation after deleting three elements from the queue...

This situation also says that Queue is Full and we cannot insert the new element because 'rear'
is still at last position. In the above situation, even though we have
empty positions in the queue we can not make use of them to insert the new element. This is the
major problem in a normal queue data structure. To overcome this problem we use a circular
queue data structure.

What is Circular Queue?

A Circular Queue can be defined as follows...

A circular queue is a linear data structure in which the operations are performed based on FIFO
(First In First Out) principle and the last position is connected back to the first position to make
a circle.

Graphical representation of a circular queue is as follows...

Implementation of Circular Queue

To implement a circular queue data structure using an array, we first perform the following
steps before we implement actual operations.

Step 1 - Include all the header files which are used in the program and define aconstant
'SIZE' with specific value.

Step 2 - Declare all user defined functions used in circular queue implementation. Step 3 -

Create a one dimensional array with above defined SIZE (int cQueue[ SIZE] )

Step 4 - Define two integer variables 'front' and 'rear' and initialize both with '- 1'. (intfront = -
1, rear = - 1)

Step 5 - Implement main method by displaying menu of operations list and makesuitable
function calls to perform operation selected by the user on circular queue.

enQueue(value) - Inserting value into the Circular Queue

In a circular queue, enQueue() is a function which is used to insert an element into thecircular
queue. In a circular queue, the new element is always inserted at rear position.
The enQueue() function takes one integer value as parameter and inserts that value into the
circular queue. We can use the following steps to insert an element into the circular queue...

Step 1 - Check whether queue is FULL. ((rear == SIZE- 1 && front == 0) || (front == rear+1))

Step 2 - If it is FULL, then display "Queue is FULL!!! Insertion is not possible!!!" and terminate the
function.

Step 3 - If it is NOT FULL, then check rear == SIZE - 1 && front != 0 if it is TRUE, then set
rear = - 1.

Step 4 - Increment rear value by one (rear++), set queue[ rear] = value and check 'front
== - 1' if it is TRUE, then set front = 0.

deQueue() - Deleting a value from the Circular Queue

In a circular queue, deQueue() is a function used to delete an element from the circular queue.
In a circular queue, the element is always deleted from front position. The deQueue() function
doesn't take any value as a parameter. We can use the following steps to delete an element from
the circular queue...

Step 1 - Check whether queue is EMPTY. (front == - 1 && rear == - 1)

Step 2 - If it is EMPTY, then display "Queue is EMPTY!!! Deletion is not possible!!!" and terminate
the function.

Step 3 - If it is NOT EMPTY, then display queue[ front] as deleted element and increment the
front value by one (front ++). Then check whether front == SIZE, if it is TRUE, then set
front = 0. Then check whether both front - 1 and rear are equal (front
- 1 == rear), if it TRUE, then set both front and rear to '- 1' (front = rear = - 1).display() -

Displays the elements of a Circular Queue

We can use the following steps to display the elements of a circular queue...Step 1 -

Check whether queue is EMPTY. (front == - 1)

Step 2 - If it is EMPTY, then display "Queue is EMPTY!!!" and terminate the function.Step 3 - If

it is NOT EMPTY, then define an integer variable 'i' and set 'i = front'.

Step 4 - Check whether 'front <= rear', if it is TRUE, then display 'queue[ i] ' value and
increment 'i' value by one (i++). Repeat the same until 'i <= rear' becomes FALSE.

Step 5 - If 'front <= rear' is FALSE, then display 'queue[ i] ' value and increment 'i' valueby one
(i++). Repeat the same until'i <= SIZE - 1' becomes FALSE.
Step 6 - Set i to 0.

Step 7 - Again display 'cQueue[ i] ' value and increment i value by one (i++). Repeat thesame
until 'i <= rear' becomes FALSE.
Linked List: Introduction, single linked list, representation of a linked list in memory,
Operations on a single linked list, Reversing a single linked list, applications: single linked list
to represent polynomial expressions, Circular linked list, Double linked list.

Linked List
One disadvantage of using arrays to store data is that arrays are static structures and therefore
cannot be easily extended or reduced to fit the data set. Arrays are also expensive to maintain
new insertions and deletions. For this another data structure called Linked Lists that addresses
some of the limitations of arrays.
When we want to work with an unknown number of data values, we use a linked list data
structure to organize that data. The linked list is a linear data structure that contains a sequence
of elements such that each element links to its next element in the sequence. Each element in a
linked list is called "Node". Each node holds its own data and the address of the next node
hence forming a chain like structure.

Advantages of Linked Lists


• They are a dynamic in nature which allocates the memory when required.
• Insertion and deletion operations can be easily implemented.
• Stacks and queues can be easily executed.
• Linked List reduces the access time.
Disadvantages of Linked Lists
• The memory is wasted as pointers require extra memory for storage.
• No element can be accessed randomly; it has to access each node sequentially.
• Reverse Traversing is difficult in linked list.
Applications of Linked Lists
• Linked lists are used to implement stacks, queues, graphs, etc.
• Linked lists let you insert elements at the beginning and end of the list.
• In Linked Lists we don't need to know the size in advance.

1
Representation Of A Linked List In Memory:
Let LIST is linear linked list. It needs two linear arrays for memory representation. Let these
linear arrays are INFO and LINK. INFO[ K] contains the information part and LINK[ K]
contains the next pointer field of node K. A variable START is used to store the location of the
beginning of the LIST and NULL is used as next pointer sentinel which indicates the end of LIST.
It is shown below:

Types of Linked Lists


There are 3 different implementations of Linked List available, they are:
• Singly Linked List
• Doubly Linked List
• Circular Linked List

Single Linked List


Simply a list is a sequence of data, and the linked list is a sequence of data linked with each
other.
The formal definition of a single linked list is as follows...
Single linked list is a sequence of elements in which every element has link to its next element in
the sequence.
In any single linked list, the individual element is called as "Node". Every "Node" contains two
fields, data field, and the next field. The data field is used to store actual value of the node and
next field is used to store the address of next node in the sequence.
The graphical representation of a node in a single linked list is as follows...

Important Points to be Remembered


• In a single linked list, the address of the first node is always stored in a

2
reference node known as "front" (Some times it is also known as "head").
• Always next part (reference part) of the last node must be NULL.

Example

Operations on a Single Linked List


The following operations are performed on a Single Linked List
• Insertion
• Deletion
• Display
Before we implement actual operations, first we need to set up an empty list. First, perform
the following steps before implementing actual operations.
Step 1 - Include all the header files which are used in the program.Step 2 -
Declare all the user defined functions.
Step 3 - Define a Node structure with two members data and nextStep 4 -
Define a Node pointer 'head' and set it to NULL.
Step 5 - Implement the main method by displaying operations menu and make suitablefunction calls in
the main method to perform user selected operation.
Insertion
In a single linked list, the insertion operation can be performed in three ways. They areas
follows...
• Inserting At Beginning of the list
• Inserting At End of the list
• Inserting At Specific location in the list

Inserting At Beginning of the list


We can use the following steps to insert a new node at beginning of the single linkedlist...
Step 1 - Create a newNode with given value.
Step 2 - Check whether list is Empty (head == NULL)
Step 3 - If it is Empty then, set newNode→next = NULL and head = newNode.
Step 4 - If it is Not Empty then, set newNode→next = head and head = newNode. Inserting
At End of the list
We can use the following steps to insert a new node at end of the single linked list...Step 1 -
Create a newNode with given value and newNode → next as NULL.
Step 2 - Check whether list is Empty (head == NULL).Step
3 - If it is Empty then, set head = newNode.
Step 4 - If it is Not Empty then, define a node pointer temp and initialize with head.
Step 5 - Keep moving the temp to its next node until it reaches to the last node in thelist (until
temp → next is equal to NULL).
Step 6 - Set temp → next = newNode.
Inserting At Specific location in the list (After a Node)
We can use the following steps to insert a new node after a node in the single linkedlist...

3
Step 1 - Create a newNode with given value.
Step 2 - Check whether list is Empty (head == NULL)
Step 3 - If it is Empty then, set newNode → next = NULL and head = newNode.
Step 4 - If it is Not Empty then, define a node pointer temp and initialize with head.
Step 5 - Keep moving the temp to its next node until it reaches to the node after which we want to
insert the newNode (until temp1 → datais equal to location, here location is the node value
after which we want to insert the newNode).
Step 6 - Every time check whether temp is reached to last node or not. If it is reached to last
node then display 'Given node is not found in the list!!! Insertion not possible!!!' and
terminate the function. Otherwise move the temp to next node.
Step 7 - Finally, Set 'newNode → next = temp → next' and 'temp → next = newNode'Deletion
In a single linked list, the deletion operation can be performed in three ways. They areas
follows...
• Deleting from Beginning of the list
• Deleting from End of the list
• Deleting a Specific Node
Deleting from Beginning of the list
We can use the following steps to delete a node from beginning of the single linkedlist...
Step 1 - Check whether list is Empty (head == NULL)
Step 2 - If it is Empty then, display 'List is Empty!!! Deletion is not possible' andterminate
the function.
Step 3 - If it is Not Empty then, define a Node pointer 'temp' and initialize with head.Step 4 -
Check whether list is having only one node (temp → next == NULL)
Step 5 - If it is TRUE then set head = NULL and delete temp (Setting Empty list
conditions)
Step 6 - If it is FALSE then set head = temp → next, and delete temp.Deleting
from End of the list
We can use the following steps to delete a node from end of the single linked list... Step 1 -
Check whether list is Empty (head == NULL)
Step 2 - If it is Empty then, display 'List is Empty!!! Deletion is not possible' andterminate
the function.
Step 3 - If it is Not Empty then, define two Node pointers 'temp1' and 'temp2' andinitialize
'temp1' with head.
Step 4 - Check whether list has only one Node (temp1 → next == NULL)
Step 5 - If it is TRUE. Then, set head = NULL and delete temp1. And terminate the function.
(Setting Empty list condition)
Step 6 - If it is FALSE. Then, set 'temp2 = temp1 ' and move temp1 to its next node. Repeat the
same until it reaches to the last node in the list. (until temp1 → next == NULL)
Step 7 - Finally, Set temp2 → next = NULL and delete temp1.Deleting a
Specific Node from the list
We can use the following steps to delete a specific node from the single linked list... Step 1 -
Check whether list is Empty (head == NULL)
Step 2 - If it is Empty then, display 'List is Empty!!! Deletion is not possible' andterminate
the function.
Step 3 - If it is Not Empty then, define two Node pointers 'temp1' and 'temp2' andinitialize
'temp1' with head.

4
Step 4 - Keep moving the temp1 until it reaches to the exact node to be deleted or to the last
node. And every time set 'temp2 = temp1' before moving the 'temp1' to its next node.
Step 5 - If it is reached to the last node then display 'Given node not found in the list! Deletion
not possible!!!'. And terminate the function.
Step 6 - If it is reached to the exact node which we want to delete, then check whether list is
having only one node or not
Step 7 - If list has only one node and that is the node to be deleted, then set head =
NULL and delete temp1 (free(temp1)).
Step 8 - If list contains multiple nodes, then check whether temp1 is the first node in the list
(temp1 == head).
Step 9 - If temp1 is the first node then move the head to the next node (head = head
→ next) and delete temp1.
Step 10 - If temp1 is not first node then check whether it is last node in the list (temp1
→ next == NULL).
Step 11 - If temp1 is last node then set temp2 → next = NULL and
delete temp1 (free(temp1)).
Step 12 - If temp1 is not first node and not last node then set temp2 → next = temp1
→ next and delete temp1 (free(temp1)). Displaying a
Single Linked List
We can use the following steps to display the elements of a single linked list...Step 1 -
Check whether list is Empty (head == NULL)
Step 2 - If it is Empty then, display 'List is Empty!!!' and terminate the function.
Step 3 - If it is Not Empty then, define a Node pointer 'temp' and initialize with head.
Step 4 - Keep displaying temp → data with an arrow (- - - >) until temp reaches to thelast node
Step 5 - Finally display temp → data with arrow pointing to NULL (temp → data - - - >NULL).

5
• head should now point to its next node i.e. the second node head = head- >next.

• curNode should also points to the second node i.e. curNode = head.

2. Now, disconnect the previous node i.e. the first node from others. We will make sure that it
points to none. As this node is going to be our last node. Perform operation prevNode-
>next = NULL.

3. Move head node to its next node i.e. head = head- >next.

4. Now, re- connect the current node to its previous node i.e. curNode- >next =
prevNode;.

5. Point the previous node to current node and current node to head node. Means theyshould
now point to prevNode = curNode; and curNode = head.

6. Repeat steps 3- 5 till head pointer becomes NULL.

6
7. Now, after all nodes has been re- connected in the reverse order. Make the last node as the
first node. Means the head pointer should point to prevNode pointer. Perform head =
prevNode;. Finally you end up with a reversed linked list of its original.

Applications: single linked list to represent polynomial expressions


Polynomials are the important application of arrays and linked lists. A polynomial is composed
of different terms where each of them holds a coefficient and an exponent. A polynomial
expression can be defined as:
A polynomial p(x) is the expression in variable x which is in the form (axn + bxn- 1 + ….
+ jx+ k), where a, b, c …., k fall in the category of real numbers and 'n' is non
negative integer, which is called the degree of polynomial.
An essential characteristic of the polynomial is that each term in the polynomialexpression
consists of two parts:
• one is the coefficient
• other is the exponent
Example:
10x2 + 26x, here 10 and 26 are coefficients and 2, 1 is its exponential value keep in .

7
Points to Mind while working with Polynomials:

• The sign of each coefficient and exponent is stored within the coefficient andthe
exponent itself
• Additional terms having equal exponent is possible one
• The storage allocation for each term in the polynomial must be done inascending and
descending order of their exponent
Polynomial can be represented in the various ways. These are:

• By the use of arrays


• By the use of Linked List
By the use of Linked List

A polynomial can be thought of as an ordered list of non zero terms. Each non zeroterm is a
two- tuple which holds two pieces of information:
• The exponent part
• The coefficient part
Node of a
Polynomial:

Coef Exp Link

For example 3x^ 2 + 5x + 7 will represent as follows.

In each node the exponent field will store the corresponding exponent and thecoefficient field
will store the corresponding coefficient. Link field points to the next

8
item in the polynomial.

We can Perform All Arithmetic operations with Polynomial expressions by using Linked list.
Example to perform Addition :( Explained in class Notes)

Circular linked list


In single linked list, every node points to its next node in the sequence and the last node points
NULL. But in circular linked list, every node points to its next node in the sequence but the last
node points to the first node in the list.

A circular linked list is a sequence of elements in which every element has a link
to its next element in the sequence and the last element has a link to the first
element.

That means circular linked list is similar to the single linked list except that the last node points
to the first node in the list

Example

Operations
In a circular linked list, we perform the following operations...
• Insertion
• Deletion
• Display
Insertion
In a circular linked list, the insertion operation can be performed in three ways. Theyare as
follows...
• Inserting At Beginning of the list
• Inserting At End of the list
• Inserting At Specific location in the list
Deletion
In a circular linked list, the deletion operation can be performed in three ways thoseare as
follows...
• Deleting from Beginning of the list
• Deleting from End of the list
• Deleting a Specific Node
Advantages of a Circular linked
list

• Entire list can be traversed from any node.

9
PACE ITSAUTONOMOUS UNIT- 3 PART- BV.SRIHARSHA
• Circular lists are the required data structure when we want a list to be accessedin a
circle or loop.

• Despite of being singly circular linked list we can easily traverse to its previousnode,
which is not possible in singly linked list.

Disadvantages of Circular linked list

• Circular list are complex as compared to singly linked lists.

• Reversing of circular list is a complex as compared to singly or doubly lists.

• If not traversed carefully, then we could end up in an infinite loop.

• Like singly and doubly lists circular linked lists also doesn’t supports direct
accessing of elements.

Applications/Uses of Circular linked list in real life

• Circular lists are used in applications where the entire list is accessed one- by- one in a
loop. Example: Operating systems may use it to switch between variousrunning
applications in a circular loop.

• It is also used by Operating system to share time for different users, generallyuses
Round- Robin time sharing mechanism.

• Multiplayer games uses circular list to swap between players in a loop.

Double Linked List

In a single linked list, every node has a link to its next node in the sequence. So, we can traverse
from one node to another node only in one direction and we cannot traverse back. We can solve
this kind of problem by using a double linked list. A double linked list can be defined as follows...

Double linked list is a sequence of elements in which every element has links to
its previous element and next element in the sequence.

In a double linked list, every node has a link to its previous node and next node. So, we can
traverse forward by using the next field and can traverse backward by using the previous field.
Every node in a double linked list contains three fields and they are shown in the following
figure...

10
PACE ITSAUTONOMOUS UNIT- 3 PART- BV.SRIHARSHA
Here, 'link1' field is used to store the address of the previous node in the sequence, 'link2'
field is used to store the address of the next node in the sequence and 'data' field is used to store
the actual value of that node.

Example

Important Points to be remembered


• In double linked list, the first node must be always pointed by head.
• Always the previous field of the first node must be NULL.
• Always the next field of the last node must be NULL.
Operations on Double Linked List
In a double linked list, we perform the following operations...
• Insertion
• Deletion
• Display

Insertion
In a double linked list, the insertion operation can be performed in three ways asfollows...
• Inserting At Beginning of the list
• Inserting At End of the list
• Inserting At Specific location in the list
Deletion
In a double linked list, the deletion operation can be performed in three ways asfollows...
• Deleting from Beginning of the list
• Deleting from End of the list
• Deleting a Specific Node Basic
structure of a doubly linked list

The basic structure of a doubly linked list contains a data field and two address fields. Here is
how it can be represented in C programming language.
Advantages of Doubly linked list
Doubly linked list is one of the important data structures. Here are various advantagesof doubly
linked list.

11
• As like singly linked list it is the easiest data structures to implement.
• Allows traversal of nodes in both direction which is not possible in singly linked list.
• Deletion of nodes is easy when compared to singly linked list, as in singly linked list
deletion requires a pointer to the node and previous node to be deleted. Which is not in
case of doubly linked list we only need the pointer which is to be deleted.
• Reversing the list is simple and straightforward.
• Can allocate or de- allocate memory easily when required during its execution.
• It is one of most efficient data structure to implement when traversing in both direction is
required.
Disadvantages of Doubly linked list
Not many but doubly linked list has few disadvantages also which can be listed below:
• It uses extra memory when compared to array and singly linked list.
• Since elements in memory are stored randomly, hence elements are accessed
sequentially no direct access is allowed.

Applications/Uses of doubly linked list in real life


There are various applications of doubly linked list in the real world. Some of them canbe listed
as:
• Doubly linked list can be used in navigation systems where both front and back
navigation is required.
• It is used by browsers to implement backward and forward navigation of visited web
pages i.e. back and forward button.
• It is also used by various applications to implement Undo and Redo functionality.
• It can also be used to represent deck of cards in games.
• It is also used to represent various states of a game.

12
UNIT-III
Trees: Basic tree concepts, Binary Trees: Properties, Representation of Binary Trees using
arrays, operations on a Binary tree, Binary Tree Traversals (recursive).
Advanced Tree Concepts: Binary search tree, Basic concepts, BST operations: Searching,
insertion, deletion, Balanced search trees- AVL Trees- Definition and Examples only, B- Trees
Definition and Examples only, Red- Black Trees- Definitions and Examples only (No operations )

In linear data structure data is organized in sequential order and in non- linear data structure data is
organized in random order. A tree is a very popular non- linear data structure used in a wide range
of applications. A tree data structure can be defined as follows...

Tree is a non- linear data structure which organizes data in hierarchical structure
and this is a recursive definition.

A tree data structure can also be defined as follows...

Tree data structure is a collection of data (Node) which is organized in


hierarchical structure recursively
In tree data structure, every individual element is called as Node. Node in a tree data structure stores
the actual data of that particular element and link to next element in hierarchical structure.

In a tree data structure, if we have N number of nodes then we can have a maximumof N- 1
number of links.
Example

Terminology

In a tree data structure, we use the following terminology...

1. Root

In a tree data structure, the first node is called as Root Node. Every tree must have a
root node. We can say that the root node is the origin of the tree data structure. In anytree,
there must be only one root node. We never have multiple root nodes in a tree.

2. Edge

In a tree data structure, the connecting link between any two nodes is called as EDGE. In a tree
with 'N' number of nodes there will be a maximum of 'N- 1' number of edges.

3. Parent

In a tree data structure, the node which is a predecessor of any node is called as
PARENT NODE. In simple words, the node which has a branch from it to any other node is called
a parent node. Parent node can also be defined as "The node which has child / children".
4. Child

In a tree data structure, the node which is descendant of any node is called as CHILD Node. In
simple words, the node which has a link from its parent node is called as child node. In a tree, any
parent node can have any number of child nodes. In a tree, all the nodes except root are child
nodes.

5. Siblings

In a tree data structure, nodes which belong to same Parent are called as SIBLINGS. In simple
words, the nodes with the same parent are called Sibling nodes.
6. Leaf

In a tree data structure, the node which does not have a child is called as LEAF Node. In
simple words, a leaf is a node with no child.

In a tree data structure, the leaf nodes are also called as External Nodes. External node is also a
node with no child. In a tree, leaf node is also called as 'Terminal' node.

7. Internal Nodes

In a tree data structure, the node which has at least one child is called as INTERNAL Node. In
simple words, an internal node is a node with at least one child.

In a tree data structure, nodes other than leaf nodes are called as Internal Nodes. The root node is
also said to be Internal Node if the tree has more than one node. Internal nodes are also called as
'Non- Terminal' nodes.
8. Degree

In a tree data structure, the total number of children of a node is called as DEGREE of that
Node. In simple words, the Degree of a node is total number of children it has. The highest
degree of a node among all the nodes in a tree is called as 'Degree of Tree'

9. Level

In a tree data structure, the root node is said to be at Level 0 and the children of root node are at
Level 1 and the children of the nodes which are at Level 1 will be at Level 2 and so on... In
simple words, in a tree each step from top to bottom is called as a Level and the Level count
starts with '0' and incremented by one at each level (Step).
10. Height

In a tree data structure, the total number of edges from leaf node to a particular node in the
longest path is called as HEIGHT of that Node. In a tree, height of the root node is said to be
height of the tree. In a tree, height of all leaf nodes is '0'.

11. Depth

In a tree data structure, the total number of egdes from root node to a particular node is called
as DEPTH of that Node. In a tree, the total number of edges from root node toa leaf node in the
longest path is said to be Depth of the tree. In simple words, the highest depth of any leaf node in
a tree is said to be depth of that tree. In a tree, depth of the root node is '0'.
12. Path

In a tree data structure, the sequence of Nodes and Edges from one node to another node is
called as PATH between that two Nodes. Length of a Path is total number of nodes in that path. In
below example the path A - B - E - Jhas length 4.

13. Sub Tree

In a tree data structure, each child from a node forms a subtree recursively. Every child node
will form a subtree on its parent node.
Tree Representations

A tree data structure can be represented in two methods. Those methods are as follows...

• List Representation

• Left Child - Right Sibling Representation

Consider the following tree...

1. List Representation

In this representation, we use two types of nodes one for representing the node with data called
'data node' and another for representing only references called 'reference node'. We start with a
'data node' from the root node in the tree. Then it is linked to an internal node through a
'reference node' which is further linked to any other node directly. This process repeats for all
the nodes in the tree.

The above example tree can be represented using List representation as follows...
2. Left Child - Right Sibling Representation

In this representation, we use a list with one type of node which consists of three fields namely
Data field, Left child reference field and Right sibling reference field. Data field stores the
actual value of a node, left reference field stores the address of the left child and right reference
field stores the address of the right sibling node. Graphical representation of that node is as
follows...

In this representation, every node's data field stores the actual value of that node. If that node
has left a child, then left reference field stores the address of that left child node otherwise stores
NULL. If that node has the right sibling, then right reference field stores the address of right
sibling node otherwise stores NULL.

The above example tree can be represented using Left Child - Right Sibling representation as
follows...

Binary Tree Data structure


In a normal tree, every node can have any number of children. A binary tree is a special type of
tree data structure in which every node can have a maximum of 2 children. One is known as a left
child and the other is known as right child.

A tree in which every node can have a maximum of two children is called Binary Tree.

In a binary tree, every node can have either 0 children or 1 child or 2 children but not more than
2 children.

Example

There are different types of binary trees and they are...

1. Strictly Binary Tree

In a binary tree, every node can have a maximum of two children. But in strictly binary tree,
every node should have exactly two children or none. That means every internal node must have
exactly two children. A strictly Binary Tree can be defined as follows...

A binary tree in which every node has either two or zero number of children is
called Strictly Binary Tree.

Strictly binary tree is also called as Full Binary Tree or Proper Binary Tree or 2- Tree

Strictly binary tree data structure is used to represent mathematical expressions. Example
2. Complete Binary Tree

In a binary tree, every node can have a maximum of two children. But in strictly binary tree,
every node should have exactly two children or none and in complete binary tree all the nodes
must have exactly two children and at every level of complete binary tree there must be 2level
number of nodes. For example at level 2 there must be 22 = 4 nodes and at level 3 there must be
23 = 8 nodes.

A binary tree in which every internal node has exactly two children and all leaf
nodes are at same level is called Complete Binary Tree.

Complete binary tree is also called as Perfect Binary Tree

3. Extended Binary Tree

A binary tree can be converted into Full Binary tree by adding dummy nodes toexisting
nodes wherever required.

The full binary tree obtained by adding dummy nodes to a binary tree is called
as Extended Binary Tree.
In above figure, a normal binary tree is converted into full binary tree by addingdummy
nodes.

Binary Tree Properties:


1) Minimum number of nodes in a binary tree of height H =
H + 1 Example-
To construct a binary tree of height = 4, we need at least 4 + 1 = 5 nodes.

2) Maximum number of nodes in a binary tree of height H =


2H+1 – 1 Example-
Maximum number of nodes in a binary tree of height 3
= 23+1 – 1
= 16 – 1
= 15 nodes
Thus, in a binary tree of height = 3, maximum number of nodes that can be inserted =15.

We cannot insert more number of nodes in this binary tree.

3) Total Number of leaf nodes in a Binary Tree = Total Number of nodes with 2 children + 1
Example- Consider the following binary tree-

Here, Number of leaf nodes = 3 ,Number of nodes with 2 children = 2


4) Maximum number of nodes at any level ‘L’ in a binary tree
= 2L Example-
Maximum number of nodes at level- 2 in a binary tree
= 22
=4
Thus, in a binary tree, maximum number of nodes that can be present at level- 2 = 4.

Binary Tree Representations

A binary tree data structure is represented using two methods. Those methods are as follows...

• Array Representation

• Linked List Representation

Consider the following binary tree...

1. Array Representation of Binary Tree


2. Linked List Representation of Binary Tree

We use a double linked list to represent a binary tree. In a double linked list, every node consists
of three fields. First field for storing left child address, second for storing actual data and third
for storing right child address.

In this linked list representation, a node has the following structure...

The above example of the binary tree represented using Linked list representation isshown as
follows...
Operations on a Binary tree
Searching or Traversal(recursive):

Traversal is a process to visit all the nodes of a tree and may print their values too. Because, all
nodes are connected via edges (links) we always start from the root (head) node. That is, we
cannot randomly access a node in a tree. There are three ways which we use to traverse a tree −
• In- order Traversal
• Pre- order Traversal
• Post- order Traversal
Generally, we traverse a tree to search or locate a given item or key in the tree or toprint all
the values it contains.

In- order Traversal


In this traversal method, the left subtree is visited first, then the root and later the right
sub- tree. We should always remember that every node may represent a subtreeitself.
If a binary tree is traversed in- order, the output will produce sorted key values in an ascending
order.

We start from A, and following in- order traversal, we move to its left subtree B. B is also
traversed in- order. The process goes on until all the nodes are visited. The outputof inorder
traversal of this tree will be −
D→B→E→A→F→C→G
Algorithm
Until all nodes are traversed −
Step 1 − Recursively traverse left subtree. Step 2
− Visit root node.
Step 3 − Recursively traverse right subtree.
Pre- order Traversal
In this traversal method, the root node is visited first, then the left subtree and finally the right
subtree.
We start from A, and following pre- order traversal, we first visit A itself and then move to its
left subtree B. B is also traversed pre- order. The process goes on until allthe nodes are visited.
The output of pre- order traversal of this tree will be −

A→B→D→E→C→F→G

Post- order Traversal


In this traversal method, the root node is visited last, hence the name. First wetraverse the
left subtree, then the right subtree and finally the root node.

We start from A, and following pre- order traversal, we first visit the left
subtree B. B is also traversed post- order. The process goes on until all the nodes arevisited. The
output of post- order traversal of this tree will be −

D→E→B→F→G→C→A
Binary Search Tree

In a binary tree, every node can have maximum of two children but there is no order of nodes
based on their values. In binary tree, the elements are arranged as they arrive to the tree, from top
to bottom and left to right.
A binary tree has the following time complexities...

• Search Operation - O(n)


• Insertion Operation - O(1)
• Deletion Operation - O(n)
To enhance the performance of binary tree, we use special type of binary tree knownas Binary
Search Tree. Binary search tree mainly focus on the search operation in binary tree. Binary
search tree can be defined as follows..
Binary Search Tree is a binary tree in which every node contains only smaller values in its
left subtree and only larger values in its right subtree.

In a binary search tree, all the nodes in left subtree of any node contains smaller valuesand all the
nodes in right subtree of that contains larger values as shown in following figure...

Example

The following tree is a Binary Search Tree. In this tree, left subtree of every node contains
nodes with smaller values and right subtree of every node contains largervalues.

Note: Every Binary Search Tree is a binary tree but all the Binary Trees need not to bebinary
search trees.

Searching a BST

The property that all the values lesser than the value of a node lies on the left subtree and all the values greater than the value of
a node lies on the right subtree helps to perform the searching in $O(h)$ time (where h is the height of the tree).
Suppose we are on a node and the value to be searched is smaller than the value of the node. In that case, we will search for the
value in the left subtree. Otherwise, if the value to be searched is larger, we will just search the right subtree.
So, our function will take the element to be searched (x) and the tree (T) i.e., SEARCH(x, T).
We will perform the search operation if the root of the tree is not null - if(T.root != null).
We will first check if the data to be searched is at the root or not. If it is at the root, we will return it.
Maximum/Minimum element of a BST

The smallest element of a binary search tree is the leftmost element of the tree and the largest element is the rightmost one.
So, to find the maximum/minimum element, we have to find the rightmost/leftmost element respectively. Thus to find the
maximum element, we will go to the right subtree every time until the rightmost element is found i.e., the right child is null.

So, we will start by passing a node (n) to our function - MAXIMUM(n).


Then, we will move to the right subtree every time until the right child is not null.
Insertion OPERATION IMPLENTATION ON BINARY SEARCH TREE:
Insert function is used to add a new element in a binary search tree at appropriate location. Insert function is to be designed in
such a way that, it must node violate the property of binary search tree at each value.
UNIT-IV
AVL tree: Avl tree is a self-balancing Binary Search Tree (BST) where the difference
between heights of left and right sub trees cannot be more than one for all nodes

AVL Tree can be defined as height balanced binary search tree in which each node is associated
with a balance factor which is calculated by subtracting the height of its right sub-tree from that
of its left sub-tree.

Tree is said to be balanced if balance factor of each node is in between -1 to 1, otherwise, the
tree will be unbalanced and need to be balanced.

Balance Factor (k) = height (left(k)) - height (right(k))


If balance factor of any node is 1, it means that the left sub-tree is one level higher than the
right sub-tree.

If balance factor of any node is 0, it means that the left sub-tree and right sub-tree contain equal
height.

If balance factor of any node is -1, it means that the left sub-tree is one level lower than the right
sub-tree.

An AVL tree is given in the following figure. We can see that, balance factor associated with each
node is in between -1 and +1. therefore, it is an example of AVL tree.
Complexity

Algorithm Average case Worst case

Space o(n) o(n)

Search o(log n) o(log n)

Insert o(log n) o(log n)

Delete o(log n) o(log n)

Operations on AVL tree


Due to the fact that, AVL tree is also a binary search tree therefore, all the operations are
performed in the same way as they are performed in a binary search tree. Searching and
traversing do not lead to the violation in property of AVL tree. However, insertion and deletion
are the operations which can violate this property and therefore, they need to be revisited.

AVL Rotations:

We perform rotation in AVL tree only in case if Balance Factor is other than -1, 0, and 1. There
are basically four types of rotations which are as follows:

1. L L rotation: Inserted node is in the left subtree of left subtree of A


2. R R rotation : Inserted node is in the right subtree of right subtree of A
3. L R rotation : Inserted node is in the right subtree of left subtree of A
4. R L rotation : Inserted node is in the left subtree of right subtree of A

Where node A is the node whose balance Factor is other than -1, 0, 1.

The first two rotations LL and RR are single rotations and the next two rotations LR and RL are
double rotations. For a tree to be unbalanced, minimum height must be at least 2, Let us
understand each rotation

1. RR Rotation
When BST becomes unbalanced, due to a node is inserted into the right subtree of the right
subtree of A, then we perform RR rotation, RR rotation is an anticlockwise rotation, which is
applied on the edge below a node having balance factor -2

In above example, node A has balance factor -2 because a node C is inserted in the right subtree
of A right subtree. We perform the RR rotation on the edge below A.
2. LL Rotation
When BST becomes unbalanced, due to a node is inserted into the left subtree of the left
subtree of C, then we perform LL rotation, LL rotation is clockwise rotation, which is applied on
the edge below a node having balance factor 2.

In above example, node C has balance factor 2 because a node A is inserted in the left subtree
of C left subtree. We perform the LL rotation on the edge below A.

3. LR Rotation
Double rotations are bit tougher than single rotation which has already explained above. LR
rotation = RR rotation + LL rotation, i.e., first RR rotation is performed on subtree and then LL
rotation is performed on full tree, by full tree we mean the first node from the path of inserted
node whose balance factor is other than -1, 0, or 1.

Let us understand each and every step very clearly:

State Action

A node B has been inserted into the


right subtree of A the left subtree of
C, because of which C has become
an unbalanced node having balance
factor 2. This case is L R rotation
where: Inserted node is in the right
subtree of left subtree of C
As LR rotation = RR + LL rotation,
hence RR (anticlockwise) on subtree
rooted at A is performed first. By
doing RR rotation, node A, has
become the left subtree of B.

After performing RR rotation, node C


is still unbalanced, i.e., having
balance factor 2, as inserted node A
is in the left of left of C

Now we perform LL clockwise


rotation on full tree, i.e. on node C.
node C has now become the right
subtree of node B, A is left subtree of
B

Balance factor of each node is now


either -1, 0, or 1, i.e. BST is balanced
now.

4. RL Rotation
As already discussed, that double rotations are bit tougher than single rotation which has
already explained above. R L rotation = LL rotation + RR rotation, i.e., first LL rotation is
performed on subtree and then RR rotation is performed on full tree, by full tree we mean the
first node from the path of inserted node whose balance factor is other than -1, 0, or 1.

State Action
A node B has been inserted into the
left subtree of C the right subtree
of A, because of which A has
become an unbalanced node having
balance factor - 2. This case is RL
rotation where: Inserted node is in
the left subtree of right subtree of A

As RL rotation = LL rotation + RR
rotation, hence, LL (clockwise) on
subtree rooted at C is performed
first. By doing RR rotation,
node C has become the right
subtree of B.

After performing LL rotation,


node A is still unbalanced, i.e. having
balance factor -2, which is because
of the right-subtree of the right-
subtree node A.

Now we perform RR rotation


(anticlockwise rotation) on full tree,
i.e. on node A. node C has now
become the right subtree of node B,
and node A has become the left
subtree of B.

Balance factor of each node is now


either -1, 0, or 1, i.e., BST is balanced
now.

Q: Construct an AVL tree having the following elements


H, I, J, B, A, E, C, F, D, G, K, L

1. Insert H, I, J
On inserting the above elements, especially in the case of H, the BST becomes unbalanced as
the Balance Factor of H is -2. Since the BST is right-skewed, we will perform RR Rotation on node
H.

The resultant balance tree is:

2. Insert B, A
On inserting the above elements, especially in case of A, the BST becomes unbalanced as the
Balance Factor of H and I is 2, we consider the first node from the last inserted node i.e. H. Since
the BST from H is left-skewed, we will perform LL Rotation on node H.

The resultant balance tree is:

3. Insert E
On inserting E, BST becomes unbalanced as the Balance Factor of I is 2, since if we travel from E
to I we find that it is inserted in the left subtree of right subtree of I, we will perform LR Rotation
on node I. LR = RR + LL rotation

3 a) We first perform RR rotation on node B

The resultant tree after RR rotation is:


3b) We first perform LL rotation on the node I

The resultant balanced tree after LL rotation is:

4. Insert C, F, D
On inserting C, F, D, BST becomes unbalanced as the Balance Factor of B and H is -2, since if we
travel from D to B we find that it is inserted in the right subtree of left subtree of B, we will
perform RL Rotation on node I. RL = LL + RR rotation.

4a) We first perform LL rotation on node E

The resultant tree after LL rotation is:

4b) We then perform RR rotation on node B


The resultant balanced tree after RR rotation is:

5. Insert G

On inserting G, BST become unbalanced as the Balance Factor of H is 2, since if we travel from G
to H, we find that it is inserted in the left subtree of right subtree of H, we will perform LR
Rotation on node I. LR = RR + LL rotation.

5 a) We first perform RR rotation on node C

The resultant tree after RR rotation is:


5 b) We then perform LL rotation on node H

The resultant balanced tree after LL rotation is:

6. Insert K
On inserting K, BST becomes unbalanced as the Balance Factor of I is -2. Since the BST is right-
skewed from I to K, hence we will perform RR Rotation on the node I.

The resultant balanced tree after RR rotation is:

7. Insert L

On inserting the L tree is still balanced as the Balance Factor of each node is now either, -1, 0,
+1. Hence the tree is a Balanced AVL tree
B Tree
B Tree is a specialized m-way tree that can be widely used for disk access. A B-Tree of order m
can have at most m-1 keys and m children. One of the main reason of using B tree is its
capability to store large number of keys in a single node and large key values by keeping the
height of the tree relatively small.

A B tree of order m contains all the properties of an M way tree. In addition, it contains the
following properties.

1. Every node in a B-Tree contains at most m children.


2. Every node in a B-Tree except the root node and the leaf node contain at least m/2
children.
3. The root nodes must have at least 2 nodes.
4. All leaf nodes must be at the same level.

It is not necessary that, all the nodes contain the same number of children but, each node must
have m/2 number of nodes.

A B tree of order 4 is shown in the following image.


While performing some
operations on B Tree, any property of B Tree may violate such as number of minimum children a
node can have. To maintain the properties of B Tree, the tree may split or join.

Operations
Searching :
Searching in B Trees is similar to that in Binary search tree. For example, if we search for an item 49 in the following
B Tree. The process will something like following :

1. Compare item 49 with root node 78. since 49 < 78 hence, move to its left sub-tree.

2. Since, 40<49<56, traverse right sub-tree of 40.

3. 49>45, move to right. Compare 49.

4. match found, return.

Searching in a B tree depends upon the height of the tree. The search algorithm takes O(log n) time to search any
element in a B tree.

Inserting
Insertions are done at the leaf node level. The following algorithm needs to be followed in order to insert an item into B
Tree.
1. Traverse the B Tree in order to find the appropriate leaf node at which the node can be inserted.

2. If the leaf node contain less than m-1 keys then insert the element in the increasing order.

3. Else, if the leaf node contains m-1 keys, then follow the following steps.

o Insert the new element in the increasing order of elements.


o Split the node into the two nodes at the median.
o Push the median element upto its parent node.
o If the parent node also contain m-1 number of keys, then split it too by following
the same steps.

Example:

Insert the node 8 into the B Tree of order 5 shown in the following image.

8 will be inserted to the right of 5, therefore insert 8.

Example 1

Delete the node 53 from the B Tree of order 5 shown in the following figure.

53 is present in the right child of element 49. Delete it.


Now, 57 is the only element which is left in the node, the minimum number of elements that
must be present in a B tree of order 5, is 2. it is less than that, the elements in its left and right
sub-tree are also not sufficient therefore, merge it with the left sibling and intervening element
of parent i.e. 49.

The node, now contain 5 keys which is greater than (5 -1 = 4 ) keys. Therefore split the node
from the median i.e. 8 and push it up to its parent node shown as follows.

Deletion
Deletion is also performed at the leaf nodes. The node which is to be deleted can either be a leaf
node or an internal node. Following algorithm needs to be followed in order to delete a node
from a B tree.

Red Black Tree


A Red Black Tree is a type of self-balancing binary search tree, in which every node is colored
with a red or black. The red black tree satisfies all the properties of the binary search tree but
there are some additional properties which were added in a Red Black Tree. The height of a Red-
Black tree is O(Logn) where (n is the number of nodes in the tree).

Properties of Red Black Tree


1. The root node should always be black in color.
2. Every null child of a node is black in red black tree.
3. The children of a red node are black. It can be possible that parent of red node is black
node.
4. All the leaves have the same black depth.
5. Every simple path from the root node to the (downward) leaf node contains the same
number of black nodes.

Representation of Red Black Tree

While representing the red black tree color of each node should be shown. In this tree leaf
nodes are simply termed as null nodes which means they are not physical nodes. It can be
checked easily in the above-given tree there are two types of node in which one of them is red
and another one is black in color. The above-given tree follows all the properties of a red black
tree that are

1. It is a binary search tree.


2. The root node is black.
3. The children’s of red node are black.
4. All the root to external node paths contain same number of black nodes.
Example: Consider path 75-90-80-88-null and 75-40-30-null in both these paths 3 black
nodes are there.

Advantages of Red Black Tree


1. Red black tree are useful when we need insertion and deletion relatively frequent.
2. Red-black trees are self-balancing so these operations are guaranteed to be O(logn).
3. They have relatively low constants in a wide variety of scenarios.

You might also like