In-place counting sort 原地计数排序

Introduction to Algorithm, 3rd edtion, P206, problem 8-2-e

Suppose that the n records have keys in the range from 1 to k. Show how to modify counting sort so that the records can be sorted in place in O(n + k) time. You may use O(k) storage outside the input array. (Hint: How would you do it for k = 3?)

要求排序是in-place的,我的思路是一边遍历原序列,一边使用swap操作将元素换到正确的位置上。和非in-place的版本一样,使用一个count数组记录每个key出现的次数,再通过累加得到每个key的正确位置;从序列末尾开始往前遍历,将每个元素和其正序位置上的元素交换,然后将其key的计数减1。每次swap都会将一个元素移动到它的最终位置上,但是在遍历的过程中可能再次移动一个之前移动过的元素(因为key的计数值减小了,会错误地认为其不在正确位置上)。为了避免这种情况,在遍历时判断元素是否在正确的区间内,仅当不再正确区间中才对元素进行移动。Python实现的算法如下:

# countingsort.py

def countingsort(seq, k):
    """In-place counting sort.

    """
    c = [0] * k
    sn = len(seq)

    for i in range(sn):
        c[seq[i]] += 1

    ac = c[:]
    for i in range(1,k):
        ac[i] += ac[i-1]

    act = ac[:]
    i = sn - 1
    while i >= 0:
        elem = seq[i]
        # 该区间为排好序的序列中elem及所有相等的元素所处的位置
        if ac[elem] - c[elem] <= i <= ac[elem] - 1:
            act[elem] -= 1
            i -= 1
            continue
        # 交换两元素,在下一次循环继续检查该位置 
        seq[i] = seq[act[elem]-1]
        seq[act[elem]-1] = elem
        act[elem] -= 1

# test
if __name__ == '__main__':
    from random import randrange
    k = 25
    n = 30
    testinput = [randrange(k) for x in range(n)]

    countingsort(testinput, k)
    assert testinput == sorted(testinput)

这个算法使用的额外空间为O(k)(两个长度为k的list),最后的while循环最多执行2n次,时间应该满足O(n+k),但是不再stable了。

你可能感兴趣的:(sort,Counting,in-place,原地计数排序)