Beispiel #1
0
    def test_quantiles(self):
        case_class = namedtuple('case_class', 'array subset_count key expected_res')
        cases = (
            case_class(array=[100], subset_count=1, key=None, expected_res=[100]),
            case_class(array=[1, 3, 5, 4, 2, 7, 6], subset_count=3, key=None, expected_res=[2, 5, 7]),
            case_class(array=[1, 3, 5, 4, 2, 7, 6], subset_count=4, key=None, expected_res=[2, 4, 5, 7]),
            case_class(array=[1, 3, 5, 4, 2, 7, 6], subset_count=7, key=None, expected_res=[1, 2, 3, 4, 5, 6, 7]),
            case_class(array=[8, 2, 1, 3, 7, 5, 4, 6], subset_count=1, key=None, expected_res=[8]),
            case_class(array=[8, 2, 1, 3, 7, 5, 4, 6], subset_count=2, key=None, expected_res=[4, 8]),
            case_class(array=[8, 2, 1, 3, 7, 5, 4, 6], subset_count=3, key=None, expected_res=[3, 5, 8]),
            case_class(array=[8, 2, 1, 3, 7, 5, 4, 6], subset_count=3, key=lambda x: -x, expected_res=[6, 4, 1]),
            case_class(array=[8, 2, 1, 3, 7, 5, 4, 6], subset_count=4, key=None, expected_res=[2, 4, 6, 8]),
        )

        for case in cases:
            # print(case.array, case.subset_count)
            res = calc_quantiles(case.array, case.subset_count, case.key)
            self.assertEqual(case.expected_res, res)

        for length in range(1, 100):
            subset_count = randint(1, length)
            array = [x * 2 for x in range(0, length)]
            rand_permutate(array)
            # print(array, subset_count)
            res = calc_quantiles(array, subset_count)
            # print(res)
            self.assertEqual(subset_count, len(res))
            if subset_count > 1:
                diffs = []
                for i in range(0, subset_count - 1):
                    self.assertEqual(0, res[i] % 2)
                    diffs.append(res[i + 1] - res[i])
                min_diff, max_diff = min_max(diffs)
                self.assertTrue(max_diff - min_diff <= 2)
            self.assertEqual(array[length - 1], res[subset_count - 1])
Beispiel #2
0
def query_count_in_range(array: List[int], queries: Tuple[(int, int)]):
    """
    Ex 8.2-4.
    :param array: Input array.
    :param queries: Range queries. For each query, the first element is the lower bound while the second the upper.
    :return: Count in range.
    """
    assert array is not None
    assert queries is not None
    n = len(array)
    qc = len(queries)
    if n == 0:
        return [0] * qc
    _min, _max = min_max(array, 0, n)
    counters = _cumulative_counts(array, _min, _max)

    ret = [None] * qc
    for i in range(qc):
        lo, hi = queries[i][0], queries[i][1]
        if lo > hi:
            ret[i] = 0
        else:
            lo = _min if lo < _min else lo
            hi = _max if hi > _max else hi
            ret[i] = counters[hi - _min] - (0 if lo == _min else
                                            counters[lo - _min - 1])
    return ret
Beispiel #3
0
def counting_sort_in_place(array: List[T], key: Callable[[T], int] = None):
    """
    Problem 8-2(e) Counting sort 'in place'. Running time is \Theta(n + k) and space is \Theta(k) where n = len(array)
    and k is the range of the input values. Not stable.
    :param array: Input array.
    :param key: Key getter.
    :return:
    """
    assert array is not None
    n = len(array)
    if n == 0:
        return []
    ret = [None] * n
    key = key or default_key
    _min, _max = min_max(array, 0, n, key)
    _min, _max = key(_min), key(_max)
    counters = _cumulative_counts(array, _min, _max, key)
    counters2 = list(counters)
    j = n - 1
    current_key = _max
    while True:
        # Put element to right place, swap out another element, until its key is equal to current key.
        elem = array[j]
        k = key(elem)
        while k != current_key:
            counters[k - _min] -= 1
            index = counters[k - _min]
            elem, array[index] = array[index], elem
            k = key(elem)
        counters[k - _min] -= 1
        array[counters[k - _min]] = elem
        j -= 1

        # Skip positions that have already got the right values.
        while current_key == _min and j < 0 or current_key != _min and j < counters2[
                current_key - _min - 1]:
            if current_key == _min:
                break
            current_key -= 1
            j = counters[current_key - _min] - 1
        if j < 0:
            break

    return ret
Beispiel #4
0
def bucket_sort(array: List[T], key: Callable[[T], int]):
    """
    Bucket sort for integers.
    :param array:
    :param key:
    :return:
    """
    assert array is not None
    if not array:
        return
    key = key or default_key
    n = len(array)
    _min, _max = min_max(array, key=key)
    min_val, max_val = key(_min), key(_max)
    bucket = [_BucketItem() for _ in range(n)]
    for i in range(n):
        current_key = key(array[i])
        j = (current_key - min_val) * n // (max_val - min_val + 1)
        assert 0 <= j < n
        tail = bucket[j].tail
        while tail:
            prev = tail.prev
            if prev is None or key(prev.data) <= current_key:
                new_node = _LinkedListNode(array[i])
                tail.prev = new_node
                new_node.next = tail
                new_node.prev = prev
                if prev is None:
                    bucket[j].head = new_node
                else:
                    prev.next = new_node
                break
            tail = tail.prev

    i = 0
    for j in range(n):
        head, tail = bucket[j].head, bucket[j].tail
        while head != tail:
            array[i] = head.data
            head = head.next
            i += 1
Beispiel #5
0
def counting_sort(array: List[T], key: Callable[[T], int] = None):
    """
    Counting sort. Running time is \Theta(n + k) and space is \Theta(n) where n = len(array) and k is the
    range of the input values. Stable.
    :param array: Input array.
    :param key: Key getter.
    :return: Sorted version of the array.
    """
    assert array is not None
    n = len(array)
    if n == 0:
        return []
    ret = [None] * n
    key = key or default_key
    _min, _max = min_max(array, 0, n, key)
    _min, _max = key(_min), key(_max)
    counters = _cumulative_counts(array, _min, _max, key)
    for j in range(n - 1, -1, -1):
        k = key(array[j])
        counters[k - _min] -= 1
        ret[counters[k - _min]] = array[j]
    return ret