Boolean values and sorting list logic. Intro to programming - python-2.x

my teacher recently wrote a program on how to sort a list with numbers and i dont understand mainly the boolean value statements and then the logic in the loop to sort the numbers so help would be appreciated in just explaining what he did. I have homework to do and sorting is part of it so im just trying to understand this example he did. Thanks
d = [8, 14, 3, 5, 2, 23] # lists
size = len( d ) # size = number of elements in list
unsorted = True # what does this really mean and do?
while unsorted : # bassicly while true, but while what is true? what would make it false?
unsorted = False #? did he just change the variable to false? if so, why, and
# how is the "while unsorted" before statement still being met
i = 0 # this bassiclly begins the indency number in the list below
while i < size-1 : # so while the indency number is less than the list
# element size it will loop through the rest
if d[i] > d[i+1] : # if the number in d[i]is greater than the number after
temp = d[i] # then variable temp gets assigned that number in d[i]
d[i] = d[i+1] # this confuses me. whats the purpose of setting d[i] to d[i+1]?
d[i+1] = temp # i think this has to do with the statement above, what does it
unsorted = True # why is this suddenly turned back to true?
i += 1 # adds 1 to to indency or i until it reaches the list size to stop loop
print d
Output ends up being a sorted list below
[2, 3, 5, 8, 14, 23]
Thanks

This is the Bubble sort sorting algorithm. To sort all elements of an array in ascending order this algorithm compares two neighbouring elements, and swaps their location if the successor i+1 of an element i has the smaller value.
Now lets comment some of your comments ;-)
unsorted = True # what does this really mean and do?
This declares and initializes your boolean value. If False you wouldn't be able to enter the following while loop.
while unsorted : # bassicly while true, but while what is true? what would make it false?
unsorted = False #? did he just change the variable to false? if so, why, and
# how is the "while unsorted" before statement still being met
The condition for execution of a while loop only gets checked before entering a new "round". Please check how a while loop works, this is a fundamental construct! The variable unsorted is set to False so the program is able to leave the loop, when the array has been sorted entirely.
i = 0 # this bassiclly begins the indency number in the list below
Yes, indeed Python uses zero based indexing (another term you should look up). This means that the first element in an array comes with the index zero
while i < size-1 : # so while the indency number is less than the list
# element size it will loop through the rest
This makes you able to loop over all elements of the array. But be aware that this line may provoke an error. It really should be:
while i < size-2
size-1 is the index of the last element in an array of length size. But since you always compare an element and its successor you don't have to check the last element of the array (it doesn't have an successor).
temp = d[i] # then variable temp gets assigned that number in d[i]
d[i] = d[i+1] # this confuses me. whats the purpose of setting d[i] to d[i+1]?
d[i+1] = temp # i think this has to do with the statement above, what does it
This is the swapping I told you about. Elements d[i] and d[i+1] switch places. To do so you need an temporary storage for one variable.
unsorted = True # why is this suddenly turned back to true?
Because he had to change the order of the elements in the array. The program should only be allowed to leave the outer while loop when no more swapping is necessary and the array elements have been sorted.

This is a bubble sort.
The concept of a bubble sort is basically swapping larger numbers towards the end of the list. The Boolean variable is used for keeping track of whether or not the list is sorted.
We know that the list is sorted if we checked every number and we don't have to swap any of them. (That's basically what the code does and the reason we need the Boolean variable)
unsorted = True # what does this really mean and do?
This keeps tracks of whether or not the list is sorted. When this is False, we are done sorting and we can print the list. However, if it is True, we have to check the list and swap the numbers to the correct spot.
while unsorted : # bassicly while true, but while what is true? what would make it false?
As I mentioned, while True: means that the list is not sorted last time we checked, so we have to check the list again(i.e. run the code in the while loop.)
unsorted = False
This might be the tricky part. We just assume that the list the sorted, unless we have to swap numbers. (The code below is the piece of code that do the swapping)
if d[i] > d[i+1] :
temp = d[i] # store the larger number in a temporary variable
d[i] = d[i+1] # put the smaller number in the spot of the larger number
d[i+1] = temp # put the larger number after the smaller number
unsorted = True # we swapped a number, so this list might not be completely sorted

Related

why Find-Minimum operation in priority queue implemented in unsorted array take only complexity = O(1) ? <steven skiena's the algorithm design manual>

