Jump to content

Talk:American flag sort

Page contents not supported in other languages.
From Wikipedia, the free encyclopedia

The sample Python code does not properly sort the array

[edit]

There is something wrong with the implementation or it is partial and needs to be changed.

from math import floor, log
from copy import copy

def get_radix_val(x, digit, radix):
    return int(floor(x / radix**digit)) % radix

def compute_offsets(a_list, start, end, digit, radix):
    counts = [0 for _ in range(radix)]
    for i in range(start, end):
        val = get_radix_val(a_list[i], digit, radix)
        counts[val] += 1
    offsets = [0 for _ in range(radix)]
    sum = 0
    for i in range(radix):
        offsets[i] = sum
        sum += counts[i]
    return offsets

def swap(a_list, offsets, start, end, digit, radix):
    i = start
    next_free = copy(offsets)
    cur_block = 0
    while cur_block < radix-1:
        if i >= start + offsets[cur_block+1]:
            cur_block += 1
            continue
        radix_val = get_radix_val(a_list[i], digit, radix)
        if radix_val == cur_block:
            i += 1
            continue
        swap_to = next_free[radix_val]
        a_list[i], a_list[swap_to] = a_list[swap_to], a_list[i]
        next_free[radix_val] += 1

def american_flag_sort_helper(a_list, start, end, digit, radix):
    offsets = compute_offsets(a_list, start, end, digit, radix)
    swap(a_list, offsets, start, end, digit, radix)
    if digit == 0:
        return
    for i in range(len(offsets)-1):
        american_flag_sort_helper(a_list, offsets[i], offsets[i+1], digit-1, radix)

def american_flag_sort(a_list, radix):
    for x in a_list:
        assert(type(x) == int)
    max_val = max(a_list)
    max_digit = int(floor(log(max_val, radix)))
    american_flag_sort_helper(a_list, 0, len(a_list), max_digit, radix)
    
A = [((20*(x**3))//1)+67500 for x in range(-15,16)]
print(A)
import random
random.shuffle(A)
print(A)
american_flag_sort(A, 4)
print(A)

The output is:

[0, 12620, 23560, 32940, 40880, 47500, 52920, 57260, 60640, 63180, 65000, 66220, 66960, 67340, 67480, 67500, 67520, 67660, 68040, 68780, 70000, 71820, 74360, 77740, 82080, 87500, 94120, 102060, 111440, 122380, 135000]
[74360, 60640, 111440, 32940, 65000, 66220, 0, 70000, 67500, 135000, 94120, 102060, 82080, 23560, 122380, 66960, 67480, 67520, 67340, 47500, 12620, 87500, 63180, 68780, 40880, 57260, 71820, 67660, 52920, 77740, 68040]
[0, 32940, 66960, 52920, 23560, 40880, 57260, 74360, 60640, 12620, 65000, 47500, 63180, 67480, 67520, 67340, 66220, 70000, 67500, 68780, 68040, 71820, 67660, 77740, 94120, 87500, 82080, 111440, 102060, 122380, 135000]

The last array, which is result from the function, is not properly sorted. Different radixes give different results, but none of them are correct.

Tested using Python 3.4.3 on Linux x64.

80.220.91.165 (talk) 10:23, 24 November 2015 (UTC)[reply]

Very late response, but this is correct, the provided Python code had several bugs. It was probably never tested. I'll go ahead and fix them. For future reference, the changes were as follows (I can't be arsed to summarize them considering how many bugs there were):
 def compute_offsets(a_list, start, end, digit, radix):
     counts = [0 for _ in range(radix)]
     for i in range(start, end):
         val = get_radix_val(a_list[i], digit, radix)
         counts[val] += 1
-    offsets = [0 for _ in range(radix)]
-    sum = 0
+    offset = start
+    offsets = [start]
     for i in range(radix):
-        offsets[i] = sum
-        sum += counts[i]
+        offset += counts[i]
+        offsets.append(offset)
     return offsets
 
 def swap(a_list, offsets, start, end, digit, radix):
-    i = start
     next_free = copy(offsets)
     cur_block = 0
-    while cur_block < radix-1:
-        if i >= start + offsets[cur_block+1]:
+    while cur_block < radix:
+        i = next_free[cur_block]
+        if i >= offsets[cur_block+1]:
             cur_block += 1
             continue
         radix_val = get_radix_val(a_list[i], digit, radix)
-        if radix_val == cur_block:
-            i += 1
-            continue
-        swap_to = next_free[radix_val]
-        a_list[i], a_list[swap_to] = a_list[swap_to], a_list[i]
+        if radix_val != cur_block:
+            swap_to = next_free[radix_val]
+            a_list[i], a_list[swap_to] = a_list[swap_to], a_list[i]
         next_free[radix_val] += 1
I'd rather replace the whole thing with something else though. I might still do that a little later.
MaksVerver (talk) 19:43, 27 July 2023 (UTC)[reply]

The original implementation is rather different--somewhat shorter, and much faster

[edit]

See: Engineering Radix Sort, p. 16, and appendix program C. — Preceding unsigned comment added by 70.16.100.236 (talk) 20:03, 20 April 2018 (UTC)[reply]

Comparing "bytes" instead of objects

[edit]

I just edited the page to say that American flag sort sorts on the basis of the bytes (mathematical representation) of the objects instead of a object-defined comparison.

I find this wording problematic because likening bytes to mathematical representation doesn't feel very accurate. Are there any better words out there? DesmondWillowbrook (talk) 17:20, 4 February 2023 (UTC)[reply]