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

Lecture 1

This document provides an introduction and overview of data structures, algorithms, and their applications. It defines key terms like data, structure, algorithm, and applications. It discusses why data structures are needed and some commonly used data structures. It also covers basic object-oriented programming concepts, pointer data types, and an example program using pointers. Finally, it discusses pseudocode, performance of data structures in terms of time complexity, asymptotic notations, and provides an introduction to multidimensional arrays.
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)
46 views

Lecture 1

This document provides an introduction and overview of data structures, algorithms, and their applications. It defines key terms like data, structure, algorithm, and applications. It discusses why data structures are needed and some commonly used data structures. It also covers basic object-oriented programming concepts, pointer data types, and an example program using pointers. Finally, it discusses pseudocode, performance of data structures in terms of time complexity, asymptotic notations, and provides an introduction to multidimensional arrays.
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
You are on page 1/ 45

CT-159 DATA STRUCTURES ALGORITHMS

AND APPLICATIONS

LECTURE 1

HUMA TABASSUM
LECTURER
DEPT. OF COMPUTER SCIENCE & INFORMATION TECHNOLOGY
NED UNIVERSITY OF ENGINEERING & TECHNOLOGY
INTRODUCTION
• Data: facts or figures.
• Structure: arrangement of, and relations between the parts or elements.
• Algorithm: a finite sequence of precise instructions for performing a
computation or for solving a problem.
• Applications: areas or domains in which the concept, design, strategy,
etc. can be used.

• Data structure is a particular way of storing and organizing information


in a computer so that it can be retrieved and used efficiently.
WHY WE NEED DATA STRUCTURES?
• Data structures are extremely important.
• We constantly use data structures in our daily lives!
• Open a file.
• Look up a contact on your phone.
• Log in to your social network.
• Web search.
• It may seem that implementing such operations are not that hard,
BUT what about efficiency??
• Number of operations
• Processor speed
• Bigger datasets
FREQUENTLY USED DATA STRUCTURES
• Array
• Linked List
• Queue
• Stack
• Graph
• Tree
• Heap
• Hash Table
CLASSIFICATION OF DATA STRUCTURES
BASIC OOP CONCEPTS
• Class
• Object
• Encapsulation
• Inheritance
• Polymorphism
• Abstract Datatype
• Or Interface
Pointer Data Type and Pointer Variables
• The values belonging to pointer data types are the memory addresses of your
computer.
• Because the set of values of a pointer data type is the addresses (memory
locations), a pointer variable is a variable whose value is an address (a
memory location).
• That is, it refers to another memory space.
• The data is typically stored in this memory space.
• Therefore, when you declare a pointer variable, you also specify the data type
of the value to be stored in the memory location pointed to by the pointer
variable.
• For example, if a pointer variable contains the address of a memory location containing
int value, it is said to be an int pointer or a pointer (variable) of type int.
• In C++, you declare a pointer variable by using the asterisk symbol (*) between
the data type and the variable name.
• The general syntax to declare a pointer variable is:
• dataType *identifier;
• As an example, consider the following statements:
int *p;
char *ch;
• In these statements, both p and ch are pointer variables. The content
of p (when properly assigned) points to a memory location of type int,
and the content of ch points to a memory location of type char.
Usually, p is called a pointer variable of type int, and ch is called a
pointer variable of type char.

• C++ provides two operators—the address of operator (&) and the


dereferencing operator (*)—to work with pointers
Address of Operator (&)
• In C++, the ampersand, &, called the address of operator, is a unary
operator that returns the address of its operand.
• For example, given the statements:
int x;
int *p;
the statement:
p = &x;
assigns the address of x to p.
• That is, x and the value of p refer to the same memory location.
Dereferencing Operator (*)
• Up till now we have used the asterisk character, *, as the binary multiplication
operator
• C++ also uses * as a unary operator
• When used as a unary operator, *, commonly referred to as the dereferencing
operator or indirection operator, refers to the object to which its operand (that is,
the pointer) points
• For example, given the statements:
int x = 25;
int *p;
p = &x; //store the address of x in p
the statement:
cout << *p << endl;
prints the value stored in the memory space pointed to by p, which is the value of
x. Also, the statement:
*p = 55;
stores 55 in the memory location pointed to by p—that is, in x
• Let us consider the following statements:
int *p;
int num;
• In these statements, p is a pointer variable of type int, and num is a
variable of type int.
• Let us assume that memory location 1200 is allocated for p, and
memory location 1800 is allocated for num.

• Consider the following statements:


