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

17Cs1102: Data Structures: Time: 2 Hours Test-1 Key Max. Marks: 50

The document contains questions from a data structures exam. It includes questions on analyzing the runtime of recursive Fibonacci, implementing Shellsort, inserting a node into a doubly linked list at a given position, explaining Merge sort using divide and conquer, and finding the maximum subsequence sum in logarithmic time.

Uploaded by

mahesh
Copyright
© © All Rights Reserved
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
93 views

17Cs1102: Data Structures: Time: 2 Hours Test-1 Key Max. Marks: 50

The document contains questions from a data structures exam. It includes questions on analyzing the runtime of recursive Fibonacci, implementing Shellsort, inserting a node into a doubly linked list at a given position, explaining Merge sort using divide and conquer, and finding the maximum subsequence sum in logarithmic time.

Uploaded by

mahesh
Copyright
© © All Rights Reserved
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 17

Odd Semester, 2018-19

Sem-In Examinations-I, Sep 2018


B. Tech. (CSE), 2017 Batch
II/IV, 1st Semester

17CS1102: DATA STRUCTURES

Time: 2 hours Test-1 Key Max. Marks: 50


1. Perform running time analysis for Recursive Fibonacci by deriving
Recurrence Relations, and solve using Iteration/Substitution method.-4M
Answer:
long fibonacci (int n) { // Recursively calculates Fibonacci number 2M
if( n == 1 || n == 2)
return 1;
else
return fibonacci(n – 1) + fibonacci(n – 2);
}
• The base case is reached when n == 1 or n == 2. The method performs one
comparison and one return statement. Therefore each of T(1) and T(2) is
some constant c.

• When n > 2, the method performs TWO recursive calls, one with the parameter
n - 1 , another with parameter n – 2, and some constant # of basic operations.

• Hence, the recurrence relation is:

T(n) =c if n = 1 or n = 2
T(n) = T(n – 1) + T(n – 2) + b if n > 2
We determine a lower bound on T(n):
Expanding: T(n) = T(n - 1) + T(n - 2) + b 2M
≥ T(n - 2) + T(n-2) + b
= 2T(n - 2) + b
= 2[T(n - 3) + T(n - 4) + b] + b by substituting T(n - 2)
in (2)
 2[T(n - 4) + T(n - 4) + b] + b
= 22T(n - 4) + 2b + b
= 22[T(n - 5) + T(n - 6) + b] + 2b + b by substituting T(n - 4)
in (2)
≥ 23T(n – 6) + (22 + 21 + 20)b
...
k k-1
 2 T(n – 2k) + (2 + 2k-2 + . . . + 21 + 20)b
= 2kT(n – 2k) + (2k – 1)b
The base case isreachedwhen n – 2k = 2  k = (n - 2) / 2
(n – 2) / 2 (n - 2) / 2
Hence T(n) ≥ 2 T(2) + [2 – 1]b
(n – 2) / 2
= (b + c)2 –b
= [(b + c) / 2]*(2)n/2 – b Recursive Fibonacci is exponential.

2. Design Shell sort routine using Shell’s increments. Trace Shell sort after
each pass for an array A = <81, 94, 11, 96, 12, 35, 17, 95, 28, 58, 41, 75, 15>
– 4M
Answer :
Shell Sort 2M
 Improves on insertion sort.

 Starts by comparing elements far apart, then elements less far apart,
and finally comparing adjacent elements (effectively an insertion sort).
By this stage the elements are sufficiently sorted that the running time
of the final stage is much closer to O(N) than O(N2).

The idea of Shellsort is the following:

a) arrange the data sequence in a two-dimensional array


b) sort the columns of the array
The effect is that the data sequence is partially sorted.
The process above is repeated, but each time with a narrower array, i.e.
with a smaller number of columns. In the last step, the array consists of
only one column.
Example: A=<81,94,11,96,12,35,17,95,28,58,41,75,15>
Step 1: arrange the array list in 7 columns, Sort The above list in column wise
81 94 11 96 12 35 17
95 28 58 41 75 15

