0% found this document useful (0 votes)
87 views

Data Structures With C++

This document discusses data structures and arrays in C++. It defines data structures as a way to organize and store data so that operations can be performed efficiently. Arrays are introduced as a basic data structure that allows storing multiple values of the same type in contiguous memory locations. The document covers declaring, initializing, and accessing single and multi-dimensional arrays in C++. It also provides an example program that calculates the sum of values in a single-dimensional array.

Uploaded by

esen turkay
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
87 views

Data Structures With C++

This document discusses data structures and arrays in C++. It defines data structures as a way to organize and store data so that operations can be performed efficiently. Arrays are introduced as a basic data structure that allows storing multiple values of the same type in contiguous memory locations. The document covers declaring, initializing, and accessing single and multi-dimensional arrays in C++. It also provides an example program that calculates the sum of values in a single-dimensional array.

Uploaded by

esen turkay
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 198

Cihan university/Sulaimany

Data structures with C++


2nd Stage
Data Structure
• Data Structure is a way of collecting and
organizing data in such a way that we can
perform operations on these data in an
effective way. Data Structures is about
rendering data elements in terms of some
relationship, for better organization and
storage.

09/11/2021 Asst.lec.Asan Bakir 2


Data Structure
• For example, we have data player's name “David" and
age 26. Here “David" is of String data type and 26 is
of integer data type.
• We can organize this data as a record like Player record.
Now we can collect and store player's records in a file
or database as a data structure. For example: "David"
30, “Poul" 31, “Steaven" 33
• In simple language, Data Structures are structures
programmed to store ordered data, so that various
operations can be performed on it easily.

09/11/2021 Asst.lec.Asan Bakir 3


Basic types of Data Structures
• Anything that can store data can be called as a data
structure, hence Integer, Float, Boolean, Char etc, all are
data structures. They are known as Primitive Data
Structures.
• Then we also have some complex Data Structures, which
are used to store large and connected data. Some example
of Abstract Data Structure are :
– Linked List
– Tree
– Graph
– Stack, Queue etc.

09/11/2021 Asst.lec.Asan Bakir 4


Types of data structures

09/11/2021 Asst.lec.Asan Bakir 5


What is Algorithm ?
• An algorithm is a finite set of instructions or logic, written in
order, to accomplish a certain predefined task. Algorithm is not
the complete code or program, it is just the core logic(solution)
of a problem, which can be expressed either as an informal high
level description as pseudocode or using a flowchart.

• An algorithm is said to be efficient and fast, if it takes less time


to execute and consumes less memory space. The performance
of an algorithm is measured on the basis of following
properties :

– Time Complexity
– Space Complexity
09/11/2021 Asst.lec.Asan Bakir 6
Time Complexity
• Time complexity of an algorithm signifies the
total time required by the program to run to
completion. The time complexity of algorithms
is most commonly expressed using the big O
notation.
• Time Complexity is most commonly estimated
by counting the number of elementary
functions performed by the algorithm.

09/11/2021 Asst.lec.Asan Bakir 7


Space Complexity
• Its the amount of memory space required by the algorithm,
during the course of its execution. Space complexity must be
taken seriously for multi-user systems and in situations where
limited memory is available.
• An algorithm generally requires space for following components :

– Instruction Space : Its the space required to store the executable version
of the program. This space is fixed, but varies depending upon the
number of lines of code in the program.
– Data Space : Its the space required to store all the constants and
variables value.
– Environment Space : Its the space required to store the environment
information needed to resume the suspended function.

09/11/2021 Asst.lec.Asan Bakir 8


Arrays
• An array is a series of elements of the same type placed in
contiguous memory locations that can be individually
referenced by adding an index to a unique identifier.

That means that, for example, five values of type int can


be declared as an array without having to declare 5
different variables (each with its own identifier). Instead,
using an array, the five int values are stored in contiguous
memory locations, and all five can be accessed using the
same identifier, with the proper index.

09/11/2021 Asst.lec.Asan Bakir 9


Arrays
• For example, an array containing 5 integer values of
type int called foo could be represented as:

• where each blank panel represents an element of the array. In


this case, these are values of type int. These elements are
numbered from 0 to 4, being 0 the first and 4 the last; In C++,
the first element in an array is always numbered with a zero (not
a one), no matter its length.
09/11/2021 Asst.lec.Asan Bakir 10
Arrays
• Like a regular variable, an array must be declared before it is used. A
typical declaration for an array in C++ is:

type name [elements];

where type is a valid type (such as int, float...), name is a valid identifier


and the elements field (which is always enclosed in square brackets []),
specifies the length of the array in terms of the number of elements.

Therefore, the foo array, with five elements of type int, can be declared


as:

 int foo [5];

09/11/2021 Asst.lec.Asan Bakir 11


Initializing arrays
• the elements in an array can be explicitly initialized to
specific values when it is declared, by enclosing those initial
values in braces {}. For example:

• int foo [5] = { 16, 2, 77, 40, 12071 };

• This statement declares an array that can be represented like


this:

09/11/2021 Asst.lec.Asan Bakir 12


Initializing arrays
• The number of values between braces {} shall not be greater than
the number of elements in the array. For example, in the example
above, foo was declared having 5 elements (as specified by the
number enclosed in square brackets, []), and the
braces {} contained exactly 5 values, one for each element.
• If declared with less, the remaining elements are set to their
default values (which for fundamental types, means they are
filled with zeroes). For example:
• int bar [5] = { 10, 20, 30 };

Will create an array like this:

09/11/2021 Asst.lec.Asan Bakir 13


Initializing arrays
• The initializer can even have no values, just
the braces: 
• int baz [5] = { };

This creates an array of five int values, each


initialized with a value of zero:

09/11/2021 Asst.lec.Asan Bakir 14


Initializing arrays
• When an initialization of values is provided for an
array, C++ allows the possibility of leaving the square
brackets empty[]. In this case, the compiler will
assume automatically a size for the array that matches
the number of values included between the braces {}:

 int foo [] = { 16, 2, 77, 40, 12071 };

• After this declaration, array foo would be 5 int long,


since we have provided 5 initialization values.
09/11/2021 Asst.lec.Asan Bakir 15
Initializing arrays
• Finally, the evolution of C++ has led to the adoption of universal
initialization also for arrays. Therefore, there is no longer need for the
equal sign between the declaration and the initializer. Both these
statements are equivalent:

int foo[] = { 10, 20, 30 };


int foo[] { 10, 20, 30 };

Static arrays, and those declared directly in a namespace (outside any


function), are always initialized. If no explicit initializer is specified, all
the elements are default-initialized (with zeroes, for fundamental
types).

09/11/2021 Asst.lec.Asan Bakir 16


Accessing the values of an array
• The values of any of the elements in an array can be accessed just like the
value of a regular variable of the same type. The syntax is:

name[index]

Following the previous examples in which foo had 5 elements and each of


those elements was of type int, the name which can be used to refer to
each element is the following:

09/11/2021 Asst.lec.Asan Bakir 17


Accessing the values of an array
• For example, the following statement stores the value 75 in the third
element of foo:
 
foo [2] = 75;
and, for example, the following copies the value of the third element
of foo to a variable called x:
 