• num = 78;
• p = &num;
• *p = 24;
• The following shows the values of the variables after the execution of
each statement.
• The declaration int *p allocates memory for p only, not for *p.
• The content of p points only to a memory location of type int.
• &p, p, and *p all have different meanings.
• &p means the address of p—that is, 1200.
• p means the content of p, which is 1800, after the statement p = &num;
executes.
• *p means the content of the memory location to which p points. Note
that after the statement p = &num; executes, the value of *p is 78; after
the statement *p = 24; executes, the value of *p is 24.
Pointer Variables
• Because C++ does not automatically initialize variables, pointer variables
must be initialized if you do not want them to point to anything.
• Pointer variables are initialized using the constant value 0, called the null pointer, or
by using the named constant NULL.
• Thus, the statement p = 0; stores the null pointer in p, that is, p points to nothing.
• The operations that are allowed on pointer variables are the assignment
and relational operations and some limited arithmetic operations.
• The value of one pointer variable can be assigned to another pointer variable of the
same type.
• Two pointer variables of the same type can be compared for equality, and so on.
• Integer values can be added and subtracted from a pointer variable.
• The value of one pointer variable can be subtracted from another pointer variable.
Functions and Pointers
• A pointer variable can be passed as a parameter to a function either
by value or by reference.
• In C++, the return type of a function can be a pointer.
• In C++, to make a pointer a reference parameter in a function
heading, * appears before the & between the data type name and the
identifier. The following example illustrates this concept:
int* pointerParameters(int* &p, double *q)
{

}
• In the function pointerParameters, both p and q are pointers. The parameter
p is a reference parameter; the parameter q is a value parameter.
Furthermore, the function pointerParameters can change the value of *q, but
not the value of q. However, the function pointer Parameters can change the
value of both p and *p.
#include <iostream>
using namespace std;
const double PI = 3.1416;
int main() {
double radius;
double *radiusPtr;
radius = 2.5;
radiusPtr = &radius;
cout << "Enter the radius: ";
cin >> *radiusPtr;
cout << endl;
cout << "Radius = " << radius << ", area = “ << PI * radius * radius << endl;
cout << "Radius = " << *radiusPtr << ", area = “
<< PI * (*radiusPtr) * (*radiusPtr) << endl << endl;
cout << "Address of radiusPtr: “ << &radiusPtr << endl;
cout << "Value stored in radiusPtr: “ << radiusPtr << endl;
cout << "Address of radius: “ << &radius << endl;
cout << "Value stored in radius: “ << radius << endl;
return 0;
}
Sample Run: In this sample run, the user input is shaded.
Enter the radius: 4.90
Radius = 4.90, area = 75.43
Radius = 4.90, area = 75.43
Address of radiusPtr: 0012FF50
Value stored in radiusPtr: 0012FF5C
Address of radius: 0012FF5C
Value stored in radius: 4.90
PSEUDOCODE
• Pseudocode is an informal high-level description of the operating
principle of a computer program or other algorithm.
• Pre-conditions should always be enforced.
• Post-conditions represent the result of applying algorithm a to data structure d.
• The type of parameters is inferred.
• All primitive language constructs are explicitly begun and ended.

1) algorithm AlgorithmName(arg1, arg2, ..., argN)


2) ...
n) end AlgorithmName
PERFORMANCE OF A DATA STRUCTURE
• When studying the performance of a data structure, there are three
things that matter most:
• Correctness: The data structure should correctly implement its interface.

• Time complexity: The running times of operations on the data structure


should be as small as possible.

• Space complexity: The data structure should use as little memory as possible.

• We shall focus on the Time Complexity.


Time Complexity
• When studying running times in the context of data structure, we can have
• Best-case running times
• Worst-case running times
• Average-case running times.
• Clearly, Tavg(N) ≤ Tworst(N).
• The exact running times will, of course, vary from computer to computer
and even from run to run on an individual computer.
• When we talk about the running time of an operation, we are referring to
the number of computer instructions performed during the operation.
• Even for simple code, this quantity can be difficult to compute exactly.
• Therefore, instead of analyzing running times exactly, we will use the
asymptotic notations.
Asymptotic Notations
• Big-O Notation (pronounced big-oh)
• Big-Ω Notation (pronounced big-omega)
• Big-Θ Notation (pronounced big-theta)
• These have some cousins
• Little-o Notation (pronounced little-oh)
• Little-ω Notation (pronounced little-omega)
• Little-θ Notation (pronounced little-theta)

