如何使用二分搜索将元素插入已排序的向量中

Posted

技术标签:

【中文标题】如何使用二分搜索将元素插入已排序的向量中【英文标题】:How to insert an element into a sorted vector using binary search 【发布时间】:2017-09-23 04:42:04 【问题描述】:

您好,我有一个问题,我不知道我使用二进制搜索插入向量的实现是否正确。 我有两个向量,一个存储类对象。第二个是假设要排序的那个。第二个向量保存第一个向量的索引,这些索引假定按字典顺序排序(从小到大)。我试图让我的程序运行 O(log(n))。这就是我所拥有的......

void Trendtracker:: add_hashtag(string ht)


    Entry tweet;
    tweet.count = 0;
    tweet.hashtag = ht;
    if (E.empty())
    
        E.push_back(tweet);
        S.push_back(0);
    


    int l, m, r;
    l = 0;
    r = S.size() -1;

    while (l < r)
    
        m =(l+r)/2;
        if(E[S[m]].hashtag == ht)//found #1
            return;
        else if (E[S[m]].hashtag < ht)// searches right
            l = m +1;
        else
            r = m-1; // searches left

    

    if( l ==r && E[S[l]].hashtag == tweet.hashtag)// found #2
        return;

    E.push_back(tweet);

    //if not found and lower than the lowest
    if(l==0 && ht < E[S[l]].hashtag)
    
        //S[0]= E.size()-1;
        S.insert(S.begin(), E.size()-1);
    

    // if not found but is higher than highest
    else if(l == S.size()-1 && E[S[l]].hashtag < ht)
    
        S.push_back(E.size()-1);
    

    // if new hashtag goes in the second index
    else if(l==0&& r==0 && E[S[r]].hashtag< ht)
    

        S.insert(S.begin()+1, E.size()-1);
    

    // if not found and l & r are somewhere in the middle
    else
    

        S.insert(S.begin()+l, E.size()-1);
    

【问题讨论】:

使用 std::lower_bound() 之类的东西,而不是自己滚动:en.cppreference.com/w/cpp/algorithm/lower_bound 如果if (E.empty()) 条件为真,那么您可以在执行该if 块后返回。执行其余代码没有意义。 【参考方案1】:

如果您经常使用容器在中间插入/删除,那么std::vector 可能不是您的最佳选择。

想一想:std::vector 将元素存储在连续的内存中,所以每次要在其中插入时,都会将其后的所有元素移动。查找速度更快(如果已排序则更快),但插入的开销是需要考虑的。

您可以查看实现链表的列表或其他类型的容器,因为插入就像创建节点一样简单,更改之前元素的 nextprev 指针,元素本身和之后的元素。

希望对你有帮助

【讨论】:

本文中提到了将二进制搜索插入向量的建议,以及关于为什么通常应该首选向量而不是列表的论点。 stroustrup.com/Software-for-infrastructure.pdf【参考方案2】:

算法的症结在于:

1)对中间索引值使用二分查找检查

  a) If the value to be inserted is less than mid value - check the (mid - 1) index if it is a valid index. If mid -1 is also less then you have to insert at current mid position.Otherwise, Change high to mid -1 and continue to search left
  b) If the value to be inserted is greater than mid value - check the (mid + 1) index if it is a valid index. If mid + 1 is also greater then you have to insert at mid + 1 position. Otherwise, change low to mid + 1 and continue to search right
  c) Handle overflow cases

下面是使用二分查找进行向量插入的示例代码:

#include <iostream>
#include <vector>

using namespace std;

void insert(vector<int> &arr,int value)

    int low = 0;
    int high = (int)(arr.size() - 1);
    int mid = low+(high - low)/2;
    int indexToInsert = -1;
    while(low<=high)
    
        if(mid < 0 || mid > arr.size()-1)
            break;
        if(value < arr[mid])
        
            //check if previous index is valid and lesser than value
            if(mid-1 >= 0)
            
                if(arr[mid-1]<value)
                
                    indexToInsert = mid;
                    break;
                
            
            high = mid - 1;
        
        else if(value > arr[mid])
        
            //check if next index is valid and greater than value
            if(mid+1 < arr.size())
            
                if(arr[mid+1]>value)
                
                    indexToInsert = mid+1;
                    break;
                
            
            low = mid + 1;
        
        mid = low+(high - low)/2;
    
    if(indexToInsert == -1)
    
        if(mid<=0)
            indexToInsert = 0;
        else if (mid>=arr.size())
            indexToInsert = (int)(arr.size());
    

    arr.insert(arr.begin() + indexToInsert, value);


void printVec(vector<int> vec)

    for(int i=0;i<vec.size();i++)
    
        cout<<vec[i]<<" ";
    
    cout<<"\n";


int main(int argc, const char * argv[]) 

    vector<int> vec;
    for(int i=1;i<10;i++)
    
        vec.push_back(i+(i*1));//used to create a ascending sorted array
        cout<<vec[i-1]<<" ";
    
    cout<<"\n";

    insert(vec, 3);
    cout<<"After insertion of 3: \n";
    printVec(vec);

    insert(vec, 25);
    cout<<"After insertion of 25: \n";
    printVec(vec);

    insert(vec, 11);
    cout<<"After insertion of 11: \n";
    printVec(vec);

    insert(vec, 1);
    cout<<"After insertion of 1: \n";
    printVec(vec);
    return 0;

如果有任何错误,请告诉我。

【讨论】:

以上是关于如何使用二分搜索将元素插入已排序的向量中的主要内容,如果未能解决你的问题,请参考以下文章

将元素插入已排序的向量中

Leetcode -- 搜索插入位置(35)(二分查找)

算法总结二分搜索

二分搜索算法

[golang] 数据结构-二分插入排序

c语言如何实现-数组排序,二分查找