VTU 3RD SEM CSE DATA STRUCTURES WITH C NOTES 10CS35, Study notes of Data Structures and Algorithms

VTU 3RD SEM CSE DATA STRUCTURES WITH C NOTES 10CS35

Typology: Study notes

2013/2014
On special offer
30 Points
Discount

Limited-time offer


Uploaded on 12/30/2014

unknown user
unknown user 🇮🇳

1 / 64

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
DATA STRUCTURES WITH C
(Common to CSE & ISE)
Subject Code: 10CS35 I.A. Marks : 25
Hours/Week : 04 Exam Hours: 03
Total Hours : 52 Exam Marks: 100
PART A
UNIT - 1 8 Hours
BASIC CONCEPTS: Pointers and Dynamic Memory Allocation, Algorithm Specification, Data Abstraction,
Performance Analysis, Performance Measurement
UNIT - 2 6 Hours
ARRAYS and STRUCTURES: Arrays, Dynamically Allocated Arrays, Structures and Unions, Polynomials,
Sparse Matrices, Representation of Multidimensional Arrays
UNIT - 3 6 Hours
STACKS AND QUEUES: Stacks, Stacks Using Dynamic Arrays, Queues, Circular Queues Using Dynamic
Arrays, Evaluation of Expressions, Multiple Stacks and Queues.
UNIT - 4 6 Hours
LINKED LISTS: Singly Linked lists and Chains, Representing Chains in C, Linked Stacks and Queues,
Polynomials, Additional List operations, Sparse Matrices, Doubly Linked Lists
PART - B
UNIT - 5 6 Hours
TREES 1: Introduction, Binary Trees, Binary Tree Traversals, Threaded Binary Trees, Heaps.
UNIT - 6 6 Hours
TREES 2, GRAPHS: Binary Search Trees, Selection Trees, Forests, Representation of Disjoint Sets, Counting
Binary Trees, The Graph Abstract Data Type.
UNIT - 7 6 Hours
PRIORITY QUEUES Single- and Double-Ended Priority Queues, Leftist Trees, Binomial Heaps, Fibonacci
Heaps, Pairing Heaps.
UNIT - 8 8 Hours
EFFICIENT BINARY SEARCH TREES: Optimal Binary Search Trees, AVL Trees, Red-Black Trees, Splay
Trees.
Text Book:
1. Horowitz, Sahni, Anderson-Freed: Fundamentals of Data Structures in C, 2nd Edition, University Press,
2007.
(Chapters 1, 2.1 to 2.6, 3, 4, 5.1 to 5.3, 5.5 to 5.11, 6.1, 9.1 to 9.5, 10)
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30
pf31
pf32
pf33
pf34
pf35
pf36
pf37
pf38
pf39
pf3a
pf3b
pf3c
pf3d
pf3e
pf3f
pf40
Discount

On special offer

Partial preview of the text

Download VTU 3RD SEM CSE DATA STRUCTURES WITH C NOTES 10CS35 and more Study notes Data Structures and Algorithms in PDF only on Docsity!

(Common to CSE & ISE)

Subject Code: 10CS35 I.A. Marks : 25 Hours/Week : 04 Exam Hours: 03 Total Hours : 52 Exam Marks: 100

PART – A

UNIT - 1 8 Hours BASIC CONCEPTS: Pointers and Dynamic Memory Allocation, Algorithm Specification, Data Abstraction, Performance Analysis, Performance Measurement

UNIT - 2 6 Hours ARRAYS and STRUCTURES: Arrays, Dynamically Allocated Arrays, Structures and Unions, Polynomials, Sparse Matrices, Representation of Multidimensional Arrays

UNIT - 3 6 Hours STACKS AND QUEUES: Stacks, Stacks Using Dynamic Arrays, Queues, Circular Queues Using Dynamic Arrays, Evaluation of Expressions, Multiple Stacks and Queues.

