未分类的N个元素的二进制搜索与线性搜索

时间:2019-02-26 18:32:36

标签: algorithm sorting time-complexity

当我们应该使用快速排序时,我试图理解一个公式。例如,我们有一个包含 N = 1_000_000 元素的数组。如果只搜索一次 ,则应该使用简单的线性搜索,但是如果要搜索10次,则应该使用排序数组 O(n log n)。我应该如何检测阈值的输入阈值以及何时使用排序的输入数组,然后使用二进制搜索?

5 个答案:

答案 0 :(得分:3)

您要解决的不平等问题可能被形容为

t * n > C * n * log(n) + t * log(n)

其中t是检查次数,而C是用于排序实现的常数(应通过实验确定)。评估此常数时,可以用数值方法解决不等式(当然有不确定性)

答案 1 :(得分:2)

就像您已经指出的那样,这取决于您要执行的搜索次数。以下语句可以得出一个很好的阈值:

n*log[b](n) + x*log[2](n) <= x*n/2 x是搜索次数; n输入大小; b排序的对数底数,具体取决于您使用的分区。

当该语句的值为真时,应将方法从线性搜索切换为排序和搜索。

通常来说,通过无序数组进行线性搜索平均需要执行n / 2步,尽管只有x接近n时,该平均值才发挥重要作用。如果您要坚持使用大Omicron或大Theta表示法,则可以忽略上面的/2

答案 2 :(得分:2)

假设n个元素和m个搜索,具有粗略的近似值

  • 排序费用为C0.n.log n

  • m二进制搜索C1.m.log n的费用,

  • m线性搜索C2.m.n的费用,

带有C2 ~ C1 < C0

现在比较

C0.n.log n + C1.m.log n vs. C2.m.n

C0.n.log n / (C2.n - C1.log n)  vs. m

对于相当大的n,收支平衡点约为C0.log n / C2

例如,以C0 / C2 = 5n = 1000000得出m = 100

答案 3 :(得分:1)

您应该绘制两个操作的复杂性。

  

线性搜索:O(n)

     

排序和二进制搜索:O(nlogn + logn)

在图中,您将看到选择一种方法优于另一种方法有意义的n

答案 4 :(得分:1)

当我查看类似quicksort的算法的预期运行时间(每个级别的预期分割不是50/50时)时,这实际上变成了一个有趣的问题。
我要回答的第一个问题是随机数据,每个级别的平均拆分是多少。当然,它必须大于50%(对于较大的细分)。好吧,给定一个大小为N的随机值数组,最小值具有(1,N-1)的细分,第二个最小值具有(2,N-2)的细分,依此类推。我将其放在快速脚本:

#models.py
from django.db import models
from datetime import datetime

# Create your models here.

class Post(models.Model):
    title = models.CharField(max_length=200)
    body = models.TextField()
    created_at = models.DateTimeField(default=datetime.now, blank=True)
    image      = models.ImageField(upload_to='blog/', null=True, blank=True)

    def __str__(self):
        return self.title




#view.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import Post

# Create your views here.
def index(request):
    posts = Post.objects.all()[:10]

    context = {
        'title' : 'Latest Posts',
        'posts' : posts,
    }

    return render(request, 'blog/index.html', context)

def details(request, id):
    post = Post.objects.get(id=id)
    queryset = Post.objects.all()

    context = {
        'post' : post,
        'object' : queryset
        }

    return render(request, 'blog/details.html', context)




#details.html
{% extends 'blog/layout.html'%}

{% block content %}
<h3 class="center-align red darken-3">{{post.title}}</h3>
<div class="card hoverable">
    <div class="card-content teal accent-4">
        {{post.body}}
    </div>
    <div class="card-action teal accent-4">
        {{post.created_at}}
    </div>

    {% if post.image.url %}

    {% for post_image in post.image.url %}

    <div class="div">
        <img src='{{post.image.url}}' class='responsive-img' /><br/>  
    </div>
    {% else %}
    <div class="div">
        </div>

    {% endfor %}
    {% endif %}
</div>
<a href="/blog/" class="btn">Go Back</a>

{% endblock %}

答案是0.75。我敢肯定,我可以证明这始终是正确的答案,但我想继续讲更难的部分。

现在,我们假设对于一些未知的对数底数,即使25/75分割也遵循nlogn进行。这意味着split = 0 for x in range(10000): split += float(max(x, 10000 - x)) / 10000 split /= 10000 print split 的问题是要通过统计手段找到num_comparisons(n) = n * log_b(n)(因为我不希望该模型在每个步骤上都是精确的)。在使用对数标识获得以下信息后,我们可以巧妙地应用最小二乘拟合:

b

现在对数可以有任何底数,只要C(n) = n * log(n) / log(b) log(n)使用相同的底数即可。这是一个线性方程,仅在等待一些数据!因此,我编写了另一个脚本来生成log(b)的数组,并用xsC(n)填充并用ys填充,并使用n*log(n)告诉我最小二乘拟合的斜率,我希望等于numpy。我运行脚本,并将1 / log(b)放入b内,具体取决于我将[2.16, 2.3]设置为多高(我将n从100变为100'000'000)。 n似乎因b而异的事实表明我的模型并不精确,但我认为此示例可以。

现在要根据这些假设实际回答您的问题,我们可以求解以下时间的临界点:n。我只是假设二进制搜索的对数底数与25/75拆分的排序方法相同。隔离N * n/2 = n*log_2.3(n) + N * log_2.3(n)会得到:

N

如果您的搜索次数N = n*log_2.3(n) / (n/2 - log_2.3(n)) 超过RHS的数量(其中N是所讨论的数组的大小),则对它进行一次排序并对其进行二进制搜索会更有效。