Skip to content

Commit

Permalink
Update basic_concepts.md
Browse files Browse the repository at this point in the history
  • Loading branch information
djeada authored Dec 4, 2024
1 parent 2efc975 commit 79c4e46
Showing 1 changed file with 17 additions and 17 deletions.
34 changes: 17 additions & 17 deletions notes/basic_concepts.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
## Introduction to Data Structures & Algorithms

Data structures and algorithms are foundational concepts in computer science, playing an essential role in designing efficient software. A data structure defines how we store and organize data on a computer, while an algorithm delineates a step-by-step procedure to perform a task or solve a problem. This article introduces the fundamental aspects of data structures and algorithms, their importance, and how they are applied in computing.
Data structures and algorithms are fundamental concepts in computer science that are key to building efficient software.

- A **data structure** specifies how data is stored and organized in memory. Examples include arrays, linked lists, stacks, queues, trees, and graphs. Choosing the right data structure can simplify solving specific problems.
- An **algorithm** is a step-by-step method for solving a problem or performing a task. Algorithms can range from simple operations like searching or sorting to complex computations in artificial intelligence or optimization.
- The combination of efficient data structures and algorithms enables developers to optimize software performance, both in terms of speed and memory usage.

### Data Structures

A data structure organizes data on a computer in a manner that enables efficient access and modification. The choice of the appropriate data structure depends on the specific use case and can significantly impact the performance of an application. Here are some common data structures:
Sure, here are the simplified explanations with the formal terms included:
A **data structure** organizes and stores data in a way that allows efficient access, modification, and processing. The choice of the appropriate data structure depends on the specific use case and can significantly impact the performance of an application. Here are some common data structures:

1. An **array** is like a row of lockers, each numbered in order, where each locker can hold one item of the same type. Formally, an array is a contiguous block of memory that stores a fixed-size sequence of elements of the same type. Arrays are effective for quick access to data by index, but their size cannot change once set, making them less flexible for adding or removing elements.

2. A **stack** is like a stack of plates. You add new plates on top (push), and take plates from the top (pop). This follows the "Last-In, First-Out" (LIFO) principle, meaning the last item added is the first one removed. Stacks are commonly used in programming for managing function calls (function call stack) and 'undo' operations in software applications.

3. A **queue** is like a line at a checkout counter. People join at the back (enqueue) and leave from the front (dequeue). This follows the "First-In, First-Out" (FIFO) principle, where the first item added is the first one removed. Queues are useful for processing items in the order they arrive, such as task scheduling or event handling in computing systems.

4. A **linked list** is like a treasure hunt where each clue (node) points to the next one. Each node contains a value and a reference (pointer) to the next node. This makes linked lists dynamic and efficient for inserting and removing elements at any position in the list.

5. A **tree** is like a family tree, starting with one person (root) and branching out to children (nodes), with each node possibly having its own children. Formally, a tree is a hierarchical data structure composed of nodes arranged in multiple levels. Trees are useful for representing hierarchical relationships, such as filesystem structures or organizational charts.

6. A **graph** is like a network of cities connected by roads. Each city is a node, and each road is an edge connecting two nodes. Edges can be one-way (directed) or two-way (undirected). Graphs are used to model complex relationships and connections between elements, such as social networks, web pages (links), and routes between locations.

