Write the code of bubble sort and explain its time and space complexities.
Implement bubble_sort(arr) to sort a list of integers in ascending order and return the sorted list. The algorithm must sort the input in place and should stop early when a complete pass makes no swaps.
Use only constant extra space. State the best-case, average-case, worst-case time complexities and the auxiliary space complexity.
def bubble_sort(arr):