make_heap
, N * pop_heap
)Divide and Conquer Strategies
Provide an Abstraction of comparison-based sorts
Key point: represent comparisons as edges on a tree. Nodes represent comparisons
What is the asymptotic height of any decision tree for sorting $N$ elements?
Theorem: Any decision tree that sorts $N$ elements has height $\Omega(N lg N)$
Thus we can claim the following:
$$ h \ge lg {\left(\frac{N}{e}\right)}^N $$
Rules of logarithms:
$$ h \ge N~lg~N - N~lg~e$$
Removing constants ($N~lg~e$)
$$\Omega(N~lg~N)$$
Idea: Don't compare the actual values. Instead, look at a single "digit" at a time
Example: $91, 06, 85, 15, 92, 35, 30, 22, 39$
int digit (int value, int place, int base = 10) {
while (place--) {
value /= base;
}
return value % base;
}
#include <vector>
using Bin = std::vector<int>;
Bin bins[10];
std::vector<int> data {91, 6, 85, 15, 92, 35, 30, 22, 39};
for (int value : data) {
bins[digit(value , 0)].push_back (value);
}
bins
{
auto i = data.begin();
for (auto & bin : bins) {
i = std::copy (bin.begin(), bin.end(), i);
bin.clear();
}
}
data
for (int value : data) {
bins[digit(value , 1)].push_back (value);
}
bins
{
auto i = data.begin();
for (auto & bin : bins) {
i = std::copy (bin.begin(), bin.end(), i);
bin.clear();
}
}
data
# d is the upper limit on the number of digits for a number
def radix_sort (nums, d=8):
# create 10 empty bins
bins = list(list() for i in range(10))
# start at the ones digit
div = 1
for digit in range(d):
# split nums into appropriate bins
for num in nums:
bins[(num // div) % 10].append(num)
# copy from bins back to nums
i = 0
for b in range(10):
for n in bins[b]:
nums[i] = n
i += 1
bins[b].clear()
# update to "next" digit
div *= 10
for digit in range(d):
...
for num in nums:
...
for b in range(10):
for n in bins[b]:
...
d
and N
d << N
(d substantially smaller than N)Radix Sort seemed nice -- but what if we had a bunch of duplicate values?
function countingSort(array, k) is
count ← new array of k zeros
for i = 1 to length(array) do
count[array[i]] ← count[array[i]] + 1
for i = 2 to k do
count[i] ← count[i] + count[i - 1]
for i = length(array) downto 1 do
output[count[array[i]]] ← array[i]
count[array[i]] ← count[array[i]] - 1
return output
k
¶Given any set of numbers:
[min, max]
max - min + 1
idx = value - min
Takeaways:
k
can be initialized to size
value - min
instead of value#include <algorithm>
#include <numeric>
constexpr int N = 10;
int A[N] = {4, 1, 2, 3, 4, 3, 1, 2, 0, 4};
// int [min, max] = *std::minmax_element(A, A + N);
constexpr int min = 0, max = 4;
constexpr int k = max - min + 1;
A
vector
)int C[k]; // counting array
std::fill_n(C, k, 0);
for (int value : A) {
++C[value - min];
}
C
// convert counts to index (via partial_sum)
std::partial_sum(C, C + k, C);
C
int B[N]; // output
for (int i = N - 1; i >= 0; --i) {
B[--C[A[i] - min]] = A[i];
}
B
std::copy_n (B, N, A);
A