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两个整数相除得到浮点数值的方法
Mar 18 Python
python3实现短网址和数字相互转换的方法
Apr 28 Python
Python实现小数转化为百分数的格式化输出方法示例
Sep 20 Python
Python实现1-9数组形成的结果为100的所有运算式的示例
Nov 03 Python
python编写分类决策树的代码
Dec 21 Python
Django框架视图层URL映射与反向解析实例分析
Jul 29 Python
python快速排序的实现及运行时间比较
Nov 22 Python
Python中的 ansible 动态Inventory 脚本
Jan 19 Python
Python操作Sqlite正确实现方法解析
Feb 05 Python
解决pip install psycopg2出错问题
Jul 09 Python
Django+Uwsgi+Nginx如何实现生产环境部署
Jul 31 Python
python中的plt.cm.Paired用法说明
May 31 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
给多个地址发邮件的类
2006/10/09 PHP
Laravel 手动开关 Eloquent 修改器的操作方法
2019/12/30 PHP
lib.utf.js
2007/08/21 Javascript
js 小贴士一星期合集
2010/04/07 Javascript
jquery实现通用版鼠标经过淡入淡出效果
2014/06/15 Javascript
js中window.open打开一个新的页面
2014/08/10 Javascript
JavaScript模板引擎用法实例
2015/07/10 Javascript
Node.js测试中的Mock文件系统详解
2016/11/21 Javascript
js中作用域的实例解析
2017/03/16 Javascript
Javascript循环删除数组中元素的几种方法示例
2017/05/18 Javascript
vue.js的简单自动求和计算实例
2019/11/08 Javascript
在Vue中使用this.$store或者是$route一直报错的解决
2019/11/08 Javascript
JavaScript缓动动画函数的封装方法
2020/11/25 Javascript
vue穿梭框实现上下移动
2021/01/29 Vue.js
Python算法之栈(stack)的实现
2014/08/18 Python
python自动化脚本安装指定版本python环境详解
2017/09/14 Python
Python数据结构与算法之列表(链表,linked list)简单实现
2017/10/30 Python
修复 Django migration 时遇到的问题解决
2018/06/14 Python
Flask框架Jinjia模板常用语法总结
2018/07/19 Python
Python运行不显示DOS窗口的解决方法
2018/10/22 Python
Python 函数返回值的示例代码
2019/03/11 Python
python常用库之NumPy和sklearn入门
2019/07/11 Python
python__name__原理及用法详解
2019/11/02 Python
OpenCV+Python--RGB转HSI的实现
2019/11/27 Python
用CSS3和table标签实现一个圆形轨迹的动画的示例代码
2019/01/17 HTML / CSS
Office DEPOT法国官网:欧迪办公用品采购
2018/01/03 全球购物
描述RIP和OSPF区别以及特点
2015/01/17 面试题
先进个人事迹材料
2014/01/25 职场文书
自荐信需注意事项
2014/01/25 职场文书
教师对学生的寄语
2014/04/03 职场文书
捐款倡议书格式范文
2014/05/14 职场文书
社会公德演讲稿
2014/05/20 职场文书
怀孕辞职信怎么写
2015/02/28 职场文书
大国崛起英国观后感
2015/06/02 职场文书
MySQL自定义函数及触发器
2022/08/05 MySQL
JS实现页面炫酷的时钟特效示例
2022/08/14 Javascript