python查找第k小元素代码分享


Posted in Python onDecember 18, 2013
# -*- coding: utf-8 -*-
from random import randint
from math import ceil, floor
def _partition(A, l, r, i):
    """以A[i]为主元划分数组A[l..r],使得:
    A[l..m-1] <= A[m] < A[m+1..r]
    """
    A[i], A[r] = A[r], A[i] # i交换到末位r,作为主元
    pivot = A[r] # 主元
    m = l # 索引标记
    for n in xrange(l, r): # l..r-1
        if A[n] <= pivot:
            A[m], A[n] = A[n], A[m] # 交换
            m += 1 # 后移
    A[m], A[r] = A[r], A[m] # 主元到m位
    return m
def _rand(A, l, r):
    """随机划分主元"""
    return randint(l, r) # A[l..r]随机取一个
def _select(A, l, r, k, pivot_selector = _rand):
    """利用快排,得A[l..r]中第k小的数,k in [l+1,r+1]:
    其尾递归方式,伪码如下:
    SELECT(A, l, r, k)
    1  while true:
    2    i ← ? // 划分主元位置
    3    m ← PARTITION(A, l, r, i) // 数组划分
    4    n ← m - l + 1 // A[l..m]元素个数
    5    if k = n // 检查A[m]是否是第k小的元素
    6      then return A[m]
    7    elseif k < n // 左划分区
    8      r = m - 1
    9    else // 右划分区
    10     k = k - n
    11     l = m + 1
    Args:
        pivot_selector(Function): 主元选取方法,默认随机方式
    """
    if not A:
        return None
    if l == r:
        return A[l]
    while True:
        i = pivot_selector(A, l, r)
        m = _partition(A, l, r, i)
        n = m - l + 1
        if k == n:
            return A[m]
        elif k < n:
            r = m - 1
        else:
            k = k - n
            l = m + 1
def rand_select(A, k):
    """默认随机划分主元方式,k in [1, len(A)]
    E[T(n)] = O(n)
    """
    return _select(A, 0, len(A) - 1, k);

def _median(A, l, r):
    """对A[l..r]插入排序(原地)后选取其中位数位置"""
    for j in xrange(l, r + 1):
        k = A[j]
        i = j
        while i > l and A[i-1] > k:
            A[i] = A[i-1]
            i -= 1
        A[i] = k
    return l + int((r - l) * 0.5) # 下中位数
def _medianOfMedians(A, l, r):
    """中位数的中位数方式:
    1. 划分为floor(n/5)个5元组,剩下(n%5)组成最后一组。
    2. 找出ceil(n/5)个组各自的中位数。先对每组插入排序,再从中选出中位数。
    3. 对第2步中找出的ceil(n/5)个中位数重复上述操作,直到仅有一个中位数。
    """
    if l == r:
        return l
    n = r - l + 1 # 元素个数
    m = int(ceil(n / 5.0)) # 划分组数,每组5个元素
    for i in xrange(m):
        # 每组起始位和结束位
        sub_l = l + i * 5
        sub_r = sub_l + 4
        if sub_r > r:
            sub_r = r
        # 对每组元素插入排序后,选取中位数
        sub_m = _median(A, sub_l, sub_r) # 中位数索引
        # 交换中位数到前几位
        j = l + i
        A[j], A[sub_m] = A[sub_m], A[j]
    return _medianOfMedians(A, l, l + m - 1) # 中位数的中位数
def bfprt_select(A, k):
    """中位数的中位数方式(BFPRT算法)
    T(n) = O(n)
    """
    return _select(A, 0, len(A) - 1, k, _medianOfMedians);

def _median3(A, l, r):
    """三数中位数方式,取l,r,(l+r)/2三数中位数"""
    c = (l + r) / 2
    keys = [l, c, r]
    i = _median(keys, 0, 2)
    return keys[i]
def median_select(A, k):
    """三数中位数方式,以消除最坏情况"""
    return _select(A, 0, len(A) - 1, k, _median3);

if __name__ == '__main__':
    import random, time
    from copy import copy
    print('preparing data...')
    n = 1000000
    nums = range(n)
    random.shuffle(nums)
    print('ready go!')
    def timeit(fnc, *args, **kargs):
        print('%s starts processing' % fnc.__name__)
        begtime = time.clock()
        retval = fnc(*args, **kargs)
        endtime = time.clock()
        print('%s takes time : %f' % (fnc.__name__, endtime - begtime))
        return retval
    test_methods = [rand_select, bfprt_select, median_select]
    k = random.randrange(n) + 1
    dashes = '---' * 10
    for test in test_methods:
        print(dashes)
        nums_new = copy(nums)
        result = timeit(test, nums_new, k)
        print('the %dth smallest element: %d' % (k, result))
