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 相关文章推荐
跟老齐学Python之Python安装
Sep 12 Python
深入讨论Python函数的参数的默认值所引发的问题的原因
Mar 30 Python
Python中利用函数装饰器实现备忘功能
Mar 30 Python
Python的Django框架中设置日期和字段可选的方法
Jul 17 Python
Python分布式进程中你会遇到的问题解析
May 28 Python
PyQt5实现从主窗口打开子窗口的方法
Jun 19 Python
正则给header的冒号两边参数添加单引号(Python请求用)
Aug 09 Python
解决pycharm中opencv-python导入cv2后无法自动补全的问题(不用作任何文件上的修改)
Mar 05 Python
python实现与redis交互操作详解
Apr 21 Python
基于python实现地址和经纬度转换
May 19 Python
用python发送微信消息
Dec 21 Python
Python 机器学习工具包SKlearn的安装与使用
May 14 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性能的编码技巧以及性能优化详细解析
2013/08/24 PHP
ThinkPHP的Widget扩展实例
2014/06/19 PHP
PHP中使用SimpleXML检查XML文件结构实例
2015/01/07 PHP
php中实现用数组妩媚地生成要执行的sql语句
2015/07/10 PHP
PHP实现批量重命名某个文件夹下所有文件的方法
2017/09/04 PHP
新浪刚打开页面出来的全屏广告代码
2007/04/02 Javascript
Javascript Select操作大集合
2009/05/26 Javascript
javascript实现的在当前窗口中漂浮框的代码
2010/03/15 Javascript
JQuery实现简单验证码提示解决方案
2012/12/20 Javascript
基于datagrid框架的查询
2013/04/08 Javascript
JS特殊函数(Function()构造函数、函数直接量)区别介绍
2013/05/19 Javascript
jQuery获得字体颜色16位码的方法
2016/02/20 Javascript
提高JavaScript执行效率的23个实用技巧
2017/03/01 Javascript
浅谈JavaScript中的属性:如何遍历属性
2017/09/14 Javascript
微信小程序使用toast消息对话框提示用户忘记输入用户名或密码功能【附源码下载】
2017/12/09 Javascript
vue element-ui 绑定@keyup事件无效的解决方法
2018/03/09 Javascript
微信小程序实现折叠与展开文章功能
2018/06/12 Javascript
EasyUI 数据表格datagrid列自适应内容宽度的实现
2019/07/18 Javascript
浅谈vue中组件绑定事件时是否加.native
2019/11/09 Javascript
vue scroll滚动判断的实现(是否滚动到底部、滚动方向、滚动节流、获取滚动区域dom元素)
2020/06/11 Javascript
[01:46]2018完美盛典章节片——坚守
2018/12/17 DOTA
[01:03:27]NAVI vs EG 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
python抓取豆瓣图片并自动保存示例学习
2014/01/10 Python
python 打印直角三角形,等边三角形,菱形,正方形的代码
2017/11/21 Python
Python装饰器原理与简单用法实例分析
2018/04/29 Python
Python3实现将本地JSON大数据文件写入MySQL数据库的方法
2018/06/13 Python
Pycharm2017版本设置启动时默认自动打开项目的方法
2018/10/29 Python
使用50行Python代码从零开始实现一个AI平衡小游戏
2018/11/21 Python
python爬虫用request库处理cookie的实例讲解
2021/02/20 Python
html5给汉字加拼音加进度条的实现代码
2020/04/07 HTML / CSS
运动会领导邀请函
2014/01/10 职场文书
食品安全工作实施方案
2014/03/26 职场文书
法人授权委托书公证范本
2014/09/14 职场文书
群众路线教育实践活动心得体会(四风)
2014/11/03 职场文书
出生证明范本
2015/06/15 职场文书
【海涛dota】偶遇拉娜娅 质量局德鲁伊第一视角解说
2022/04/01 DOTA