81 28 11 41 12 15 17
95 94 58 96 75 35
The sorted list as PASS 7: 81 28 11 41 12 15 17 95 94 58 96 75 35.
Step 2:Arrange the above array list in 5 columns, sort columns wise.
81 28 11 41 12 15 17 11 41 12
15 17 95 94 58 -> 81 28 35 94 58
96 75 35 96 75 95
The sorted list at AFTER 5 SORT: 15,17,11,41,12,81,28,35,94,58,96,75,95.
STEP 3: arrange the above updated array list in 3 columns
15 17 11 15 12 11
41 12 81 - 28 17 75
28 35 94 41 35 81
58 96 75 58 96 94
95 95
The updated array at this stage is : 15,12,11,28,17,75,41,35,81,58,96,94,95.
Step 4: Arrange the above list in 1 column and sort the array
15
12
11
28
17
75
41
35
81
58
96
94
95
After 1-sort 11 12 15 17 28 35 41 58 75 81 94 95 96.
Routine: 2M
void shellsort( int a[ ], unsigned int n )
{
unsigned int i, j, increment;
int tmp;
/*1*/ for( increment = n/2; increment > 0; increment /= 2 )
/*2*/ for( i = increment+1; i<=n; i++ )
{
/*3*/ tmp = a[i];
/*4*/ for( j = i; j > increment; j -= increment )
/*5*/ if( tmp< a[j-increment] )
/*6*/ a[j] = a[j-increment];
else
/*7*/ break;
/*8*/ a[j] = tmp;
}
}.
3 . Develop an algorithm to insert an element in ith position of doubly linked
list.
-4M

void insert_Pos() -2M


{
struct node *temp,*p;
int pos,len,i=1;
printf(“Enter the position where element to be inserted\n”);
scanf(“%d”,&pos);
len=length();
if(pos>len)
{
printf(“Invalid location \n Current list is having %d nodes”,len);
}
else
{
p=root ;
While(i<pos)
{
p=p->right;
i++;
}

Temp=(struct node*)malloc(sizeof(struct node)); -2M


Scanf(“%d”,&temp->data);

Temp->right=p->right;
p->right->left=temp;
p->right=temp;
temp->left=p;
}
}

4. Define divide and conquer strategy. State three steps of Merge sort. Write
the recursive merge-sort algorithm that takes an array as its input and gives
output. -4M
Answer:
Divide and Conquer: -1M
Divide and Conquer is an algorithmic paradigm. A typical Divide and Conquer
algorithm solves a problem using following three steps.
1. Divide: Break the given problem into subproblems of same type. -1M
2. Conquer: Recursively solve these subproblems
3. Combine: Appropriately combine the answers
Merge Sort is also a sorting algorithm follow Divide and Conquer strategy.
1. The algorithm divides the array in two halves,
2. Recursively sorts them and
3. Finally merges the two sorted halves.

void m_sort( int a[], input_type tmp_array[ ], int left, int right ) -2M
{
int center;
if( left < right )
{
center = (left + right) / 2;
m_sort( a, tmp_array, left, center );
m_sort( a, tmp_array, center+1, right );
merge( a, tmp_array, left, center+1, right );
}
for(i=left;i<right;i++)
{
printf(“%d\t”,A[i]);
}
}
void merge( int a[ ], int tmp_array[ ], int l_pos, int r_pos, int right_end )
{
int i, left_end, num_elements, tmp_pos;
left_end = r_pos - 1;
tmp_pos = l_pos;
num_elements = right_end - l_pos + 1;
/* main loop */
while( ( 1_pos <= left_end ) && ( r_pos <= right_end ) )
if( a[1_pos] <= a[r_pos] )
tmp_array[tmp_pos++] = a[l_pos++];
else
tmp_array[tmp_pos++] = a[r_pos++];
while( l_pos <= left_end ) /* copy rest of first half */
tmp_array[tmp_pos++] = a[l_pos++];
while( r_pos <= right_end ) /* copy rest of second half */
tmp_array[tmp_pos++] = a[r_pos++];
/* copy tmp_array back */
for(i=1; i <= num_elements; i++, right_end-- )
a[right_end] = tmp_array[right_end];
}
5. Develop a program to find the solution for the maximum subsequence
sum problem with logarithmic time. -4M
int max_sub_sequence_sum( int a[], unsigned int n ) -1M
{
return max_sub_sum( a, 0, n-1 );
}

int max_sub_sum( int a[], int left, int right ) -3M