• We generally use asymptotic notation to simplify functions.


• For example, in place of 5nlogn + 8n - 200 we can write, simply, O(nlogn).
ARRAY
• An array is a collection of a fixed number of components all of the
same data type.
• The components in an array are termed as elements.
• You have already studied one-dimensional arrays in detail.

• Today, we will discuss multi-dimensional arrays.


Multidimensional Arrays
• C++ allows multidimensional arrays.
• The general form for declaring a one-dimensional array is:
dataType arrayName[intExp1][intExp2]….[intExpn];
• The simplest form of the multidimensional array is the two-dimensional array
• A two-dimensional array is, in essence, a list of one-dimensional arrays OR can
be considered a table with x rows and y columns
int a[3][4];
• The two-dimensional array a can be shown as
• Multidimensional arrays may be initialized by specifying bracketed values
for each row
int a[3][4] = {
{0, 1, 2, 3} , // initializers for row indexed by 0
{4, 5, 6, 7} , // initializers for row indexed by 1
{8, 9, 10, 11} // initializers for row indexed by 2
};
• The nested braces, which indicate the intended row, are optional. The
following initialization is equivalent to
• int a[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
• An element in 2-dimensional array is accessed by using the subscripts,
i.e., row index and column index of the array
• int val = a[2][5];
#include <iostream> • The code on the left produces the following output
using namespace std;

int main () { a[0][0]: 0


// an array with 5 rows and 2 columns. a[0][1]: 0
int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6},{4,8}}; a[1][0]: 1
a[1][1]: 2
// output each array element's value a[2][0]: 2
for ( int i = 0; i < 5; i++ ) a[2][1]: 4
for ( int j = 0; j < 2; j++ ) { a[3][0]: 3
a[3][1]: 6
cout << "a[" << i << "][" << j << "]: "; a[4][0]: 4
cout << a[i][j]<< endl; a[4][1]: 8
}

return 0;
}
Row and Column Major Ordering

Row Major Order Column Major Order


• Row major ordering assigns • If the element of an array is
successive elements, moving being stored in column-wise
across the rows and then down fashion then it is called column-
the columns, to successive major ordering in an array.
memory locations.
#include<stdio.h>
#define n 3
#define m 3
#define max_size 100
int main() {
// Initialising a 2-d array
int grid[n][m] = {{1, 2, 3},
{4, 5, 6},
{7, 8, 9}};
// storing elements in 1-d array
int i, j, k = 0; Output:
int array[max_size]; 123456789
for (i=0; i<n; i++) {
for (j=0; j<m; j++) {
array[k] = grid[i][j];
k++; }
}
// displaying elements in 1-d array
if((n*m) < max_size){
for (l=0; l<n*m; l++)
cout << array[l];}
else
cout << “Array size exceeded.”;
return 0;
}
Dynamic Array
• One limitation of static arrays is that they're fixed size.
• A dynamic array is an array which allows dynamic allocation.
• This is done through new keyword.
int* arr = NULL; // Pointer to int, initialize to nothing.
int n; // Size needed for array
cin >> n; // Read in the size
arr = new int[n]; // Allocate n ints and save ptr in arr.
for (int i=0; i<n; i++) {
arr[i] = 0; // Initialize all elements to zero.
}
. . . // Use arr as a normal array
delete [] arr; // When done, free memory pointed to by a.
arr = NULL; // Clear a to prevent using invalid memory reference.
Safe Array
• In C++, there is no check to determine whether the array index is out of bounds.
• During program execution, an out-of- bound array index can cause serious
problems.
• Safe array solves the out-of-bound array index problem.
• Safely in this context would mean that access to the array elements must not be out of range,
i.e., the position of the element must be validated prior to access.

