我正在尝试使用双指针解决区间问题。基本前提是在我的映射中存储指向 Interval 结构的双指针,以便我可以更新间隔,而无需迭代映射中的任何其他值。使用双指针似乎会对我的间隔造成一些意外的变化,我不明白为什么。
这是我当前的代码:
#include <iostream>
#include <vector>
#include <utility>
#include <unordered_map>
using namespace std;
int main()
{
vector<pair<int, char>> sequence = {
{0,'a'},
{1,'-'},
{2,'b'},
{3,'c'},
{4,'-'},
{5,'d'},
{6,'e'},
{7,'-'},
{8,'f'},
{10,'g'},
{11,'-'},
{12, '-'}
};
struct Interval {
string word;
bool startH;
bool endH;
Interval(string word) : word(word), startH(false), endH(false) {}
};
Interval* hyphen = new Interval("-");
Interval** hPtr = ‐
auto consolidate = [&hPtr](Interval**& left, Interval**& right) {
//cout << "\t(" << (*left)->word << " " << (*right)->word << ")" << endl;
if (left == hPtr && right == hPtr) return;
if (left == hPtr) {
(*right)->startH = true;
}
else if (right == hPtr) {
(*left)->endH = true;
}
else {
(*right)->startH = (*left)->startH;
(*right)->word = (*left)->word + (*right)->word;
(*left) = (*right);
}
if ((*right)->startH && (*right)->endH) {
cout << "RESULT: " << (*right)->word << endl;
}
else if ((*left)->startH && (*left)->endH) {
cout << "RESULT: " << (*left)->word << endl;
}
};
unordered_map<int, Interval**> intervals;
for (auto pair : sequence) {
int index = pair.first;
char c = pair.second;
cout << "----" << index << ", " << c << "-----" << endl;
int preIndex = index - 1;
int postIndex = index + 1;
auto it_pre = intervals.find(preIndex);
auto it_post = intervals.find(postIndex);
//HERE 1
//if (it_pre != intervals.end()) cout << (*(it_pre->second))->word << endl;
Interval** currentIntervalPtr;
if (c == '-') {
currentIntervalPtr = hPtr;
}
else {
Interval* currentInterval = new Interval(string(1, c));
currentIntervalPtr = ¤tInterval;
}
//HERE 2
//if (it_pre != intervals.end()) cout << (*(it_pre->second))->word << endl;
if (it_pre != intervals.end()) {
Interval** prePtr = it_pre->second;
//cout << "PRE: <" << (*currentIntervalPtr)->word << ", " << (*prePtr)->word << ">>" << endl;
consolidate(prePtr, currentIntervalPtr);
}
if (it_post != intervals.end()) {
Interval** postPtr = it_post->second;
//cout << "POST: <" << (*currentIntervalPtr)->word << ", " << (*postPtr)->word << ">>" << endl;
consolidate(currentIntervalPtr, postPtr);
}
intervals[index] = currentIntervalPtr;
}
return 0;
}
在我的两个打印语句(HERE 1 和 HERE 2)之间, (*(it_pre->second))->word 的值发生了变化。我在这些语句之间所做的只是创建一个新的、不相关的间隔,所以我不明白为什么我的地图值会发生变化。
任何见解将不胜感激。我是使用双指针的新手,所以我可能只是忽略了一些简单的东西。
代码中的主要问题在于以下几行:
Interval* currentInterval = new Interval(string(1, c));
currentIntervalPtr = ¤tInterval;
当您执行 ¤tInterval 时,您将获得 currentInterval 指针变量(它是循环中的局部变量)的地址。一旦循环迭代完成, currentInterval 变量就会超出范围并变得无效,但地址仍保留在间隔映射中,指向一些垃圾内存。
因此,在后续的循环迭代中,该内存可能会被重用,从而导致意外的行为。
要解决此问题,您可以将映射更改为存储指针而不是双指针。如果要更新间隔,可以直接通过存储的指针来完成。
这是代码的调整版本:
unordered_map<int, Interval*> intervals;
在循环中,当您创建新间隔时,只需将其直接分配给地图即可:
if (c == '-') {
currentIntervalPtr = hyphen;
} else {
currentIntervalPtr = new Interval(string(1, c));
}
当从地图上查找区间时:
if (it_pre != intervals.end()) {
Interval* preInterval = it_pre->second;
consolidate(preInterval, currentIntervalPtr);
}
if (it_post != intervals.end()) {
Interval* postInterval = it_post->second;
consolidate(currentIntervalPtr, postInterval);
}
您还需要调整合并函数以使用单个指针:
auto consolidate = [&hyphen](Interval*& left, Interval*& right) {
// ... same as before
};
通过这些更改,您的间隔映射将正确存储和访问间隔,而无需双指针。代码会更简单,行为也将符合预期。
这里:
else { Interval* currentInterval = new Interval(string(1, c)); currentIntervalPtr = ¤tInterval; }
...您正在将该块的本地变量的地址分配给
currentIntervalPtr
。当块的执行终止时,该指针变量的生命周期结束,之后取消引用 currentIntervalPtr
会产生未定义的行为。
特别注意,指针变量的生命周期与其值所指向的已分配
Interval
对象的生命周期完全分开且独立。
我不太跟踪你想通过这里的双指针获得什么,但也许你可以将
Interval
指针存储在循环外部声明的向量中,而不是指向块范围变量的指针,并且使用指向该向量元素的指针。但我也认为,您可以使用 vector<Interval *>
和单指针来代替 vector<Interval>
和双指针。