Deque实现的复杂性

huangapple go评论66阅读模式
英文:

Complexity of Deque implementation

问题

我认为这个复杂性主要是由于 balanceVectors() 函数引起的,该函数需要从两个向量的开头删除和插入元素。然而,我不确定如何使用摊销常数时间来实现这一点。任何有关降低复杂性的帮助将不胜感激。

Here is the translated code portion:

我认为这个复杂性主要是由于 `balanceVectors()` 函数引起的,该函数需要从两个向量的开头删除和插入元素。然而,我不确定如何使用摊销常数时间来实现这一点。任何有关降低复杂性的帮助将不胜感激。

Please note that the code itself remains in English, as programming code is typically written in English for consistency and compatibility. If you have any specific questions or need further assistance with the code, please feel free to ask.

英文:

I was asked to implement a deque in a programming course using two vectors (frontVector and backVector), which should contain half of the data of the deque. However, my implementation seems to be taking so much runtime. Here is the template with all functions included.

template <typename T>
MyDeque<T>::MyDeque() {}

template <typename T>
MyDeque<T>::MyDeque(int n) : frontVector(n/2), backVector(n/2 + n%2) {}

template <typename T>
MyDeque<T>::MyDeque(std::initializer_list<T> vals) : frontVector(), backVector(int(vals.size())) {
    int i = 0;
    for (const auto& item : vals) {
        backVector[i++]=item;
    }
    balanceVectors();
}

template <typename T>
void MyDeque<T>::push_back(T val) {
    backVector.push_back(val);
    balanceVectors();
}

template <typename T>
void MyDeque<T>::push_front(T val) {
    frontVector.insert(frontVector.begin(),val);
    balanceVectors();
}

template <typename T>
void MyDeque<T>::pop_back() {
    if (!backVector.empty()) {
        backVector.pop_back();
        balanceVectors();
    }
    else if (!frontVector.empty()) {
        frontVector.pop_back();
        balanceVectors();
    }
}

template <typename T>
void MyDeque<T>::pop_front() {
    if (!frontVector.empty()) {
        frontVector.erase(frontVector.begin());
        balanceVectors();
    }
    else if (!backVector.empty()) {
        backVector.pop_back();
        balanceVectors();
    }
}

template <typename T>
T& MyDeque<T>::back() {
    if (!backVector.empty()) {
        return backVector.back();
    }
    return frontVector.front();
}

template <typename T>
const T& MyDeque<T>::back() const {
    if (!backVector.empty()) {
        return backVector.back();
    }
    return frontVector.front();
}

template <typename T>
T& MyDeque<T>::front() {
    if (!frontVector.empty()) {
        return frontVector.front();
    }
    return backVector.back();
}

template <typename T>
const T& MyDeque<T>::front() const {
    if (!frontVector.empty()) {
        return frontVector.back();
    }
    return backVector.front();
}

template <typename T>
bool MyDeque<T>::empty() const {
  return frontVector.empty() && backVector.empty();
}

template <typename T>
int MyDeque<T>::size() const {
  return int(frontVector.size()) + int(backVector.size());
}

template <typename T>
T& MyDeque<T>::operator[](int i) {
    if (i < static_cast<int>(frontVector.size())) {
        return frontVector[i];
    } 
    else {
        return backVector[i - frontVector.size()];
    }
}

template <typename T>
const T& MyDeque<T>::operator[](int i) const {
    if (i < static_cast<int>(frontVector.size())) {
        return frontVector[i];
    } 
    else {
        return backVector[i - frontVector.size()];
    }
}


template <typename T>
void MyDeque<T>::balanceVectors() {
    if (backVector.size() > frontVector.size() + 1) {
        frontVector.push_back(backVector.front());
        backVector.erase(backVector.begin());
    } 
    else if (frontVector.size() > backVector.size() + 1) {
        backVector.insert(backVector.begin(), frontVector.back());
        frontVector.pop_back();
    }
}

template class MyDeque<int>;
template class MyDeque<double>;
template class MyDeque<char>;
template class MyDeque<std::string>;

I think that this complexity is because of the balanceVectors() function, which requires removing and inserting elements from the beginning of both vectors. However, I am not sure how can this be implemented using amortized constant time. Any help in decreasing the complexity will be appreciated.

答案1

得分: 1

你有两个问题:

  • 由于你只能高效地推送到向量的末尾,所以你需要以与deque相对于deque相反的顺序表示deque的前半部分,以便在内部向前推送时将其推送到向量的后面。

  • 由于重新平衡涉及O(n)的复制,

英文:

You have two problems:

  • Since you can only efficiently push to the end of a vector, you need
    to represent the front part of the deque in reverse order
    relative to the deque so that when you push to the front internally you are
    pushing to the back of a vector.

  • Since rebalancing involves O(n) copying you should not rebalance unless you have to. Never rebalance after pushing. Only rebalance before you would have to pop from either the front vector or the back vector but can't because it is empty.

Also note that there is a symmetry to the rebalancing logic such that you rebalance by doing one copy with a reverse iterator and one copy with a forward iterator when rebalancing from front to back or from back to front.

Here is some example code if you need it.

huangapple
  • 本文由 发表于 2023年4月19日 17:46:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76053053.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定