UNIT - 4 6 Hours LINKED LISTS: Singly Linked lists and Chains, Representing Chains in C, Linked Stacks and Queues, Polynomials, Additional List operations, Sparse Matrices, Doubly Linked Lists

PART - B

UNIT - 5 6 Hours TREES – 1: Introduction, Binary Trees, Binary Tree Traversals, Threaded Binary Trees, Heaps.

UNIT - 6 6 Hours TREES – 2, GRAPHS: Binary Search Trees, Selection Trees, Forests, Representation of Disjoint Sets, Counting Binary Trees, The Graph Abstract Data Type.

UNIT - 7 6 Hours PRIORITY QUEUES Single- and Double-Ended Priority Queues, Leftist Trees, Binomial Heaps, Fibonacci Heaps, Pairing Heaps.

UNIT - 8 8 Hours EFFICIENT BINARY SEARCH TREES: Optimal Binary Search Trees, AVL Trees, Red-Black Trees, Splay Trees.

Text Book:

  1. Horowitz, Sahni, Anderson-Freed: Fundamentals of Data Structures in C, 2nd^ Edition, University Press,
    (Chapters 1, 2.1 to 2.6, 3, 4, 5.1 to 5.3, 5.5 to 5.11, 6.1, 9.1 to 9.5, 10)

TABLE OF CONTENTS

  • UNIT 1: BASIC CONCETPS 1-
  • UNIT 2: ARRAYS & STRUCTURES 13-
  • UNIT 3: STACKS & QUEUES 27-
  • UNIT 5: TREES 37-
  • UNIT 6: TREES(CONT.) & GRAPHS 51-

There is a giant asleep within everyone. When that giant awakens, miracles happen.

DYNAMIC MEMORY ALLOCATION

  • This is process of allocating memory-space during execution-time (or run-time).
  • This is used if there is an unpredictable storage requirement.
  • Memory-allocation is done on a heap.
  • Memory management functions include: → malloc (memory allocate) → calloc (contiguous memory allocate) → realloc (resize memory) → free (deallocate memory)
  • malloc function is used to allocate required amount of memory-space during run-time.
  • If memory allocation succeeds, then address of first byte of allocated space is returned. If memory allocation fails, then NULL is returned.
  • free() function is used to deallocate(or free) an area of memory previously allocated by malloc() or calloc(). #include<stdio.h> void main() { int i,pi; pi=(int)malloc(sizeof(int)); *pi=1024; printf("an integer =%d",pi); free(pi); }

Program 1.2: Allocation and deallocation of memory

  • If we frequently allocate the memory space, then it is better to define a macro as shown below: #define MALLOC(p,s)
    if(!((p)==malloc(s)))
    {
    printf("insufficient memory");
    exit(0);
    }
  • Now memory can be initialized using following: MALLOC(pi,sizeof(int)); MALLOC(pf,sizeof(float))

DANGLING REFERENCE

  • Whenever all pointers to a dynamically allocated area of storage are lost, the storage is lost to the program. This is called a dangling reference.

POINTERS CAN BE DANGEROUS

  1. Set all pointers to NULL when they are not actually pointing to an object. This makes sure that you will not attempt to access an area of memory that is either → out of range of your program or → that does not contain a pointer reference to a legitimate object
  2. Use explicit type casts when converting between pointer types. pi=malloc(sizeof(int)); //assign to pi a pointer to int pf=(float*)pi; //casts an ‘int’ pointer to a ‘float’ pointer
  3. Pointers have same size as data type 'int'. Since int is the default type specifier, some programmers omit return type when defining a function. The return type defaults to ‘int’ which can later be interpreted as a pointer. Therefore, programmer has to define explicit return types for functions.

void swap(int *p,int q) //both parameters are pointers to ints { int temp=p; //declares temp as an int and assigns to it the contents of what p points to p=q; //stores what q points to into the location where p points *q=temp; //places the contents temp in location pointed to by q }

