两种线性时间选取第i小的元素的方法+ python实现(未完结)

先看第一种比较简单并且也比较容易理解的`
思路如下:
快速排序的核心过程可以直接得到我们当前选择元素在最后将所有元素排好序后当前元素所在位置。
所以我们可以考虑对快速排序进行改编,由于我们不需要知道每个元素的具体位置所以,我们可以选择性地执行快速排序的核心过程。

随机选取元素然后和第一个元素进行交换,并且最终将所有小于和大于当前选取的元素的其他元素进行重新排序,小的排在左边大的排在右边。

代码如下:

import numpy as np
import random

A = [random.randint(1, 100) for i in range(10)]

def randomizedPartition(A, p, r):
    i = np.random.randint(p, r+1)
    print(i,A[i])
    A[r], A[i]= A[i], A[r]
    x = A[r]
    i = p-1
    for j in range(p,r):
        if A[j]<=x:
            i+=1
            A[i], A[j]=A[j], A[i]

    A[i+1], A[r] = A[r], A[i+1]
    print(A)
    return i+1

randomizedPartition(A, 0,len(A)-1)

def randomizedSelect(A, p, r, i):
    if p==r:
        return A[p]
    q=randomizedPartition(A, p ,r)
    k=q-p+1
    if i==k:
        return A[q]
    elif i<k:
        return randomizedSelect(A,p,q-1,i)
    else:
        return randomizedSelect(A,q+1,r,i-k)

    pass

print(randomizedSelect(A,0, len(A)-1, int(input('请输入你要的第i位'))))

运行结果如图:


4 59
[30, 59, 100, 89, 65, 67, 94, 86, 68, 64]
请输入你要的第i位5
9 64
[30, 59, 64, 89, 65, 67, 94, 86, 68, 100]
4 65
[30, 59, 64, 65, 100, 67, 94, 86, 68, 89]
9 89
[30, 59, 64, 65, 67, 86, 68, 89, 94, 100]
6 68
[30, 59, 64, 65, 67, 68, 86, 89, 94, 100]
67

Process finished with exit code 0

另一种升级版本的方法,思路:我们不断获取中位数,比上面的随机选取数要靠谱很多,并且我们还可以改革数据存储结构,让获取中位数更加简单一些
我们尽量把数变成奇数行尽量方的一堆数

例如假设数组一共有100个元素那么我们可以把它变形成11行10列其中最后一列只有第一个行有元素

我们先通过快速排序的核心方法取出每一列的中位数,放在每一列的中间然后将小的元素放在中间元素的上面,大的放在下面。

之后我们把所有的列通过中位数的大小从小到大排序,小的放左边,大的放右边

这时候我们发现在整个数组最中间的就是这个数组真正的中位数,中位数左方肯定都是不比它大的数,右边肯定都是不比它小的数。我们这样分类,每次将目标缩小到原来的四分之3(由1/4和1/2组成)

我们第一次对根号n个列找中位数通过快速排序核心算法每个最多花费根号n的时间
所以

T(n) = T(n/2)+ T(n/4)+ O(n)

由主定理推导 a=1 b=4 fn = n

属于
fn比在这里插入图片描述大的时候fn为主导,复杂度为fn即n线性时间就可以完成

下面的代码实现了将A中的所有列的中位数的中位数放在最中间,并且小的放在左边大的放在右边

# 这个算法我失败了我的心有点乱

import numpy as np
import random


maxNum = 10000
aimLength = random.randint(100, 10000)
print(aimLength)
# 我们要获取的第aimI小的元素位序
aimI = random.randint(0, aimLength)


rowNum = int(aimLength**0.5)


A = [random.randint(1, maxNum) for i in range(aimLength)]

# 判断A之后要分成多少行
if rowNum%2 ==1:
    pass
else:
    rowNum +=1

# 下面我们进行判断我们准备把数组化成二维但是可能出现排不满的情况,所以进行添加,用足够大的数进行添加。
if aimLength%rowNum ==0:
    pass
else:
    while True:
        aimLength+=1
        A.append(maxNum)
        if aimLength%rowNum ==0:
            break


A = np.array(A).reshape((rowNum, int(aimLength/rowNum)))
print(A)
# 完成对初始数组A的处理


# resultCol =

def randomizedPartition(A, p, r):
    i = np.random.randint(p, r+1)
    A[r], A[i]= A[i], A[r]
    x = A[r]
    i = p-1
    for j in range(p,r):
        if A[j]<=x:
            i+=1
            A[
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值