Python 相关文章推荐
vc6编写python扩展的方法分享
Jan 17 Python
python统计字符串中指定字符出现次数的方法
Apr 04 Python
Python基本语法经典教程
Mar 11 Python
遗传算法python版
Mar 19 Python
解决Python3中的中文字符编码的问题
Jul 18 Python
使用 Python 实现文件递归遍历的三种方式
Jul 18 Python
python用opencv批量截取图像指定区域的方法
Jan 24 Python
Python趣味实例,实现一个简单的抽奖刮刮卡
Jul 18 Python
Python趣味入门教程之循环语句while
Aug 26 Python
python3.8.3安装教程及环境配置的详细教程(64-bit)
Nov 28 Python
Python闭包的定义和使用方法
Apr 11 Python
Python实现仓库管理系统
May 30 Python
python获取beautifulphoto随机某图片代码实例
Dec 18 #Python
python使用urllib2模块获取gravatar头像实例
Dec 18 #Python
python2.7删除文件夹和删除文件代码实例
Dec 18 #Python
python使用xmlrpc实例讲解
Dec 17 #Python
python三元运算符实现方法
Dec 17 #Python
用python写asp详细讲解
Dec 16 #Python
python模块restful使用方法实例
Dec 10 #Python
You might like
php循环输出数据库内容的代码
2008/05/24 PHP
php下防止单引号,双引号在接受页面转义的设置方法
2008/09/25 PHP
PHP number_format() 函数定义和用法
2012/06/01 PHP
Laravel中基于Artisan View扩展包创建及删除应用视图文件的方法
2016/10/08 PHP
Laravel 集成 Geetest验证码的方法
2018/05/14 PHP
php实例化一个类的具体方法
2019/09/19 PHP
web前端开发也需要日志
2010/12/09 Javascript
JavaScript XML和string相互转化实现代码
2011/07/04 Javascript
基于jquery实现图片广告轮换效果代码
2011/07/07 Javascript
javascript 正则表达式相关应介绍
2012/11/27 Javascript
基于jquery中children()与find()的区别介绍
2013/04/26 Javascript
js中onload与onunload的使用示例
2013/08/25 Javascript
jQuery实现的多张图无缝滚动效果【测试可用】
2016/09/12 Javascript
微信小程序  自定义创建详细介绍
2016/10/27 Javascript
基于jPlayer三分屏的制作方法
2016/12/21 Javascript
JavaScript制作简单的框选图表
2017/05/15 Javascript
javaScript动态添加Li元素的实例
2018/02/24 Javascript
vue.js轮播图组件使用方法详解
2018/07/03 Javascript
JS常见构造模式实例对比分析
2018/08/27 Javascript
Element-ui自定义table表头、修改列标题样式、添加tooltip、:render-header使用
2019/04/11 Javascript
Java Varargs 可变参数用法详解
2020/01/28 Javascript
原生jQuery实现只显示年份下拉框
2020/12/24 jQuery
[04:19]DOTA2亚洲邀请赛 现场花絮
2015/03/11 DOTA
[01:42]辉夜杯战队访谈宣传片—FANTUAN
2015/12/25 DOTA
复制粘贴功能的Python程序
2008/04/04 Python
python2.6.6如何升级到python2.7.14
2018/04/08 Python
python集合比较(交集,并集,差集)方法详解
2018/09/13 Python
对python的unittest架构公共参数token提取方法详解
2018/12/17 Python
numpy.random.shuffle打乱顺序函数的实现
2019/09/10 Python
英国时尚首饰品牌:Missoma
2020/06/29 全球购物
建筑工程管理专业自荐信范文
2013/12/28 职场文书
环保建议书600字
2014/05/14 职场文书
2014年保育员工作总结
2014/12/02 职场文书
认识实习感想
2015/08/10 职场文书
抖音动画片,皮皮虾,《治愈系》动画在用这首REMIX作为背景音乐,Anak ,The last world with you完整版
2022/03/16 杂记
SQL Server 中的事务介绍
2022/05/20 SQL Server