Skip to content
58 changes: 58 additions & 0 deletions src/sorting/countingsort.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
function counting_sort(arr, key_function)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. This function should be returned directly for require to work with this as expected rather than polluting globals;
  2. I would rename arr to list for consistency with the rest of the code.
  3. key_function should have a comment explaining what it does and what it defaults to. Especially since this sorting algorithm has special requirements (keys must be integers).

-- If no key_function is provided, use identity function
key_function = key_function or function(x) return x end

-- Step 1: Find the range of keys (min_key and max_key)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code is self-explanatory, no comment needed. You can also simplify this to

local min_key, max_key = math.huge, -math.huge
for _, elem in ipairs(list) do
    local key = key_function(elem)
    min_key = math.min(min_key, key)
    max_key = math.max(max_key, key)
end

local min_key, max_key = math.huge, -math.huge
for i = 1, #arr do
local key = key_function(arr[i])
if key < min_key then
min_key = key
end
if key > max_key then
max_key = key
end
end

-- Step 2: Initialize the count array
local count = {}
for i = min_key, max_key do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You get a problem here when arr is empty. Please add a special case to return early in that case.
Furthermore, as it currently is, this may (unnecessarily) populate the hash part if min_key is not 1, so please shift accordingly to prevent that.

count[i] = 0
end

-- Step 3: Count the occurrences of each key. In this case key is same as arr[i]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary comment, also slightly misleading (keys are produced by the key function).

for i = 1, #arr do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again use ipairs

local key = key_function(arr[i])
count[key] = count[key] + 1
end

-- Step 4: Compute cumulative counts to get final positions
for i = min_key + 1, max_key do
count[i] = count[i] + count[i - 1]
end

-- Step 5: Build the output array (in stable order)
local output = {}
for i = #arr, 1, -1 do
local element = arr[i]
local key = key_function(element)
output[count[key]] = element
count[key] = count[key] - 1
end

-- Step 6: Copy the output array back to the original array
for i = 1, #arr do
arr[i] = output[i]
end
end

-- Sample array
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add proper tests rather than some example code at the end of the file. This can essentially use the same tests as Radix Sort: check_sort(countingsort, nil, true), see https://github.com/TheAlgorithms/Lua/blob/main/.spec/sorting/sort_spec.lua.

local arr = {100, 2, 2, 8, 3, 10000000, 1}

-- Simple usage with identity key function
counting_sort(arr)

-- Print sorted array
for i, v in ipairs(arr) do
print(v)
end