线性时间排序和选择

        在上一篇的排序中提到的算法,在排序的最终结果中各元素的次序依赖于它们之间的比较,我们把这类排序算法称为比较排序。下面总结三种线性时间复杂度的排序算法:计数排序,基数排序和桶排序,这三种算法是用运算而不是比较来确定排序顺序的。

线性时间排序


计数排序

        假设n个输入元素中的每一个都是在0到k之间内的一个整数,其中k为某个整数,当k=Ο(n)时,排序的运行时间是θ(n)。计数排序的思想是:对每一个输入元素x,确定小于x的元素个数,利用这一信息,就可以直接把x放到它在输出数组中的位置上了。 计数排序是稳定的。
        伪代码:假设输入是一个数组A[1..n],B[1..n]存放排序的输出,C[0..k]存放A中每个元素的个数

counting_sort(A,B,k)

let C be a new array

for i = 0 to k

       C[i] = 0

// step1 :C[i] now contains the number of elements equal to i

for j = 1 to A.length

       C[A[j]] = C[A[j]] + 1

// step2 :C[i] now contains the number of elements less than or equal to i

for i = 1 to k

        C[i] = C[i] + C[i - 1]

// step3 :ouput each element at the particular position of B from the A's tail with C

for j = A.length to 1

        B[C[A[j]]] = A[j]

        C[A[j]] = C[A[j]] - 1


通过以下数组的变化能更好理解上面的代码:

数组A
12345678
25302303


通过代码中step1的运算(C[A[j]] = C[A[j]] + 1)得出以下数组C

数组C
012345
202301

通过代码中step2的运算(C[i] = C[i] + C[i - 1])数组C的值发生变化

数组C
012345
224778


通过代码中step3的运算,依次输出A的元素到数组B

以下以A[8] = 3为例:根据数组C可知,3的前面有7个小于或等于它的数,因此把3放在输出数组B第7个位置,同时将数组C里C[3]的值减1

数组B
12345678
      3 


数组C
012345
224678


基数排序

        基数排序是对给定的n个d位数,从最低有效位开始每一数位进行排序,经过d轮 稳定排序后,到最高位排序完毕后,即是一个有序的n个d位数。如果d位数的每个数位有k个可能的取值,使用的稳定排序耗时为θ(n+k),则可以在θ(d(n+k))时间内完成基数排序。
        伪代码:
radix_sort(A, d)
     for i = 1 to d
        use a stable sort to sort array A on digit i

桶排序

        与计数排序假设输入排序属于一个小的区间内的整数不同,桶排序假设输入数据服从均匀分布,由随机过程产生,将元素均匀独立的分布在[0,1)区间上。
桶排序将[0,1)区间划分为n个 大小相同的子区间,或称为桶。然后将n个输入元素分别放到各个桶中(因为输入数据是均匀独立的分布在[0,1)区间上,所以一般不会出现很多数据落在同一个桶中的情况),先对桶中元素进行排序,然后按照次序将每个桶中元素列出来。

AB   
0.780   
0.1710.120.17 
0.3920.210.230.26
0.2630.39  
0.724   
0.945   
0.2160.68  
0.1270.720.78 
0.238   
0.6890.94  

        伪代码:根据以上表格,假设A是输入数组,B为桶数组,B中存放链表
bucket_sort(A)

n = A.length

let B[0..n-1] be a new array

for i = 0 to n-1

let B[i] be an empty list

for i = 1 to n

insert A[i] into list B[nA[i]] // nA[i]向下取整

for i = 0 to n-1

sort list B[i]

concatenate the lists B[0],B[1],..B[n-1] together in order


选择(中位数和顺序统计量)

        在一个由n个元素组成的集合中,第i个 顺序统计量是该集合中第i小的元素。中位数即是它所属元素的“中点元素”(但n为奇数时,中位数位于i=(n+1)/2处;当n为偶数时,存在两个中位数,分别位于i = n/2和i= n/2 + 1处)。
        以下讨论从一个由n个互异的元素构成的集合中选择第i个顺序统计量的问题。我们可以在O(nlgn)时间内通过堆排序或归并排序对数据排序后找出第i个元素即可,下面介绍一种 不需要排序期望是线性时间的分治算法。
        一篇对快速排序中,在一趟排序(ramdomized_partition:每次选择pivot位置时通过随机过程取得)后会找出一个pivot,该pivot左边的值均小于pivot位置的值,右边的值均大于pivot位置的值,基于ramdomized_partition,比较一趟排序后的pivot值与i的大小,决定在大数边数组选择第i - pivot小的数,或者在小数边数组继续选择第i小的数。
       伪代码:返回数组A[p..r]中第i小的元素
randomized_select(A,p,r,i)
if p == r
return A[p]
q = ramdomized_partition(A,p,r)
k = q - p + r
if k == i
return A[q]
else if k < i
return randomized_select(A,q+1,r,i - k)
else 
return randomized_select(A,p,q - 1,i)


同样一道来自庞果英雄会的一道题,可以利用以上的选择算法。

要建立一个信号基站服务n个村庄,这n个村庄用平面上的n个点表示。假设基站建立的位置在(X,Y),则它对某个村庄(x,y)的距离为max{|X – x|, |Y – y|}, 其中| |表示绝对值,我们的目标是让所有村庄到信号基站的距离和最小。 基站可以建立在任何实数坐标位置上,也可以与某村庄重合。 输入: 给定每个村庄的位置x[],y[],x,y都是整数,满足:-1000000000 < x,y < 1000000000 村庄个数大于1,小于101。 输出: 所有村庄到信号基站的距离和的最小值。
提示:max{|a|, |b|} = (|a + b| + |a - b|)/2(a与b之间的距离d(a,b) = |a + b| + |a - b|,称为曼哈顿距离)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值