How to Sort a List in Python Without Using Sort Function

Learn to sort lists in Python without relying on sort(). Join our Python course and become proficient in core programming techniques!

Table of Contents

how to sort a Python list manually and enhance your coding skills! Learn the best techniques and start mastering Python today with 3RI Technologies.


Introduction

Sorting a list in Python is an essential skill for programmers, crucial for organizing data in a specific order, whether for computations, analysis, or optimizing efficiency. Gaining knowledge about techniques to manually sort a list improves your coding and problem-solving skills. In this blog post, we will explore alternative methods to sort a list, equipping you with versatile techniques to handle diverse data scenarios effectively and enhance your programming proficiency.

What is Sorting?

Sorting involves placing items in a collection in a certain order, such as descending or ascending. This fundamental concept in computer science and programming plays a critical role in the functionality of algorithms and data structures. Sorting is pivotal in various applications, ranging from search engines and databases to everyday technologies like recommendation systems and e-commerce platforms.

The importance of sorting becomes evident in its diverse real-world applications. For instance, e-commerce websites utilize sorting to display products based on user preferences like price, ratings, or relevance. Similarly, data analysts depend on sorted datasets for clearer visualization, streamlined interpretation, and accurate decision-making. These examples demonstrate how sorting simplifies data handling and enhances user experiences.

Beyond its applications, understanding sorting methods deepens our knowledge of how computers process and organize data. Exploring alternative ways to sort a list in Python not only sharpens coding skills but also fosters problem-solving capabilities. By mastering these techniques, programmers can optimize performance in various scenarios, making their applications more efficient and reliable.

If you are eager to enhance your coding proficiency and delve deeper into sorting, keep reading to learn techniques that don’t rely on Python’s built-in sort function.

Sorting Techniques

1. Bubble Sort:

The algorithm compares adjacent items and swaps them if needed, continuing through the list until it’s ordered. Although it’s straightforward, it becomes sluggish with large datasets due to the number of comparisons and swaps required.  Bubble Sort employs nested loops to compare every element with every other element, resulting in repeated comparisons, its time complexity is O(n²).

Example

def bubble_sort(arr):

    length = len(arr)

    for i in range(length):

        for j in range(length – i – 1):

            if arr[j] > arr[j + 1]:

                # Swap elements if the first one is larger than the second

                arr[j], arr[j + 1] = arr[j + 1], arr[j]

# Example list to sort

numbers = [64, 34, 25, 12, 22, 11, 90]

bubble_sort(numbers)

print(“Sorted List:”, numbers)



2. Selection Sort

The algorithm constantly selects the largest or smallest item from the unsorted section and adds it to the sorted section. Though fewer swaps occur compared to Bubble Sort, the high number of comparisons makes it inefficient for large lists. Selection Sort iterates through the list to determine whether element is the smallest or biggest in each pass, it also has an O(n²) time complexity.

Example:

def selection_sort(arr):

    for i in range(len(arr)):

        smallest = i

        for j in range(i + 1, len(arr)):

            if arr[j] < arr[smallest]:

                smallest = j

        arr[i], arr[smallest] = arr[smallest], arr[i]

# Example list to sort

numbers = [64, 34, 25, 12, 22, 11, 90]

selection_sort(numbers)

print(“Sorted List:”, numbers)

3. Insertion Sort

In Insertion sort technique, each new element is inserted into its proper place among the previously sorted components to build a sorted section.This makes it ideal for nearly sorted lists but inefficient when working with larger, unsorted datasets. Insertion Sort’s time complexity is O(n²) due to shifting elements for each insertion in the worst case.

Example:

def insertion_sort(arr):

    for i in range(1, len(arr)):

        current_value = arr[i]

        j = i – 1

        while j >= 0 and current_value < arr[j]:

            arr[j + 1] = arr[j]

            j -= 1

        arr[j + 1] = current_value

# Example list to sort

numbers = [64, 34, 25, 12, 22, 11, 90]

insertion_sort(numbers)

print(“Sorted List:”, numbers)

Want to Book A Free Expert Guidance Session?

Get Free Career Counseling from Experts !



4. Merge Sort

It breaks down the list into progressively smaller chunks, sorting each part and then merging them back together in sequence. Its design allows it to handle large lists efficiently, offering stability by maintaining the order of duplicate values. Merge Sort has O(n log n) time complexity, as the list is divided recursively, and merging takes linear time.

Example:

def merge_sort(arr):

    if len(arr) > 1:

        mid = len(arr) // 2

        left = arr[:mid]

        right = arr[mid:]

        merge_sort(left)

        merge_sort(right)

        i = j = k = 0

        while i < len(left) and j < len(right):

            if left[i] < right[j]:

                arr[k] = left[i]

                i += 1

            else:

                arr[k] = right[j]

                j += 1

            k += 1

        while i < len(left):

            arr[k] = left[i]

            i += 1

            k += 1

        while j < len(right):

            arr[k] = right[j]

            j += 1

            k += 1

arr = [38, 27, 43, 3, 9, 82, 10]

merge_sort(arr)

print(“Merge Sort:”, arr)

5. Quick Sort

The list is split around a pivot element, and smaller and larger elements are grouped accordingly. Recursively applied to smaller sections, Quick Sort is typically fast, though its performance can degrade with poor pivot choices. Quick Sort has an average of O(n log n), but if the pivot is not chosen well, it may decrease to O(n²).

Example:

def quick_sort(arr):

    if len(arr) <= 1:

        return arr

    pivot = arr[0]

    less = [x for x in arr[1:] if x <= pivot]

    greater = [x for x in arr[1:] if x > pivot]

    return quick_sort(less) + [pivot] + quick_sort(greater)

