Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 49 additions & 16 deletions sorting_algorithms.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
"""
Sorting Algorithms Comparison Script

Includes:
- Bubble Sort
- Selection Sort
- Insertion Sort
- Native Python sort() and sorted()
"""

def bubble_sort(arr):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Module Documentation

Module-level docstring was removed, eliminating critical context about the module's purpose and contents. This reduces maintainability by forcing developers to infer the module's role from individual functions.

Suggested change
def bubble_sort(arr):
"""
Sorting Algorithms Comparison Script
Includes:
- Bubble Sort
- Selection Sort
- Insertion Sort
- Merge Sort
- Native Python sort() and sorted()
"""
Standards
  • Clean-Code-Documentation
  • Maintainability-Context
  • Clean-Code-Comments

"""
Performs in-place Bubble Sort on a list.
Comment on lines 1 to 3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Module-Level Docstring

The PR removes the module-level docstring that provided important context about the file's purpose and contents. Module-level docstrings are essential for maintainability as they help developers understand the purpose and contents of a module without having to read through the implementation details. The removal of this documentation reduces the code's self-documenting nature and makes it harder for new developers to understand the module's purpose.

Suggested change
def bubble_sort(arr):
"""
Performs in-place Bubble Sort on a list.
"""
Sorting Algorithms Comparison Script
Includes:
- Bubble Sort
- Selection Sort
- Insertion Sort
- Merge Sort
- Native Python sort() and sorted()
"""

Standard: PEP 257 - Python Docstring Conventions, Google Python Style Guide - Documentation

Expand Down Expand Up @@ -52,8 +42,45 @@ def insertion_sort(arr):
arr[j + 1] = key


def merge_sort(arr):
"""
Performs Merge Sort (not in-place).
Recursively divides the list and merges sorted halves.
"""
if len(arr) <= 1:
return arr

mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])

return merge(left, right)
Comment on lines +45 to +57
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential Stack Overflow in Recursive Merge Sort Implementation

The merge_sort function uses unbounded recursion without a depth limit. For very large arrays, this could lead to a stack overflow, potentially causing a denial of service. While Python's default recursion limit (typically 1000) provides some protection, this implementation doesn't account for that limit and could exhaust available stack space with sufficiently large inputs.

Suggested change
def merge_sort(arr):
"""
Performs Merge Sort (not in-place).
Recursively divides the list and merges sorted halves.
"""
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
import sys
def merge_sort(arr, max_depth=sys.getrecursionlimit() - 100):
"""
Performs Merge Sort (not in-place).
Recursively divides the list and merges sorted halves.
Includes a maximum recursion depth check to prevent stack overflow.
"""
def _merge_sort_recursive(arr, depth=0):
if len(arr) <= 1:
return arr
if depth >= max_depth:
# Fall back to Python's built-in sort for very deep recursions
result = arr.copy()
result.sort()
return result
mid = len(arr) // 2
left = _merge_sort_recursive(arr[:mid], depth + 1)
right = _merge_sort_recursive(arr[mid:], depth + 1)
return merge(left, right)
return _merge_sort_recursive(arr)

Standard: CWE-674
Standard: OWASP Top 10 2021: A06:2021-Vulnerable and Outdated Components


Comment on lines +45 to +58
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent Return Behavior in Sorting Algorithms

The merge_sort function is implemented as a non-in-place algorithm that returns a new sorted list, while the other sorting functions (bubble_sort, selection_sort, insertion_sort) modify the input list in-place and don't return anything. This inconsistency creates a logical error in how the functions are used in the test code, where arr4 is not being modified but arr4_sorted holds the sorted result. This breaks the pattern established by the other sorting functions and could lead to confusion or bugs when these functions are used interchangeably.

