2

我编写了一个 C++ 程序,目的是快速将一个元素插入到排序的向量中。它有时有效,但并非一直有效,我无法弄清楚原因。当我用纸和铅笔按照算法进行操作时,它可以解决,但是出了点问题。请帮忙?

#include <time.h>
#include <cstdlib>
#include <vector>
#include <iostream>
using namespace std;

vector<int> sortedVec;

int main() {
    // Random seed
    srand(time(NULL));

    // Put in n random elements
    for (int i = 0; i < 10; i++) sortedVec.push_back(rand()%10);

    // Sort the vector
    bool swapped = true;
    int endDecrement = 0;
    while (swapped) {
        swapped = false;
        endDecrement++;
        for (int i = 0; i < sortedVec.size()-endDecrement; i++) {
            if (sortedVec.at(i) > sortedVec.at(i+1)) {
                int swap = sortedVec.at(i);
                sortedVec.at(i) = sortedVec.at(i+1);
                sortedVec.at(i+1) = swap;
                swapped = true;
            }
        }
    }

    cout<<"Sorted random list:"<<endl;
    for (int i = 0; i < sortedVec.size(); i++) cout<<sortedVec.at(i)<<endl;

    int toInsert = rand()%10;
    cout<<"Random element to insert = "<<toInsert<<endl;

    // Insert a random int to the sorted vector
    int minIndex = 0;
    int maxIndex = sortedVec.size()-1;
    while (true) {
        int mid = (maxIndex-minIndex)>>1;
        if (toInsert == sortedVec.at(mid) || maxIndex-minIndex < 2) {
            sortedVec.insert(sortedVec.begin()+mid, toInsert);
            break;
        }
        else if (toInsert < sortedVec.at(mid)) maxIndex = mid;
        else if (toInsert > sortedVec.at(mid)) minIndex = mid;
    }

    cout<<"Random list with inserted element:"<<endl;
    for (int i = 0; i < sortedVec.size(); i++) cout<<sortedVec.at(i)<<endl;

    return 0;
}
4

5 回答 5

2

正如评论所指出的,您提出的解决基本问题的方法相当复杂。

您的问题可以time(NULL)在随机生成器初始化中替换为更有吸引力的常量,该常量可以提供观察到的行为以进行调试。

没有那个,我将对罪魁祸首出价:

int maxIndex = sortedVec.size()-1;

我认为应该是

int maxIndex = sortedVec.size();

或者你从不考虑顶级元素。

于 2012-10-05T06:09:16.113 回答
2

根据评论,让我们假设我们有一个类似的结构:

struct data {
    int fval;
    // other stuff we don't care about right now
};

而且,我们假设我们有一个向量:

std::vector<data> items;

如果我们想在向量中按顺序插入一个新项目,我们真的不想std::insert. 这需要 O(log N) 搜索,然后是 O(N) 插入。相反,我们可以将两者结合起来,因此我们只需要一个 O(N) 操作即可找到正确的位置并进行插入。这是一个简单的版本:

void insert(std::vector<int> &vec, int new_val) { 
    if (vec.empty()) {
        vec.push_back(new_val);
        return;
    }

    vec.resize(vec.size()+1);
    std::vector<int>::reverse_iterator pos = vec.rbegin();

    for ( ; *(pos+1) > new_val && (pos+1) != vec.rend(); ++pos)
        *pos = *(pos+1);
    *pos = new_val;
}

在您的情况下,您想插入一个data结构并进行比较(pos+1)->fval > new_val.fval,但基本思想在其他方面几乎相同。实际上,这可能应该作为通用算法来实现,但我目前没有时间。

于 2012-10-05T17:29:08.860 回答
1

标准库中有用于排序的工具:

#include <algorithm>
#include <vector>

template <typename T, typename A, typename C>
class SortedVector {
public:
    SortedVector() {}

    // Initialization
    template <typename It>
    SortedVector(It begin, It end): _data(begin, end) {
        std::sort(_data.begin(), _data.end(), _comparator);

        // if we wanted unicity
        _data.erase(std::unique(_data.begin(), _data.end(), _comparator), _data.end());
    }

    // Addition of element (without checking for unicity)
    void add(T const& element) {
        _data.push_back(element);
        std::inplace_merge(_data.begin(), prev(_data.end()), _data.end(), _comparator);
        // or simply: std::sort(_data.begin(), _data.end(), _comparator);
        // it is surprisingly efficient actually because most sort implementations
        // account for partially sorted range. It is not, however, stable.
    }

    // Addition of element with unicity check
    bool add(T const& element) {
        typename std::vector<T, A>::iterator it =
            std::lower_bound(_data.begin(), _data.end(), element, _comparator);
        if (it != _data.end() and not _comparator(element, *it)) {
            return false;
        }
        size_t const n = it - _data.begin();

        _data.push_back(element);
        std::copy(_data.begin() + n, _data.end() - 1, _data.begin() + n + 1);
        // C++11: std::move
        _data[n] = element;
    }

private:
    std::vector<T, A> _data;
    C _comparator;
};
于 2012-10-05T07:00:36.587 回答
0

我编写了一个 C++ 程序,目的是快速将一个元素插入到排序的向量中

你不应该那样做。std::vector 不适合快速插入到自定义位置。编辑:顺便说一句,您正在更换,而不是插入。因为使用矢量是可以的。

此外,您的代码也因不使用标准函数而受到影响。std::sort,如果你真的想手动交换元素,你也有 std::swap。

这也是不必要的:

int mid = (maxIndex-minIndex)>>1;

编译器可以并且很容易将 /2 优化为 >>1;

编辑:

您的代码已损坏,这有望向您展示原因:http: //ideone.com/pV5oW

于 2012-10-05T11:21:26.867 回答
0

我更改了它,并且很确定它现在适用于所有情况:

if (toInsert < sortedVec.at(0)) sortedVec.insert(sortedVec.begin(), toInsert);
else if (toInsert > sortedVec.at(sortedVec.size()-1)) sortedVec.push_back(toInsert);
else {  
    int minIndex = 0;
    int maxIndex = sortedVec.size();
    while (true) {
        int mid = (maxIndex+minIndex)>>1;
        if (toInsert == sortedVec.at(mid) || maxIndex-minIndex < 2) {
            sortedVec.insert(sortedVec.begin()+mid+1, toInsert);
            break;
        }
        else if (toInsert < sortedVec.at(mid)) maxIndex = mid;
        else if (toInsert > sortedVec.at(mid)) minIndex = mid;
    }
}

@LeGEC 和 @chac,感谢您研究我发布的算法,它帮助很大。@Jerry Coffin,我确实让 std::upper_bound 可以为此工作,但不能为我的 Node 类的变量工作,不过也谢谢你。

于 2012-10-05T22:39:33.807 回答