




























































































Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
“Comprehensive Data Structures notes covering arrays, stacks, queues, linked lists, trees, graphs, sorting and searching algorithms. Includes examples, diagrams, and explanations to help students understand concepts efficiently. Ideal for exam preparation and self-study for Computer Science & IT courses. 129 pages in total.”
Typology: Lecture notes
1 / 129
This page cannot be seen from the preview
Don't miss anything!





























































































Basic Concepts: Introduction to Data Structures: A data structure is a way of storing data in a computer so that it can be used efficiently and it will allow the most efficient algorithm to be used. The choice of the data structure begins from the choice of an abstract data type (ADT). A well-designed data structure allows a variety of critical operations to be performed, using as few resources, both execution time and memory space, as possible. Data structure introduction refers to a scheme for organizing data, or in other words it is an arrangement of data in computer's memory in such a way that it could make the data quickly available to the processor for required calculations. A data structure should be seen as a logical concept that must address two fundamental concerns.
structure used to represent the standard data types of any one of the computer languages. Variables, arrays, pointers, structures, unions, etc. are examples of primitive data structures. Compound Data structure: Compound data structure can be constructed with the help of any one of the primitive data structure and it is having a specific functionality. It can be designed by user. It can be classified as Linear data structure Non-linear data structure Linear Data Structure: Linear data structures can be constructed as a continuous arrangement of data elements in the memory. It can be constructed by using array data type. In the linear Data Structures the relationship of adjacency is maintained between the data elements. Operations applied on linear data structure: The following list of operations applied on linear data structures
considerable desirable. Efficiency of Algorithms: The performances of algorithms can be measured on the scales of time and space. The performance of a program is the amount of computer memory and time needed to run a program. We use two approaches to determine the performance of a program. One is analytical and the other is experimental. In performance analysis we use analytical methods, while in performance measurement we conduct experiments. Time Complexity: The time complexity of an algorithm or a program is a function of the running time of the algorithm or a program. In other words, it is the amount of computer time it needs to run to completion. Space Complexity: The space complexity of an algorithm or program is a function of the space needed by the algorithm or program to run to completion. The time complexity of an algorithm can be computed either by an empirical or theoretical approach. The empirical or posteriori testing approach calls for implementing the complete algorithms and executing them on a computer for various instances of the problem. The time taken by the execution of the programs for various instances of the problem are noted and compared. The algorithm whose implementation yields the least time is considered as the best among the candidate algorithmic solutions. Analyzing Algorithms Suppose M is an algorithm, and suppose n is the size of the input data. Clearly the complexity f(n) of M increases as n increases. It is usually the rate of increase of f(n) with some standard functions. The most common computing times are O(1), O(log 2 n), O(n), O(n log 2 n), O(n^2 ), O(n^3 ), O(2n) Example:
The total frequency counts of the program segments A, B and C given by 1, (3n+1) and (3n 2 +3n+1) respectively are expressed as O(1), O(n) and O(n^2 ). These are referred to as the time complexities of the program segments since they are indicative of the running times of the program segments. In a similar manner space complexities of a program can also be expressed in terms of mathematical notations,
Little oh(o): Definition: f(n) = O(g(n)) ( read as f of n is little oh of g of n), if f(n) = O(g(n)) and f(n) ≠ Ω(g(n)). Time Complexity: Time Complexities of various Algorithms: Numerical Comparision of Different Algorithms: S.No. log 2 n n nlog 2 n n^2 n^3 2 n
Computational Time(CPU consumption). Memory Space(RAM consumption). Communication bandwidth consumption.
Fib(2) = Fib(1) + Fib(0) = 1 Fib(3) = Fib(2) + Fib(1) = 2 Fib(4) = Fib(3) + Fib(2) = 3 Fib(5) = Fib(4) + Fib(3) = 5 Fib(6) = Fib(5) + Fib(4) = 8
nterms = 10
#nterms = int(input("How many terms? "))
n1 = 0 n2 = 1 count = 0
if nterms <= 0: print("Please enter a positive integer") elif nterms == 1: print("Fibonacci sequence upto",nterms,":") print(n1) else:
print("Fibonacci sequence upto",nterms,":") while count < nterms: print(n1,end=' , ') nth = n1 + n
n1 = n n2 = nth count += 1 Tail Recursion: Tail recursion is a form of linear recursion. In tail recursion, the recursive call is the last thing the function does. Often, the value of the recursive call is returned. As such, tail recursive functions can often be easily implemented in an iterative manner; by taking out the recursive call and replacing it with a loop, the same effect can generally be achieved. In fact, a good compiler can recognize tail recursion and convert it to iteration in order to optimize the performance of the code. A good example of a tail recursive function is a function to compute the GCD, or Greatest Common Denominator, of two numbers:
Recursive algorithms for Factorial, GCD, Fibonacci Series and Towers of Hanoi: Factorial(n) Input: integer n ≥ 0 Output: n!
if n == 1: print "Move disk 1 from rod",from_rod,"to rod",to_rod return TowerOfHanoi(n-1, from_rod, aux_rod, to_rod) print "Move disk",n,"from rod",from_rod,"to rod",to_rod TowerOfHanoi(n-1, aux_rod, to_rod, from_rod) n = 4 TowerOfHanoi(n, 'A', 'C', 'B') Searching Techniques: Linear Search: Searching is a process of finding a particular data item from a collection of data items based on specific criteria. Every day we perform web searches to locate data items containing in various pages. A search typically performed using a search key and it answers either True or False based on the item is present or not in the list. Linear search algorithm is the most simplest algorithm to do sequential search and this technique iterates over the sequence and checks one item at a time, until the desired item is found or all items have been examined. In Python the in operator is used to find the desired item in a sequence of items. The in operator makes searching task simpler and hides the inner working details. Consider an unsorted single dimensional array of integers and we need to check whether 31 is present in the array or not, then search begins with the first element. As the first element doesn't contain the desired value, then the next element is compared to value 31 and this process continues until the desired element is found in the sixth position. Similarly, if we want to search for 8 in the same array, then the search begins in the same manner, starting with the first element until the desired element is found. In linear search, we cannot determine that a given search value is present in the sequence or not until the entire array is traversed.
Source Code : def linear_search(obj, item, start=0): for i in range(start, len(obj)): if obj[i] == item: return i return - 1 arr=[1,2,3,4,5,6,7,8] x= result=linear_search(arr,x) if result==-1: print ("element does not exist") else: print ("element exist in position %d" %result) Time Complexity of Linear Search: Any algorithm is analyzed based on the unit of computation it performs. For linear search, we need to count the number of comparisons performed, but each comparison may or may not search the desired item. Case Best Case Worst Case Average Case If item is present 1 n n / 2 If item is not present n n n Binary Search: In Binary search algorithm, the target key is examined in a sorted sequence and this algorithm starts searching with the middle item of the sorted sequence. a. If the middle item is the target value, then the search item is found and it returns True. b. If the target item < middle item, then search for the target value in the first half of the list. c. If the target item > middle item, then search for the target value in the second half of the list. In binary search as the list is ordered, so we can eliminate half of the values in the list in each iteration. Consider an example, suppose we want to search 10 in a sorted array of elements, then we first determine
of the list will be eliminated. If this process is repeated for several times, then there will be just one item left in the list. The number of comparisons required to reach to this point is n/2i^ = 1. If we solve for i , then it gives us i = log n. The maximum number is comparison is logarithmic in nature, hence the time complexity of binary search is O(log n). Case Best Case Worst Case Average Case If item is present 1 O(log n) O(log n) If item is not present O(log n) O(log n) O(log n) Fibonacci Search: It is a comparison based technique that uses Fibonacci numbers to search an element in a sorted array. It follows divide and conquer approach and it has a O(log n) time complexity. Let the element to be searched is x, then the idea is to first find the smallest Fibonacci number that is greater than or equal to length of given array. Let the Fibonacci number be fib(nth^ Fibonacci number). Use (n-2)th Fibonacci number as index and say it is i, then compare a[i] with x, if x is same then return i. Else if x is greater, then search the sub array after i, else search the sub array before i. Source Code :
from bisect import bisect_left
def fibMonaccianSearch(arr, x, n):
fibMMm2 = 0 # (m-2)'th Fibonacci No. fibMMm1 = 1 # (m-1)'th Fibonacci No. fibM = fibMMm2 + fibMMm1 # m'th Fibonacci
while (fibM < n): fibMMm2 = fibMMm fibMMm1 = fibM fibM = fibMMm2 + fibMMm
offset = - 1;
while (fibM > 1):
i = min(offset+fibMMm2, n-1)
if (arr[i] < x): fibM = fibMMm fibMMm1 = fibMMm fibMMm2 = fibM - fibMMm offset = i
elif (arr[i] > x): fibM = fibMMm fibMMm1 = fibMMm1 - fibMMm fibMMm2 = fibM - fibMMm
else : return i
if(fibMMm1 and arr[offset+1] == x): return offset+1;
return - 1
arr = [10, 22, 35, 40, 45, 50, 80, 82, 85, 90, 100] n = len(arr) x = 80 print("Found at index:", fibMonaccianSearch(arr, x, n)) Time Complexity of Fibonacci Search: Time complexity for Fibonacci search is O(log 2 n) Sorting Techniques: Sorting in general refers to various methods of arranging or ordering things based on criteria's (numerical, chronological, alphabetical, hierarchical etc.). There are many approaches to sorting data and each has its own merits and demerits.
Various Passes of Bubble Sort Source Code:
def bubbleSort(arr): n = len(arr)
for i in range(n):
for j in range(0, n-i-1):
if arr[j] > arr[j+1] :
arr[j], arr[j+1] = arr[j+1], arr[j]
arr = [64, 34, 25, 12, 22, 11, 90] bubbleSort(arr) print ("Sorted array is:") for i in range(len(arr)): print ("%d" %arr[i]) Step-by-step example: Let us take the array of numbers "5 1 4 2 8", and sort the array from lowest number to greatest number using bubble sort. In each step, elements written in bold are being compared. Three passes will be required. First Pass: ( 5 1 4 2 8 ) ( 1 5 4 2 8 ), Here, algorithm compares the first two elements, and swaps since 5 > 1. ( 1 5 4 2 8 ) ( 1 4 5 2 8 ), Swap since 5 > 4 ( 1 4 5 2 8 ) ( 1 4 2 5 8 ), Swap since 5 > 2 ( 1 4 2 5 8 ) ( 1 4 2 5 8 ), Now, since these elements are already in order (8 > 5), algorithm does not swap them. Second Pass: ( 1 4 2 5 8 ) ( 1 4 2 5 8 ) ( 1 4 2 5 8 ) ( 1 2 4 5 8 ), Swap since 4 > 2 ( 1 2 4 5 8 ) ( 1 2 4 5 8 ) ( 1 2 4 5 8 ) ( 1 2 4 5 8 ) Now, the array is already sorted, but our algorithm does not know if it is completed. The algorithm needs one whole pass without any swap to know it is sorted. Third Pass: ( 1 2 4 5 8 ) ( 1 2 4 5 8 ) ( 1 2 4 5 8 ) ( 1 2 4 5 8 ) ( 1 2 4 5 8 ) ( 1 2 4 5 8 )