Data Structures
Data Structures
Data Structures
DATA STRUCTURES
These refer to groups of data elements that are organized in a single unit so that
they can be used more efficiently as compared to the simple data types such as
integers and strings. An example of a data structure is the array. Ordinary variables
store one value at a time while an array will store more than one value at a time in a
single variable name.
Data structures are important for grouping sets of similar data together and passing
them as one. For example, if you have a method that prints a set of data but you don't
know when writing the procedure how large that set is going to be, you could use an
array to pass the data to that method and loop through it.
Data structures can be classified using various criteria.
a) Linear
In linear data structures, values are arranged in linear fashion. A linear data structure
traverses the data elements sequentially. The elements in the structure are adjacent to
one another other and every element has exactly two neighbour elements to which it is
connected. Arrays, linked lists, stacks and queues are examples of linear data
structures.
b) Non-Linear
The data values in this structure are not arranged in order but every data item is
attached to several other data items in a way that is specific for reflecting
relationships. Tree, graph, table and sets are examples of non-linear data structures.
c) Homogenous
In this type of data structures, values of the same types of data are stored, as in an
array.
d) Non-homogenous
In this type of data structures, data values of different types are grouped, as in
structures and classes.
e) Dynamic
In dynamic data structures such as references and pointers, size and memory locations
can be changed during program execution. These data structures can grow and shrink
during execution.
f) Static
With a static data structure, the size of the structure is fixed. Static data structures
such as arrays are very good for storing a well-defined number of data items.
56
ARRAYS
An array is a named list of elements, all with the same data type. It is better defined as
a consecutive group of memory locations all of which have the same name and the
same data type. Arrays store a fixed-size sequential collection of elements of the same
type.
All arrays consist of contiguous memory locations. The lowest address corresponds to
the first element and the highest address to the last element.
DECLARING ARRAYS
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:
double balance[10];
57
Now 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:
The number of values between braces { } can not be larger than the number of
elements that we declare for the array between square brackets [ ]. Following is an
example to assign a single element of the array:
If you omit the size of the array, an array just big enough to hold the initialization is
created. Therefore, if you write:
You will create exactly the same array as you did in the previous example.
balance[4] = 50.0;
The above statement assigns element number 5th in the array a value of 50.0. Array
with 4th index will be 5th ie. last element because all arrays have 0 as the index of
their first element which is also called base index. Following is the pictorial
representation of the same array we discussed above:
The above statement will take 10th element from the array and assign the value to
salary variable. Following is an example which will use all the above mentioned three
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;
58
/* 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 */
}
return 0;
}
When the above code is compiled and executed, it produces the following result:
Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109
SORT TECHNIQUES
Bubble Sort
In the bubble sort, as elements are sorted they gradually "bubble" (or rise) to their
proper location in the array, like bubbles rising in a glass of soda. The bubble sort
repeatedly compares adjacent elements of an array. The first and second elements
are compared and swapped if out of order. Then the second and third elements are
compared and swapped if out of order. This sorting process continues until the last
two elements of the array are compared and swapped if out of order.
When this first pass through the array is complete, the bubble sort returns to elements
one and two and starts the process all over again.
The table below follows an array of numbers before, during, and after a bubble sort
59
fordescending order. A "pass" is defined as one full trip through the array comparing
and if necessary, swapping, adjacent elements. Several passes have to be made
through the array before it is finally sorted
Array at beginning: 84 69 76 86 94 91
After Pass #1: 84 76 86 94 91 69
After Pass #2: 84 86 94 91 76 69
After Pass #3: 86 94 91 84 76 69
After Pass #4: 94 91 86 84 76 69
After Pass #5 (done): 94 91 86 84 76 69
The bubble sort is an easy algorithm to program, but it is slower than many other
sorts. With a bubble sort, it is always necessary to make one final "pass" through the
array to check to see that no swaps are made to ensure that the process is finished. In
actuality, the process is finished before this last pass is made.
60
printf("\nThe total marks is %d\n", total);
printf("Mean marks is %f\n", meanmark);
}
Exchange Sort
The exchange sort is similar to its cousin, the bubble sort, in that it compares
elements of the array and swaps those that are not in their proper positions. (Some
people refer to the "exchange sort" as a "bubble sort".) The difference between these
two sorts is the manner in which they compare the elements. The exchange sort
compares the first element with each following element of the array, making any
necessary swaps.
When the first pass through the array is complete, the exchange sort then takes the
second element and compares it with each following element of the array swapping
elements that are out of order. This sorting process continues until the entire array is
ordered.
Let's examine our same table of elements again using an exchange sort for descending
order. Remember, a "pass" is defined as one full trip through the array comparing and
if necessary, swapping elements.
Array at beginning: 84 69 76 86 94 91
After Pass #1: 94 69 76 84 86 91
After Pass #2: 94 91 69 76 84 86
After Pass #3: 94 91 86 69 76 84
After Pass #4: 94 91 86 84 69 76
After Pass #5 (done): 94 91 86 84 76 69
The exchange sort, in some situations, is slightly more efficient than the bubble sort.
It is not necessary for the exchange sort to make that final complete pass needed by
the bubble sort to determine that it is finished.
61
{
int i, j;
int temp; // holding variable
int num[5];
//intialize array
for(i =0; i<=4; i++){
printf("Enter a number:");
scanf("%d",&num[i]);
}
//sort array
for (i=0; i< (4); i++) // element to be compared
{
for(j = (i+1); j < 5; j++) // rest of the elements
{
if (num[i] < num[j]) // descending order
{
temp= num[i]; // swap
num[i] = num[j];
num[j] = temp;
}
}
}
//print sorted array
printf("\nSorted array:\n");
Selection Sort
The selection sort is a combination of searching and sorting.
During each pass, the unsorted element with the smallest (or largest) value is
moved to its proper position in the array.
The number of times the sort passes through the array is one less than the number of
items in the array. In the selection sort, the inner loop finds the next smallest (or
largest) value and the outer loop places that value into its proper location.
Let's look at our same table of elements using a selection sort for descending order.
Remember, a "pass" is defined as one full trip through the array comparing and if
necessary, swapping elements.
Array at beginning: 84 69 76 86 94 91
After Pass #1: 84 91 76 86 94 69
62
After Pass #2: 84 91 94 86 76 69
After Pass #3: 86 91 94 84 76 69
After Pass #4: 94 91 86 84 76 69
After Pass #5 (done): 94 91 86 84 76 69
While being an easy sort to program, the selection sort is one of the least efficient.
The algorithm offers no way to end the sort early, even if it begins with an already
sorted list.
Shell Sort
The shell sort is named after its inventor D. L. Shell. Instead of comparing adjacent
elements, like the bubble sort, the shell sort repeatedly compares elements that are a
certain distance away from each other (d represents this distance). The value
of d starts out as half the input size and is halved after each pass through the array.
The elements are compared and swapped when needed. The equation d= (N + 1) / 2
is used. Notice that only integer values are used for d since integer division is
occurring.
Let's look at our same list of values for descending order with the shell sort.
Remember, a "pass" is defined as one full trip through the array comparing and if
necessary, swapping elements.
Array at beginning: 84 69 76 86 94 91 d
After Pass #1: 86 94 91 84 69 76 3
After Pass #2: 91 94 86 84 69 76 2
63
After Pass #3: 94 91 86 84 76 69 1
After Pass #4 (done): 94 91 86 84 76 69 1
First Pass: d = (6 + 1) / 2 = 3. Compare 1st and 4th , 2nd and 5th, and 3rd and 6th
items since they are 3 positions away from each other))
Second Pass: value for d is halved d = (3 + 1) / 2 = 2. Compare items two places
away such as 1st and 3rd ……
Third Pass: value for d is halved d = (2 + 1) / 2 = 1. Compare items one place away
such as 1st and 2nd …..
Last Pass: sort continues until d = 1 and the pass occurs without any swaps.
This sorting process, with its comparison model, is an efficient sorting algorithm.
Quick Sort
The quicksort is considered to be very efficient, with its "divide and conquer"
algorithm. This sort starts by dividing the original array into two sections (partitions)
based upon the value of the first element in the array. Since our example sorts into
descending order, the first section will contain all the elements greater than the first
element. The second section will contain elements less than (or equal to) the first
element. It is possible for the first element to end up in either section.
64
94 91 86 84 69 76
Done: 94 91 86 84 76 69
This sort uses recursion - the process of "calling itself". Recursion will be studied at a
later date.
int middle;
if (top < bottom)
{
middle = partition(num, top, bottom);
quicksort(num, top, middle); // sort first section
quicksort(num, middle+1, bottom); // sort second section
}
return;
}
do
{
i++;
} while (x <array[i]);
if (i < j)
{
temp = array[i];
array[i] = array[j];
65
array[j] = temp;
}
}while (i < j);
return j; // returns middle subscript
}
Merge Sort
The merge sort combines two sorted arrays into one larger sorted array.
As the diagram below shows, Array A and Array B merge to form Array C.
Here is how it works: The first element of array A is compared with the first element
of array B. If the first element of array A is smaller than the first element of array B,
the element from array A is moved to the new array C. The subscript of array A is
now increased since the first element is now set and we move on.
If the element from array B should be smaller, it is moved to the new array C. The
subscript of array B is increased. This process of comparing the elements in the two
arrays continues until either array A or array B is empty. When one array is empty,
any elements remaining in the other (non-empty) array are "pushed" into the end of
array C and the merge is complete.
66
}
indexC++; //move to the next position in the new array
}
// Move remaining elements to end of new array when one merging array is empty
while (indexA < 5)
{
arrayC[indexC] = arrayA[indexA];
indexA++;
indexC++;
}
while (indexB < 5)
{
arrayC[indexC] = arrayB[indexB];
indexB++;
indexC++;
}
return;
}
SEARCHING ARRAYS
When working with arrays, it is often necessary to perform a search or "lookup" to
determine whether an array contains a value that matches a certain key value The
process of locating a particular element value in an array is called searching. There are
two types of search mechanisms: serial/linear search and binary search
a) Serial Search
The technique used here is called a serial search, because the integer elements of the
array are compared one by one to the user input being looked for (userValue) until
either a match is found or all elements of the array are examined without finding a
match.
In the code below, if a match is found, the text “There is a match” is printed on the
form and the execution of the procedure is terminated (Exit Sub). If no match is
found, the program exits the loop and prints the text “No match found”.
#include <stdio.h>
int main()
{
int array[5]={10,7,8,2,5}, searchvalue, c;
67
printf("\n\t%d is present at location %d.\n",
searchvalue, c+1);
break;
}
}
if (c == 5) // if looped more than 5 times ie 6 times
printf("\n\t%d is not present in the array.\n",
searchvalue);
return 0;
}
Binary Search
Binary search uses the concept of splitting your searchable array in two, discarding the half
that does not have the element for which you are looking.
You place your items in an array and sort them. Then you simply get the middle element and
test if it is <, >, or = to the element for which you are searching. If it is less than, you discard
the greater half, get the middle index of the remaining elements and do it again. Binary search
divides your problem in half every time you execute your loop.
#include <stdio.h>
int main()
{
int c, first, last, middle, n, search, array[100];
first = 0;
last = n - 1;
middle = (first+last)/2;
68
}
if ( first > last )
printf("Not found! %d is not present in the list.\n", search);
return 0;
}
LINKED LISTS
A linked list is a dynamic data structure whose length can be increased or decreased at
run time.
How Linked lists are different from arrays? Consider the following points :
• An array is a static data structure. This means the length of array cannot be
altered at run time. While, a linked list is a dynamic data structure.
• In an array, all the elements are kept at consecutive memory locations while in
a linked list the elements (or nodes) may be kept at any location but still
connected to each other.
When to prefer linked lists over arrays? Linked lists are preferred mostly when you
don’t know the volume of data to be stored. For example, In an employee
management system, one cannot use arrays as they are of fixed length while any
number of new employees can join. In scenarios like these, linked lists (or other
dynamic data structures) are used as their capacity can be increased (or decreased) at
run time (as an when required).
POINTERS
A pointer is a variable whose value is the address of another variable, i.e., direct
address of the memory location. Like any variable or constant, you must declare a
pointer before you can use it to store any variable address. The general form of a
pointer variable declaration is:
type *var-name;
Here, type is the pointer's base type; it must be a valid C data type and var-name is
the name of the pointer variable. The asterisk * you used to declare a pointer is the
69
same asterisk that you use for multiplication. However, in this statement the asterisk
is being used to designate a variable as a pointer. Following are the valid pointer
declaration:
The actual data type of the value of all pointers, whether integer, float, character, or
otherwise, is the same, a long hexadecimal number that represents a memory address.
The only difference between pointers of different data types is the data type of the
variable or constant that the pointer points to.
There are few important operations, which we will do with the help of pointers very
frequently. (a) we define a pointer variable (b) assign the address of a variable to a
pointer and (c) finally access the value at the address available in the pointer variable.
This is done by using unary operator * that returns the value of the variable located at
the address specified by its operand. Following example makes use of these
operations:
#include <stdio.h>
int main ()
{
int var = 20; /* actual variable declaration */
int *ip; /* pointer variable declaration */
return 0;
}
When the above code is compiled and executed, it produces result something as
follows:
NULL Pointers in C
70
It is always a good practice to assign a NULL value to a pointer variable in case you
do not have exact address to be assigned. This is done at the time of variable
declaration. A pointer that is assigned NULL is called a null pointer.
The NULL pointer is a constant with a value of zero defined in several standard
libraries. Consider the following program:
#include <stdio.h>
int main ()
{
int *ptr = NULL;
return 0;
}
When the above code is compiled and executed, it produces the following result:
On most of the operating systems, programs are not permitted to access memory at
address 0 because that memory is reserved by the operating system. However, the
memory address 0 has special significance; it signals that the pointer is not intended to
point to an accessible memory location. But by convention, if a pointer contains the
null (zero) value, it is assumed to point to nothing.
C STRINGS
In C, one or more characters enclosed between double quotes is called a string. C does
not have built-in string data type. Instead, C supports strings using one-dimensional
arrays. A string is defined as a null terminated array i.e. \0. This means that you must
define the array that is going to hold a string to be one byte larger than the largest
string it is going to hold, in order to make room for the null.
To read a string from the keyboard, you must use another of C’s standard library
functions, gets( ) , which requires the stdio.h header file. The gets ( ) function reads
characters until you presss <ENTER>. The carriage return is not stored, but it is
replaced by a null, wich terminates the string. E.g.
#include<stdio.h>
Main ( )
Char str [80];
Int I;
Printf (ËNter a string: \n”);
71
gets(str);
The following declaration and initialization create a string consisting of the word
"Hello". To hold the null character at the end of the array, the size of the character
array containing the string is one more than the number of characters in the word
"Hello".
Initialization of strings
In C, string can be initialized in a different number of ways.
char c[]="abcd";
OR,
char c[5]="abcd";
OR,
char c[]={'a','b','c','d','\0'};
OR;
char c[5]={'a','b','c','d','\0'};
char *c="abcd";
String variable c can only take a word. It is beacause when white space is
encountered, the scanf() function terminates.
#include <stdio.h>
int main(){
char name[20];
printf("Enter name: ");
scanf("%s",name);
printf("Your name is %s.",name);
return 0;
}
72
Output
Here, program will ignore Ritchie because, scanf() function takes only string before
the white space.
The C library function int strcmp(const char *str1, const char *str2) compares the
string pointed to by str1 to the string pointed to by str2.
PARAMETERS
• str1 -- This is the first string to be compared.
• str2 -- This is the second string to be compared.
RETURN VALUE
73
Example
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[15];
char str2[15];
int ret;
strcpy(str1, "abcdef");
strcpy(str2, "ABCDEF");
if(ret > 0)
{
printf("str1 is less than str2");
}
else if(ret < 0)
{
printf("str2 is less than str1");
}
else
{
printf("str1 is equal to str2");
}
return(0);
}
More Examples
1) C Program to Find the Length of a String
#include <stdio.h>
int main()
{
char s[1000],i;
printf("Enter a string: ");
scanf("%s",s);
for(i=0; s[i]!='\0'; ++i);
printf("Length of string: %d",i);
return 0;
}
Output
74
printf("Enter first string: ");
scanf("%s",s1);
printf("Enter second string: ");
scanf("%s",s2);
for(i=0; s1[i]!='\0'; ++i); /* i contains length of string
s1. */
for(j=0; s2[j]!='\0'; ++j, ++i)
{
s1[i]=s2[j];
}
s1[i]='\0';
printf("After concatenation: %s",s1);
return 0;
}
Output
QUEUES
Queue is a specialized data storage structure (Abstract data type). Unlike arrays,
access of elements in a Queue is restricted. It has two main operations enqueue and
dequeue. Insertion in a queue is done using enqueue function and removal from a
queue is done using dequeue function. An item can be inserted at the end (‘rear’) of
the queue and removed from the front (‘front’) of the queue. It is therefore, also called
First-In-First-Out (FIFO) list. Queue has five properties - capacity stands for the
maximum number of elements Queue can hold, size stands for the current size of the
Queue, elements is the array of elements, front is the index of first element (the index
at which we remove the element) and rear is the index of last element (the index at
which we insert the element).
Primitive operations
a) enqueue (q, x): inserts item x at the rear of the queue q
b) x = dequeue (q): removes the front element from q and returns its value.
c) isEmpty(q) : true if the queue is empty, otherwise false.
Example
enqueue(q, ‘A’);
enqueue(q, ‘B’);
enqueue(q, ‘C’);
x = dequeue(q);
enqueue(q, ‘D’);
enqueue(q, ‘E’);
75
x= dequeue (q) -> x= ‘A’
STACKS
A stack is a 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.
Consequently, a stack is said to have "first in last out" behavior (or "last in, first out").
The first item added to a stack will be the last item removed from a stack.
76