我试图比较3种算法排序所花费的时间:对于合并排序,我使用struct实现了链表,用于就地排序--只切换每个节点的地址,而不复制和粘贴数据。
然而,当目标数组大小超过特定的数字时(大约在130760~130770之间),它会在递归调用merge方法时抛出错误EXC_BAD_ACCESS(代码= 2,地址=...)。大小确实很重要,因为较小的大小不会重现异常。
合并排序类的代码如下:
template <typename T>
class MergeSort {
private:
struct Node {
T data;
Node* next;
Node(T d) : data(d), next(nullptr) {}
};
Node* head;
int size;
long count = 1;
void split(Node** head, Node** left, Node** right) {
Node* fast = *head;
Node* slow = *head;
while (fast->next && fast->next->next) {
fast = fast->next->next;
slow = slow->next;
}
*left = *head;
*right = slow->next;
slow->next = nullptr;
}
Node* merge(Node* left, Node* right) {
Node* result = nullptr;
count++;
if (!left) return right;
if (!right) return left;
if (left->data <= right->data) {
result = left;
result->next = merge(left->next, right);
} else {
result = right;
result->next = merge(left, right->next);
}
return result;
}
void mergeSort(Node** headRef) {
Node* head = *headRef;
Node* left = nullptr;
Node* right = nullptr;
if (!head || !head->next) return;
split(&head, &left, &right);
mergeSort(&left);
mergeSort(&right);
*headRef = merge(left, right);
}
public:
MergeSort() : head(nullptr), size(0) {}
void insert(T data) {
Node* newNode = new Node(data);
newNode->next = head;
head = newNode;
size++;
}
void sort() {
mergeSort(&head);
std::cout << "Total merge count: " << count << std::endl;
}
void override(T arr[]) {
Node* current = head;
int i = 0;
while (current) {
arr[i++] = current->data;
current = current->next;
}
}
};
该异常来自读取MergeSort示例本身的错误地址。
enter image description here
在本例中,"this"的实际地址为0x16d4a3448,尝试读取的地址为0x16cca7ff0。
我发现在抛出错误时,这两个地址的差总是十进制数8369240,这是一个非常有趣的数字。
当指向null的节点靠近"右-〉下一个"时,也总是出现这个问题。
我也试过改变数组元素的类型,但是没有改变数组的临界大小,所以堆栈溢出可能不是问题所在。
似乎由于某种原因,如果数组的大小超过某个固定值,它会读取错误的示例地址,但我不知道为什么会发生这种情况。
供您参考,我目前正在M1 macbook air上使用Clion 2022.3.1。
我试着改变元素的类型并监视right-〉next指向什么,但这两种方法对临界大小的影响都不大。
我还在Clion做了另一个项目,它稍微改变了临界尺寸,不是很大。
我发现使用lldb的AddressSanitizer对监控内存泄漏有帮助,但是我不知道如何使用它,如果你能给我一些信息的话。(我对调试工具不太友好,因为我不是CS专业的,只是初学者)
先谢谢你。
1条答案
按热度按时间7gyucuyw1#
merge函数为每个合并的节点调用自身。这将导致大型列表的堆栈溢出。请将merge()更改为迭代。