Suggested change
def merge_sort(arr):
"""
Performs Merge Sort (not in-place).
Recursively divides the list and merges sorted halves.
"""
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
def merge_sort(arr):
"""
Performs Merge Sort.
Recursively divides the list and merges sorted halves.
This is not an in-place implementation, but modifies the input list
to maintain consistency with other sorting functions.
"""
if len(arr) <= 1:
return
# Create a temporary array for the sorted result
temp_arr = arr.copy()
mid = len(arr) // 2
left_half = temp_arr[:mid]
right_half = temp_arr[mid:]
merge_sort(left_half)
merge_sort(right_half)
merged = merge(left_half, right_half)
# Copy the sorted result back to the original array
for i in range(len(merged)):
arr[i] = merged[i]

Standard: Design by Contract - Interface Consistency Principle

Comment on lines +45 to +58
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inefficient Space Complexity in Merge Sort Implementation

The current merge_sort implementation creates multiple new arrays during recursion (arr[:mid] and arr[mid:]), resulting in O(n log n) space complexity. For large datasets, this can lead to excessive memory usage and potential performance degradation. Each recursive call allocates new memory for the subarrays, which is inefficient compared to an in-place implementation that would use O(n) auxiliary space.

Suggested change
def merge_sort(arr):
"""
Performs Merge Sort (not in-place).
Recursively divides the list and merges sorted halves.
"""
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
def merge_sort(arr):
"""
Performs Merge Sort with improved space complexity.
Uses an auxiliary array to reduce memory allocations.
"""
if len(arr) <= 1:
return arr.copy()
# Create auxiliary array once
result = arr.copy()
aux = [0] * len(arr)
return _merge_sort_internal(result, aux, 0, len(arr) - 1)
def _merge_sort_internal(arr, aux, low, high):
"""Helper function for merge sort implementation."""
if low >= high:
return arr
mid = (low + high) // 2
_merge_sort_internal(arr, aux, low, mid)
_merge_sort_internal(arr, aux, mid + 1, high)
_merge(arr, aux, low, mid, high)
return arr

Standard: Algorithm Optimization Best Practices - Memory Efficiency in Recursive Algorithms


def merge(left, right):
"""
Helper function to merge two sorted lists.
"""
result = []
i = j = 0

# Merge the two halves
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
Comment on lines +60 to +74
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inefficient Merge Implementation

Using append() in a loop creates O(n) operations for each append as list may need resizing. This impacts merge sort performance, especially with large arrays.

Suggested change
def merge(left, right):
"""
Helper function to merge two sorted lists.
"""
result = []
i = j = 0
# Merge the two halves
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
def merge(left, right):
"""
Helper function to merge two sorted lists.
"""
result = [0] * (len(left) + len(right))
i = j = k = 0
# Merge the two halves
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result[k] = left[i]
i += 1
else:
result[k] = right[j]
j += 1
k += 1
# Append any remaining elements
while i < len(left):
result[k] = left[i]
i += 1
k += 1
while j < len(right):
result[k] = right[j]
j += 1
k += 1
return result
Standards
  • ISO-IEC-25010-Performance-Time-Behaviour
  • Algorithm-Opt-Memory-Allocation
  • Algorithm-Opt-List-Operations


# Append any remaining elements
result.extend(left[i:])
result.extend(right[j:])
return result


# Sample input
original = [6, 6, 2]
original = [6, 6, 2, 3, 2]

print("Original list:")
print(original)
Expand All @@ -76,13 +103,19 @@ def insertion_sort(arr):
print("\nInsertion Sort result:")
print(arr3)

# Python built-in sort (in-place)
# Merge Sort (not in-place)
arr4 = original.copy()
arr4.sort()
arr4_sorted = merge_sort(arr4)
print("\nMerge Sort result:")
print(arr4_sorted)

# Python built-in sort (in-place)
arr5 = original.copy()
arr5.sort()
print("\nPython .sort() result:")
print(arr4)
print(arr5)

# Python built-in sorted() (returns new list)
arr5 = sorted(original)
arr6 = sorted(original)
print("\nPython sorted() result (non-in-place):")
print(arr5)
print(arr6)