arr = [10, 7, 8, 9, 1, 5]

print(“Quick Sort:”, quick_sort(arr))

6. Heap Sort

With this technique, a heap structure is built with the maximum or smallest element serving as the heap’s root. It sorts the list effectively by periodically switching the root with the last element. Heap Sort is perfect for huge datasets since it has a time complexity of O(n log n) because it uses heap operations (insertion and deletion).

Example:

import heapq

def heap_sort(arr):

    heapq.heapify(arr)

    sorted_arr = [heapq.heappop(arr) for _ in range(len(arr))]

    return sorted_arr

arr = [34, 21, 56, 9, 45, 18]

print(“Heap Sort:”, heap_sort(arr))

7. Counting Sort

This sorting technique measures the frequency of each item in the input list without using comparison. It then arranges each element in the proper location using this count. Counting Sort performs well for small ranges, as its time complexity is O(n + k), where n is the number of elements and k is the range of the input values.

Example:

def counting_sort(arr):

    highest_value = max(arr)

    frequency = [0] * (highest_value + 1)

    for value in arr:

        frequency[value] += 1

    sorted_list = []

    for index, count in enumerate(frequency):

        sorted_list.extend([index] * count)

    return sorted_list

numbers = [4, 2, 2, 8, 3, 3, 1]

print(“Sorted List:”, counting_sort(numbers))

8. Radix Sort

Radix Sort organizes integers by sorting them starting from the least significant digit and moving towards the most significant digit. It uses a helper function, Counting Sort, to handle individual digits. Large datasets with a restricted range of integer values benefit greatly from Radix Sort’s high efficiency and time complexity of O(nk), where n is the number of elements and k is the number of digits in the highest number.

Example:

def counting_sort_for_radix(array, place_value):

    size = len(array)

    output = [0] * size

    count = [0] * 10

    for number in array:

        digit = (number // place_value) % 10

        count[digit] += 1

    for i in range(1, 10):

        count[i] += count[i – 1]

    for i in range(size – 1, -1, -1):

        digit = (array[i] // place

Advanced Sorting Techniques

Advanced sorting techniques come with their own advantages and challenges depending on their efficiency and complexity. The sorting technique you choose is mostly determined by the particular requirements of your assignment, including the amount and kind of data. Each algorithm has strengths in different situations, so it’s important to consider factors like the data’s structure and the required performance when deciding which sorting technique to apply.

  • Bubble Sort: In Bubble Sort technique, each pair of adjacent elements is compared, and they are swapped if they are out of order. The largest unsorted element in the list gets “bubbled” to its correct spot each time it is passed through. The algorithm is simple and intuitive but inefficient for larger datasets, as it requires multiple iterations to achieve the sorted result.
  • Selection Sort: In this technique, the first unsorted element is swapped with the smallest (or largest) element, which is repeatedly selected from the unsorted section of the list. The sorted portion grows one element at a time, with the algorithm making fewer swaps compared to Bubble Sort. Despite its ease of use, the sheer amount of comparisons it does makes it inefficient for huge collections of data.
  • Insertion Sort: In Insertion Sort technique, each item in the list is selected from the unsorted area and placed in the appropriate location inside the sorted segment. To determine the element’s proper placement, it compares it to those that have previously been sorted and moves them as needed. This makes Insertion Sort efficient for partially sorted lists or small datasets, as it requires fewer operations in such cases.
  • Merge Sort: Using a divide-and-conquer strategy, Merge Sort divides the list into increasingly smaller sublists until each sublist has a single member. After then, these sublists are merged together in a sorted order. This sorting technique guarantees stable sorting and excels at handling large datasets efficiently due to its structured and recursive design.
  • Quick Sort: Quick Sort also follows a divide-and-conquer paradigm, but instead of dividing the list into equal halves, it partitions the list around a chosen pivot element. Items smaller than the pivot go to one side, and items greater than it go to the other. This process repeats recursively for the sublists, leading to a highly efficient sorting algorithm in most cases, although it can degrade under certain circumstances.
  • Heap Sort: Heap Sort makes sure that the largest (or smallest) entry is always at the root of the list by organizing it into a binary heap structure. It then repeatedly swaps the root with the last element in the heap and shrinks the heap size until the list is fully sorted. It is particularly useful when dealing with large datasets and is efficient in scenarios where the data is too large to be stored in memory simultaneously.
  • Counting Sort: Counting Sort places the elements in the output array in the correct order by determining the frequency of each element in the input array, ensuring efficient sorting for specific types of data. It works best with integer data within a known range, making it highly efficient for sorting datasets with limited range values, but less effective for large ranges or complex data types.
  • Radix Sort: In Radix Sort, components are arranged according to their individual digits, beginning with the least important digit. By applying Counting Sort to each digit, it gradually sorts the list. It is highly effective when sorting large datasets with numerical values or fixed-length strings, as it eliminates the need for direct comparisons between elements.

Unlock the Secrets to a Powerful LinkedIn Profile !



Conclusion

Sorting a list manually in Python helps programmers gain a deeper understanding of core algorithmic principles. Techniques such as bubble sort and insertion sort offer insight into how basic algorithms operate, while more advanced methods like merge sort and quicksort are valuable for optimizing performance in large datasets. By manually implementing these sorting techniques, developers enhance their problem-solving and coding skills, which are essential in both professional programming and competitive environments. These exercises build a solid foundation for understanding complex algorithms, making it easier to solve intricate problems. Mastering sorting algorithms is an excellent way to boost coding proficiency, improve efficiency, prepare for advanced software development tasks, and sharpen critical thinking, ultimately becoming more effective at coding challenges.

Get in Touch

3RI team help you to choose right course for your career. Let us know how we can help you.