Python: How can I make my implementation of bubble

2019-02-27 12:40发布

问题:

Here is my code - a bubble sort algorithm for sorting list elements in asc order:

foo = [7, 0, 3, 4, -1]
cnt = 0
for i in foo:
    for i in range(len(foo)-1):
        if foo[cnt] > foo[cnt + 1]:
            temp = foo[cnt]
            c[cnt] = c[cnt + 1]
            c[cnt + 1] = temp
        cnt = cnt + 1
    cnt = 0

I've been revising my code, but it is still too inefficient for an online judge. Some help would be greatly appreciated!

回答1:

Early Exit BubbleSort

  1. The first loop has no bearing on what happens inside
  2. The second loop does all the heavy lifting. You can get rid of count by using enumerate
  3. To swap elements, use the pythonic swap - a, b = b, a.
  4. As per this comment, make use of an early exit. If there are no swaps to be made at any point in the inner loop, that means the list is sorted, and no further iteration is necessary. This is the intuition behind changed.
  5. By definition, after the ith iteration of the outer loop, the last i elements will have been sorted, so you can further reduce the constant factor associated with the algorithm.
foo = [7, 0, 3, 4, -1]
for i in range(len(foo)):
    changed = False
    for j, x in enumerate(foo[:-i-1]):
        if x > foo[j + 1]:
            foo[j], foo[j + 1] = foo[j + 1], foo[j]
            changed = True

    if not changed:
        break

print(foo)
[-1, 0, 3, 4, 7]

Note that none of these optimisations change the asymptotic (Big-O) complexity of BubbleSort (which remains O(N ** 2)), instead, only reduces the constant factors associated.



回答2:

One easy optimization is to start second loop from i+1 index:

for i in range(0, len(foo)):
    for j in range(i+1, len(foo)):
        if (foo[i] > foo[j]):
            temp = foo[i]
            foo[i] = foo[j]
            foo[j] = temp

Since you already sorted everything up to index i there is no need to iterate over it again. This can save you more than 50% of comparisons - in this case it's 10 versus 25 in your original algorithm.



回答3:

You need to understand the big Oh notation in order to understand how efficient your algorithm is in terms of usage of computational resources independent of computer architecture or clock rate. It basically helps you analyze the worst case running time or memory usage of your algorithm as the size of the input increases. In summary, the running time of your algorithm will fall into one of these categories (from fastest to slowest);

O(1): Constant time. Pronounced (Oh of 1). The fastest time.

O(lg n): Logarithmic time. Pronounced (Oh of log n). Faster than linear time. Traditionally, it is the fastest time bound for search.

O(n): Linear time. Pronounced (Oh of n, n is the size of your input e.g size of an array). Usually something when you need to examine every single bit of your input.

O(nlgn): The fastest time we can currently achieve when performing a sort on a list of elements.

O(n**2): Oh of n squared. Quadratic time. Often this is the bound when we have nested loops.

O(2**n): Really, REALLY big! A number raised to the power of n is slower than n raised to any power.

In your case, you are using nested loops which is O(n2). The code i have written uses a single while loop and has a growth complexity of O(n) which is faster than O(n2). I haven't really tried it on a very large array but in your case it seems to work. Try it and let me know if it works as expected.

k = [7, 0, 3, 4, -1]
n = len(k)
i = 0
count = 0
while count < n**2: # assuming we wouldn't go through the loop more than n squared times
    if i == n - 1:
        i = 0
        count += 1
        swapped = False
    elif k[i] > k[i+1]:
        temp = k[i]
        k[i] = k[i+1]
        k[i+1] = temp
        i+=1
        swapped = True
    elif swapped == False:
        i += 1
    elif swapped == True and i < n - 1:
        i += 1

Note: In the example list (k), we only need to loop through the list three times in order for it to be sorted in ascending order. So if you change the while loop to this line of code while count < 4:, it would still work.