void set(int pos, Element val) { //set method


if (pos<0 || pos>=size)
cout<<"Boundary Error\n";
else
Array[pos] = val;
}
Dynamic Memory Allocation
• Constructors and Destructors
• https://www.codementor.io/@supernerdd7/constructor-and-destructor-in-c-
1r8kkogm6j
• Dynamic Memory Allocation for 1-D Array
char* pvalue = NULL; // Pointer initialized with null
pvalue = new char[20]; // Request memory for the variable
delete [] pvalue; // Delete array pointed to by pvalue
• Dynamic Memory Allocation for 2-D Array
• double** pvalue = NULL; // Pointer initialized with null
• pvalue = new double [3][4]; // Allocate memory for a 3x4 array
• delete [] pvalue; // Delete array pointed to by pvalue
Jagged Array
• Jagged array is an array of arrays that can have a different number of
columns in each of its rows.
//Dynamically creating an array of integer p for (int i = 0 ; i < 3 ; i++)
ointers of size "rows"
int** ptr = new int* [ rows ]; {
for (int j = 0 ; j < cols[i] ; j++)
//Dynamically allocating memory for colum std :: cout << ptr[i][j] << "\t";
ns in each row std :: cout << std :: endl;
for (int i = 0; i < rows; i++) {
ptr[i] = new int[cols[i]]; }
}
for ( i = 0 ; i < rows ; i++ )
time_t t ; delete[ ] ptr[ i ] ;
time ( &t ) ;
srand ( ( unsigned int ) t ) ; //deleting the array that contains our actual
data
for (int i = 0 ; i < rows ; i++) delete [ ] ptr; //deleting the array that holds
{ the pointers pointing to our actual data
for (int j = 0 ; j < cols[i] ; j++)
ptr[i][j] = rand() % 10;
}
OPERATIONS ON DATA STRUCTURES
• Typically, following operations are performed on data structures.
• Search
• Sort
• Insert
• Delete

• For these operations, there are various algorithms; some of which will
be explored in this course.
Searching
• In data structures, the process of finding the desired information from
the set of items stored in the form of elements in the computer
memory is referred to as searching.
• These sets of items are in various forms, such as an array, tree, graph,
or linked list.
• We can also define searching in data structures as locating the
desired element of specific characteristics in a collection of items.
• The two most common searching algorithms are
• Linear Search
• Binary Search
Linear Search
(Linear Search) LINEAR(DATA, N, ITEM)
Here DATA is a linear array with N elements, and ITEM is a given item of information. This algorithm
finds the location LOC of ITEM in DATA or sets LOC:=NULL if the search is unsuccessful.
1. [Initialize] Set K := 1 and LOC := NULL.
2. Repeat steps 3 and 4 while LOC = NULL and K ≤ N.
3. If ITEM = DATA[K], then: Set LOC := K.
4. Set K := K + 1 [Increments counter.]
[End of Step 2 loop.]
5. [Successful?]
If LOC = NULL, then:
Write: ITEM is not in the array DATA.
Else:
Write: LOC is the location of ITEM.
[End of IF structure.]
6. Exit.
Example
Complexity Analysis of Linear Search
• Best Case
• The best case occurs when ITEM is the first element in the array DATA.
• Thus, f(N) = 1 => O(f(N)) = 1 => O(1)
• Worst Case
• Clearly the worst case occurs when ITEM is the last element in the array DATA
or is not there at all.
• Thus, f(N) = N (or N+1) => O(f(N)) = N => O(N)
• Average Case
𝑁+1
• f(N) = => O(f(N)) = N => O(N)
2
Binary Search
(Binary Search) BINARY(DATA, N, ITEM)
Here DATA is a sorted array with lower bound LB and upper bound UB, and ITEM is a given item of
information. The variables BEG, END, and MID denote, respectively, the beginning, end, and middle
locations of a segment of elements of DATA. This algorithm finds the location LOC of ITEM in DATA,
or sets LOC:=NULL.
1. [Initialize] Set BEG := LB, END := UB, MID := int((BEG + END)/2), and LOC := NULL.
2. Repeat steps 3 and 4 while BEG ≤ END and DATA[MID] ≠ ITEM.
3. If ITEM < DATA[MID], then: Set END := MID – 1.
Else: Set BEG := MID + 1.
[End OF If Structure.]
4. Set MID := int((BEG + END)/2).
[End of Step 2 loop.]
5. If DATA[MID] = ITEM, then:
Set LOC:= MID.
Write: LOC is the location of ITEM.
Else:
Write: ITEM is not in the array DATA.
[End of IF structure.]
6. Exit.
Example
Complexity Analysis of Binary Search
• Best Case
• The best case occurs when ITEM is the MID element in the array DATA.
• Thus, f(N) = 1 => O(f(N)) = 1 => O(1)
• Worst Case
• Clearly the worst case occurs when ITEM is the first or last element in the
array DATA, or is not there at all.
• At first iteration, length of DATA is N. In second iteration, it becomes N/2; in third, N/4,
and so on until only 1 element remains.
• Thus, f(N) = log2N => O(f(N)) = log2N => O(log2N)
• Average Case
• f(N) = log2N => O(f(N)) = log2N => O(log2N)

• Remember, if the list is NOT sorted, then O(Nlog2N).

You might also like