![ds](https://user-images.githubusercontent.com/37275728/185381435-9335db5b-8c9a-4e74-87dc-deac3c0356f1.png)
Expand All @@ -35,7 +33,7 @@ Think of an algorithm like a recipe for cooking. It consists of a series of step

#### Algorithms vs. Programs

Understanding the difference between an algorithm and a program is essential. Here’s a simple explanation with formal terms included:
Understanding the difference between an algorithm and a program helps clarify their roles in problem-solving:

An algorithm is like a high-level blueprint for solving a specific problem. It is abstract and language-independent, detailing a sequence of steps without any specific syntax. You can think of an algorithm as a recipe that outlines a method for solving a problem, and it can be represented in various ways, such as in plain text or as a flowchart.

Expand Down Expand Up @@ -92,7 +90,7 @@ sum = num1 + num2
print("The sum is", sum)
```

Here’s a key point to remember: algorithms are abstract steps that always terminate after a finite number of steps. In contrast, some programs can run indefinitely until an external action stops them. For example, an operating system is a program designed to run continuously in a loop until the computer is turned off.
Algorithms are abstract steps that always terminate after a finite number of steps. In contrast, some programs can run indefinitely until an external action stops them. For example, an operating system is a program designed to run continuously in a loop until the computer is turned off.

#### Types of Algorithms

Expand Down Expand Up @@ -180,10 +178,12 @@ Steps:
Pattern matched starting at index 10 in the text.
```

#### Essential Algorithms for Software Engineers
#### Important Algorithms for Software Engineers

* As a software engineer, mastering every algorithm isn't expected or necessary. Instead, it is more valuable to be proficient in leveraging libraries and packages that encapsulate widely-used algorithms. However, the ability to discern the most effective algorithm for a particular task based on its efficiency, the nature of the problem, and other relevant factors is crucial.
* Understanding algorithms can significantly augment your problem-solving capabilities, particularly when you're beginning your programming journey. It provides a strong foundation in logical thinking, exposes you to various strategies for problem-solving, and helps you appreciate the nuances involved in choosing the most appropriate solution. After grasping the fundamentals of algorithms, the focus generally shifts towards using pre-built libraries and packages for problem-solving rather than creating algorithms from scratch.
- As a software engineer, it is not necessary to **master every algorithm**. Instead, knowing how to effectively use libraries and packages that implement widely-used algorithms is more practical.
- The important skill is the ability to **select the right algorithm** for a task by considering factors such as its efficiency, the problem’s requirements, and any specific constraints.
- Learning **algorithms** during the early stages of programming enhances problem-solving skills. It builds a solid foundation in logical thinking, introduces various problem-solving strategies, and helps in understanding how to approach complex issues.
- Once the **fundamentals of algorithms** are understood, the focus often shifts to utilizing pre-built libraries and tools for solving real-world problems, as writing algorithms from scratch is rarely needed in practice.

### Understanding Algorithmic Complexity

Expand All @@ -192,7 +192,7 @@ Algorithmic complexity helps us understand the computational resources (time or
* **Best case complexity** is the minimum time or space an algorithm requires for a given input size. For instance, an algorithm with a best case time complexity of O(1) always runs in constant time, regardless of the input size.
* **Average case complexity** signifies the average time or space an algorithm needs for all possible inputs of a given size. Calculating this can be more challenging because it requires understanding the distribution of possible inputs and their effect on the algorithm's performance.
* **Worst case complexity** indicates the maximum time or space an algorithm may take for any input of a certain size. This type of complexity is often the most critical since it provides an upper bound on the algorithm's execution time, offering predictability.
* **Space complexity** represents the total amount of memory an algorithm needs relative to the input size. This becomes important when memory resources are limited and the algorithm's efficiency is crucial.
* **Space complexity** represents the total amount of memory an algorithm needs relative to the input size. This becomes important when memory resources are limited and the algorithm's efficiency is necessary.
* **Time complexity** measures the computational time an algorithm takes as the input size grows. This is the most frequently analyzed type of complexity because the speed of an algorithm often determines its usability.

#### Analyzing Algorithm Growth Rates
Expand Down Expand Up @@ -298,8 +298,8 @@ WHILE m > 0:

### Misconceptions

* Formal proof of Big O complexity is rarely necessary in everyday programming or software engineering. However, having a fundamental understanding of theoretical complexity is crucial when selecting appropriate algorithms, especially when solving complex problems. It aids in understanding the trade-offs between different solutions and predicting the algorithm's performance.
* It's not essential to assign Big O complexity for every single function or chunk of code you write. However, if you're dealing with large datasets or performance-critical applications, understanding the time and space complexity of your algorithms and data structures can help you make informed decisions about scalability and efficiency.
* Formal proof of Big O complexity is rarely necessary in everyday programming or software engineering. However, having a fundamental understanding of theoretical complexity is important when selecting appropriate algorithms, especially when solving complex problems. It aids in understanding the trade-offs between different solutions and predicting the algorithm's performance.
* It's not required to assign Big O complexity for every single function or chunk of code you write. However, if you're dealing with large datasets or performance-critical applications, understanding the time and space complexity of your algorithms and data structures can help you make informed decisions about scalability and efficiency.
* Big O notation is not a predictor of an algorithm's precise running time for a given input size. Instead, it provides an upper bound on the growth rate of the algorithm's running time or space usage as the input size increases. It's a tool to compare the scalability of different algorithms, ignoring implementation details and specific characteristics of the input data.
* In real-world scenarios, the actual running time of an algorithm can be influenced by various factors, including the specific characteristics of the input data, the efficiency of the implementation, and the hardware and software environment in which it runs. Big O notation doesn't account for these factors.
* While it's crucial to consider performance, it shouldn't come at the cost of code readability and maintainability. Clear, simple code is often more valuable than highly optimized code, especially if the optimizations complicate the code without offering substantial performance improvements. Instead of optimizing every detail, focus on identifying and addressing the actual bottlenecks in your code, as these are the areas where optimizations can make a significant difference.
* While it's good to consider performance, it shouldn't come at the cost of code readability and maintainability. Clear, simple code is often more valuable than highly optimized code, especially if the optimizations complicate the code without offering substantial performance improvements. Instead of optimizing every detail, focus on identifying and addressing the actual bottlenecks in your code, as these are the areas where optimizations can make a significant difference.

0 comments on commit 79c4e46

Please sign in to comment.