Merge branch 'main' into main

pull/194/head
Krishna Kaushik 2024-05-17 11:25:38 +05:30 zatwierdzone przez GitHub
commit 08cea50cf3
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
12 zmienionych plików z 768 dodań i 6 usunięć

127
CODE_OF_CONDUCT.md 100644
Wyświetl plik

@ -0,0 +1,127 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

Wyświetl plik

@ -1,6 +1,6 @@
[![Discord Server Invite](https://img.shields.io/badge/DISCORD-JOIN%20SERVER-5663F7?style=for-the-badge&logo=discord&logoColor=white)](https://bit.ly/heyfoss)
This project is an participating in GSSoC 2024.
This project is participating in GSSoC 2024.
![gssoc-logo](https://github.com/foss42/awesome-generative-ai-apis/assets/1382619/670b651a-15d7-4869-a4d1-6613df09fa37)
@ -225,7 +225,7 @@ Some of the popular languages are Java, C, C++, C#, Go, Swift, JavaScript, PHP,
## Introduction to Python
Guido van Rossum started the development of Python in December 1989. He released the first version (0.9.9) of Python for general public on February 20, 1991.
Guido van Rossum started the development of Python in December 1989. He released the first version (0.9.0) of Python for general public on February 20, 1991.
The language evolved over the next few decades and so did its definition, the current version of which is stated below:

Wyświetl plik

@ -0,0 +1,146 @@
# Advanced Python
## Functions as First class objects
Functions in Python are so called first class objects, which means they can be treated as variables, viz. functions can be used as arguments or they can be returned using the return keyword.
**Example**
```python
def func1():
def func2():
print("Printing from the inner function, func2")
return func2
```
Assigning func1 to function_call object
```python
function_call=func1()
```
Calling the function
```python
>>> function_call()
```
**Output**
```
Printing from the inner function, func2
```
Here we have seen the use of function as a first class object, func2 was returned as the result of the execution of the outer function, func1.
## *args
\* is an iterating operator used to unpack datatypes such as lists, tuples etc.
**For example**
```python
tuple1=(1,2,4,5,6,7)
print(tuple1)
print(*tuple1)
```
In the above we have defined a tuple called tuple1 with the items (1,2,4,5,6,7).
First we print normally and the output for that is:
```
(1, 2, 4, 5, 6, 7)
```
Then we print with the \* operator, where we will get the output as:
```
1 2 4 5 6 7
```
Here the \* operator has unpacked the tuple, tuple1.
Now that you have understood why \* is used, we can take a look at *args. *args is used in functions so that positional arguments are stored in the variable args. *args is just a naming convention, *anything can be used
*args makes python functions flexible to handle dynamic arguments.
```python
def test1(*args):
print(args)
print(f"The number of elements in args = {len(args)}")
a=list(range(0,10))
test1(*a)
```
In the above snippet, we are sending a list of numbers to the test function which returns the following output:
```
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
The number of elements in args = 10
```
If in the test1 we do not use \* in the argument
```python
def test1(*args):
print(args)
print(f"The number of elements in args = {len(args)}")
a=list(range(0,10))
test1(a)
```
we get the following result. This is a tuple containing a list.
```
([0, 1, 2, 3, 4, 5, 6, 7, 8, 9],)
The number of elements in args = 1
```
## **kwargs
**kwargs stands for keyword arguments. This is used for key and value pairs and similar to *args, this makes functions flexible enough to handle dynamic key value pairs in arguments.
```python
def test2(**kwargs):
print(kwargs)
print(f"The number of elements in kwargs = {len(kwargs)}")
test2(a=1,b=2,c=3,d=4,e=5)
```
The above snippet uses some key-value pairs and out test2 function gives the following output:
```
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
The number of elements in kwargs = 5
```
A dictionary with keys and values is obtained.
## Decorators (@decorators)
Now that we understand what first class object, *args, **kwargs is, we can move to decorators. Decorators are used to perform a task that needs to be performed for existing functions. If some task has to be performed for each function, we can write a function which will perform the task without us having to make changes in each function.
**Sample Code:**
```python
import time
def multiplication(a,b):
start=time.time()
c=a*b
total=time.time()-start
print("Time taken for execution of multiplication",total)
return c
def addition(a,b):
start=time.time()
c=a+b
total=time.time()-start
print("Time taken for execution of addition ",total)
return c
multiplication(4,5)
addition(4,5)
```
In the above code, we had to calculate time and print the execution time seperately for each function leading to repeatation of code. This is where decorators come in handy.
The same functionality can be achieved with the help of a decorator.
**Here's how:**
```python
import time
def time_find(function):
def wrapper(*args, **kwargs):
starttime=time.time()
function(*args, **kwargs)
total=time.time()-starttime
print(f"Time Taken by {function.__name__} to run is ",total)
return wrapper
@time_find #to use a decorator, simply use @<decorator name> above a function.
def multiply(a, b):
print(a*b)
@time_find
def addition(a,b):
print(a+b)
multiply(4,5)
addition(4,5)
```
The above method eleminates redundant code and makes the code cleaner. You may have observed that we have used *args and **kwargs in the wrapper function. This is so that this decorator function is flexible for all types of functions and their parameters and this way it can find out the execution time of any function with as many parameters as needed, we just need to use our decorator @time_find.

Wyświetl plik

@ -1,3 +1,3 @@
# List of sections
- [Section title](filename.md)
- [Decorators/\*args/**kwargs](decorator-kwargs-args.md)

Wyświetl plik

@ -0,0 +1,56 @@
# API Methods
| Method | Summary | CRUD | Accepts Request Body | Idempotent | Safe | Response Body |
|---------|----------------------------------------------------------|--------|-----------------------|------------|------|---------------|
| GET | To fetch a single resource or group of resources | Read | No | Yes | Yes | Yes |
| PUT | To update an entire resource in one go | Update | Yes | Yes | No | Yes |
| POST | To create a new resource | Create | Yes | No | No | Yes |
| PATCH | To partially update a resource | Update | Yes | No | No | Yes |
| DELETE | To delete a resource | Delete | No | Yes | No | No |
| OPTIONS | To get information on permitted operations | Read | No | Yes | Yes | Yes |
| HEAD | To get metadata of the endpoint | Read | No | Yes | Yes | No |
| TRACE | For diagnosing purposes | Read | No | Yes | Yes | No |
| CONNECT | To make the two-way connection between the client and the resource | - | No | No | No | No |
## Method Details:
- **GET**:
- The GET method is used to retrieve data from a specified resource. It does not typically alter the state of the resource and is safe and idempotent. It can accept query parameters in the URL to filter or sort the results. A response body is returned with the requested data.
- **POST**:
- The POST method is used to submit data to be processed to a specified resource. It is commonly used for creating new resources, and it may or may not require a request body containing the data to be created. It is not idempotent nor safe. A response body is returned with the newly created resource's details.
- **PUT**:
- The PUT method is used to update a specified resource with new data. It typically requires a request body containing the complete representation of the resource to be updated. It is idempotent and not safe. A response body is returned with the updated resource's details.
- **PATCH**:
- The PATCH method is used to apply partial modifications to a resource. It typically requires a request body containing the specific changes to be made. It is not idempotent nor safe. A response body is returned with the updated resource's details.
- **DELETE**:
- The DELETE method is used to delete a specified resource. It does not typically require a request body, as the resource to be deleted is identified in the request URI. It is idempotent but not safe. No response body is returned.
- **OPTIONS**:
- The OPTIONS method is used to describe the communication options for the target resource. It does not typically require a request body and is safe and idempotent. A response body is returned with information about the supported HTTP methods and other metadata.
- **HEAD**:
- The HEAD method is similar to the GET method, but it only retrieves the headers of the response without the body. It does not typically require a request body and is safe and idempotent.
- **TRACE**:
- The TRACE method is used to test the connectivity between the client and the server. It does not typically require a request body and is safe and idempotent.
- **CONNECT**:
- The CONNECT method is used to establish a tunnel to the server using a proxy. It does not typically require a request body and is neither safe nor idempotent.
### Definitions:
- **CRUD**:
- CRUD stands for Create, Read, Update, and Delete, representing the four basic functions of persistent storage. These operations are commonly used in database and RESTful API designs.
- **Accepts Request Body**:
- Indicates whether the HTTP method typically accepts a request body containing data to be processed or modified. If yes, the method may require the client to include data in the request body.
- **Idempotent**:
- An idempotent operation means that making the same request multiple times will produce the same result as making it once. In the context of HTTP methods, an idempotent method does not change the server state after multiple identical requests.
- **Safe**:
- A safe operation does not modify the state of the server or its resources. It only retrieves data without causing any side effects. Safe methods are typically used for read-only operations.

Wyświetl plik

@ -1,3 +1,3 @@
# List of sections
- [Section title](filename.md)
- [API Methods](api-methods.md)

Wyświetl plik

@ -1,3 +1,4 @@
# List of sections
- [Section title](filename.md)
- [Sorting Algorithms](sorting-algorithms.md)

Wyświetl plik

@ -0,0 +1,329 @@
# Sorting Algorithms
In computer science, a sorting algorithm takes a collection of items and arranges them in a specific order. This order is usually determined by comparing the items using a defined rule.
## Real Life Example of Sorting
- Sorting a deck of cards
- Sorting names in alphabetical order
- Sorting a list of items, etc.
# Some common sorting techniques
# 1. Bubble Sort
Bubble sort is a basic sorting technique that iteratively steps through a list, comparing neighboring elements. If elements are out of order, it swaps them. While easy to understand, bubble sort becomes inefficient for large datasets due to its slow execution time.
**Algorithm Overview:**
- **Pass by Pass:** During each pass, the algorithm iterates through the list.
- **Comparing Neighbors:** In each iteration, it compares adjacent elements in the list.
- **Swapping for Order:** If the elements are in the wrong order (typically, the first being larger than the second), it swaps their positions.
- **Bubbling Up the Largest:** This swapping process effectively pushes the largest element encountered in a pass towards the end of the list, like a bubble rising in water.
- **Repeating Until Sorted:** The algorithm continues making passes through the list until no more swaps are needed. This indicates the entire list is sorted.
## Bubble Sort Code in Python
```python
def bubble_sort(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 = [5, 3, 8, 1, 2]
bubble_sort(arr)
print("Sorted array:", arr) # Output: [1, 2, 3, 5, 8]
```
## Example with Visualization
Let's sort the list `[5, 3, 8, 1, 2]` using bubble sort.
1. **Pass 1:**
- Comparing neighbors: `[3, 5, 1, 2, 8]`
- Swapping: `[3, 5, 1, 2, 8]``[3, 1, 5, 2, 8]``[3, 1, 2, 5, 8]`
- Result: `[3, 1, 2, 5, 8]`
2. **Pass 2:**
- Comparing neighbors: `[1, 3, 2, 5, 8]`
- Swapping: `[1, 3, 2, 5, 8]``[1, 2, 3, 5, 8]`
- Result: `[1, 2, 3, 5, 8]`
3. **Pass 3:**
- Comparing neighbors: `[1, 2, 3, 5, 8]`
- No swapping needed, the list is already sorted.
## Complexity Analysis
- **Worst Case:** `O(n^2)` comparisons and swaps. This happens when the list is in reverse order, and we need to make maximum swaps.
- **Best Case:** `O(n)` comparisons. This occurs when the list is already sorted, but we still need O(n^2) swaps because of the nested loops.
- **Average Case:** `O(n^2)` comparisons and swaps. This is the expected number of comparisons and swaps over all possible input sequences.
</br>
<hr>
</br>
# 2. Selection Sort
Selection sort is a simple sorting algorithm that divides the input list into two parts: a sorted sublist and an unsorted sublist. The algorithm repeatedly finds the smallest (or largest, depending on sorting order) element from the unsorted sublist and moves it to the sorted sublist. It's not efficient for large datasets but performs better than bubble sort due to fewer swaps.
**Algorithm Overview:**
- **Initial State:** The entire list is considered unsorted initially.
- **Selecting the Minimum:** The algorithm repeatedly selects the smallest element from the unsorted sublist and moves it to the sorted sublist.
- **Expanding the Sorted Sublist:** As elements are moved to the sorted sublist, it expands until all elements are sorted.
- **Repeating Until Sorted:** The process continues until the entire list is sorted.
## Example with Visualization
Let's sort the list `[5, 3, 8, 1, 2]` using selection sort.
1. **Pass 1:**
- Initial list: `[5, 3, 8, 1, 2]`
- Find the minimum: `1`
- Swap with the first element: `[1, 3, 8, 5, 2]`
2. **Pass 2:**
- Initial list: `[1, 3, 8, 5, 2]`
- Find the minimum: `2`
- Swap with the second element: `[1, 2, 8, 5, 3]`
3. **Pass 3:**
- Initial list: `[1, 2, 8, 5, 3]`
- Find the minimum: `3`
- Swap with the third element: `[1, 2, 3, 5, 8]`
4. **Pass 4:**
- Initial list: `[1, 2, 3, 5, 8]`
- Find the minimum: `5`
- No swapping needed, the list is already sorted.
## Selection Sort Code in Python
```python
def selection_sort(arr):
n = len(arr)
for i in range(n):
min_index = i
for j in range(i+1, n):
if arr[j] < arr[min_index]:
min_index = j
arr[i], arr[min_index] = arr[min_index], arr[i]
arr = [5, 3, 8, 1, 2]
selection_sort(arr)
print("Sorted array:", arr) # Output: [1, 2, 3, 5, 8]
```
## Complexity Analysis
- **Worst Case**: `O(n^2)` comparisons and O(n) swaps. This occurs when the list is in reverse order, and we need to make maximum comparisons and swaps.
- **Best Case**: `O(n^2)` comparisons and O(n) swaps. This happens when the list is in sorted order, but the algorithm still needs to iterate through all elements for comparisons.
- **Average Case**: `O(n^2)` comparisons and O(n) swaps. This is the expected number of comparisons and swaps over all possible input sequences.
</br>
<hr>
</br>
# 3. Quick Sort
Quick sort is a popular divide-and-conquer sorting algorithm known for its efficiency on average. It works by selecting a 'pivot' element from the array and partitioning the other elements into two sub-arrays according to whether they are less than or greater than the pivot. The sub-arrays are then recursively sorted.
**Algorithm Overview:**
- **Pivot Selection:** Choose a pivot element from the array. Common strategies include selecting the first, last, middle, or a randomly chosen element.
- **Partitioning:** Rearrange the array so that all elements less than the pivot are on its left, and all elements greater than the pivot are on its right. This step ensures that the pivot element is placed in its correct sorted position.
- **Recursion:** Apply the above steps recursively to the sub-arrays formed by partitioning until the base case is reached. The base case is usually when the size of the sub-array becomes 0 or 1, indicating it is already sorted.
- **Base Case:** If the sub-array size becomes 0 or 1, it is already sorted.
## Example with Visualization
Let's sort the list `[5, 3, 8, 1, 2]` using quick sort.
1. **Initial Array:** `[5, 3, 8, 1, 2]`
2. **Choose Pivot:** Let's choose the last element, `2`, as the pivot.
3. **Partitioning:**
- We'll partition the array around the pivot `2`. All elements less than `2` will be placed to its left, and all elements greater than `2` will be placed to its right.
- After partitioning, the array becomes `[1, 2, 5, 3, 8]`. The pivot element, `2`, is now in its correct sorted position.
4. **Recursion:**
- Now, we recursively sort the sub-arrays `[1]` and `[5, 3, 8]`.
- For the sub-array `[5, 3, 8]`, we choose `8` as the pivot and partition it.
- After partitioning, the sub-array becomes `[3, 5, 8]`. The pivot element, `8`, is now in its correct sorted position.
5. **Concatenation:**
- Concatenating the sorted sub-arrays `[1]`, `[2]`, `[3, 5, 8]`, we get the final sorted array `[1, 2, 3, 5, 8]`.
## Quick Sort Code in Python (Iterative)
```python
def partition(arr, low, high):
pivot = arr[high]
i = low - 1
for j in range(low, high):
if arr[j] < pivot:
i += 1
arr[i], arr[j] = arr[j], arr[i]
arr[i + 1], arr[high] = arr[high], arr[i + 1]
return i + 1
def quick_sort_iterative(arr):
stack = [(0, len(arr) - 1)]
while stack:
low, high = stack.pop()
if low < high:
pi = partition(arr, low, high)
stack.append((low, pi - 1))
stack.append((pi + 1, high))
# Example usage:
arr = [38, 27, 43, 3, 9, 82, 10]
quick_sort_iterative(arr)
print("Sorted array:", arr) # Output: [3, 9, 10, 27, 38, 43, 82]
```
## Quick Sort Code in Python (Recursive)
```python
def quick_sort(arr):
if len(arr) <= 1:
return arr
else:
pivot = arr[-1]
left = [x for x in arr[:-1] if x < pivot]
right = [x for x in arr[:-1] if x >= pivot]
return quick_sort(left) + [pivot] + quick_sort(right)
arr = [5, 3, 8, 1, 2]
sorted_arr = quick_sort(arr)
print("Sorted array:", sorted_arr) # Output: [1, 2, 3, 5, 8]
```
## Complexity Analysis
- **Worst Case**: The worst-case time complexity of quick sort is `O(n^2)`. This occurs when the pivot selection consistently results in unbalanced partitioning, such as choosing the smallest or largest element as the pivot.
-**Best Case**: The best-case time complexity is `O(n log n)`. This happens when the pivot selection leads to well-balanced partitioning, halving the array size in each recursive call.
- **Average Case**: The average-case time complexity is `O(n log n)`. This is the expected time complexity when the pivot selection results in reasonably balanced partitioning across recursive calls.
- **Space Complexity**: Quick sort has an `O(log n)` space complexity for the recursion stack, as it recursively sorts sub-arrays.
</br>
<hr>
</br>
# 4. Merge Sort
Merge sort is a divide-and-conquer algorithm that recursively divides the input list into smaller sublists until each sublist contains only one element. Then, it repeatedly merges adjacent sublists while maintaining the sorted order until there is only one sublist remaining, which represents the sorted list.
**Algorithm Overview:**
- **Divide:** Split the input list into smaller sublists recursively until each sublist contains only one element.
- **Merge:** Repeatedly merge adjacent sublists while maintaining the sorted order until there is only one sublist remaining, which represents the sorted list.
## Example with Visualization
Let's sort the list `[38, 27, 43, 3, 9, 82, 10]` using merge sort.
1. **Initial Division:**
- Divide the list into sublists: `[38, 27, 43, 3, 9, 82, 10]`
- Visually it looks like
`[38], [27], [43], [3], [9], [82], [10]`
2. **Merge Passes:**
- Merge adjacent sublists while maintaining sorted order:
- Pass 1: `[27, 38]`, `[3, 43]`, `[9, 82]`, `[10]`
- Pass 2: `[3, 27, 38, 43]`, `[9, 10, 82]`
- Pass 3: `[3, 9, 10, 27, 38, 43, 82]`
3. **Final Sorted List:**
- `[3, 9, 10, 27, 38, 43, 82]`
## Merge Sort Code in Python (Iterative)
```python
def merge_sort_iterative(arr):
n = len(arr)
curr_size = 1
while curr_size < n:
left = 0
while left < n - 1:
mid = min(left + curr_size - 1, n - 1)
right = min(left + 2 * curr_size - 1, n - 1)
merge(arr, left, mid, right)
left += 2 * curr_size
curr_size *= 2
def merge(arr, left, mid, right):
n1 = mid - left + 1
n2 = right - mid
L = [0] * n1
R = [0] * n2
for i in range(n1):
L[i] = arr[left + i]
for j in range(n2):
R[j] = arr[mid + 1 + j]
i = j = 0
k = left
while i < n1 and j < n2:
if L[i] <= R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
while i < n1:
arr[k] = L[i]
i += 1
k += 1
while j < n2:
arr[k] = R[j]
j += 1
k += 1
arr = [38, 27, 43, 3, 9, 82, 10]
merge_sort_iterative(arr)
print("Sorted array:", arr) # Output: [3, 9, 10, 27, 38, 43, 82]
```
## Merge Sort Code in Python (Recursive)
```python
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2
left_half = arr[:mid]
right_half = arr[mid:]
merge_sort(left_half)
merge_sort(right_half)
i = j = k = 0
# Merge the two sorted halves
while i < len(left_half) and j < len(right_half):
if left_half[i] < right_half[j]:
arr[k] = left_half[i]
i += 1
else:
arr[k] = right_half[j]
j += 1
k += 1
# Check if any elements are remaining in the left half
while i < len(left_half):
arr[k] = left_half[i]
i += 1
k += 1
# Check if any elements are remaining in the right half
while j < len(right_half):
arr[k] = right_half[j]
j += 1
k += 1
# Example usage:
arr = [38, 27, 43, 3, 9, 82, 10]
merge_sort(arr)
print("Sorted array:", arr) # Output: [3, 9, 10, 27, 38, 43, 82]
```
## Complexity Analysis
- **Time Complexity**: `O(n log n)` for all cases. Merge sort always divides the list into halves until each sublist contains only one element, and then merges them back together, resulting in O(n log n) time complexity.
- **Space Complexity**: `O(n)` auxiliary space. In the iterative version, merge sort uses additional space for creating temporary sublists during merging operations.
</br>
<hr>
</br>

Wyświetl plik

@ -1,3 +1,3 @@
# List of sections
* Introduction_to_Pandas_Library_and_DataFrames.md
* Introduction_to_Pandas_Library_and_DataFrames.md

Wyświetl plik

@ -0,0 +1,72 @@
# Pandas Series Vs NumPy ndarray
NumPy ndarray and Pandas Series are two fundamental data structures in Python for handling and manipulating data. While they share some similarities, they also have distinct characteristics that make them suitable for different tasks.
Both NumPy ndarray and Pandas Series are essential tools for data manipulation in Python, Choosing between them depends on the nature of your data and the specific tasks you need to perform.
## NumPy ndarray
NumPy is short form for Numerical Python, provides a powerful array object called `ndarray`, It is very important for many scientific and mathematical Python libraries. ndarray is also called n-dimensional array. Indexing in ndarray is integer based indexing (like arr[0], arr[3], etc.).
Features of NumPy `ndarray`:
- **Homogeneous Data**: All elements in a NumPy array are of the same data type, which allows for efficient storage and computation.
- **Efficient Computation and Performance**: NumPy arrays are designed for numerical operations and are highly efficient. They support vectorized operations, allowing you to perform operations on entire arrays rather than individual elements.
- **Multi-dimensional**: NumPy arrays can be multi-dimensional, making them suitable for representing complex numerical data structures like matrices and n-dimensional arrays.
Example of creating a NumPy array:
```python
import numpy as np
narr = np.array(['A', 'B', 'C', 'D', 'E'])
print(narr)
```
Output:
```python
['A' 'B' 'C' 'D' 'E']
```
### Usage of NumPy ndarray:
- When you need to perform mathematical operations on numerical data.
- When youre working with multi-dimensional data.
- When computational efficiency is important.
- When you need to store data of same data type.
## Pandas Series
Pandas is a Python library used for data manipulation and analysis, introduces the `Series` data structure, which is designed for handling labeled one-dimensional data efficiently. Indexing in Pandas Series is Label-based. It effectively handles heterogeneous data.
Features of Pandas `Series`:
- **Labeled Data**: Pandas Series associates a label (or index) with each element of the array, making it easier to work with heterogeneous or labeled data.
- **Heterogeneous Data**: Unlike NumPy arrays, Pandas Series can hold data of different types (integers, floats, strings, etc.) within the same object.
- **Data Alignment**: One of the powerful features of Pandas Series is its ability to automatically align data based on label.
Example of creating a Pandas Series:
```python
import pandas as pd
series = pd.Series([1,'B', 5, 7, 6, 8], index = ['a','b','c','d','e','f'])
print(series)
```
Output:
```python
a 1
b B
c 5
d 7
e 6
f 8
dtype: object
```
### Usage of Pandas Series:
- When you need to manipulate and analyze labeled data.
- When youre dealing with heterogeneous data or missing values.
- When you need more high-level, flexible data manipulation functions.
- When you are dealing with One-dimensional data.

Wyświetl plik

@ -1,3 +1,3 @@
# List of sections
- [Section title](filename.md)
- [Installing Matplotlib](matplotlib_installation.md)

Wyświetl plik

@ -0,0 +1,31 @@
# Matplotlib Installation
Matplotlib is a widely used Python library for creating static, animated, and interactive visualizations. It can be installed using `pip`, Python's package manager.
## Prerequisites
Before installing Matplotlib, ensure you have Python installed on your system. You can download and install Python from the [official Python website](https://www.python.org/).
## Installation Steps
1. **Install Matplotlib**: Open your terminal or command prompt and run the following command to install Matplotlib using `pip`:
```bash
pip install matplotlib
```
2. **Verify Installation**: After installation, you can verify if Matplotlib is installed correctly by importing it in a Python environment:
```python
import matplotlib
print(matplotlib.__version__)
```
Output:
```
3.4.3
```