DS Unit 1 PDF
DS Unit 1 PDF
DS Unit 1 PDF
UNIT-1
1. Asymptotic Notations
2. One Dimensional array
3. Multi Dimensional array
4. Pointer arrays.
1. Definition
2. Single linked list
3. Circular linked list
4. Double linked list
5. Circular Double linked list
6. Application of linked lists.
Page 1
Data Structures
Overview
Data Structure is a systematic way to organize data in order to use it efficiently. Following
terms are the foundation terms of a data structure.
Inte rface − Each data structure has an interface. Interface represents the set of
Operations that a data structure supports. An interface only provides the list of
supported operations, type of parameters they can accept and return type of these
operations.
Implementation − Implementation provides the internal representation of a
data structure. Implementation also provides the definition of the algorithms used
in the operations of the data structure.
As applications are getting complex and data rich, there are three common problems that
applications face now-a-days.
Data Search − Consider an inventory of 1 million(106) items of a store. If the
application is to search an item, it has to search an item in 1 million(106) items
every time slowing down the search. As data grows, search will become slower.
Processor Speed − Processor speed although being very high, falls limited if the
data grows to billion records.
To solve the above- mentioned problems, data structures come to rescue. Data can be
organized in a data structure in such a way that all items may not be required to be
searched, and the required data can be searched almost instantly.
Page 2
Data Structures
Algorithms –basics
Algorithm Analysis
Efficiency of an algorithm can be analyzed at two different stages, before implementation
and after implementation. They are the following −
A Priori Analysis − This is a theoretical analysis of an algorithm. Efficiency of an
Page 4
Data Structures
algorithm is measured by assuming that all other factors, for example, processor
speed, are constant and have no effect on the implementation.
A Posterior Analysis − This is an empirical analysis of an algorithm. The selected
algorithm is implemented using programming language. This is then executed on
target computer machine. In this analysis, actual statistics like running time and
space required, are collected.
We shall learn about a priori algorithm analysis. Algorithm analysis deals with the
execution or running time of various operations involved. The running time of an operation
can be defined as the number of computer instructions executed per operation.
Algorithm Complexity
Suppose X is an algorithm and n is the size of input data, the time and space used by the
algorithm X are the two main factors, which decide the efficiency of X.
Time Factor – Time is measured by counting the number of key operations such
as comparisons in the sorting algorithm.
Space Factor − Space is measured by counting the maximum memory space
required by the algorithm.
The complexity of an algorithm f(n) gives the running time and/or the storage space
required by the algorithm in terms of n as the size of input data.
Space Complexity
Space complexity of an algorithm represents the amount of memory space required by
the algorithm in its life cycle. The space required by an algorithm is equal to the s um of
the following two components −
A fixed part that is a space required to store certain data and variables, that are
independent of the size of the proble m. For example, simple variables and
constants used, program size, etc.
A variable part is a space require d by variables, whose size depends on the size
of the problem. For example, dynamic me mory allocation, recursion stack space,
etc.
Space complexity S(P) of any algorithm P is S(P) = C + SP(I), where C is the fixed part
and S(I) is the variable part of the algorithm, which depends on instance characteristic I.
Following is a simple example that tries to explain the concept −
Algorithm: SUM(A, B)
Step 1 - START
Step 2 - C ← A + B + 10
Step 3 - Stop
Here we have three variables A, B, and C and one constant.
Hence S(P) = 1+3. Now,space depends on data types of given variables and constant types and it will
be multiplied accordingly.
Time Complexity
Time complexity of an algorithm represents the amount of time required by the algorithm
to run to completion.
Time requirements can be defined as a numerical function T(n),
where T(n) can be measured as the number of steps, provided each step consumes
constant time.
For example, addition of two n-bit integers takes n steps. Consequently, the total
computational time is T(n) = c*n,
where c is the time taken for the addition of two bits.
Here, we observe that T(n) grows linearly as the input size increases.
Page 5
Data Structures
Asymptotic Notations
For example,
for a function f(n),Ο(f(n)) = { g(n) : there exists c > 0 and n0 such that g(n) ≤ c.f(n) for all n
> n0. }
Omega Notation, Ω
The notation Ω(n) is the formal way to express the lower bound of an algorithm's runningtime.
It measures the best case time complexity or the best amount of time an algorithm
can possibly take to complete.
Page 6
Data Structures
θ(f(n)) = { g(n) if and only if g(n) = Ο(f(n)) and g(n) = Ω(f(n)) for all n >n0. }
Basic Operations
The data in the data structures are processed by certain operations. The particular data
structure chosen largely depends on the frequency of the operation that needs to be
performed on the data structure.
Traversing
Searching
Insertion
Deletion
Sorting
Merging
Declaring Arrays
Page 8
Data Structures
To declare an array in C, a programmer specifies the type of the elements and the number of
elements required by an array as follows −
type arrayName [ arraySize ];
This is called a single-dimensional array.
The arraySize must be an integer constant greater than zero and type can be any valid C data type.
For example, to declare a 10-element array called balance of type double, use this statement −
double balance[10];
Here balance is a variable array which is sufficient to hold up to 10 double numbers.
Initializing Arrays
You can initialize an array in C either one by one or using a single statement as follows −
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
The number of values between braces { } cannot be larger than the number of elements that we
declare for the array between square brackets [ ].
If you omit the size of the array, an array just big enough to hold the initialization is created.
Therefore, if you write −
double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};
You will create exactly the same array as you did in the previous example. Following is an example
to assign a single element of the array −
balance[4] = 50.0;
The above statement assigns the 5th element in the array with a value of 50.0. All arrays have 0 as
the index of their first element which is also called the base index and the last index of an array will be total
size of the array minus 1. Shown below is the pictorial representation of the array we discussed above −
The following example Shows how to use all the three above mentioned concepts viz. declaration,
assignment, and accessing arrays −
#include <stdio.h>
int main () {
int n[ 10 ]; /* n is an array of 10 integers */
int i,j;
/* initialize elements of array n to 0 */
for ( i = 0; i < 10; i++ ) {
n[ i ] = i + 100; /* set element at location i to i + 100 */
}
/* output each array element's value */
for (j = 0; j < 10; j++ ) {
printf("Element[%d] = %d\n", j, n[j] );
}
return 0;
}
When the above code is compiled and executed, it produces the following result −
Element[0] = 100
Element[1] = 101
Page 9
Data Structures
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109
Arrays in Detail
Arrays are important to C and should need a lot more attention. The following important concepts related to
array should be clear to a C programmer −
S.N. Concept & Description
1 Multi-dimensional arrays
C supports multidimensional arrays. The simplest form of the multidimensional
array is the two-dimensional array.
4 Pointer to an array
You can generate a pointer to the first element of an array by simply specifying the
array name, without any index.
Page 10
Data Structures
Thus, every element in the array a is identified by an element name of the form a[ i ][ j ], where 'a' is
the name of the array, and 'i' and 'j' are the subscripts that uniquely identify each element in 'a'.
Initializing Two-Dime nsional Arrays
Multidimensional arrays may be initialized by specifying bracketed values for each row.
Following is an array with 3 rows and each row has 4 columns.
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 equivale nt to
the previous example −
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
Accessing Two-Dime nsional Array Elements
An element in a two-dimensional array is accessed by using the subscripts, i.e., row index and
column index of the array. For example −
int val = a[2][3];
The above statement will take the 4th element from the 3rd row of the array.
Let us check the following program where we have used a nested loop to handle a two-dimensional
array −
#include <stdio.h>
int main () {
/* an array with 5 rows and 2 columns*/
int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6},{4,8}};
int i, j;
/* output each array element's value */
for ( i = 0; i < 5; i++ ) {
for ( j = 0; j < 2; j++ ) {
printf("a[%d][%d] = %d\n", i,j, a[i][j] );
}
}
return 0;
}
When the above code is compiled and executed, it produces the following result −
a[0][0]: 0
a[0][1]: 0
a[1][0]: 1
a[1][1]: 2
a[2][0]: 2
a[2][1]: 4
a[3][0]: 3
a[3][1]: 6
a[4][0]: 4
a[4][1]: 8
As explained above, you can have arrays with any number of dimensions, although it is likely that
most of the arrays you create will be of one or two dimensions.
Page 11
Data Structures
Pointe r arrays
It is most likely that you would not understand this section until you are through with the chapter
'Pointers'.
Assuming you have some understanding of pointers in C, let us start: An array name is a constant
pointer to the first element of the array. Therefore, in the declaration −
double balance[50];
balance is a pointer to &balance[0], which is the address of the first element of the array balance.
Thus, the following program fragment assigns p as the address of the first element of balance −
double *p;
double balance[10];
p = balance;
It is legal to use array names as constant pointers, and vice versa. Therefore, *(balance + 4) is a
legitimate way of accessing the data at balance[4].
Once you store the address of the first element in 'p', you can access the array elements using *p,
*(p+1), *(p+2) and so on. Given below is the example to show all the concepts discussed above −
#include <stdio.h>
int main () {
/* an array with 5 elements */
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
int i;
p = balance;
/* output each array element's value */
printf( "Array values using pointer\n");
for ( i = 0; i < 5; i++ ) {
printf("*(p + %d) : %f\n", i, *(p + i) );
}
printf( "Array values using balance as address\n");
for ( i = 0; i < 5; i++ ) {
printf("*(balance + %d) : %f\n", i, *(balance + i) );
}
return 0;
}
When the above code is compiled and executed, it produces the following result −
Array values using pointer
*(p + 0) : 1000.000000
*(p + 1) : 2.000000
*(p + 2) : 3.400000
*(p + 3) : 17.000000
*(p + 4) : 50.000000
Array values using balance as address
*(balance + 0) : 1000.000000
*(balance + 1) : 2.000000
*(balance + 2) : 3.400000
*(balance + 3) : 17.000000
*(balance + 4) : 50.000000
In the above example, p is a pointer to double, which means it can store the address of a variable of double
type. Once we have the address in p, *p will give us the value available at the address stored in p, as we have
shown in the above example.
Page 12
Data Structures
Definition
Single linked list
Circular linked list
Double linked list
Circular Double linked list
Application of linked lists.
LINKED LISTS:
DEFINITION:A linked list is a sequence of data structures, which are connected together via links.
Linked List is a sequence of links which contains items. Each link contains a connection to another link.
Linked list is the second most-used data structure after array.
Following are the important terms to understand the concept of Linked List.
Link − Each link of a linked list can store a data called an element.
Next − Each link of a linked list contains a link to the next link called Next.
LinkedList − A Linked List contains the connection link to the first link called First.
Linked List Representation
Linked list can be visualized as a chain of nodes, where every node points to the next node.
As per the above illustration, following are the important points to be considered.
Linked List contains a link element called first.
Each link carries a data field(s) and a link field called next.
Each link is linked with its next link using its next link.
Last link carries a link as null to mark the end of the list.
Types of Linked List
Following are the various types of linked list.
Single Linked List − Item navigation is forward only.
Doubly Linked List − Items can be navigated forward and backward.
Circular Linked List − Last item contains link of the first element as next and the first element has a link to
the last element as previous.
SINGLE LINKED LISTS:
Basic Operations
Following are the basic operations supported by a list.
Insertion − Adds an element at the beginning of the list.
Deletion − Deletes an element at the beginning of the list.
Display − Displays the complete list.
Search − Searches an element using the given key.
Delete − Deletes an element using the given key.
Insertion Operation
Adding a new node in linked list is a more than one step activity.
We shall learn this with diagrams here. First, create a node using the same structure and find the
location where it has to be inserted.
Page 13
Data Structures
Imagine that we are inserting a node B (NewNode), between A (LeftNode) and C (RightNode). Then point
B.next to C −
NewNode.next −> RightNode;
It should look like this −
Now, the next node at the left should point to the new node.
LeftNode.next −> NewNode;
This will put the new node in the middle of the two. The new list should look like this −
Similar steps should be taken if the node is being inserted at the beginning of the list. While inserting it at
the end, the second last node of the list should point to the new node and the new node will point to NULL.
Deletion Operation
Deletion is also a more than one step process. We shall learn with pictorial representation. First, locate the
target node to be removed, by using searching algorithms.
The left (previous) node of the target node now should point to the next node of the target node −
LeftNode.next −> TargetNode.next;
Page 14
Data Structures
This will remove the link that was pointing to the target node. Now, using the following code, we will
remove what the target node is pointing at.
TargetNode.next −> NULL;
We need to use the deleted node. We can keep that in memory otherwise we can simply deallocate memory
and wipe off the target node completely.
Reverse Operation
This operation is a thorough one. We need to make the last node to be pointed by the head node and reverse
the whole linked list.
First, we traverse to the end of the list. It should be pointing to NULL. Now, we shall make it point to its
previous node −
We have to make sure that the last node is not the lost node. So we'll have some temp node, which looks like
the head node pointing to the last node. Now, we shall make all left side nodes point to their previous nodes
one by one.
Except the node (first node) pointed by the head node, all nodes should point to their predecessor, making
them their new successor. The first node will point to NULL.
Page 15
Data Structures
We'll make the head node point to the new first node by using the temp node.
As per the above illustration, following are the important points to be considered.
Doubly Linked List contains a link element called first and last.
Each link carries a data field(s) and two link fields called next and prev.
Each link is linked with its next link using its next link.
Each link is linked with its previous link using its previous link.
The last link carries a link as null to mark the end of the list.
Basic Operations
Following are the basic operations supported by a list.
Insertion − Adds an element at the beginning of the list.
Deletion − Deletes an element at the beginning of the list.
Insert Last − Adds an element at the end of the list.
Delete Last − Deletes an element from the end of the list.
Insert After − Adds an element after an item of the list.
Delete − Deletes an element from the list using the key.
Display forward − Displays the complete list in a forward manner.
Display backward − Displays the complete list in a backward manner.
Insertion Operation
Following code demonstrates the insertion operation at the beginning of a doubly linked list.
Page 16
Data Structures
Example
//insert link at the first location
void insertFirst(int key, int data) {
//create a link
struct node *link = (struct node*) malloc(sizeof(struct node));
link->key = key;
link->data = data;
if(isEmpty()) {
//make it the last link
last = link;
} else {
//update first prev link
head->prev = link;
}
//point it to old first link
link->next = head;
//point first to new first link
head = link;
}
Deletion Operation
Following code demonstrates the deletion operation at the beginning of a doubly linked list.
Example
//delete first item
struct node* deleteFirst() {
//save reference to first link
struct node *tempLink = head;
//if only one link
if(head->next == NULL) {
last = NULL;
} else {
head->next->prev = NULL;
}
head = head->next;
//return the deleted link
return tempLink;
}
Insertion at the End of an Operation
Following code demonstrates the insertion operation at the last position of a doubly linked list.
Example
//insert link at the last location
void insertLast(int key, int data) {
//create a link
struct node *link = (struct node*) malloc(sizeof(struct node));
link->key = key;
link->data = data;
if(isEmpty()) {
//make it the last link
last = link;
} else {
//make link a new last link
Page 17
Data Structures
last->next = link;
//mark old last node as prev of new link
link->prev = last;
}
//point last to new last node
last = link;
}
As per the above illustration, following are the important points to be considered.
The last link's next points to the first link of the list in both cases of singly as well as doubly linked list.
The first link's previous points to the last of the list in case of doubly linked list.
Basic Operations
Following are the important operations supported by a circular list.
insert − Inserts an element at the start of the list.
delete − Deletes an element from the start of the list.
display − Displays the list.
Insertion Operation
Following code demonstrates the insertion operation in a circular linked list based on single linked list.
Example
//insert link at the first location
void insertFirst(int key, int data) {
//create a link
struct node *link = (struct node*) malloc(sizeof(struct node));
link->key = key;
link->data= data;
if (isEmpty()) {
head = link;
head->next = head;
} else {
//point it to old first node
link->next = head;
Page 18
Data Structures
printf(" ]") }
END OF UNIT -1
Page 19