Need help understanding bubble sort solution code - python

So, I was learning about Bubble Sort and saw this code:
def bubblesort(list_a):
indexing_length = len(list_a) - 1
sorted = False
while not sorted:
sorted = True
for i in range(0, indexing_length):
if list_a[i] > list_a[i+1]:
sorted = False
list_a[i], list_a[i+1] = list_a[i+1], list_a[i] # flip position
return list_a
I tried running this code on my notebook so I could understand this better. I tried 5, 2, 3, 7, 10, 1, 8 and the process was like this:
--> 2, 5, 3, 7, 10, 1, 8
--> 2, 3, 5, 7, 10, 1, 8
--> 2, 3, 5, 7, 1, 10, 8
--> 2, 3, 5, 7, 1, 8, 10
I ended up with unsorted array because I thought for loop does only one iteration. Am I understanding something wrong? Could anyone explain it to me little bit easier please?

Bubble Sort is the simplest sorting algorithm that works by repeatedly swapping the adjacent elements if they are in wrong order. This sorting algorithm also known as Brute Force Approach, the reason is that during sorting each element of list will compare with the every other element of the same list and if the compared number are not in order so it will swap the position. Lets have a look on your example list [5, 2, 3, 7, 10, 1, 8].
1st pass: compare 0th index(5) and 1st index(2) and compare it
if 0th index(5) > 1st index(2) then it will swap the position else no swap counter will increase. [5, 2, 3, 7, 10, 1, 8] condition True(5 > 2), SWAP [2, 5, 3, 7, 10, 1, 8], then again compare [2, 5, 3, 7, 10, 1, 8] condition True(5 > 3), SWAP [2, 3, 5, 7, 10, 1, 8], and so on.
[2, 3, 5, 7, 10, 1, 8] True(10>1).
[2, 3, 5, 7, 1, 10, 8] True(10>8).
[2, 3, 5, 7, 1, 8, 10]
2nd pass:
[2, 3, 5, 7, 1, 8, 10]
[2, 3, 5, 7, 1, 8, 10]
[2, 3, 5, 7, 1, 8, 10] True(7>1).
[2, 3, 5, 1, 7, 8, 10]
[2, 3, 5, 1, 7, 8, 10]
3rd pass:
[2, 3, 5, 1, 7, 8, 10]
[2, 3, 5, 1, 7, 8, 10] True(5>1).
[2, 3, 1, 5, 7, 8, 10]
[2, 3, 1, 5, 7, 8, 10]
4th pass:
[2, 3, 1, 5, 7, 8, 10] True(3>1).
[2, 1, 3, 5, 7, 8, 10]
[2, 1, 3, 5, 7, 8, 10]
5th pass:
[2, 1, 3, 5, 7, 8, 10] True(2>1).
[1, 2, 3, 5, 7, 8, 10]
[1, 2, 3, 5, 7, 8, 10]
6th pass:
[1, 2, 3, 5, 7, 8, 10]
7th pass:
[1, 2, 3, 5, 7, 8, 10]
def bubbleSort(arr):
n = len(arr)
for i in range(n):
print(arr[i])
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
print(arr[j], arr[j+1])
arr[j], arr[j + 1] = arr[j + 1], arr[j]
print(arr)
arr = [5, 2, 3, 7, 10, 1, 8]
bubbleSort(arr)
print("Sorted array")
print(arr)

The list will be [2, 3, 5, 7, 1, 8, 10] after the for loop completes the first time, but the value of sorted will be False. Since you're still inside the while not sorted loop, everything inside that loop will run again, including another for loop starting at index 0.
This will keep going until the list is sorted when the for loop completes, since that will make the while loop's condition False.

Related

