Skip to content

Commit

Permalink
Update comments and refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
GarrisonJ committed Apr 16, 2024
1 parent b96bbc3 commit dcb33e5
Showing 1 changed file with 88 additions and 37 deletions.
125 changes: 88 additions & 37 deletions lib/sorted_containers/sorted_list.rb
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
# frozen_string_literal: true

# The SortedContainers module provides data structures for sorted collections.
module SortedContainers
class Error < StandardError; end

# The SortedList class is a sorted list implementation.
class SortedList
DEFAULT_LOAD_FACTOR = 1000

attr_reader :size


# Initializes a new SortedList object.
#
# @param iterable [Enumerable] An optional iterable object to initialize the list with.
def initialize(iterable = [])
@lists = []
@maxes = []
@load_factor = DEFAULT_LOAD_FACTOR
@size = 0
update(iterable)
end


# Adds a value to the sorted list.
#
# @param value [Object] The value to add.
def add(value)
i = bisect_right(@maxes, value)
if i == @maxes.size
Expand All @@ -30,95 +38,138 @@ def add(value)
@size += 1
end

# Adds a value to the sorted list using the << operator.
#
# @param value [Object] The value to add.
def <<(value)
add(value)
end


# Removes a value from the sorted list.
#
# @param value [Object] The value to remove.
def remove(value)
i = bisect_left(@maxes, value)
return if i == @maxes.size

idx = @lists[i].index(value)
raise "Value not found: #{value}" unless idx

internal_delete(i, idx)
end

# Retrieves the value at the specified index.
#
# @param index [Integer] The index of the value to retrieve.
# @return [Object] The value at the specified index.
def [](index)
raise "Index out of range" if index < 0 || index >= @size
raise "Index out of range" if index.negative? || index >= @size

@lists.each do |sublist|
if index < sublist.size
return sublist[index]
else
index -= sublist.size
end
return sublist[index] if index < sublist.size

index -= sublist.size
end
end

# Deletes the value at the specified index.
#
# @param index [Integer] The index of the value to delete.
def delete_at(index)
raise "Index out of range" if index < 0 || index >= @size
raise "Index out of range" if index.negative? || index >= @size

@lists.each do |sublist|
deleted = false
@lists.each_with_index do |sublist, sublist_index|
if index < sublist.size
internal_delete(@lists.index(sublist), index)
return
internal_delete(sublist_index, index)
deleted = true
break
else
index -= sublist.size
end
end

raise "Index out of range" unless deleted
end

# Clears the sorted list, removing all values.
def clear
@lists.clear
@maxes.clear
@size = 0
end

# Checks if the sorted list contains a value.
#
# @param value [Object] The value to check.
# @return [Boolean] True if the value is found, false otherwise.
def contains(value)
i = bisect_left(@maxes, value)
return false if i == @maxes.size

sublist = @lists[i]
idx = bisect_left(sublist, value)
return idx < sublist.size && sublist[idx] == value
idx < sublist.size && sublist[idx] == value
end

# Converts the sorted list to an array.
#
# @return [Array] An array representation of the sorted list.
def to_a
@lists.flatten
end

private


# Performs a left bisect on the array.
#
# @param array [Array] The array to bisect.
# @param value [Object] The value to bisect with.
# @return [Integer] The index where the value should be inserted.
def bisect_left(array, value)
array.bsearch_index { |x| x >= value } || array.size
end


# Performs a right bisect on the array.
#
# @param array [Array] The array to bisect.
# @param value [Object] The value to bisect with.
# @return [Integer] The index where the value should be inserted.
def bisect_right(array, value)
array.bsearch_index { |x| x > value } || array.size
end

def expand(i)
list = @lists[i]
if list.size > (@load_factor * 2)
half = list.slice!(@load_factor, list.size - @load_factor)
@lists.insert(i + 1, half)
@maxes[i] = @lists[i].last
@maxes.insert(i + 1, half.last)
end

# Expands a sublist if it exceeds the load factor.
#
# @param sublist_index [Integer] The index of the sublist to expand.
def expand(sublist_index)
sublist = @lists[sublist_index]
return unless sublist.size > (@load_factor * 2)

half = sublist.slice!(@load_factor, sublist.size - @load_factor)
@lists.insert(sublist_index + 1, half)
@maxes[sublist_index] = @lists[sublist_index].last
@maxes.insert(sublist_index + 1, half.last)
end

def internal_delete(i, idx)
@lists[i].delete_at(idx)
if @lists[i].empty?
@lists.delete_at(i)
@maxes.delete_at(i)

# Deletes a value from a sublist.
#
# @param sublist_index [Integer] The index of the sublist.
# @param idx [Integer] The index of the value to delete.
def internal_delete(sublist_index, idx)
@lists[sublist_index].delete_at(idx)
if @lists[sublist_index].empty?
@lists.delete_at(sublist_index)
@maxes.delete_at(sublist_index)
else
@maxes[i] = @lists[i].last
@maxes[sublist_index] = @lists[sublist_index].last
end
@size -= 1
end


# Updates the sorted list with values from an iterable object.
#
# @param iterable [Enumerable] The iterable object to update the list with.
def update(iterable)
iterable.each { |item| add(item) }
end
Expand Down

0 comments on commit dcb33e5

Please sign in to comment.