查找第n小的元素

依据快速排序的partition方法, 改进,寻找用于划分的值V
将输入数组划分成n/5组,每组中的有一个中位数,找出所有中位数的中位数,即为V

#coding:utf-8

#最坏情况下O(n)找到第n小的元素

def insert_sort(L, begin, end):
    if end>begin:
        for i in xrange(begin+1,end+1):
            while i > begin:
                if L[i-1] > L[i]:
                    L[i-1], L[i]=L[i], L[i-1]
                    i -= 1
                else:
                    break

def get_v(L, begin, end):
    if end==begin:
        return L[begin]
    length = end-begin+1
    mid=[]
    group_num = length/5
    remained_num = length%5
    for s in xrange(group_num):
        index = s*5+begin
        insert_sort(L, index, index+4)
        mid.append(L[index+2])
    if remained_num:
        index = begin+group_num*5
        insert_sort(L, index, index+remained_num-1)
        if remained_num%2==0:
            mid.append(L[index-1+remained_num/2])
        else:
            mid.append(L[index-1+remained_num/2+1])

    mid_num = select(mid,0,len(mid)-1,len(mid)/2)

def partition(L, begin, end, v):
    '''基于值v快速划分'''
    for i in xrange(begin, end+1):
        if L[i]==v:
            break
    L[begin], L[i]=L[i], L[begin]
    while end > begin:
        while end>begin and L[begin]<=L[end]:
            end -= 1
        if end>begin :
            L[begin], L[end] = L[end], L[begin]
            begin += 1
        while end > begin and L[begin] <= L[end]:
            begin += 1
        if end > begin:
            L[begin], L[end] = L[end], L[begin]
            end -= 1
    return begin

def select(L, begin, end, k):
    if end>=begin:
        v = get_v(L, begin, end) #获取理想的值
        index = partition(L, begin, end, v)
        le = index-begin+1
        if le == k:
            return L[index]
        elif le > k:
            return select(L, begin, index-1, k)
        else:
            return select(L, index+1, end, k-le)


if __name__ == "__main__":
    import sys
    L = sys.argv[1:]
    if not L:
        import random
        L = [random.randint(1, 10) for i in xrange(10)]
    print L
    print select(L,0,len(L)-1,3)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值