{
int max_left_sum, max_right_sum;
int max_left_border_sum, max_right_border_sum;
int left_border_sum, right_border_sum;
int center, i;
/*1*/ if ( left == right ) /* Base Case */
/*2*/ if( a[left] > 0 )
/*3*/ return a[left];
else
/*4*/ return 0;
/*5*/ center = (left + right )/2;
/*6*/ max_left_sum = max_sub_sum( a, left, center );
/*7*/ max_right_sum = max_sub_sum( a, center+1, right );
/*8*/ max_left_border_sum = 0; left_border_sum = 0;
/*9*/ for( i=center; i>=left; i-- )
{
/*10*/ left_border_sum += a[i];
/*11*/ if( left_border_sum > max_left_border_sum )
/*12*/ max_left_border_sum = left_border_sum;
}
/*13*/ max_right_border_sum = 0; right_border_sum = 0;
/*14*/ for( i=center+1; i<=right; i++ )
{
/*15*/ right_border_sum += a[i];
/*16*/ if( right_border_sum > max_right_border_sum )
/*17*/ max_right_border_sum = right_border_sum;
}
/*18*/ return max3( max_left_sum, max_right_sum, max_left_border_sum +
max_right_border_sum);
}

6. Differentiate in terms of running time to insert a new node at the


beginning and at the end of a single linked list .-6M
Ans for :
Node insert_beg(Node head,int value) { 2M
Node newnode;
newnode=(Node)malloc(sizeof(struct node));
newnode->data=value;
if(head==NULL) {
newnode->nextnode=NULL;
head=newnode;
}
else
{
newnode->nextnode=head;
head=newnode;
}
return head;
}
Time complexity to insert node at head position of the list is O(1) as it does constant
amount of work. 1M

Node insert_end(Node head,int value) { 2M


Node newnode,ptr;
newnode=(Node)malloc(sizeof(Node));
newnode->data=value;
ptr=head;
while(ptr->nextnode!=NULL) ptr=ptr->nextnode;
ptr->nextnode=newnode;
newnode->nextnode=NULL;
return head;
}

Time complexity of append/insert at end position is O(n), where n is the number of


nodes in linked list. Since there is a loop from head to end, the function does O(n)
work. 1M

This method can also be optimized to work in O(1) by keeping an extra pointer to tail
of linked list.

7. Develop an algorithm to reverse a stack without using extra space in


O(n). - 6M

Answer:

Here in the below code we are changing the head pointing address in terms of pointer
to pointer reference, means address of head is passed from main() and its content is
being modified in stack_reverse function itself.

Struct node 1M
{
Int data;
Struct node *next;
};

void stack_reverse(struct node **head) 3M


{
struct node *temp, *prev;

if (*head == NULL)
{
printf("Stack does not exist\n");
}
else if ((*head)->next == NULL)
{
printf("Single node stack reversal brings no difference\n");
}
else if ((*head)->next->next == NULL)
{
(*head)->next->next = *head;
*head = (*head)->next;
(*head)->next->next = NULL;
}
else
{
prev = *head;
temp = (*head)->next;
*head = (*head)->next->next;
prev->next = NULL;
while ((*head)->next != NULL)
{
temp->next = prev;
prev = temp;
temp = *head;
*head = (*head)->next;
}
temp->next = prev;
(*head)->next = temp;
}
}
Time complexity of delete a node from end position is O(n), where n is the number
of nodes in linked list. Since there is a loop from head to end, the function does O(n)
work. 2M
8. Write and Analyze an algorithm to convert the given infix expression
into postfix and prefix expression for: (A – B) / ((D + E) * F). -6M
Answer:
Infix to Postfix Conversion Algorithm -2M
Let Q be any infix expression and we have to convert it to postfix expression P. For
this the following procedure will be followed.
1. Push left parenthesis onto STACK and add right parenthesis at the end of Q.

2. Scan Q from left to right and repeat step 3 to 6 for each element of Q until the
STACK is empty.
3. If an operand is encountered add it to P.
4. If a left parenthesis is encountered push it onto the STACK.
5. If an operator is encountered, then
 Repeatedly pop from STACK and add to P each operator
which has same precedence as or higher precedence than the operator
encountered.
 Push the encountered operator onto the STACK.
6. If a right parenthesis is encountered, then
 Repeatedly pop from the STACK and add to P each operator
until a left parenthesis is encountered.
 Remove the left parenthesis; do not add it to P.
7. Exit

1. Add a right parenthesis at the end of the string(A-B) /((D+E)*F) )