Program 1.3: Swap function

Happiness isn't a place you get to, it's an inner state you create. Anyone can be happy, it's available to everyone & is available right now.

ALGORITHM SPECIFICATION

  • An algorithm is a finite set of instructions that accomplishes a particular task.
  • Algorithm must satisfy following criteria:
    1. Input: There are zero or more quantities that are externally supplied.
    2. Output: At least one quantity is produced.
    3. Definiteness: Each instruction is clear & unambiguous.
    4. Finiteness: If we trace out instructions of an algorithm, then for all cases, algorithm terminates after a finite number of steps.
    5. Effectiveness: Every instruction must be basic enough and feasible.
  • Algorithm can be described in following ways:
    1. We can use natural language consisting of some mathematical equations.
    2. We can use graphic representations such as flowcharts.
    3. We can use combination of C and English language constructs.
  • Algorithm 1.1: Selection sort algorithm. for(i=0;i<n;i++) { Examine list[i] to list[n-1] and suppose that the smallest integer is at list[min]; Interchange list[i] and list[min]; }
  • Algorithm 1.2: finding the smallest integer. assume that minimum is list[i] compare current minimum with list[i+1] to list[n-1] and find smaller number and make it the new minimum
  • Algorithm 1.3: Binary search. assumption :sorted n(≥1) distinct integers stored in the array list return i if list [ i ] = searchnum; - 1 if no such index exists denote left and right as left and right ends of the list to be searched ( left =0 & right =n-1) let middle =( left + right )/2 middle position in the list compare list[middle] with searchnum and adjust left or right compare list[middle] with searchnum 1) searchnum < list[middle] set right to middle- 1 2) searchnum = list[middle] return middle 3) searchnum > list[middle] set left to middle+ if searchnum has not been found and there are more integers to check recalculate middle and continue search
  • Algorithm 1.4: Permutations. given a set of n(≥1) elements print out all possible permutations of this set e.g. if set {a,b,c} is given, then set of permutations is {(a,b,c), (a,c,b), (b,a,c), (b,c,a), (c,a,b), (c,b,a)}

int binsearch(int list[], int searchnum, int left, int right) { // search list[0]<= list[1]<=...<=list[n-1] for searchnum int middle; while (left<= right) { middle= (left+ right)/2; switch(compare(list[middle], searchnum)) { case -1: left= middle+ 1; break; case 0: return middle; case 1: right= middle- 1; } } return -1; }

int compare(int x, int y) { if (x< y) return -1; else if (x== y) return 0; else return 1; }

Program 1.4: Iterative Implementation of Binary Search

The level of thinking that got you to where you now are, will not get you to where you dream of being.

DATA ABSTRACTION

  • The process of separating logical properties of data from implementation details of data is called data abstraction. Data Type
  • A data type is a collection of objects and a set of operations that act on those objects.
  • For e.g., data type 'int' consists of → objects {0,+1,-1,+2,-2.... } → operations such as arithmetic operators + - * / ADT (ABSTRACT DATA TYPE)
  • This is a data type that is organized in such a way that → specification of objects is separated from representation of objects → specification of operations on objects is separated from implementation of operations
  • For example, Specification: The specification of operations on objects consists of names of functions, type of arguments and return type. But, no information is given about how to implement in a programming language. So, specifications are implementation independent. Implementation: The implementation of operations consists of a detailed algorithm using which we can code (i.e. functions) using any programming language(C or C++).
  • ADTs can be implemented in C++ using a concept called class.
  • ADT definition contains 2 main sections: → Objects & → Functions
  • Functions of a data type can be classified into
    1. Constructor: These functions create a new instance of the designated type. For ex, NaturalNumber Zero() ::= 0
    2. Transformers: These functions create an instance of the designated type, generally by using one or more other instances. For ex, NaturalNumber Successor(x) ::= if(x==INT_MAX) return INT_MAX else return x+
    3. Reporters: These functions provide information about an instance of the type, but they do not change the instance. For ex, Boolean IsZero(x) ::= if(x is zero) return TRUE else return FALSE

For your life to be great, your faith must be bigger than your fears.

PERFORMANCE ANALYSIS

  • The process of estimating time & space consumed by program is called performance analysis.
  • Efficiency of a program depends on 2 factors:
    1. Space efficiency (primary & secondary memory) &
    2. Time efficiency (execution time of program)

SPACE COMPLEXITY

  • Space complexity of a program is the amount of memory required to run the program completely.
  • Total space requirement of any program is given by S(P)= fixed space requirement + variable space requirement S(P)= c + Sp(I) 1) Fixed Space Requirements - This component refers to space requirements that do not depend on the number and size of the program's inputs and outputs. - Fixed requirements include → program space (space for storing machine language program) → data space (space for constants, variables, structures) 2) Variable Space Requirements - This component consists of space needed by structured variables whose size depends on particular instance of problem being solved. This also includes additional space required when a function uses recursion.

