Algorithm In C Language
Algorithm in C language
An algorithm is a sequence of instructions that are carried out in a predetermined sequence in order to solve a problem or complete a work. A function is a block of code that can be called and executed from other parts of the program.
A set of instructions for resolving an issue or carrying out a certain activity. In computer science, algorithms are used for a wide range of operations, from fundamental math to intricate data processing.
One of the common algorithms used in C is the sorting algorithm. A sorting algorithm arranges a collection of items in a certain order, such as numerically or alphabetically.
There are many sorting algorithms, each with advantages and disadvantages. The most common sorting algorithms in C are quicksort, merge, and sort.
One of the key features of C is pointer support. This allows efficient manipulation of data structures such as arrays, queues etc. This makes it suitable for implementing algorithms that require complex data manipulation, such as sorting and algorithmic searching.
One of the famous examples of software library implemented in C is the Standard Template Library (STL). This library provides a wide variety of algorithms for tasks such as sorting, searching, and manipulating data structures.
From the data structure point of view, following are some important categories of algorithms −
- Search − Algorithm to search an item in a data structure.
- Sort − Algorithm to sort items in a certain order.
- Insert − Algorithm to insert item in a data structure.
- Update − Algorithm to update an existing item in a data structure.
- Delete − Algorithm to delete an existing item from a data structure.
Features of the algorithm
It defines several important features of the algorithm, including:
- Inputs: Algorithms must receive inputs that can be represented as values or data.
- Output: The algorithm should produce some output. It can be a consequence of a problem or a solution designed to solve it.
- Clarity: Algorithms must be precisely defined, using unambiguous instructions that a computer or other system can follow unambiguously.
- Finiteness: The algorithm requires a limited steps. It means that it should be exited after executing a certain number of commands.
- Validity: The algorithm must be valid. In other words, it should be able to produce a solution to the problem that the algorithm is designed to solve in a reasonable amount of time.
- Effectiveness: An algorithm must be effective, meaning that it must be able to produce a solution to the problem it is designed to solve in a reasonable amount of time.
- Generality: An algorithm must be general, meaning that it can be applied to a wide range of problems rather than being specific to a single problem.
Algorithmic analysis is the process of evaluating algorithm performance in terms of efficiency, complexity and other criteria.Typically, this is done to evaluate many algorithms and select the optimal solution for a certain issue or a software.
Analysis of algorithms usually involves measuring their time and space complexity.
As with space complexity, which describes the amount of memory or disk space needed, time complexity describes how long an algorithm determines to perform a task.
There are different ways to analyze the time complexity of algorithms, such as Big O and Omega notation. The Omega symbol provides an upper bound for the algorithm’s time complexity, while the Omega symbol provides a lower bound.
In addition to measuring time and space complexity, algorithm analysis also includes other criteria such as stability, parallelism, and scalability.
- Stability:- This refers to the ability of the algorithm to maintain the relative order of the elements in the data set.
- Parallelization:- This is referring to the capacity to execute operations in parallel across several processors.
- Scalability:- On the other hand, it refers to the ability of an algorithm to handle large volumes of data and other inputs.
They include two types of analysis.
- Posterior analysis.
Prior is a method of algorithm analysis that focuses on estimating the performance of an algorithm based on its mathematical properties without actually executing the algorithm.
This approach allows you to analyze the time and space complexity of algorithms and other metrics without the need to implement and run the algorithms.
Posterior analysis, on the other hand, is a method of algorithm analysis that actually executes the algorithm and measures its performance.
This approach provides more accurate and detailed information about the performance of the algorithm, but requires the implementation and execution of the algorithm.
Algorithmic complexity is a measure to measure the efficiency and performance of the algorithm. Algorithms are usually evaluated in terms of the time and space required to solve a problem or achieve a specific goal.
Two factors are used in the complexity of the algorithm.
- Time factor.
- Space factor.
- The amount of time an algorithm needs to do a task is referred to as time complexity.It is usually measured by the number of operations or steps an algorithm must perform to solve a problem.
- The time complexity of an algorithm is important because it determines how long it takes to execute and can have a significant impact on program and system performance.
- The time complexity of an algorithm can be expressed using Big O notation, a way of expressing an upper bound on the time complexity of an algorithm.
- An algorithm with time complexity O(n) means that the time required to run the algorithm is directly proportional to the size of the input data (n).
- Other common time complexities are O(n^2) quadratic complexity and O(log n) logarithmic complexity.
- On the other hand, space complexity refers to the amount of memory or storage space required to execute the algorithm.
- This is important because it determines the number of resources required to run algorithms that can affect the overall performance of your application or system.
- If the space complexity of the algorithm is O(n), it uses an amount of memory that grows linearly with the size of the input.
- If the algorithm has O(1) space complexity, it uses a fixed amount of memory regardless of the size of the input.
How to write an algorithm
1. First define the problem you want the algorithm to solve.
For example, suppose we want to write an algorithm to find the maximum value from a list of numbers.
2. Break the problem down into smaller, manageable steps.
- Initialize the ‘max’ variable to the first value in the list.
- For each subsequent value in the list, compare with “max”.
- If the value is greater than “max”, set “max” to that value.
- Continue doing this until every value in the list has been compared.
- Returns the final “max” value.
3. Write your algorithm in pseudocode or a programming language.
Algorithm written in pseudo code:
- MAX (list)
- max = list
- For i = 1 the length of the list
- list IF[i] > max
- max = list[i]
- End for
- Maximum return
- Maximum end
4. Test your algorithm to make sure it is correct and efficient.
You can test the algorithm by entering different lists of numbers and verifying that it returns the maximum correct value. You can also analyze the time complexity of your algorithm to determine how well it scales for larger inputs.
Input: [1, 5, 2, 7, 3]
Explanation: 7 is the maximum value in the list.
5. Optimize the algorithm.
Look for ways to optimize algorithms for making them faster and more efficient. This may involve modifying pseudocode or implementing more efficient data structures or algorithms.
Basic writing of algorithms
Example: – The sum of two integers.
Step 1 – Get started
Step 2 – Declare three integers a, b, c
Step 3 – Define the values of a and b
Step 4 – Add the values of a and b
Step 5 – Save the output of step 4 in c
Step 6 – Print c
Step 7 – Stop
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 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 sum 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 problem. For example, simple variables and constants used, program size, etc.
- A variable part is a space required by variables, whose size depends on the size of the problem. For example, dynamic memory 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 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.
Type of algorithms used in C language.
1. Sorting algorithms
C provides a rich set of data types and operators that can be used to implement various sorting algorithms such as bubble sort, insertion sort and quick sort.
These algorithms are useful in many applications because they can be used to sort data of different sizes and types.
There are different sorting algorithms.
(i) Bubble sort: An uncomplicated sorting algorithm that compares nearby components repeatedly and switches them out if they are out of order.
The Algorithm for Bubble sort is:-
- Start with an unsorted list of elements.
- Compare the first two elements in the list. If the first element is larger than the second element, swap them.
- Move on to the next pair of elements and repeat step 2 until the end of the list is reached.
- For each item on the list, repeat steps 2 and 3 once more. that is referred to as passes.
- Repeat steps 2-4 for the entire list. As you repeat the passes, elements will “bubble up” to their correct position in the sorted list.
- Once a pass is completed and no swaps are made, the list is sorted, and the algorithm can stop.
- The final sorted list is returned.
(ii) Insertion sort: a method of sorting that creates a sorted list one individual element at a time by placing each one in the appropriate spot.
The Algorithm for Insertion sort is:-
- Initialize an empty sorted list and an unsorted list of the elements to be sorted.
- The first member from the unsorted list should be taken and placed in the appropriate position in the sorted list.
- Repeat step 2 for each subsequent element in the unsorted list.
- Compare the current element with the elements in the sorted list, starting with the element immediately to the left.
- Swap the two elements if the current element is smaller than the element to its left.
- If the current element is larger than the element to its left, insert it at its correct position in the sorted list.
- Repeat steps 4-6 for each subsequent element in the unsorted list.
- Once all elements have been processed, the sorted list will contain all elements in the correct order.
- The sorting process is complete.
(iii) Selection sort: a method of sorting that consistently starts the sorted listing with the smallest detail from the unordered listing.
The Algorithm for Selection sort is:-
- Begin by setting the primary element of list as the min element.
- Repeat through the remaining items in the list, comparing each one to the current minimum.
- Set a new minimum if an element is found to be smaller than the existing one.
- Change the current minimum to the first element of the list whenever it reaches its conclusion.
- For the remaining unsorted portion of the listing, repeat steps 2-4, but begin with the second item on the list (as the first element is already sorted).
- Continue sorting the list in this manner until it is all sorted.
(iv) Quick sort: A divide-and-conquer sorting algorithm that chooses a pivot element and splits the list into sublists depending on whether the elements are fewer than or more than the pivot. After that, the sublists are sorted repeatedly until the full list is sorted.
The Algorithm for Quick sort is:-
- Choose a pivot element from the list. This is typically the first element, but it can also be a random element or the median of the list.
- Divide the list into two sublists: one containing elements less than the pivot and one containing elements greater than the pivot.
- Recursively sort the sublist containing elements less than the pivot using the same process.
- Use the same procedure to recursively sort the sublist of entries larger than the pivot.
- Concatenate the sorted sublists with the pivot element in between to form a fully sorted list.
- Return the fully sorted list.
(v) Merge sort: The divide-and-conquer sort algorithm divides the list into two halves, sorts each half, and then merges the two halves in sorted order.
- Make two sublists out of the list: one with elements below the pivot and one with elements above the pivot.
- Produces a new sorted sublist by iteratively merging sublists until only one sublist exists. This will be your sorted list.
- Steps to merge two sub-directories:-
- Create an empty list to hold the sorted elements.
- Compares the first element of each sublist.
- Adds the smaller element to the new list and removes it from the parent sublist.
- Repeat the steps 2 and 3 until a list is completly empty.
- Adds the remaining elements from other sublists to a new list.
- Replaces the merged sublist with the new sorted list.
- Repeat this process until all sublists are merged into one sorted list.
(vi) Heapsort: A sorting algorithm that sorts elements using a data structure called heap.
This is the classification algorithm:
- Build max heap: Starting with the first non-leaf node, compare each node with its child nodes and replace the nodes with the largest of its children to satisfy the max heap property.
- Swap root with last element: Swap the root (largest element) with the last element in the stack.
- Stack the rest of the elements. Starting from the root, each node is compared with its children, swapping nodes with their older children until the max heap property is satisfied.
- Repeat steps 2 and 3 with the newly stacked elements, except for the last element in the correct position.
- Repeat this process until only one element remains in the stack. This is now sorted.
- Heapify Down: Starting from the root node, it compares elements with its children and swaps with the larger of the two until the max heap property is satisfied.
- Heapify Up: Start with the last element in the heap, compare it to its parent, and swap it with the parent to satisfy the max heap property.
(vii) Radix sort: A sorting algorithm that sorts elements based on the digits or digits of their binary representation.
The Algorithm for Radix sort is:-
- determine how many digits are contained in the input listing’s largest element.
- Initialize a variable, say digit place, to 1, which represents the current digit place.
- Create an empty list for each possible digit value from 0 to 9.
- Iterate through the input list and add each element to the appropriate list based on the value of the current digit place.
- Concatenate all the lists together to form the new list in the order of the digit lists.
- Multiply digitPlace by 10 to move to the next digit place.
- Repeat steps 4-6 for each digit place until all digits in the largest element have been considered.
- The final list will be sorted in ascending order by the digits of the elements.
- Return the final sorted list.
Let’s try to learn another algorithm-writing by using an example.
Problem − Design an algorithm to add two numbers and display the result.
Step 1 − START
Step 2 − declare three integers a, b & c
Step 3 − define values of a & b
Step 4 − add values of a & b
Step 5 − store output of step 4 to c
Step 6 − print c
Step 7 − STOP
Algorithms tell the programmers how to code the program. Alternatively, the algorithm can be written as −
Step 1 − START ADD
Step 2 − get values of a & b
Step 3 − c ← a + b
Step 4 − display c
Step 5 − STOP
In design and analysis of algorithms, usually the second method is used to describe an algorithm. It makes it easy for the analyst to analyze the algorithm ignoring all unwanted definitions. He can observe what operations are being used and how the process is flowing.
Writing step numbers, is optional.
We design an algorithm to get a solution of a given problem. A problem can be solved in more than one ways.
Hence, many solution algorithms can be derived for a given problem. The next step is to analyze those proposed solution algorithms and implement the best suitable solution.
2. Searching algorithms
C also provides the tools necessary to implement a variety of searching algorithms, such as linear search and binary search. These algorithms can quickly find specific items in a data set, making them useful for a wide range of applications.
There are many types of search algorithms.
(i) Linear search: A basic search algorithm that examines each item in the listing one by one until it finds the desired item.
Algorithm for Linear search:-
- Define the input for the algorithm: The input for a linear search algorithm is a list of elements (or an array) and a target element we are searching for.
- Initialize a variable called “index” to -1: This variable will be used to store the index of the target element if it is found.
- Loop through the list of elements: Starting from the first element, check each element in the list one by one.
- Compare the present element to the desired element for evaluation: Keep the index of the current element in the index variable and exit the loop if the modern element and the goal element are identical.
- Return the index of the target element: After the loop completes, return the value stored in the index variable. If the target element is not found, the value of the index will be -1.
(ii) Binary search: A search algorithm that operates by splitting the listing into halves and searches within of those halves is more likely to include the element.
Algorithm for Binary search:-
- Input: A sorted list of n elements and a target element x.
- Initialize variables: Set the low index to 0, the high index to n-1, and mid to (low+high)/2.
- Start a loop: While the low index is less than or equal to the high index, repeat the following steps.
- Compare the mid element with x: If the mid element is equal to x, return the mid index.
- Update the low or high index: If x is greater than the mid element, set the low index to mid + 1. Else, set the high index to mid – 1.
- Update the mid index: Mid = (low+high)/2.
- End of the loop: If the low index is greater than the high index, then x is not in the list, and the algorithm returns a failure.
- Output: The index of x in the list or failure message.
(iii) Depth-first search: A search algorithm that examines each branch as far as is feasible before turning around.
The following guidelines apply to depth-first search:
- select the graph’s starting vertex or node to start with.
- Add a visiting mark to the first vertex.
- Directly place the beginning vertex into a stack.
- Until the stack is empty, repeat the following actions: –
- Remove the stack’s top vertex.
- Mark as visited and insert into the stack each unvisited neighbour of the popped vertex.
- Continue this process until all vertices in the graph have been visited.
- Once all vertices have been visited, the algorithm is complete, and a depth-first search is performed on the graph.
(iv) Breadth-first search: A search algorithm that explores all the neighbors of a node before moving to the next level.
The algorithm for the breadth-first search is:-
- Start with the root node or the initial state.
- Add the root node to a queue.
- Check if the queue is empty; if yes, then terminate the algorithm.
- Take the first element from the queue and mark it as visited.
- Amplify the contemporary node by adding all its unvisited neighbors to the queue.
- Until the desired node is located or the queue is empty, repeat steps 3 to 5.
- Return the path from the preliminary state to the target state if the goal node is found.
- Terminate the set of rules and report that the goal state was not identified if the queue is empty.
(v) Interpolation Search: A search algorithm that uses the values of the searched elements to estimate the position in the index.
It is important that the array is evenly distributed. Otherwise, it is an algorithm.
It works as expected.
The algorithm can be summarized as follows.
- Get the input list and key value to search.
- Initialize the lower and upper variables at the first and last indices of the list.
- If the Lower value is less than or equal to higher value, then :-
- Calculate the estimated location using the following formula:
pos = low + ((high – low) / (arr[high] – arr[low])) * (x – arr[low]).
- Return the position if the estimated position value is a key value.
- c) If the estimated position value is less than the key value, set it lower.
Position + 1.
- d) If the value of the estimated position is greater than the key Set value, position – 1 up.
- Calculate the estimated location using the following formula:
- If the key value is not found, return -1 to indicate that the value is not in the list.
(vi) Jump search: A search method that iterates over the list in constant-length steps until it finds the relevant element or determines that it is no longer present.
The jump search algorithm is as follows:
- First, set the jump size to the square root of the number of array elements.
- Sets a variable named “current” to the first element of the array.
- Iterates over the array by jumping by jump size while incrementing a variable called “jump”.
- Move on to the following leap if the existing element is smaller than the desired element.
- If the current element is larger than the target element, perform a linear search between the current element and the previous jump element to find the target element.
- If the target element is not found in the array, it returns -1 to indicate that it is not in the array.
- If the element is found, it returns the element’s index in the array.
3. Graph algorithms
C’s support for pointers and data structures such as arrays and linked lists makes it suitable for implementing algorithms that manipulate graphs, such as finding the shortest path between two nodes in a graph.
There are different types of graph algorithms.
- Dijkstra’s Algorithm: An algorithm that finds the shortest path between two nodes in a graph by continuously updating the shortest distance from each node.
- Algorithm A*: A method that continually updates the shortest course to each node in a graph to determine the shortest route between them.
- Prim’s Algorithm: An approach for figuring out the weighted connected graph’s smallest spanning tree.
- Kruskal’s algorithm: An approach to identify the linked weighted graph’s lowest spanning tree.
- Bellman-Ford Algorithm: An algorithm that, even when the graph has negative edge weights, displays the shortest path between a particular supply node and every other node in the network.
4. Cryptographic Algorithms
C supports low-level operations and efficient data manipulation, making it ideal for implementing algorithms used in cryptography, such as data encryption and decryption algorithms.
There are different types of encryption algorithms.
- Hash Algorithms: These algorithms produce fixed-size outputs (hash) from arbitrary-sized inputs. Examples include MD5, SHA-1 and SHA-2.
- Symmetric key algorithms: The encryption and decryption steps in such algorithms employ the same private key. AES, DES, and Blowfish are a few examples.
- Asymmetric key algorithms: A public key and a non-public key are used by those methods as separate keys for encryption and decryption. Some examples include RSA, ECC, and DSA.
- Key exchange algorithms: These algorithms allow two parties to exchange keys over an insecure channel securely. For example, we can mention Diffie-Hellman and Elliptic Curve Diffie-Hellman.
Advantages of the algorithm
Algorithms have many advantages.
- Speed and efficiency: Algorithms can process large amounts of data quickly and accurately, making them useful for tasks that are too time-consuming or error-prone for people to perform.
- Consistency: Algorithms follow a set of predetermined guidelines. It can produce consistent results without being influenced by personal biases and emotions.
- Automation: Algorithms can perform tasks automatically, leaving people free to focus on more complex or creative tasks.
- Increased accuracy: Algorithms can often achieve higher levels of accuracy than humans, especially when dealing with large amounts of data.
- Better Decision Making: Algorithms help us make more informed and objective decisions by analyzing data and identifying patterns and trends that are not easily visible to people.
- Scalability: Algorithms can be easily scaled up or down to meet changing demands and workloads.
Disadvantages of the algorithm
Algorithms are very useful for programming, but algorithms have drawbacks.
- Limited scope: Algorithms can only solve problems within their scope and may not be able to solve complex or abstract problems.
- Bias: Algorithms can perpetuate and reinforce biases in the data used for training, leading to unfair results.
- Insufficient transparency: Many algorithms conceal the process through which they arrive at their conclusions. This could make it tough to think about or check the results.
- Reliance on the fineness of the data: The correctness of the set of rules is heavily dependent on the fineness and applicability of the data utilised in instruction. Inaccurate or inaccurate effects may be the result of faulty data.
- restrained adaptability: Algorithms are designed to follow guidelines and won’t adapt to changing circumstances and conditions.