2. Push ( at the stack

Scanned Stack Postfix


Input expression

( (( ( Push into stack

A (( A Operand, add to postfix string


- (( - A Operator , push into stack

B (( - AB Operand, add to postfix string

) ( AB- ), Pop all the elements unti ‘(‘ is


encountered

/ (/ Operator , push into stack

( (/( ( Push into stack

( (/(( ( Push into stack

D (/(( AB-D Operand, add to postfix string

+ (/(( + AB-D Operator , push into stack

E (/(( + AB-DE Operand, add to postfix string

) (/( AB-DE+ ), Pop all the elements unti ‘(‘ is


encountered

* (/( * Operator , push into stack

F (/( * AB-DE+F Operand, add to postfix string

) (/ AB-DE+F* ), Pop all the elements unti ‘(‘ is


encountered

) AB-DE+F*/ ), Pop all the elements unti ‘(‘ is


encountered

The Postfix expression is AB-DE+F*/ - 2M


To convert into prefix.
Step 1: Reverse the string(A-B) /((D+E)*F) . We have )F*)E+D((/)B-A(
Step 2 : Convert the ) to ( and ( to )
Step 3: The expression is (F*(E+D)) /(B-A)
Step 4 : Convert into Postfix

Scanned Stack Postfix


Input expression

( (( ( Push into stack

F (( F Operand, add to postfix string

* (( * F Operator , push into stack

( (( * ( ( Push into stack

E FE Operand, add to postfix string

+ (( * ( + Operator , push into stack


D FED Operand, add to postfix string

) (( * FED+ ), Pop all the elements until ‘(‘ is


encountered

) ( FED+* Operand, add to postfix string

/ (/ Operator , push into stack

( (/ ( FED+*

B (/ ( FED+*B Operand, add to postfix string

- (/ (- FED+*B Operator , push into stack and


pop the highest precedence.

A (/ (- FED+*BA Operand, add to postfix string

) FED+*BA- ), Pop all the elements until ‘(‘ is


encountered

) FED+*BA-/ ), Pop all the elements until ‘(‘ is


encountered

Postfix :FED+*BA-/
Step 5: Reverse the string
Prefix expression is /–AB*+DEF -1M
The algorithm will take O(n) where n is the length of the string . The push and pop
operation in the stack will also in the time complexity of O(n). Hence , time
complexity is O(n) -1M

9. Illustrate the operation of BUCKET-SORT on the array A = <79, 13, 16,


64, 39, 20, 89, 53, 71, 42> by specifying the algorithm using linked list.
-6M

Answer:

Sorting data 3M
Algorithm 3M

Below is a simple implementation of bucket sort. It uses half the number of buckets
as the numbers of elements in the sequence to store. It goes through all the
elements in the sequence, and stores them in buckets. The bucket number to store
the element at is given by a hash function. The hash function assumes numbers in
sequence are uniformly distributed. Each bucket as a linked list to dynamically store
as many elements as it needs.

void bucketsort(int seq[], int size, int max) {


int i, j, left;
int bucket_numb;
int numb_buckets = size / BUCKETRATIO;
/* allocate and initialize buckets */
bucket_t *buckets = malloc(sizeof(bucket_t) * numb_buckets);
for (i = 0; i < numb_buckets; i++) {
buckets[i].size = 0;
buckets[i].list = NULL;
} /* distribute array elements into buckets */
for (i = 0; i < size; i++) {
bucket_numb = hash(seq[i], numb_buckets, max);
/* allocate and initialize node to put into bucket */
node_t *newnode = malloc(sizeof(node_t));
newnode->data = seq[i];
newnode->next = NULL;
/* store node into linked list of bucket bucket_numb
*/
buckets[bucket_numb].size++;
newnode->next = buckets[bucket_numb].list; /* store at first place */
buckets[bucket_numb].list = newnode;
printf("Element %d stored in bucket %d (size %d)\n", newnode->data,
bucket_numb,

buckets[bucket_numb].size);
/* instead, we could store in-order, and then we wouldn't have to apply
sorting to each list */
}
/* go through all buckets. Get elements out and overwrite sequence.
Then order the section of sequence with elements from bucket */
j = 0;
node_t *prev;
for (i = 0; i < numb_buckets; i++) {
if (buckets[i].size > 0) {
left = j;
node_t *listptr = buckets[i].list;
while (listptr != NULL) {
seq[j++] = listptr->data;
printf("Retrieved %d from bucket %d\n", seq[j-1], i);
prev = listptr;
listptr = listptr->next;
free(prev); /* deallocate memory */
}
/* sort subarray */
insertsort(seq, left, j);
}
}
}
void insertsort(int *seq, int left, int right) {
int i, j, element;
for (i = left + 1; i < right; i++) {
element = seq[i];
for (j = i-1; i >=0 && seq[j] > element; j--) {
seq[j+1] = seq[j];
}
seq[j+1] = element;
}
}
int hash(int value, int numb_buckets, int max){
/* for an uniform distribution, this hash should give the best
distribution of numbers throughout the buckets */
int key = value * numb_buckets / max;
return key;
}

10. Write a routine to perform insert and delete operations on single linked
list. Develop a routine to find whether the given elements in the single
linked list are unique (without duplication) or not and prove that it takes
quadratic time. -12M
Answer:
typedef struct list 4M
{
int data;
struct list *link;
}node;

Insertion: //Assume start is declare as local to main function.

node *insert(node *start)


{
node *newnode,*temp;
int pos,item,i;

printf("Enter the item to be inserted:\t");


scanf("%d",&item);
printf("Enter the position of insertion:\t");
scanf("%d",&pos);
newnode=(node *)malloc(sizeof(node));
newnode->data=item;
newnode->link=NULL;
if((pos==1) || (start==NULL)) // Insertion at begin
{
newnode->link=start;
start=newnode;
}
Else // Insert middle or end
{
temp=start;
i=2;
while((i<pos) && (temp!=NULL))
{
temp=temp->link;
i++;
}
newnode->link=temp->link;
temp->link=newnode;
}
return start;
}
Deletion: 4M

node *del(node *start)


{
node *cur,*prev,*temp;
int item;
printf("Enter an item value to be deleted:\t");
scanf("%d",&item);
if(start==NULL)
printf("Can't delete. List is empty");
else if(start->data==item) // Deleting first node.
{
temp=start;
start=start->link;
free(temp);
}
else
{
cur=start;
while((cur->data!=item) && (cur!=NULL))
{
prev=cur;
cur=cur->link;
}
if(cur==NULL)
printf("Element not found");
else // Deleting particular node.
{
temp = cur;
prev->link=cur->link;
free(temp);
}
return start;
}
To Find unique elements in linked list: 2M
void uniqueness()
{
struct node *t1,*t2;
for(t1=start;t1->next!=NULL;t1=t1->next)
{
t2=t1->next;
while(t1->data!=t2->data && t2!=NULL)
{
t2=t2->next;
}
if(t1->data==t2->data)
{
printf("\n Linked List not unique");
exit(1);
}
}
printf("\n Linked List is unique");
}
Time Complexity: 2M
No.of elements =n.
Each element should be checked with remaining all the elements. So,
No.of comparions in iteration1 = n-1
No.of comparions in iteration2 = n-2
……….
………
No.of comparions in iteration n-2 = 2
No.of comparions in iteration n-1 = 1

Total no.of comparions = (n-1)+(n-2)+…..2+1


= n(n-1)/2
=n2/2-n/2
Time complexity =O(n2)

11. Illustrate a non recursive, in-place version of the quick-sort algorithm.


The algorithm should still be based on the same divide-and-conquer approach,
but use an explicit stack to process sub problems -12M

Ans:

#include <stdio.h> 2M
Void swap ( int* a, int* b )
{
intt = *a;
*a = *b;
*b = t;
}

Int partition (int arr[], int l, int h) 3M


{
intx = arr[h];
inti = (l - 1);

for(intj = l; j <= h- 1; j++)


{
if(arr[j] <= x)
{
i++;
swap (&arr[i], &arr[j]);
}
}
swap (&arr[i + 1], &arr[h]);
return(i + 1);
}

voidquickSortIterative (intarr[], intl, inth) 3M


{
intstack[ h - l + 1 ];

inttop = -1;
stack[ ++top ] = l;
stack[ ++top ] = h;
while( top>= 0 )
{
h = stack[ top-- ];
l = stack[ top-- ];
intp = partition( arr, l, h );
if( p-1 > l )
{
stack[ ++top ] = l;
stack[ ++top ] = p - 1;
}
if( p+1 < h )
{
stack[ ++top ] = p + 1;
stack[ ++top ] = h;
}
}
}

Void printArr( intarr[], intn ) 2M


{
inti;
for( i = 0; i< n; ++i )
printf( "%d ", arr[i] );
}

Int main() 2M
{
Int arr[] = {4, 3, 5, 2, 1, 3, 2, 3};
intn = sizeof( arr ) / sizeof( *arr );
quickSortIterative( arr, 0, n - 1 );
printArr( arr, n );
return0;
}

You might also like