float abc(float a, float b, float c) { return a + b + b * c + (a + b - c) / (a + b) + 4.00; // Sabc(I) = 0 }

Program 1.8: Simple arithmetic function

int sum(int list[],int n) { int temp=0; int i; for(i=0;i<n;i++) temp=temp+list[i]; return temp; }

Program 1.9: Iterative function for summing a list of numbers

  • In above program, there is no variable space requirement. This has only fixed space requirement ie Ssum(I) = 0. However, if same program is expressed recursively, then it is as shown below.

float rsum(int list[], int n) { if(n) return rsum(list,n-1)+list[n-1]; return 0; }

Program 1.10: Recursive function for summing a list of numbers

  • Space needed for one recursive call for above program is given below Type Name Number of bytes parameter:float list[] 2 parameter:integer n 2 return address: 2 TOTAL per recursive call 6 Ssum(I)= Ssum(n)=6n

The man who succeeds above his fellows is the one who early in life clearly discerns his object and towards that object habitually directs his powers.

TABULAR METHOD

  • The following procedure is used to obtain step-count:
    1. Determine step count for each statement. This is called step/execution(s/e).
    2. Find out number of times each statement is executed. This is called frequency. The frequency of non-executable statement is zero.
    3. Multiply s/e(obtained in 1) and frequency(obtained in 2) to get total steps for each statement.
    4. Add the totals(obtained in 3) to get step count for entire function.

Figure 1.2: Step count table

Figure 1.3: Step count table for recursive summing functions

Figure 1.4: Step count table for matrix addition

  • The best case step count is the minimum number of steps that can be executed for the given parameters. The worst-case step count is the maximum number of steps that can be executed for the given parameters. The average step count is the average number of steps executed on instances with the given parameters.

When you align your outer world with your inner world, the universe throws its winds beneath your wings & sends you more of its treasures.

ASYMPTOTIC NOTATION

  • The asymptotic behavior of a function is the study of how the value of a function f(n) varies for large value of n, where n=input size.
  • Various types of asymptotic notations are:
    1. Big(oh) notation(worst case time complexity)
    2. Omega notation (best case time complexity)
    3. Theta notation (average case time complexity) 1) Big Oh Notation
  • Big oh is a measure of the longest amount of time taken by algorithm to complete execution.
  • This is used for finding worst case time efficiency.
  • A function f(n)=O(g(n)) iff there exists positive constants c and n 0 such that f(n)<=c.g(n) for all n, n>=n 0.
  • Here, c.g(n) is the upper bound. The upper bound on f(n) indicates that function f(n) will not consume more than the specified time c.g(n) i.e. running time of function f(n) may be equal to c.g(n) but it will never be worse than the upper bound.
  • For ex, 3n+2=O(n) as 3n+2<4n for all n>2. 2) Omega Notation
  • Omega is a measure of the least amount of time taken by algorithm to complete execution.
  • This is used for finding best case time efficiency.
  • A function f(n)= Ω(g(n)) iff there exists positive constant c and n 0 such that f(n)>=cg(n) for all n, n>=n 0
  • Here, c.g(n) is the lower bound. The lower bound on f(n) will consume at least the specified time c.g(n) i.e. running time of function f(n) may be equal to c.g(n) but it will never be better than the lower bound.
  • For ex, 3n+2= (n) as 3n+2• =3n for all n>=1. 3) Theta Notation
  • This is a measure of the least as well as longest amount of time taken by the algorithm to complete.
  • A function f(n)= Θ(g(n)) iff there exists positive constants c 1 ,c 2 and n 0 such that c 1 g(n)<=f(n)<=c 2 g(n) for all n, n>=n 0.
  • Theta notation is more precise than both the big oh and omega notations.
  • This notation is used to denote both lower bound and upper bound on a function.
  • For ex, 3n+2= (n) as 3n+2>=3n for all n>=2 and 3n+2<=4n for all n>=2,so c 1 =3,c 2 =4 and n 0 =2.