In steven skiena's the algorithm design manual (page 85),
The author show in a table that priority queue implemented in unsorted array only take O(1) for both insertion and find minimum operation.
For my understanding unsorted array wasn't able get the minimum item in O(1) , because it has to search through the whole array to get the minimum.
is there any details i missed out in priority queue ?
It's (mostly) written there under the table:
The trick is using an extra variable to store a pointer/index to the minimum ...
Presumably, the next word is "value", meaning it's a simple O(1) dereference to get the minimum.
When inserting an item, you just append it to the end and, if it's less than the current minimum, update that pointer/index. That means O(1) for the insert.
The only "expensive" operation is then delete-minimum. You know where it is due to the pointer/index but it will take O(n) operations to shuffle the array elements beyond it down one.
And, since the cost is already O(n), you may as well take the opportunity to search the array for the new minimum and store its position in the pointer/index.
The pseudo-code for those operations be something along the lines of (first up, initialisation and insertion, and assuming zero-based indexes):
class prioQ:
array = [] # Empty queue.
lowIndex = 0 # Index of lowest value (for non-empty queue).
def insert(item):
# Add to end, quick calc if array empty beforehand.
array.append(item)
if len(array) == 1:
lowIndex = 0
return
# Adjust low-index only if inserted value smaller than current.
if array[lowIndex] > item:
lowIndex = len(array) - 1
Then a function to find the actual minimum value:
def findMin():
# Empty array means no minimum. Otherwise, return minimum.
if len(array) == 0: return None
return array[lowIndex]
And, finally, to extract the minimum value (remove it from the queue and return it):
def extractMin():
# Empty array means no minimum. Otherwise save lowest value.
if len(array) == 0: return None
retVal = array[lowIndex]
# Shuffle down all following elements to delete lowest one
for index = lowIndex to len(array) - 2 inclusive:
array[index] = array[index + 1]
# Remove final element (it's already been shuffled).
delete array[len(array) - 1]
# Find lowest element and store.
if len(array) > 0:
lowIndex = len(array) - 1
for index = len(array) - 2 to 0 inclusive:
if array[index] <= array[lowIndex]:
lowIndex = index
# Return saved value.
return retVal
As an aside, the two loops in the extractMin function could be combined in to one for efficiency. I've left it as two separate loops for readability.
One thing you should keep in mind, there are actually variations of the priority queue that preserve insertion order (within a priority level) and variations that do not care about that order.
For the latter case, you don't have to shuffle all the elements to remove an extracted one, you can simply move the last one in the array over the extracted one. This may result in some time savings if you don't actually need to preserve insertion order - you still have to scan the entire array looking for the new highest-priority item but at least the number of shuffle assignments will be reduced.
#paxdiablo's answer gives the scheme referred to in the book. Another way to achieve the same complexity is to always store the minimum at the first index in the array:
To insert x in O(1) time, either insert it at the end (if it is bigger than the current minimum), or copy the current minimum to the end and then store x at index 0.
To query the minimum in O(1) time, return the value at index 0.
To delete the minimum in O(n) time, search for the new minimum from index 1 onwards, write it at index 0, then "fill in the gap" by swapping the element at the last index to where the new minimum used to be.

For Loop. Why is it less than < not less than or equal to <=?