x = foo[2];

Therefore, the expression foo[2] is itself a variable of type int.

09/11/2021 Asst.lec.Asan Bakir 18


Accessing the values of an array
• Do not confuse these two possible uses of
brackets [] with arrays.

int foo[5]; // declaration of a new array


foo[2] = 75; // access to an element of the array.

The main difference is that the declaration is preceded


by the type of the elements, while the access is not.

09/11/2021 Asst.lec.Asan Bakir 19


Array example
// arrays example
#include <iostream>
using namespace std;
 
int foo [] = {16, 2, 77, 40, 12071};
int n, result=0;
 
int main ()
{
for ( n=0 ; n<5 ; ++n )
{
result += foo[n];
}
cout << result;
system("pause");
return 0;
}
Result =12206
09/11/2021 Asst.lec.Asan Bakir 20
09/11/2021 Asst.lec.Asan Bakir 21
Multidimensional arrays
• Multidimensional arrays can be described as
"arrays of arrays". For example, a
bidimensional array can be imagined as a two-
dimensional table made of elements, all of
them of a same uniform data type.

09/11/2021 Asst.lec.Asan Bakir 22


Multidimensional arrays

• jimmy represents a bidimensional array of 3 per 5


elements of type int. The C++ syntax for this is:
•  
• int jimmy [3][5];
09/11/2021 Asst.lec.Asan Bakir 23
Multidimensional arrays
• and, for example, the way to reference the second
element vertically and fourth horizontally in an
expression would be: 
• jimmy[1][3]

 
(remember that array indices always begin with zero).

09/11/2021 Asst.lec.Asan Bakir 24


Multidimensional arrays
• multidimensional arrays are just an abstraction for
programmers, since the same results can be achieved
with a simple array, by multiplying its indices:

int jimmy [3][5]; // is equivalent to


int jimmy [15]; // (3 * 5 = 15)

• With the only difference that with multidimensional


arrays, the compiler automatically remembers the
depth of each imaginary dimension.
09/11/2021 Asst.lec.Asan Bakir 25
Multidimensional arrays
The following two pieces of code produce the exact same result, but one
uses a bidimensional array while the other uses a simple array: 
multidimensional array pseudo-multidimensional array

#define WIDTH 5
#define WIDTH 5
#define HEIGHT 3
#define HEIGHT 3
int jimmy [HEIGHT * WIDTH];
int jimmy [HEIGHT][WIDTH];
int n,m;
int n,m;
int main ()
int main ()
{
{
for (n=0; n<HEIGHT; n++)
for (n=0; n<HEIGHT; n++)
for (m=0; m<WIDTH; m++)
for (m=0; m<WIDTH; m++)
{
{
jimmy[n][m]=(n+1)*(m+1);
jimmy[n*WIDTH+m]=(n+1)*(m+1);
}
}
}
}

09/11/2021 Asst.lec.Asan Bakir 26


Multidimensional arrays
• None of the two code snippets above produce any output
on the screen, but both assign values to the memory block
called jimmy in the following way: 

 
Note that the code uses defined constants for the width
and height, instead of using directly their numerical values.
This gives the code a better readability, and allows changes
in the code to be made easily in one place.

09/11/2021 Asst.lec.Asan Bakir 27


Arrays as parameters
• At some point, we may need to pass an array
to a function as a parameter. In C++, it is not
possible to pass the entire block of memory
represented by an array to a function directly
as an argument. But what can be passed
instead is its address. In practice, this has
almost the same effect, and it is a much faster
and more efficient operation.

09/11/2021 Asst.lec.Asan Bakir 28


Arrays as parameters
• To accept an array as parameter for a function,
the parameters can be declared as the array
type, but with empty brackets, omitting the
actual size of the array. For example:

void procedure (int arg[])

09/11/2021 Asst.lec.Asan Bakir 29


Arrays as parameters
• This function accepts a parameter of type
"array of int" called arg. In order to pass to this
function an array declared as: 
int myarray [40];
• it would be enough to write a call like this: 
procedure (myarray);

09/11/2021 Asst.lec.Asan Bakir 30


Arrays as parameters
#include <iostream>
using namespace std;
void printarray (int arg[], int length) {
for (int n=0; n<length; ++n)
cout << arg[n] << ' ';
cout << '\n';
}
int main ()
{
int firstarray[] = {5, 10, 15};
int secondarray[] = {2, 4, 6, 8, 10};
printarray (firstarray,3);
printarray (secondarray,5);
system("pause");
return 0;
}

09/11/2021 Asst.lec.Asan Bakir 31


Arrays as parameters
• In this example, the first parameter (int arg[])
accepts any array whose elements are of type int,
whatever its length. For that reason, we have
included a second parameter that tells the
function the length of each array that we pass to it
as its first parameter. This allows the for loop that
prints out the array to know the range to iterate in
the array passed, without going out of range.

09/11/2021 Asst.lec.Asan Bakir 32


Character sequences
• because strings are, in fact, sequences of
characters, we can represent them also as
plain arrays of elements of a character type.
For example, the following array:

char foo [20];

09/11/2021 Asst.lec.Asan Bakir 33


Character sequences
 
char foo [20];
is an array that can store up to 20 elements of type char. It can
be represented as:

Therefore, this array has a capacity to store sequences of up to 20


characters. But this capacity does not need to be fully exhausted:
the array can also accommodate shorter sequences. For example,
at some point in a program, either the sequence "Hello" or the
sequence "Merry Christmas" can be stored in foo, since both
would fit in a sequence with a capacity for 20 characters.

09/11/2021 Asst.lec.Asan Bakir 34


Character sequences
• By convention, the end of strings represented in character sequences is
signaled by a special character: the null character, whose literal value can be
written as '\0' (backslash, zero).

In this case, the array of 20 elements of type char called foo can be


represented storing the character sequences "Hello"and "Merry Christmas" as:

 
Notice how after the content of the string itself, a null character ('\0') has been
added in order to indicate the end of the sequence. The panels in gray color
represent char elements with undetermined values.

09/11/2021 Asst.lec.Asan Bakir 35


Initialization of null-terminated character
sequences
• Because arrays of characters are ordinary
arrays, they follow the same rules as these.
For example, to initialize an array of characters
with some predetermined sequence of
characters, we can do it just like any other
array: 
 
char myword[] = { 'H', 'e', 'l', 'l', 'o', '\0' };

09/11/2021 Asst.lec.Asan Bakir 36


Initialization of null-terminated character
sequences
• The above declares an array of 6 elements of
type char initialized with the characters that form the
word "Hello" plus anull character '\0' at the end.

But arrays of character elements have another way to be


initialized: using string literals directly.

string literals have already shown up several times. These are