To live your highest life, the trick is to have the heart & the mind working together in harmony.

PRACTICAL COMPLEXITIES

  • The time complexities of a program are useful in determining better algorithm among the algorithms that perform the same task. i.e. by comparing the time complexities of two algorithms that perform the same task, we can determine which algorithm is better.
  • For ex, let time complexities of two programs P and Q be (n) and (n^2 ) respectively. Since, order of P is less than order of Q, the program P is faster than Q.
  • Time complexity of an algorithm is normally expressed as a function of ‘n’ as shown in following table.

Figure 1.7: Function values

Figure 1.8: Plot of function values

Breakdowns always lead to breakthroughs.

PERFORMANCE MEASUREMENT

  • The measure of how fast an algorithm is executed on a specific machine and how efficiently the algorithm uses space on that machine during execution is called performance measurement.
  • Performance measurement wrt time can be obtained using 2 methods:
    1. Using clock() function
    2. Using time() function

Figure 1.10: Event timing in C

Using clock() Function

  • This function → returns amount of processor-time that has elapsed since the program running → is accessed through statement: #include<time.h>
  • To find the time, we use clock() function twice in the program, once at: → start of event → end of event
  • The difference between stop-time and start-time gives processor-time for the activity to be completed.
  • To convert into seconds, we divide it by "ticks per second" which is identified using symbolic constant CLOCKS_PER_SEC. Using time() Function
  • This function → returns time measured in seconds → has one parameter which specifies a location to hold the time
  • When we do not want to store the time, pass NULL as the parameter.
  • To find the time, we use time() function twice in the program, once at: → start of the event → end of the event
  • When start-time and stop-time are passed as parameters to the function time(), the function returns the difference between 2 times measured in seconds.

Program 1.15: Sequential search Program 1.16: program to time program 1.

For every finger we point at another, we have three pointing back at us.

ARRAYS IN C

  • A one-dimensional array can be declared as follows: int list[5]; //array of 5 integers int *plist[5]; //array of 5 pointers to integers
  • Compiler allocates 5 consecutive memory-locations for each of the variables 'list' and 'plist'.
  • Address of first element list[0] is called base-address.
  • Memory-address of list[i] can be computed by compiler as +i*sizeof(int) where =base address

void print1(int ptr, int rows) { / print out a one-dimensional array using a pointer */ int i; printf(“Address Contents\n”); for (i=0; i < rows; i++) printf(“%8u%5d\n”, ptr+i, *(ptr+i)); printf(“\n”); }

void main() { int one[] = {0, 1, 2, 3, 4}; print1(&one[0], 5) }

Program 2.2:Program to print both address of ith element of given array & the value found at that address(Fig 2.1)

Figure 2.1: one dimensional array addressing

The people who endure more pain & suffering are meant for greater things on the planet.