Below is a question from a tutorial I'm doing.
Code the first line of a for loop with the usual counter, the usual starting value, and the usual incrementing. Limit the number of loops by the number of elements in the array pets.
My answer is:
for (var i = 0; i <= pets.length; i++) {
The tutorial answer is:
for (var i = 0; i < pets.length; i++) {
Why is it < if we are trying to find the length of the array?
In programming languages, most of the time, indexes and arrays start at 0 and not 1. So, the first element would be 0, and not 1.
Therefor, you need to put less than as you need to compensate for the numbering system.
Cheers
Imagine you have an array of size 1. On the first iteration, i would be zero and fulfill both conditions. On the second, i would only fulfill the <=, but remember you've already looped through every element in the array, so you will likely get an error in your loop for trying to access an element not in your array.
Arrays are indexed starting with 0, and up to arr.length - 1. The last index does not have the same index value as the length of the array. Notice, that by starting at zero and iterating up to the length of the array minus one, the entire length of the array has still been traversed.
You start counting from 0 and not 1. Consider what would happen if you put in an equals there. It would try to access array[pets.length] which is an array out of bounds exception in most languages. pets.length gives you the NUMBER OF ITEMS in the array. What you need is an index. Starting from 0 and not 1 you can go upto pets.length - 1. Hope that clears it up.

What is the most efficient way to sort a number list into alternating low-high-low sequences?

Suppose you are given an unsorted list of positive integers, and you wish to order them in a manner such that the elements alternate as: (less than preceding element), (greater than preceding element), (less than preceding element), etc... The very first element in the output list may ignore the rule. So for example, suppose your list was: 1,4,9,2,7,5,3,8,6.
One correct output would be...
1,9,2,8,3,7,4,6,5
Another would be...
3,4,2,7,5,6,1,9,8
Assume that the list contains no duplicates, is arbitrarily large, and is not already sorted.
What is the most processing efficient algorithm to achieve this?
Now, the standard approach would be to simply sort the list in ascending order first, and then peel elements from the ends of the list in alternation. However, I'd like to know: Is there a more time-efficient way to do this without first sorting the list?
My reason for asking: (read this only if you care)
Apparently this is a question my sister's boyfriend poses to people at job interviews out in San Francisco. My sister asked me the question, and I immediately came up with the standard response. That's what everyone answers. However, apparently one girl came up with a completely different solution that does not require sorting the list, and it appears to work. My sister couldn't explain to me this solution, but the idea has been confounding me since last night. I'd appreciate any help! Thanks!
You can do this in O(n) by placing each element in turn at the end, or at the penultimate position based on a comparison with the current last element.
For example,
1,4,9,2,7,5,3,8,6
Place 1 at end, current list [1]
4>1 true so place 4 at end, current list [1,4]
9<4 false so place 9 at penultimate position [1,9,4]
2>4 false so place 2 at penultimate [1,9,2,4]
7<4 false so place 7 at penultimate [1,9,2,7,4]
5>4 true so place 5 at end [1,9,2,7,4,5]
3<5 true so place 3 at end [1,9,2,7,4,5,3]
8>3 true so place 8 at end [1,9,2,7,4,5,3,8]
6<8 true so place 6 at end [1,9,2,7,4,5,3,8,6]
Note that the equality tests alternate, and that we place at the end if the equality is true, or at the penultimate position if it is not true.
Example Python Code
A=[1,4,9,2,7,5,3,8,6]
B=[]
for i,a in enumerate(A):
if i==0 or (i&1 and a>B[-1]) or (i&1==0 and a<B[-1]):
B.insert(i,a)
else:
B.insert(i-1,a)
print B
One solution is this. Given in Pseudocode.
Assuming, nums has at least two elements and all elements in nums are distinct.
nums = [list of numbers]
if nums[0] < nums[1]: last_state = INCREASING else: last_state = DECREASING
for i = 2 to len(nums - 1):
if last_state = INCREASING:
if nums[i] > nums[i-1]:
swap (nums[i], nums[i-1])
last_state = DECREASING
else
if nums[i] < nums[i-1]:
swap (nums[i], nums[i-1])
last_state = INCREASING
Proof of correctness:
After each loop iteration, elements upto index i in nums remain alternating and last_state is represent the order of i th and i-1 th elements.
Note that a swapping happens only if last 3 items considered are in order. (Increasing or Decreasing) Therefore, if we swapped ith element with i-1 th element, the order of i-2 th element and i-1th element will not change.

Calculate Median in An Array - Can someone tell me what is going on in this line of code?

This is a solution for calculating the median value in an array. I get the first three lines, duh ;), but the third line is where the magic is happening. Can someone explain how the 'sorted' variable is using and why it's next to brackets, and why the other variable 'len' is enclosed in those parentheses and then brackets? It's almost like sorted is all of a sudden being used as an array? Thanks!
def median(array)
sorted = array.sort
len = sorted.length
return ((sorted[(len - 1) / 2] + sorted[len / 2]) / 2.0).to_f
end
puts median([3,2,3,8,91])
puts median([2,8,3,11,-5])
puts median([4,3,8,11])
Consider this:
[1,2,2,3,4] and [1,2,3,4]. Both arrays are sorted, but have odd and even numbers of elements respectively. So, that piece of code is taking into account these 2 cases.
sorted is indeed an array. You sort [2,3,1,4] and you get back [1,2,3,4]. Then you calculate the middle index (len - 1) / 2 and len / 2 for even / odd number of elements, and find the average of them.
Yes, array.sort is returning an array and it is assigned to sorted. You can then access it via array indices.
If you have an odd number of elements, say 5 elements as in the example, the indices come out to be:
(len-1)/2=(5-1)/2=2
len/2=5/2=2 --- (remember this is integer division, so the decimal gets truncated)
So you take the value at index 2 and add them, and then divide by 2, which is the same as the value at index 2.
If you have an even number of elements, say 4,
(len-1)/2=(4-1)/2=1 --- (remember this is integer division, so the decimal gets truncated)
len/2=4/2=2
So in this case, you are effectively averaging the two middle elements 1 and 2, which is the definition of median for when you have an even number of elements.
It's almost like sorted is all of a sudden being used as an array?
Yes, it is. On line 2 it's being initialized as being an array with the same elements as the input, but in ascending order (default sort is ascending). On line 3 you have len which is initialized with the length of the sorted array, so yeah, sorted is being used as an array since then, because that's what it is.

Elements mixing algorithm

Not sure about title.
Here is what I need.
Lets for example have this set of elements 20*A, 10*B, 5*C, 5*D, 2*E, 1*F
I need to mix them so there are not two same elements next to each other and also I can for example say I don't want B and C to be next to each other. Elements have to be evenly spread (if there are 2 E one should be near begining/ in firs half a and second near end/in second half. Number of elements can of course change.
I haven't done anything like this yet. Is there some knowledge-base of this kind of algorithms where could I find some hints and methods how to solve this kind of problem or do I have to do all the math myself?
I think the solution is pretty easy.
Start with an array x initialised to empty values such that there is one space for each item you need to place.
Then, for each (item, frequency) pair in descending order of frequency, assign item values to x in alternating slots starting from the first empty slot.
Here's how it works for your example:
20*A A_A_A_A_A_A_A_A_A_A_A_A_A_A_A_A_A_A_A_A
10*B ABABABABABABABABABABA_A_A_A_A_A_A_A_A_A
5*C ABABABABABABABABABABACACACACACA_A_A_A_A
2*E ABABABABABABABABABABACACACACACAEAEA_A_A
1*F ABABABABABABABABABABACACACACACAEAEAFA_A
At this point we fail, since x still has an empty slot. Note that we could have identified this right from the start since we need at least 19 slots between the As, but we only have 18 other items.
UPDATE
Leonidas has now explained that the items should be distributed "evenly" (that is, if we have k items of a particular kind, and n slots to fill, each "bucket" of n/k slots must contain one item of that kind.
We can adapt to this constraint by spreading out our allocations rather than simply going for alternating slots. In this case (and let's assume 2 Fs so we can solve this), we would have
20*A A_A_A_A_A_A_A_A_A_A_A_A_A_A_A_A_A_A_A_A
10*B ABA_ABA_ABA_ABA_ABA_ABA_ABA_ABA_ABA_ABA
5*C ABACABA_ABACABA_ABACABA_ABACABA_ABACABA
2*E ABACABAEABACABA_ABACABAEABACABA_ABACABA
2*F ABACABAEABACABAFABACABAEABACABAFABACABA
You can solve this problem recursively:
def generate(lastChar, remDict):
res = []
for i in remDict:
if i!=lastChar):
newRemDict = remDict
newRemDict[i]-=1
subres = generate(i,newRemDict)
res += [i+j for j in subres]
return res
Note that I am leaving out corner conditions and many checks that need to be done. But only the core recursion is shown. You can also quit pursuing a branch if more than half+1 of the remaining letters is a same letter.
I ran into a similar problem, and after evaluating various metrics, I came up with the idea of grabbing the first item for which the proportion through the source array is less than the proportion through the result array. There is a case where all of these values may come out as 1, for instance when halfway through merging a group of even arrays - everything's exactly half done - so I grab something from the first array in that case.
This solution does use the source array order, which is something that I wanted. If the calling routine wants to merge arrays A, B, and C, where A has 3 elements but B and C have 2, we should get A,B,C,A,B,C,A, not A,C,B,A,C,B,A or other possibilities. I find that choosing the first of my source arrays that's "overdue" (by having a proportion that's lower than our overall progress), I get a nice spacing with all arrays.
Source in Python:
#classmethod
def intersperse_arrays(cls, arrays: list):
# general idea here is to produce a result with as even a balance as possible between all the arrays as we go down.
# Make sure we don't have any component arrays of length 0 to worry about.
arrays = [array for array in arrays if len(array) > 0]
# Handle basic cases:
if len(arrays) == 0:
return []
if len(arrays) == 1:
return arrays[0]
ret = []
num_used = []
total_count = 0
for j in range(0, len(arrays)):
num_used.append(0)
total_count += len(arrays[j])
while len(ret) < total_count:
first_overdue_array = None
first_remaining_array = None
overall_prop = len(ret) / total_count
for j in range(0, len(arrays)):
# Continue if this array is already done.
if len(arrays[j]) <= num_used[j]:
continue
current_prop = num_used[j] / len(arrays[j])
if current_prop < overall_prop:
first_overdue_array = j
break
elif first_remaining_array is None:
first_remaining_array = j
if first_overdue_array is not None:
next_array = first_overdue_array
else:
# Think this only happens in an exact tie. (Halfway through all arrays, for example.)
next_array = first_remaining_array
if next_array is None:
log.error('Internal error in intersperse_arrays')
break # Shouldn't happen - hasn't been seen.
ret.append(arrays[next_array][num_used[next_array]])
num_used[next_array] += 1
return ret
When used on the example given, I got:
ABCADABAEABACABDAFABACABADABACDABAEABACABAD
(Seems reasonable.)

Resources