specified by enclosing the text between double quotes ("). For
example:
 
"the result is: "

09/11/2021 Asst.lec.Asan Bakir 37


Initialization of null-terminated character
sequences
• Sequences of characters enclosed in double-quotes (")
are literal constants. And their type is, in fact, a null-
terminated array of characters. This means that string
literals always have a null character ('\0') automatically
appended at the end.

Therefore, the array of char elements called myword can


be initialized with a null-terminated sequence of
characters by either one of these two statements:
• char myword[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
• char myword[] = "Hello";
09/11/2021 Asst.lec.Asan Bakir 38
Initialization of null-terminated character
sequences
• In both cases, the array of
characters myword is declared with a size of 6
elements of type char: the 5 characters that
compose the word "Hello", plus a final null
character ('\0'), which specifies the end of the
sequence and that, in the second case, when
using double quotes (") it is appended
automatically.

09/11/2021 Asst.lec.Asan Bakir 39


Strings and null-terminated character
sequences
// strings and NTCS:
#include <iostream>
#include <string>
using namespace std;
 
int main ()
What is your name? Omer
{
Where do you live? Greece
char question1[] = "What is your name? ";
string question2 = "Where do you live? ";
Hello, Omer from Greece!
char answer1 [80];
string answer2;
cout << question1;
cin >> answer1;
cout << question2;
cin >> answer2;
cout << "Hello, " << answer1;
cout << " from " << answer2 << "!\n";
return 0;
}
09/11/2021 Asst.lec.Asan Bakir 40
Strings and null-terminated character
sequences
• In this example, both arrays of characters using null-
terminated sequences and strings are used. They are quite
interchangeable in their use together with cin and cout, but
there is a notable difference in their declarations: arrays have a
fixed size that needs to be specified either implicit or explicitly
when declared; question1 has a size of exactly 20 characters
(including the terminating null-characters) and answer1 has a
size of 80 characters; while strings are simply strings, no size is
specified. This is due to the fact that strings have a dynamic
size determined during runtime, while the size of arrays is
determined on compilation, before the program runs.

09/11/2021 Asst.lec.Asan Bakir 41


Pointers and arrays
• The concept of arrays is related to that of pointers. In
fact, arrays work very much like pointers to their first
elements, and, actually, an array can always be
implicitly converted to the pointer of the proper type.
For example, consider these two declarations:
– int myarray [20];
– int * mypointer;

• The following assignment operation would be valid:  


mypointer = myarray;

09/11/2021 Asst.lec.Asan Bakir 42


Pointers and arrays
• After that, mypointer and myarray would be
equivalent and would have very similar
properties. The main difference being
that mypointer can be assigned a different
address, whereas myarray can never be assigned
anything, and will always represent the same
block of 20 elements of type int. Therefore, the
following assignment would not be valid:
 myarray = mypointer;

09/11/2021 Asst.lec.Asan Bakir 43


Pointers and arrays
// more pointers
#include <iostream>
using namespace std;
 
int main ()
{
int numbers[5];
int * p;
p = numbers; *p = 10;
p++; *p = 20;
p = &numbers[2]; *p = 30;
p = numbers + 3; *p = 40;
p = numbers; *(p+4) = 50;
for (int n=0; n<5; n++)
cout << numbers[n] << ", ";
return 0;
}
09/11/2021 Asst.lec.Asan Bakir 44
Pointers and arrays
• Pointers and arrays support the same set of
operations, with the same meaning for both.
The main difference being that pointers can be
assigned new addresses, while arrays cannot.

09/11/2021 Asst.lec.Asan Bakir 45


Pointers and arrays
• In the arrays, brackets ([]) were explained as specifying the index of an
element of the array. Well, in fact these brackets are a dereferencing
operator known as offset operator. They dereference the variable they
follow just as *does, but they also add the number between brackets to
the address being dereferenced. For example:

– a[5] = 0; // a [offset of 5] = 0
– *(a+5) = 0; // pointed to by (a+5) = 0

These two expressions are equivalent and valid, not only if a is a pointer,
but also if a is an array.

09/11/2021 Asst.lec.Asan Bakir 46


Data Structure with C++

Types of Sorting Techniques

2nd stage

09/11/2021 Asst.lect. Asan Bakir 47


Types of Sorting Techniques
• Bubble Sort
• Insertion Sort
• Selection Sort
• Quick Sort
• Merge Sort
• Heap Sort

09/11/2021 Asst.lect. Asan Bakir 48


Bubble Sorting
• Bubble Sort is an algorithm which is used to sort N elements
that are given in a memory for eg: an Array with N number
of elements. Bubble Sort compares all the element one by
one and sort them based on their values.
• It is called Bubble sort, because with each iteration the
smaller element in the list bubbles up towards the first place,
just like a water bubble rises up to the water surface.
• Sorting takes place by stepping through all the data items
one-by-one in pairs and comparing adjacent data items and
swapping each pair that is out of order.

09/11/2021 Asst.lect. Asan Bakir 49


Bubble Sorting

09/11/2021 Asst.lect. Asan Bakir 50


Sorting using Bubble Sort Algorithm
• Let's consider an array with values {5, 1, 6, 2, 4, 3}
int a[6] = {5, 1, 6, 2, 4, 3};
int i, j, temp;
for(i=0; i<6; i++)
{
for(j=0; j<6-i-1; j++)
{
if( a[j] > a[j+1])
{
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
//now you can print the sorted array after this
09/11/2021 Asst.lect. Asan Bakir 51
Sorting using Bubble Sort Algorithm

• Note: Above is the algorithm, to sort an array


using Bubble Sort. Although the above logic
will sort and unsorted array, still the above
algorithm isn't efficient and can be enhanced
further. Because as per the above logic, the for
loop will keep going for six iterations even if
the array gets sorted after the second
iteration.

09/11/2021 Asst.lect. Asan Bakir 52


Sorting using Bubble Sort Algorithm

• Hence we can insert a flag and can keep


checking whether swapping of elements is
taking place or not. If no swapping is taking
place that means the array is sorted and we
can jump out of the for loop.

09/11/2021 Asst.lect. Asan Bakir 53


Sorting using Bubble Sort Algorithm
int a[6] = {5, 1, 6, 2, 4, 3};
int i, j, temp;
for(i=0; i<6; i++) In this code, if in a complete
{ single cycle of j iteration(inner
int flag = 0; //taking a flag variable for loop), no swapping takes
for(j=0; j<6-i-1; j++) place, and flag remains 0, then
{ we will break out of the for
if( a[j] > a[j+1]) loops, because the array has
{
already been sorted.
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
flag = 1; //setting flag as 1, if swapping occurs
}
}
if(!flag) //breaking out of for loop if no swapping takes place
{
break;
}
}
09/11/2021 Asst.lect. Asan Bakir 54
Insertion Sorting
• It is a simple Sorting algorithm which sorts the array by shifting elements
one by one. Following are some of the important characteristics of
Insertion Sort.

1. It has one of the simplest implementation


2. It is efficient for smaller data sets, but very inefficient for larger lists.
3. Insertion Sort is adaptive, that means it reduces its total number of steps
if given a partially sorted list, hence it increases its efficiency.
4. It is better than Selection Sort and Bubble Sort algorithms.
5. Its space complexity is less, like Bubble Sorting, insertion sort also
requires a single additional memory space.
6. It is Stable, as it does not change the relative order of elements with
equal keys

09/11/2021 Asst.lect. Asan Bakir 55


Insertion Sorting

09/11/2021 Asst.lect. Asan Bakir 56


How Insertion Sorting Works

09/11/2021 Asst.lect. Asan Bakir 57


Sorting using Insertion Sort Algorithm
int a[6] = {5, 1, 6, 2, 4, 3};
int i, j, key;
for(i=1; i<6; i++){
key = a[i];
j = i-1;
while(j>=0 && key < a[j])
{
a[j+1] = a[j];
j--;
}
a[j+1] = key;
}

09/11/2021 Asst.lect. Asan Bakir 58


Sorting using Insertion Sort Algorithm
• We took an array with 6 integers. We took a variable key, in
which we put each element of the array, in each pass, starting
from the second element, that is a[1].
• Then using the while loop, we iterate, until j becomes equal to
zero or we find an element which is greater than key, and then
we insert the key at that position.
• In the above array, first we pick 1 as key, we compare it with
5(element before 1), 1 is smaller than 5, we shift 1 before 5.
Then we pick 6, and compare it with 5 and 1, no shifting this
time. Then 2 becomes the key and is compared with, 6 and 5,
and then 2 is placed after 1. And this goes on, until complete
array gets sorted.

09/11/2021 Asst.lect. Asan Bakir 59


Insertion Sorting in C++
#include <iostream>
using namespace std;
//member functions declaration
void insertionSort(int arr[], int length);
void printArray(int array[],int size);
int main()
{
int array[5]= {5,4,3,2,1};
insertionSort(array,5);
return 0;
}

09/11/2021 Asst.lect. Asan Bakir 60


void insertionSort(int arr[], int length)
{
int i, j ,tmp;
for (i = 1; i < length; i++) {
j = i;
while (j > 0 && arr[j - 1] > arr[j])
{
tmp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = tmp;
j--;
}
printArray(arr,5);
}
}

09/11/2021 Asst.lect. Asan Bakir 61


void printArray(int array[], int size)
{
cout<< "Sorting the array using Insertion sort ";
int j;
for (j=0; j < size;j++)
for (j=0; j < size;j++)
cout <<" "<< array[j];
cout << endl;
}

09/11/2021 Asst.lect. Asan Bakir 62


Selection Sorting
• Selection sorting is conceptually the most
simplest sorting algorithm. This algorithm first
finds the smallest element in the array and
exchanges it with the element in the first
position, then find the second smallest
element and exchange it with the element in
the second position, and continues in this way
until the entire array is sorted.

09/11/2021 Asst.lect. Asan Bakir 63


How Selection Sorting Works

09/11/2021 Asst.lect. Asan Bakir 64


How Selection Sorting Works
• In the first pass, the smallest element found is
1, so it is placed at the first position, then
leaving first element, smallest element is
searched from the rest of the elements, 3 is
the smallest, so it is then placed at the second
position. Then we leave 1 and 3, from the rest
of the elements, we search for the smallest
and put it at third position and keep doing
this, until array is sorted.
09/11/2021 Asst.lect. Asan Bakir 65
Sorting using Selection Sort Algorithm
void selectionSort(int a[], int size)
{
int i, j, min, temp;
for(i=0; i < size-1; i++ ) {
min = i; //setting min as i
for(j=i+1; j < size; j++) {
if(a[j] < a[min]) //if element at j is less than element at min position
{
min = j; //then set min as j
}
}
temp = a[i];
a[i] = a[min];
a[min] = temp;
}}

09/11/2021 Asst.lect. Asan Bakir 66


Quick Sort Algorithm
• Quick Sort, as the name suggests, sorts any list
very quickly. Quick sort is not stable search, but it
is very fast and requires very less additional space.
It is based on the rule of Divide and Conquer(also
called partition-exchange sort). This algorithm
divides the list into three main parts :
1. Elements less than the Pivot element
2. Pivot element
3. Elements greater than the pivot element

09/11/2021 Asst.lect. Asan Bakir 67


How Quick Sorting Works

09/11/2021 Asst.lect. Asan Bakir 68


How Quick Sorting Works
• In the list of elements, mentioned in below example,
we have taken 25 as pivot. So after the first pass, the
list will be changed like this.
• 6 8 17 14 25 63 37 52
• Hence after the first pass, pivot will be set at its
position, with all the elements smaller to it on its left
and all the elements larger than it on the right. Now 6
8 17 14 and 63 37 52 are considered as two separate
lists, and same logic is applied on them, and we keep
doing this until the complete list is sorted.
09/11/2021 Asst.lect. Asan Bakir 69
Sorting using Quick Sort Algorithm
/* a[] is the array, p is starting index, that is 0, and r is the last index of array.
*/ 
void quicksort(int a[], int p, int r) {
if(p < r) {
int q;
q = partition(a, p, r);
quicksort(a, p, q);
quicksort(a, q+1, r);
}

int partition(int a[], int p, int r){
int i, j, pivot, temp;
pivot = a[p];

09/11/2021 Asst.lect. Asan Bakir 70


i = p;
j = r;
while(1) {
while(a[i] < pivot && a[i] != pivot)
i++;
while(a[j] > pivot && a[j] != pivot)
j--;
if(i < j) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
else {
return j;
}
}
}
09/11/2021 Asst.lect. Asan Bakir 71
Merge Sort Algorithm
• Merge Sort follows the rule of Divide and Conquer. But it
doesn't divides the list into two halves. In merge sort the
unsorted list is divided into N sublists, each having one
element, because a list of one element is considered
sorted. Then, it repeatedly merge these sublists, to
produce new sorted sublists, and at lasts one sorted list is
produced.
• Merge Sort is quite fast, and has a time complexity of O(n
log n). It is also a stable sort, which means the "equal"
elements are ordered in the same order in the sorted list.

09/11/2021 Asst.lect. Asan Bakir 72


How Merge Sort Works

• Like we can see in the above example, merge sort first breaks the unsorted list
into sorted sublists, and then keep merging these sublists, to finlly get the
complete sorted list.
09/11/2021 Asst.lect. Asan Bakir 73
Sorting using Merge Sort Algorithm
• /* a[] is the array, p is starting index, that is 0, and r is the last
index of array.  Lets take a[5] = {32, 45, 67, 2, 7} as the array to
be sorted. */
 void mergesort(int a[], int p, int r){
int q;
if(p < r) { q = floor( (p+r) / 2);
mergesort(a, p, q);
mergesort(a, q+1, r);
merge(a, p, q, r);
}
}

09/11/2021 Asst.lect. Asan Bakir 74


void merge(int a[], int p, int q, int r){
int b[5]; //same size of a[]
int i, j, k;
k = 0;
i = p; j = q+1;
while(i <= q && j <= r) {
if(a[i] < a[j]) {
b[k++] = a[i++]; // same as b[k]=a[i]; k++; i++; }

09/11/2021 Asst.lect. Asan Bakir 75


else {
b[k++] = a[j++];
}
}
while(i <= q) { b[k++] = a[i++];
}
while(j <= r) {
b[k++] = a[j++];
}
for(i=r; i >= p; i--) {
a[i] = b[--k]; // copying back the sorted list to a[] }  
}
09/11/2021 Asst.lect. Asan Bakir 76
Heap Sort Algorithm
• Heap Sort is one of the best sorting methods
being in-place and with no quadratic worst-
case scenarios. Heap sort algorithm is divided
into two basic parts :
– Creating a Heap of the unsorted list.
– Then a sorted array is created by repeatedly
removing the largest/smallest element from the
heap, and inserting it into the array. The heap is
reconstructed after each removal.

09/11/2021 Asst.lect. Asan Bakir 77


What is a Heap ?
• Heap is a special tree-based data structure,
that satisfies the following special heap
properties :
• Shape Property : Heap data structure is
always a Complete Binary Tree, which means
all levels of the tree are fully filled.

09/11/2021 Asst.lect. Asan Bakir 78


09/11/2021 Asst.lect. Asan Bakir 79
• Heap Property : All nodes are either [greater
than or equal to] or [less than or equal
to] each of its children. If the parent nodes are
greater than their children, heap is called
a Max-Heap, and if the parent nodes are
smalled than their child nodes, heap is
called Min-Heap.

09/11/2021 Asst.lect. Asan Bakir 80


09/11/2021 Asst.lect. Asan Bakir 81
How Heap Sort Works
• Initially on receiving an unsorted list, the first step in
heap sort is to create a Heap data structure(Max-Heap
or Min-Heap). Once heap is built, the first element of
the Heap is either largest or smallest(depending upon
Max-Heap or Min-Heap), so we put the first element of
the heap in our array. Then we again make heap using
the remaining elements, to again pick the first element
of the heap and put it into the array. We keep on doing
the same repeatedly until we have the complete sorted
list in our array.

09/11/2021 Asst.lect. Asan Bakir 82


• In the this algorithm,
initially heapsort() function is called, which
calls buildheap() to build heap, which inturn
uses satisfyheap() to build the heap.

09/11/2021 Asst.lect. Asan Bakir 83


Sorting using Heap Sort Algorithm
void heapsort(int[], int);
void buildheap(int [], int);
void satisfyheap(int [], int, int); 
void main(){
int a[10], i, size;
cout << "Enter size of list"; // less than 10, because max size of array is 10 cin
>> size;
cout << "Enter" << size << "elements";
for( i=0; i < size; i++) {
cin >> a[i];
} heapsort(a, size);
getch();
}

09/11/2021 Asst.lect. Asan Bakir 84


void heapsort(int a[], int length){
buildheap(a, length);
int heapsize, i, temp;
heapsize = length - 1;
for( i=heapsize; i >= 0; i--) {
temp = a[0];
a[0] = a[heapsize];
a[heapsize] = temp;
heapsize--;
satisfyheap(a, 0, heapsize);
}
for( i=0; i < length; i++)
{ cout << "\t" << a[i];
}
}
09/11/2021 Asst.lect. Asan Bakir 85
void buildheap(int a[], int length){
int i, heapsize;
heapsize = length - 1;
for( i=(length/2);
i >= 0; i--) {
satisfyheap(a, i, heapsize);
}

void satisfyheap(int a[], int i, int heapsize){ int l, r, largest, temp;
l = 2*i;
r = 2*i + 1;

09/11/2021 Asst.lect. Asan Bakir 86


if(l <= heapsize && a[l] > a[i]) {
largest = l;
}
else {
largest = i;
}
if( r <= heapsize && a[r] > a[largest]) { largest = r;
} if(largest != i) {
temp = a[i];
a[i] = a[largest];
a[largest] = temp;
satisfyheap(a, largest, heapsize);
}
}

09/11/2021 Asst.lect. Asan Bakir 87


Data Structures

Stacks & Queue


2nd stage

88
Stacks
• Stack is an abstract data type with a bounded
(predefined) capacity. It is a simple data
structure that allows adding and removing
elements in a particular order. Every time an
element is added, it goes on the top of the
stack, the only element that can be removed is
the element that was at the top of the stack,
just like a pile of objects.

89
Stack data structure

90
Basic features of Stack
• Stack is an ordered list of similar data type.
• Stack is a LIFO structure. (Last in First out).
• push() function is used to insert new elements into
the Stack and pop() is used to delete an element
from the stack. Both insertion and deletion are
allowed at only one end of Stack called Top.
• Stack is said to be in Overflow state when it is
completely full and is said to be in Underflow state
if it is completely empty.

91
Applications of Stack
• The simplest application of a stack is to
reverse a word. You push a given word to stack
- letter by letter - and then pop letters from
the stack.
• There are other uses also
like : Parsing, Expression Conversion(Infix to
Postfix, Postfix to Prefix etc) and many more.

92
Implementation of Stack
• Stack can be easily implemented using an
Array or a Linked List. Arrays are quick, but are
limited in size and Linked List requires
overhead to allocate, link, unlink, and
deallocate, but is not limited in size. Here we
will implement Stack using array.

93
94
Push Operation
• The process of putting a new data element onto
stack is known as a Push Operation. Push
operation involves a series of steps −
– Step 1 − Checks if the stack is full.
– Step 2 − If the stack is full, produces an error and exit.
– Step 3 − If the stack is not full, increments top to point
next empty space.
– Step 4 − Adds data element to the stack location,
where top is pointing.
– Step 5 − Returns success.
95
96
Pop Operation
• Accessing the content while removing it from
the stack, is known as a Pop Operation. In an
array implementation of pop() operation, the
data element is not actually removed,
instead top is decremented to a lower position
in the stack to point to the next value. But in
linked-list implementation, pop() actually
removes data element and deallocates
memory space.
97
• A Pop operation may involve the following
steps −
– Step 1 − Checks if the stack is empty.
– Step 2 − If the stack is empty, produces an error
and exit.
– Step 3 − If the stack is not empty, accesses the
data element at which top is pointing.
– Step 4 − Decreases the value of top by 1.
– Step 5 − Returns success.

98
99
• Stacks have some useful terminology associated with
them:
• Push To add an element to the stack
• Pop To remove an element from the stock
• Peek To look at elements in the stack without removing
them
• LIFO Refers to the last in, first out behavior of the stack
• FILO Equivalent to LIFO

100
Position of Top Status of Stack

-1 Stack is Empty

0 Only one element in Stack

N-1 Stack is Full

N Overflow state of Stack

101
Data Structures

Queue Data Structures

102
Queue Data Structures
• Queue is also an abstract data type or a linear data
structure, in which the first element is inserted from
one end called REAR(also called tail), and the
deletion of existing element takes place from the
other end called as FRONT(also called head). This
makes queue as FIFO data structure, which means
that element inserted first will also be removed first.
• The process to add an element into queue is
called Enqueue and the process of removal of an
element from queue is called Dequeue.
103
104
Basic features of Queue
• Like Stack, Queue is also an ordered list of elements of similar
data types.

• Queue is a FIFO( First in First Out ) structure.

• Once a new element is inserted into the Queue, all the


elements inserted before the new element in the queue must
be removed, to remove the new element.

• peek( ) function is oftenly used to return the value of first


element without dequeuing it.

105
Applications of Queue
• Queue, as the name suggests is used whenever we need to have any
group of objects in an order in which the first one coming in, also gets
out first while the others wait for there turn, like in the following
scenarios :

• Serving requests on a single shared resource, like a printer, CPU task


scheduling etc.

• In real life, Call Center phone systems will use Queues, to hold people
calling them in an order, until a service representative is free.

• Handling of interrupts in real-time systems. The interrupts are handled in


the same order as they arrive, First come first served.

106
Implementation of Queue
• Queue can be implemented using an Array, Stack or
Linked List. The easiest way of implementing a
queue is by using an Array.
• Initially the head(FRONT) and the tail(REAR) of the
queue points at the first index of the array (starting
the index of array from 0). As we add elements to
the queue, the tail keeps on moving ahead, always
pointing to the position where the next element will
be inserted, while the head remains at the first
index.
107
Queue Using Array
• structure can be implemented using one dimensional array. But,
queue implemented using array can store 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
increment 'front' value by one and then display the value at 'front'
position as deleted element.

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

109
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).

110
111
• When we remove element from Queue, we can follow two possible
approaches (mentioned [A] and [B] in the diagram).
• In [A] approach, we remove the element at head position, and then
one by one move all the other elements on position forward. In
approach [B] we remove the element from head position and then
move head to the next position.

• Approach [A] there is an overhead of shifting the elements one


position forward every time we remove the first element.

• Approach [B] there is no such overhead, but whenever we move head


one position ahead, after removal of first element, the size on Queue is
reduced by one space each time.

112
Introduction to Linked Lists

Data Structures
2nd stage
Linked List
• Linked List is a linear data structure and it is
very common data structure which consists of
group of nodes in a sequence which is divided
in two parts. Each node consists of its own
data and the address of the next node and
forms a chain. Linked Lists are used to create
trees and graphs.
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.
Types of Linked Lists
1. Singly Linked List : Singly linked lists contain
nodes which have a data part as well as an
address part i.e. next, which points to the next
node in sequence of nodes. The operations we
can perform on singly linked lists are insertion,
deletion and traversal.
Singly Linked List
Types of Linked Lists
2. Doubly Linked List : In a doubly linked list,
each node contains two links the first link
points to the previous node and the other link
points to the next node in the sequence.
Doubly Linked List
Types of Linked Lists

3.Circular Linked List : In the circular linked list


the last node of the list contains the address
of the first node and forms a circular chain.
Circular Linked List
Linear Linked List
• The element can be inserted in linked list in 2
ways :
– Insertion at beginning of the list.
– Insertion at the end of the list.
• We will also be adding some more useful
methods like :
– Checking whether Linked List is empty or not.
– Searching any element in the Linked List
– Deleting a particular Node from the List
Example
• Before inserting the node in the list we will create a class Node. Like shown below :
class Node {
public:
int data; Node class basically
//pointer to the next node creates a node for
node* next; the data which you
enter to be
node() { included into Linked
data = 0; List. Once the node
next = NULL; is created, we use
} various functions to
node(int x) fit in that node into
{ the Linked List.
data = x;
next = NULL;
}
}
Linked list class
class LinkedList {
public:
node *head;
//declaring the functions
//function to add Node at front
int addAtFront(node *n);
//function to check whether Linked list is empty
int isEmpty();
//function to add Node at the End of list
int addAtEnd(node *n);
//function to search a value
node* search(int k);
//function to delete any Node
node* deleteNode(int x);
LinkedList() {
head = NULL;
}
}
Insertion at the Beginning
• Steps to insert a Node at beginning :

1. The first Node is the Head for any Linked List.


2. When a new Linked List is instantiated, it just has the Head, which is Null.
3. Else, the Head holds the pointer to the first Node of the List.
4. When we want to add any Node at the front, we must make the head
point to it.
5. And the Next pointer of the newly added Node, must point to the
previous Head, whether it be NULL(in case of new List) or the pointer to
the first Node of the List.
6. The previous Head Node is now the second Node of Linked List, because
the new Node is added at the front.
int LinkedListaddAtFront(node *n)
{ int i = 0;
//making the next of the new Node point to Head n-
>next = head;
//making the new Node as Head
head = n;
i++;
//returning the position where Node is added return i;
}
-> for accessing object member variables and methods via pointer to object
Inserting at the End
1. If the Linked List is empty then we simply,
add the new Node as the Head of the Linked
List.
2. If the Linked List is not empty then we find
the last node, and make it’s next to the new
Node, hence making the new node the last
Node.
int LinkedListaddAtEnd(node *n) {
//If list is empty
if(head == NULL)
{
//making the new Node as Head
head = n;
//making the next pointe of the new Node as Null
n->next = NULL;
}
else {
//getting the last node
node *n2 = getLastNode();
n2->next = n;
}
}
 node* LinkedList getLastNode()
{
//creating a pointer pointing to Head
node* ptr = head;
//Iterating over the list till the node whose Next pointer points to null
//Return that node, because that will be the last node.
while(ptr->next!=NULL)
{
//if Next is not Null, take the pointer one step forward
ptr = ptr->next;
}
return ptr;
}
Searching for an Element in the List

• In searching we do not have to do much, we


just need to traverse like we did while getting
the last node, in this case we will also
compare the data of the Node. If we get the
Node with the same data, we will return it,
otherwise we will make our pointer point the
next Node, and so on.
Deleting a Node from the List
• Deleting a node can be done in many ways, like we first
search the Node with data which we want to delete and then
we delete it. In our approach, we will define a method which
will take the data to be deleted as argument, will use the
search method to locate it and will then remove the Node
from the List.
– To remove any Node from the list, we need to do the following :
– If the Node to be deleted is the first node, then simply set the Next
pointer of the Head to point to the next element from the Node to
be deleted.
– If the Node is in the middle somewhere, then find the Node before
it, and make the Node before it point to the Node next to it.
Checking whether the List is empty or not

We just need to check whether the Head of the


List is NULL or not.
int LinkedListisEmpty() {
if(head == NULL) {
return 1;
} else
{ return 0;
}
}
• If you are still figuring out, how to call all these
methods, then below is how
your main() method will look like. As we have
followed OOP standards, we will create the
objects of LinkedList class to initialize our List
and then we will create objects of Node class
whenever we want to add any new node to
the List.
int main() {
LinkedList L;
//We will ask value from user, read the value and add the value to our Node
int x;
cout << "Please enter an integer value : ";
cin >> x;
Node *n1;
//Creating a new node with data as x
n1 = new Node(x);
//Adding the node to the list
L.addAtFront(n1);
}

Similarly you can call any of the functions of the LinkedList class, add as many Nodes you
want to your List.
Nonlinear Data structures

2nd Stage
Linear data structures
• Linear data structures organize their data elements in a linear fashion,
where data elements are attached one after the other. Data elements in a
liner data structure are traversed one after the other and only one
element can be directly reached while traversing. Linear data structures
are very easy to implement, since the memory of the computer is also
organized in a linear fashion. Some commonly used linear data structures
are arrays, linked lists, stacks and queues. An arrays is a collection of data
elements where each element could be identified using an index. A linked
list is a sequence of nodes, where each node is made up of a data
element and a reference to the next node in the sequence. A stack is
actually a list where data elements can only be added or removed from
the top of the list. A queue is also a list, where data elements can be
added from one end of the list and removed from the other end of the
list.
Nonlinear data structures
• In nonlinear data structures, data elements are not organized in a
sequential fashion. A data item in a nonlinear data structure could
be attached to several other data elements to reflect a special
relationship among them and all the data items cannot be
traversed in a single run.
• Data structures like multidimensional arrays, trees and graphs are
some examples of widely used nonlinear data structures.
– A multidimensional array is simply a collection of one-dimensional arrays.
– A tree is a data structure that is made up of a set of linked nodes, which
can be used to represent a hierarchical relationship among data elements.
– A graph is a data structure that is made up of a finite set of edges and
vertices. Edges represent connections or relationships among vertices that
stores data elements.
Difference between Linear and Nonlinear
Data Structures
• Main difference between linear and nonlinear data structures
lie in the way they organize data elements. In linear data
structures, data elements are organized sequentially and
therefore they are easy to implement in the computer’s
memory. In nonlinear data structures, a data element can be
attached to several other data elements to represent specific
relationships that exist among them. Due to this nonlinear
structure, they might be difficult to be implemented in
computer’s linear memory compared to implementing linear
data structures. Selecting one data structure type over the
other should be done carefully by considering the relationship
among the data elements that needs to be stored.
Graph
• A graph is a set of items that are connected by
edges and each item is known as node or
vertex. In other words, a graph can be defined
as the set of vertices and there is a binary
relation between these vertices.
• In implementation of a graph, the nodes are implemented
as objects or structures. The edges can be represented in
different ways. One of the ways is that each node can be
associated with an incident edges array. If the information
is to be stored in nodes rather than edges then the arrays
acts as pointers to nodes and also represent edges. One of
the advantages of this approach is that additional nodes
can be added to the graph. Existing nodes can be
connected by adding elements to arrays. But there is one
disadvantage because time is required in order to
determine whether there is an edge between the nodes.
• Other way to do this is to keep a two
dimensional array or matrix M that has
Boolean values. The existence of edge from
node i to j is specified by entry Mij. One of the
advantages of this method is to find out if
there is any edge between two nodes.
Tree
• Tree is also a data structure used in computer science. It is
similar to the structure of the tree and has a set of nodes
that are linked to each other.
• A node of a tree may contain a condition or value. It can
also be a tree of its own or it can represent a separate
data structure. Zero or more nodes are present in a tree
data structure. If a node has a child then it is called parent
node of that child. There can be at most one parent of a
node. The longest downward path from the node to a leaf
is the height of the node. The depth of node is
represented by the path to its root.
• In a tree, the topmost node is called root
node. The root node has no parents as it is the
top most one. From this node, all tree
operations begin. By using links or edges,
other nodes can be reached from the root
node. The bottom-most level nodes are called
leaf nodes and they don’t have any children.
The node that has number of child nodes is
called inner node or internal node.
Difference between graph and tree:
• A tree can be described as a specialized case of graph with
no self loops and circuits.
• There are no loops in a tree whereas a graph can have
loops.
• There are three sets in a graph i.e. edges, vertices and a set
that represents their relation while a tree consists of nodes
that are connected to each other. These connections are
referred to as edges.
• In tree there are numerous rules spelling out how
connections of nodes can occur whereas graph has no rules
dictating the connection among the nodes.
Tree data structure

2nd Stage
Tree
• Tree: So far, we have been studying mainly linear
types of data structures: arrays, lists, stacks and
queues. Now we defines a nonlinear data structure
called Tree. This structure is mainly used to
represent data containing a hierarchical relationship
between nodes/elements e.g. family trees and
tables of contents. There are two main types of tree:
• General Tree
• Binary Tree
General Tree
• General Tree: A tree where a node can has any
number of children / descendants is called
General Tree. For example:
Following figure is also an example of general
tree where root is “Desktop”.
Binary Tree
• Binary Tree: A tree in which each element may has 0-child
, 1-child or maximum of 2-children. A Binary Tree T is
defined as finite set of elements, called nodes, such that
• a) T is empty (called the null tree or empty tree.) b) T
contains a distinguished node R, called the root of T, and
the remaining nodes of T form an ordered pair of disjoint
binary trees T1 and T2.
• If T does contain a root R, then the two trees T1 and T2
are called, respectively, the left sub tree and right sub tree
of R.
• If T1 is non empty, then its node is called the left successor of R;
similarly, if T2 is non empty, then its node is called the right
successor of R. The nodes with no successors are called the
terminal nodes.
• If N is a node in T with left successor S1 and right successor S2,
then N is called the parent(or father) of S1 and S2. Analogously, S1
is called the left child (or son) of N, and S2 is called the right child
(or son) of N.
• Furthermore, S1 and S2 are said to siblings (or brothers). Every
node in the binary tree T, except the root, has a unique parent,
called the predecessor of N.
• The line drawn from a node N of T to a successor is called an edge,
and a sequence of consecutive edges is called a path.
• A terminal node is called a leaves, and a path ending in a leaves is
called a branch.
• The depth (or height) of a tree T is the maximum
number of nodes in a branch of T. This turns out to
be 1 more than the largest level number of T. Level of
node & its generation: Each node in binary tree T is
assigned a level number, as follows.
• The root R of the tree T is assigned the level number
0, and every other node is assigned a level number
which is 1 more than the level number of its parent.
Furthermore, those nodes with the same level
number are said to belong to the same generation.
Complete Binary Tree
• Complete Binary Tree: Consider a binary tree
T. each node of T can have at most two
children. Accordingly. A tree is said to be
complete if all its levels, except possibly the
last have the maximum number of possible
nodes, and if all the nodes at the last level
appear as far left as possible.
Extended Binary Tree: 2-Tree
• Extended Binary Tree: 2-Tree:
• A binary tree T is said to be a 2-tree or an
extended binary tree if each node:
– N has either 0 or 2 children.
– In such a case, the nodes, with 2 children are
called internal nodes,
– node with 0 children are called external node.
Traversing of Binary Tree:
Traversing of Binary Tree:
Preparing a Tree from an infix arithmetic
expression
Binary Search Tree:
• Suppose T is a binary tree, the T is called a
binary search tree or binary
• sorted tree if each node N of T has the
following property:
– The values of at N (node) is greater than every
value in the left sub tree of
– N and is less than every value in the right sub tree
of N.
• Binary Search Tree using these values: (50, 30,
55, 25, 10, 35, 31,37, 20, 53, 60, 62)
Following figure shows a binary search tree. Notice that this
tree is obtained by inserting the values 13, 3, 4, 12, 14, 10, 5,
1, 8, 2, 7, 9, 11, 6, 18 in that order, starting from an empty
tree.
sorting
• Sorting: Note that inorder traversal of a binary
search tree always gives a sorted
• sequence of the values. This is a direct
consequence of the BST property.
• This provides a way of sorting a given sequence of
keys: first, create a BST with these keys and then
do an inorder traversal of the BST so created.
• Inorder Travers (LNR) : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 15, 18
Search
• Search: is straightforward in a BST. Start with
the root and keep moving left or right using
the BST property. If the key we are seeking is
present, this search procedure will lead us to
the key. If the key is not present, we end up in
a null link.
Insertion
• Insertion in a BST is also a straightforward
operation. If we need to insert an element n,
we traverse tree starting from root by
considering the above stated rules. Our
traverse procedure ends in a null link. It is at
this position of this null link that n will be
included.
Deletion in BST
• Deletion in BST: Let x be a value to be deleted
from the BST and let N denote the node
containing the value x. Deletion of an element
in a BST again uses the BST property in a critical
way. When we delete the node N containing x,
it would create a "gap" that should be filled by a
suitable existing node of the BST. There are two
possible candidate nodes that can fill this gap,
in a way that the BST property is not violated:
• 1) Node containing highest valued element among
all descendants of left child of N.
• 2)Node containing the lowest valued element
among all the descendants of the right child of N.
There are three possible cases to consider:
– Deleting a leaf (node with no children): Deleting a leaf is easy, as we
can simply remove it from the tree.
– Deleting a node with one child: Delete it and replace it with its child.
– Deleting a node with two children: Call the node to be deleted "N". Do
not delete N. Instead, choose its in-order successor node "S". Replace
the value of “N” with the value of “S”. (Note: S itself has up to one child.)
• As with all binary trees, a node's in-order
successor is the left-most child of its right
subtree. This node will have zero or one child.
Delete it according to one of the two simpler
cases above.
Graph data structure

Data structure
2nd stage
Directed and Undirected Graphs
A graph is a mathematical structure consisting of a set of
vertices and a set of edges connecting the vertices. Formally, we
view the edges as pairs of vertices; an edge (v, w) connects
vertex v with vertex w. We write G = (V,E) to denote that G is a
graph with vertex set V and edge set E.
A graph G = (V,E) is undirected if for all vertices v,w Є V we have
(v,w) Є E if, and only if, (w, v) Є E, that is, if all edges go both
ways. If we want to emphasise that the edges have a direction,
we call a graph directed. For brevity, a directed graph is often
called a digraph, and an undirected graph is simply called a
graph. We shall not use this convention here; for us `graph‘
always means `directed or undirected graph'.
When drawing graphs, we represent a vertex
by a point or circle containing the name of the
vertex, and an edge by an arrow connecting
two vertices. When drawing undirected
graphs, instead of drawing two arrows (one in
each direction) between all vertices, we just
draw one line connecting the vertices.
• Figure shows a drawing of the
(directed) graph G = (V,E) with
vertex set
V ={ 0,1,2, 3, 4, 5, 6}
and edge set

E = {(0, 2), (0, 4), (0, 5), (1; 0), (2,1), (2, 5),
(3, 1), (3, 6), (4, 0), (4, 5), (6, 3), (6, 5)}
Use of graph
• Graphs are a useful mathematical model for
numerous .real life. problems and structures.
Here are a few examples:
• Airline route maps:
Vertices represent airports, and there is an edge
from vertex A to vertex B if there is a direct
flight from the airport represented by A to the
airport represented by B.
• Road Maps.
Edges represent streets and vertices represent
crossings.
• Electrical Circuits.
Vertices represent diodes, transistors,
capacitors, switches, etc., and edges represent
wires connecting them.
• Computer Networks.
Vertices represent computers and edges
represent network connections (cables)
between them.
• The World Wide Web.
Vertices represent webpages, and edges
represent hyperlinks.
• Flowcharts.
A flowchart illustrates the flow of control in a
procedure. Essentially, a flowchart consists of
boxes containing statements of the procedure
and arrows connecting the boxes to describe
the flow of control. In a graph representing a
flowchart, the vertices represent the boxes
and the edges represent the arrows.
Data structures for graphs
• Let G = (V,E) be a graph with n vertices. We
assume that the vertices of G are numbered 0,
…., n - 1 in some arbitrary manner.
The adjacency matrix data structure
• For example, the adjacency matrix for the
graph in Figure
The adjacency list data structure
• The adjacency list representation of a graph G
with n vertices consists of an array vertices
with n entries, one for each vertex. The entry
for vertex v is a list of all vertices w such there
is an edge from v to w. We make assumptions
on the order in which the vertices adjacent to
a vertex v appear in the adjacency list, and our
algorithms should work for any order.
• shows an adjacency list representation of the
graph in Figure
Traversing Graphs
• Most algorithms for solving problems on
graphs examine or process each vertex and
each edge of the graph in some particular
order. The skeleton of such an algorithm will
be a traversal of the graph, that is, a strategy
for visiting the vertices and edges in a suitable
order.
• Breadth-first search (BFS) and depth-first search (DFS) are
two traversals that are particularly useful. Both start at
some vertex v and then visit all vertices reachable from v
(that is, all vertices w such that there is a path from v to
w).

• If there are vertices that remain unvisited, that is, if there


are vertices that are not reachable from v, then BFS and
DFS pick a new vertex v and visit all vertices reachable
from v. They repeat this process until they have finally
visited all vertices.
Breadth-first search
• A BFS starting at a vertex v first visits v, then it
visits all neighbours of v (i.e. ,all vertices w
such that there is an edge from v to w), then
all neighbors of the neighbors that have not
been visited before, then all neighbors of the
neighbors of the neighbors that have not been
visited before, et cetera.
• For example, a BFS of the graph in Figure
shown bellow starting at vertex 0 would visit
the vertices in the following order:
0, 2, 5, 4, 1
• It first visits 0, then the neighbours 2; 5; 4 of 0. Next are the
neighbours of 2, which are 1 and 5. Since 5 has been visited
before, only 1 is added to the list. All neighbours of 5, 4, and
1 have already been visited, so we have found all vertices
that are reachable from 0. Note that there are other orders
in which a BFS starting at 0 may visit the vertices of the
graph, because the neighbours of 0 may be visited in a
different order. An example is 0; 5; 4; 2; 1. The vertices 3 and
6 are not reachable from 0, so we have to start another BFS,
say at 3. It first visits 3 and then 6.
• It is important to realize that the traversal
heavily depends on the vertex we start at. For
example, if we start a BFS at vertex 6 it will
visit all vertices in one sweep, maybe in the
following order:
6, 5, 3, 1, 0, 2, 4
Other possible orders are 6, 3, 5, 1, 0, 2, 4 and
6, 5, 3, 1, 0, 4, 2 and 6, 3, 5, 1, 0, 4, 2.
Algorithm BFS
Depth-first search
• A DFS starting at a vertex v first visits v, then some
neighbour w of v, then some neighbour x of w that
has not been visited before, et cetera. Once it gets
stuck, the DFS backtracks until it finds the first vertex
that still has a neighbour that has not been visited
before. It continues with this neighbour until it has to
backtrack again.
• Eventually, it will visit all vertices reachable from v.
Then a new DFS is started at some vertex that is not
reachable from v, until all vertices have been visited.
• a DFS in the graph of Figure shown starting at
0 may visit the vertices in the order
0, 2, 1, 5, 4
• After it has visited 0; 2; 1 the DFS backtracks
to 2, visits 5, then backtracks to 0, and visits 4.
A DFS starting at 0 might also visit the vertices
in the order 0; 4; 5; 2; 1 or 0; 5; 4; 2; 1 or 0; 2;
5; 1; 4. As for BFS, this depends on the order
in which the neighbours of a vertex are
processed.
Algorithm dfsFromVertex(G, v)

You might also like