How can I make this python function generate such a list [[1], [1, 2]...[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]?

all = []
def generate(i, current):
if i < 11:
current.append(i)
all.append(current)
i+= 1
generate(i, current)
generate(1, [])
print(all)
I want this function to generate
[[1], [1, 2]...[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
instead of
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]],
but don't know how to fix it.
Do you know the solution?
Here's my go:
def listGen(start, stop):
res = []
for i in range(start, stop+1):
res.append([x for x in range(start, i+1)])
return res
You could also simplify this to:
def listGen(start, stop):
return [[x for x in range(start, i+1)] for i in range(start, stop+1)]
Input: print(listGen(1, 10))
Output: [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
def generate_array():
result = []
for i in range(1, 11):
current_array = []
for j in range(1, i + 1):
current_array.append(j)
result.append(current_array)
return result
print(generate_array())
The code uses two nested for loops, where the outer loop iterates over range(1, 11) and the inner loop iterates over range(1, i + 1). The values of i and j are used to generate the sublists and append them to the result list, which is returned at the end of the function.
The core issue you have is that when you do:
all.append(current)
current is the exact same list all over the place so when you append to it in the prior line you effectively append to it everywhere. To fix that and the lightest change to your code you would append to copy of it.:
all = []
def generate(i, current):
if i < 11:
current.append(i)
all.append(current.copy()) ## <--- append a copy
i+= 1
generate(i, current)
generate(1, [])
print(all)
alternatively you could pass a copy like:
all = []
def generate(i, current):
if i < 11:
current.append(i)
all.append(current)
i+= 1
generate(i, current.copy()) ## <--- pass a copy
generate(1, [])
print(all)
In either case, the important part is that we get a distinct current to work with.
Note that the use of all as a variable clobbers the function all() and you might not want to do that. As I'm sure lots of others will point out, there are many ways to skin this cat.

New line in List

Lets say I have a list called l1:
l1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
And I want to print it as
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
How would I do that in python on 3.9
I tried to us a \n, but that has not worked for me.
list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(list[:5])
print(list[5:])
outputs:
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]
if you want them to be printed on the same line then you can use:
print(list[:5],list[5:])
which will return:
[1, 2, 3, 4, 5] [6, 7, 8, 9, 10]
Slicing would probably work for you.
l1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(l1[:5]) # print first half
print(l1[5:]) # print second half
This should print both halves on separate lines, which is what I think you're trying to do with \n?
[1, 2, 3, 4, 5]
[6, 7, 8, 9, 10]

what is the name of this sorting algorithm? is it bubble sort? most easy sorting?

what is the name of this sort? its just like bubble sort but its easy to write but harder in term of complexity.codes are in python language.
def sort(arr):
n = len(arr)
for i in range(n):
for j in range(n):
if arr[i] < arr[j] :
arr[j], arr[i] = arr[i], arr[j]
but bubble sort is like this :
def bubbleSort(arr):
n = len(arr)
# Traverse through all array elements
for i in range(n):
# Last i elements are already in place
for j in range(0, n-i-1):
# traverse the array from 0 to n-i-1
# Swap if the element found is greater
# than the next element
if arr[j] > arr[j+1] :
arr[j], arr[j+1] = arr[j+1], arr[j]
It is neither selection sort nor bubble sort, but an unnecessary bad sort. All of them, your sort, selection sort and bubble sort are of the same complexity, O(n^2).
Your sort sweeps over the array in two loops without consideration for if an element has reached its proper place (as in selection sort) or if an element has gained a place relative to the next (as in bubble sort). The extra code in bubble and selection sort make them far better than yours.
Compare, yourself:
def sort(arr):
print(arr)
n = len(arr)
for i in range(n):
for j in range(n):
if arr[i] < arr[j] :
arr[j], arr[i] = arr[i], arr[j]
print(arr)
def selectionsort(arr):
print(arr)
n = len(arr)
for i in range(n-1):
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]
print(arr)
def bubblesort(arr):
print(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]
print(arr)
print("sort:")
sort([4,6,3,2,7,1,8,5])
print("selectionsort:")
selectionsort([4,6,3,2,7,1,8,5])
print("bubblesort:")
bubblesort([4,6,3,2,7,1,8,5])
with the results:
sort:
[4, 6, 3, 2, 7, 1, 8, 5]
[6, 4, 3, 2, 7, 1, 8, 5]
[7, 4, 3, 2, 6, 1, 8, 5]
[8, 4, 3, 2, 6, 1, 7, 5]
[4, 8, 3, 2, 6, 1, 7, 5]
[3, 8, 4, 2, 6, 1, 7, 5]
[3, 4, 8, 2, 6, 1, 7, 5]
[2, 4, 8, 3, 6, 1, 7, 5]
[2, 3, 8, 4, 6, 1, 7, 5]
[2, 3, 4, 8, 6, 1, 7, 5]
[2, 3, 4, 6, 8, 1, 7, 5]
[1, 3, 4, 6, 8, 2, 7, 5]
[1, 2, 4, 6, 8, 3, 7, 5]
[1, 2, 3, 6, 8, 4, 7, 5]
[1, 2, 3, 4, 8, 6, 7, 5]
[1, 2, 3, 4, 6, 8, 7, 5]
[1, 2, 3, 4, 6, 7, 8, 5]
[1, 2, 3, 4, 5, 7, 8, 6]
[1, 2, 3, 4, 5, 6, 8, 7]
[1, 2, 3, 4, 5, 6, 7, 8]
selectionsort:
[4, 6, 3, 2, 7, 1, 8, 5]
[1, 6, 3, 2, 7, 4, 8, 5]
[1, 2, 3, 6, 7, 4, 8, 5]
[1, 2, 3, 6, 7, 4, 8, 5]
[1, 2, 3, 4, 7, 6, 8, 5]
[1, 2, 3, 4, 5, 6, 8, 7]
[1, 2, 3, 4, 5, 6, 8, 7]
[1, 2, 3, 4, 5, 6, 7, 8]
bubblesort:
[4, 6, 3, 2, 7, 1, 8, 5]
[4, 3, 6, 2, 7, 1, 8, 5]
[4, 3, 2, 6, 7, 1, 8, 5]
[4, 3, 2, 6, 1, 7, 8, 5]
[4, 3, 2, 6, 1, 7, 5, 8]
[3, 4, 2, 6, 1, 7, 5, 8]
[3, 2, 4, 6, 1, 7, 5, 8]
[3, 2, 4, 1, 6, 7, 5, 8]
[3, 2, 4, 1, 6, 5, 7, 8]
[2, 3, 4, 1, 6, 5, 7, 8]
[2, 3, 1, 4, 6, 5, 7, 8]
[2, 3, 1, 4, 5, 6, 7, 8]
[2, 1, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
It doesn't make a big difference on small arrays but on large arrays it make a lot of difference (but then there are other methods).

Why are for loop and np.random.shuffle not work as expected in Python?

I try to randomly shuffle the list in a for loop and then append it to another list. Expect to produce 5 lists in different orders, but the results are all in the same order. The code and output are as follows:
list_data = []
for i in range(10):
list_data.append(i)
print(list_data)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
random_list = []
for j in range(5):
np.random.shuffle(list_data)
random_list.append(list_data)
print(list_data)
print(random_list)
# [6, 4, 5, 7, 8, 2, 0, 1, 3, 9]
# [2, 9, 4, 3, 5, 0, 7, 1, 6, 8]
# [3, 0, 9, 1, 5, 7, 8, 6, 4, 2]
# [6, 1, 7, 2, 0, 4, 9, 8, 5, 3]
# [3, 2, 5, 9, 8, 4, 6, 7, 1, 0]
# [[3, 2, 5, 9, 8, 4, 6, 7, 1, 0], [3, 2, 5, 9, 8, 4, 6, 7, 1, 0], [3, 2, 5, 9, 8, 4, 6, 7, 1, 0], [3, 2, 5, 9, 8, 4, 6, 7, 1, 0], [3, 2, 5, 9, 8, 4, 6, 7, 1, 0]]
Although you already have an answer I'd like to help you shorten it into 3 lines of code, and you don't need numpy either. This can be achieved by list comprehension. This code below does what you want.
Note: I used random.sample instead of numpy.random.shuffle, because that shuffles the list inplace and returns None.
import random
list_data = [i for i in range(10)]
random_list = [random.sample(list_data, len(list_data)) for j in range(5)]

Duplicate problems with Selection Sort

If I have a list where all values are unique, the code runs fine. However, if there is a duplicate value within the list, when finding the minimum value for the next iteration, it pulls from the entire list rather than just the remainder of the list.
for n in range(0,len(lst)):
a = min(lst[n:]) #minimum value within remainder of set
i = lst.index(a) #index value for minimum value within remainder of set
temp = lst[n]
lst[n] = a
lst[i] = temp
Results look like this:
lst = [6, 8, 9, 1, 3, 4, 7, 5, 4]
[1, 8, 9, 6, 3, 4, 7, 5, 4]
[1, 3, 9, 6, 8, 4, 7, 5, 4]
[1, 3, 4, 6, 8, 9, 7, 5, 4]
[1, 3, 6, 4, 8, 9, 7, 5, 4]
[1, 3, 6, 8, 4, 9, 7, 5, 4]
[1, 3, 6, 8, 9, 4, 7, 5, 4]
[1, 3, 6, 8, 9, 7, 4, 5, 4]
[1, 3, 6, 8, 9, 7, 5, 4, 4]
[1, 3, 6, 8, 9, 7, 5, 4, 4]
I'm looking for it to return this:
[1, 3, 4, 4, 5, 6, 7, 8, 9]
When n is 4, the next minimum is 4 again, but lst.index() finds the first 4 at position 3 instead.
Start searching for the miminum from n; the .index() method takes a second argument start, from where to start searching:
i = lst.index(a, n)
Note that Python can assign to two targets in place, no need to use a temporary intermediate. range() with just one argument starts from 0:
for n in range(len(lst)):
a = min(lst[n:])
i = lst.index(a, n)
lst[n], lst[i] = a, lst[n]
Demo:
>>> lst = [6, 8, 9, 1, 3, 4, 7, 5, 4]
>>> for n in range(0,len(lst)):
... a = min(lst[n:])
... i = lst.index(a, n)
... lst[n], lst[i] = a, lst[n]
...
>>> lst
[1, 3, 4, 4, 5, 6, 7, 8, 9]

Categories