C++-将项添加到排序数组的最快方法

C++ - Fastest way to add an item to a sorted array

本文关键字:方法 数组 排序 添加 C++-      更新时间:2023-10-16

我有一个数据库,里面有大约20万个项目,按用户名排序。现在,当我将一个项添加到数组末尾并调用快速排序函数对该数组进行排序时,几乎需要一秒钟的时间来进行排序,这是不可接受的。肯定有相当多的优化可以做。例如,如果我按顺序将每个字符串从n-1到0进行比较,然后相应地移动项目,则性能会高得多。

另一个想法是,我可以执行从0到n-1的二进制搜索,这不是实际搜索,而是类似于利用我已经排序的数组。然而,我没能写出一个合适的函数来返回一个索引,这个索引应该放在我的新元素的位置。

void quick_sort(int left, int right)
{
    int i = left, j = right;
    if (left >= right) return;
    char  pivotC[128];
    DataEntry *tmp;
    strcpy_a(pivotC, sizeof pivotC, User[(left + right) / 2]->username);
    while (i <= j)
    {
        while (StringCompare(User[i]->username, pivotC))
            i++;
        while (StringCompare(pivotC, User[j]->username))
            j--;
        if (i <= j) 
        {
            tmp = User[i];
            User[i] = User[j];
            User[j] = tmp;
            i++;
            j--;
        }
    }
    if (left < j)
        quick_sort(left, j);
    if (i < right)
        quick_sort(i, right);
}

非常感谢您的帮助。

解决方案是重写代码以使用stl,我不明白为什么人们用C++编写C代码。

你需要一个用户的矢量

std::vector<User> users;
//then you can keep it ordered at each insertion
auto it = upper_bound(users.begin(), users.end(), user_to_insert, 
    [](auto& lhs, auto& rhs ) { /* implementation left to the reader */});
users.insert(it, user_to_insert);

现在,您可以以更好、更干净的方式使用相同的功能

如果你想学习如何对二进制搜索进行编码,那么重新设计轮子是可以的,否则重用会更好。

std::lower_bound对已排序的范围[first, last)执行二进制搜索,如果已存在,则向搜索到的元素x返回迭代器;否则迭代器将指向大于CCD_ 4的第一个元素。由于暴露insert的标准容器会在迭代器之前插入,因此可以按原样使用此迭代器。这里有一个简单的例子。

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
int main()
{
    std::list<int> data = { 1, 5, 7, 8, 12, 34, 52 };
    auto loc = std::lower_bound(data.begin(), data.end(), 10);
    // you may insert 10 here using loc
    std::cout << *loc << 'n';
    loc = std::lower_bound(data.begin(), data.end(), 12);
    // you may skip inserting 12 since it is in the list (OR)
    // insert it if you need to; it'd go before the current 12
    std::cout << *loc << 'n';
}

12

12

简单、直接的方法导致二进制搜索过于主流。只需要几行:

int where_to_add(int array[], int element)
{
    int i;
    for (i = length; i >= 0 && array[i-1] > element; i--);
    return i;
}

如果这是您想要的答案,请告诉我

二进制搜索的兴趣有限,因为无论如何都需要插入,这仍然是一个耗时的操作(O(N))。所以你的第一个想法是先线性搜索,然后插入就足够了;你可以组合成一个向后循环。(这是StraightInsertionSort的一个步骤。)

处理动态排序列表的真正有效的方法是维护平衡树或使用哈希表。

如果您正在对一个只有几个新的错位尾部项的排序列表进行排序,那么您应该利用插入排序实际有效的罕见情况。在只有几个尾部错位值的排序列表上实现插入排序可以在O(n)时间内进行排序。您只是将一些不合适的值插入到适当的位置,而快速排序则是选择一个枢轴并完成整个快速排序过程。此外,如果你没有将某种类型的高效数据透视选择过程纳入你的快速排序中,并在已经排序的列表上采用"前3项的平均值"方法,你将在O(n^2)时间内进行排序。

您可以这样进行二进制搜索。。这里你可以假设,如果val是字符串类型,那么使用字符串比较函数进行比较,int AR[]是字符串的集合,或者你可以将它们映射到integer。随着数组的排序,我认为二进制搜索将为您提供最佳性能。

int bsearch(int AR[], int N, int VAL)
{
    int Mid,Lbound=0,Ubound=N-1;
    while(Lbound<=Ubound)
    {
        Mid=(Lbound+Ubound)/2;
        if(VAL>AR[Mid])
            Lbound=Mid+1;
        else if(VAL<AR[Mid])
            Ubound=Mid-1;
        else
            return Mid;
    }
    return 0;
}

据我所见,您正在使用C数组来存储条目,这意味着每当您尝试插入新条目时,由于可能需要在数组中移动大量条目,因此会对大量条目的性能造成巨大损失。

如果您计划保留一个C数组,而不使用一些stl排序的容器(不过主要考虑std::map),您可以尝试将C数组拆分为两个数组。一个是第一个数组,包含键和第二个数组元素的索引。您仍然需要对第一个数组进行排序,但它的元素只有两个字(一个用于键,一个用于索引),而不是一个包括键和一些值的大块,并且应该更快。当插入一个项时,您在第二个数组的末尾进行分配,并使用索引将其作为一对键插入第一个数组中。如果你计划动态删除一个元素,你可以更聪明一点,但你的问题似乎没有涵盖它

但即便如此,它可能仍然太慢,所以您确实应该考虑std::map或一些算法,如使用AVL的二进制树、红黑树、飞溅树等,在这些算法中您不需要物理移动元素。

int add(Container c, int r, int l, Unit t)
{
    if(c[r]>t)
        return r;
    if(c[l]<t)
        return l+1;
    if(c[r]==c[l])
    {
         if(c[r]==t)
            return -1;
         return -1;
    }
    int m=(r+l)/2;
    if(c[m]==t)
          return -1;
    if(c[m]>t)
          return add(c,m,l,t);
    if(c[m]<t)
          return add(c,r,m,t);
}

它可能会给你需要添加的索引。。。我希望它能有所帮助。它假设您不需要在它已经存在时添加。