DYNAMICALLY ALLOCATED ARRAYS

ONE-DIMENSIONAL ARRAYS

  • When writing programs, sometimes we cannot reliably determine how large an array must be.
  • A good solution to this problem is to → defer this decision to run-time & → allocate the array when we have a good estimate of required array-size
  • Dynamic memory allocation can be performed as follows: int i,n,list; printf("enter the number of numbers to generate"); scanf("%d",&n); if(n<1) { printf("improper value"); exit(0); } MALLOC(list, nsizeof(int));
  • The above code would allocate an array of exactly the required size and hence would not result in any wastage.

TWO DIMENSIONAL ARRAYS

  • These are created by using the concept of array of arrays.
  • A 2-dimensional array is represented as a 1-dimensional array in which each element has a pointer to a 1-dimensional array as shown below int x[5][7]; //we create a 1-dimensional array x whose length is 5; //each element of x is a 1-dimensional array whose length is 7.
  • Address of x[i][j] = x[i]+j*sizeof(int)

Figure 2.2: Array-of-arrays representation

#include <stdlib.h> int **array; array = malloc(nrows * sizeof(int *)); if(array == NULL) { printf("out of memory\n"); exit or return } for(i = 0; i < nrows; i++) { array[i] = malloc(ncolumns * sizeof(int)); if(array[i] == NULL) { printf("out of memory\n"); exit or return } }

Program 2.3: Dynamically create a two-dimensional array

We have forty million reasons for failure, but not a single excuse.

STRUCTURES

  • This is collection of elements whose data types are different. typedef struct { char name[10]; int age; float salary; }humanBeing;
  • Dot operator(.) is used to access a particular member of the structure. For ex, person.age=10; person.salary=35000; strcpy(person.name,"james");
  • Variables can be declared as follows humanBeing person1,person2;
  • Structures cannot be directly checked for equality or inequality. So, we can write a function to do this. if(humansEqual(person1,person2)) printf("two human beings are same"); else printf("two human beings are different");

int humansEqual(humanBeing person1,humanBeing person2) { if(strcmp(person1.name,person2.name)) return 0; if(person1.age!=person2.salary) return 0; if(person.salary!=person2.salary) return 0; return 1; }

  • We can embed a structure within a structure. typedef struct { int month; int day; int year; }date;

typedef struct { char name[10]; int age; float salary; data dob; }humanBeing;

When you shift from a compulsion to survive toward a commitment to serve others, your life cannot help but explode into success.

SELF-REFERENTIAL STRUCTURES

  • A self-referential structure is one in which one or more of its components is a pointer to itself.
  • These require dynamic storage management routines (malloc & free) to explicitly obtain and release memory. typedef struct { char data; struct list *link; //list is a pointer to a list structure }list;
  • Consider three structures and values assigned to their respective fields: list item1,item2,item3; item1.data='a'; item2.data='b'; item3.data='c'; item1.link=item2.link=item3.link=NULL;
  • We can attach these structures together as follows item1.link=&item2; tem2.link=&item3;

UNION

  • This is similar to a structure, but the fields of a union must share their memory space. This means that only one field of the union is "active" at any given time. For ex, typedef struct { enum tagField{female,male} sex; typedef union { int children; int beard; }u; }sexType;

typedef struct { char name[10]; int age; float salary; date dob; sexType sexInfo; }humanBeing;

humanBeing person1,person2;

  • We can assign values to person1 and person2 as: person1.sexInfo.sex=male; person1.sexInfo.u.beard=FALSE; and person2.sexInfo.sex=female; person1.sexInfo.u.children=3;

INTERNAL IMPLEMENTATION OF STRUCTURES

  • The size of an object of a struct or union type is the amount of storage necessary to represent the largest component, including any padding that may be required.
  • Structures must begin and end on the same type of memory boundary. For ex, an even byte boundary (2, 4, 6 or 8).