[英]Deleting an array of linked list in c++
我創建了存儲桶來插入我的數據,除了刪除所有節點外,一切正常。 如果我使用delete[] container
刪除我的容器,那么只會刪除我所有鏈表的第一個節點。 我認為我所做的是合乎邏輯的,但它不起作用。 你能告訴我為什么嗎?(只有函數的最后一個循環值得關注,其他代碼供參考。)
#include <iostream>
#include <cmath>
using namespace std;
struct bucket{
int val;
bucket* next;
};
int countDigit(int max){
int digits = 0;
while(max>0){
max = max/10;
digits++;
}
return digits;
}
int findMax(int* arr, int l, int r){
int max = arr[l];
for(int i = l+1; i<=r; i++){
if(max<arr[i]){
max = arr[i];
}
}
return max;
}
void createBucket(int* arr, int l, int r){
int max = findMax(arr, l, r);
int digits = findDigit(max);
int divide = pow(10, digits-1);
int maxPos = max/divide;
int pos;//position of elements in the container
bucket* container = new bucket[maxPos+1];
bucket* cursor;
//copying elements to their respective buckets
for(int i=l; i<=r; i++){
pos = arr[i]/divide;
if(container[pos].val == 0){
container[pos].val = arr[i];
container[pos].next = NULL;
}
else{
bucket* node = new bucket;
cursor = &container[pos];
node->val = arr[i];
while(cursor->next!=NULL){
cursor = cursor->next;
}
cursor->next = node;
node->next = NULL;
}
}
//copying the elements from the buckets to their respective position
int j = 0;
for(int i = 0; i<maxPos+1; i++){
cursor = &container[i];
while(cursor!=NULL && cursor->val!=0){
arr[j] = cursor->val;
cursor = cursor->next;
j++;
}
}
//deleting all nodes
bucket* tmp;
for(int i= 0; i<maxPos+1; i++){
cursor = &container[i];
while(cursor!=NULL){
tmp = cursor;
cursor = cursor->next;
delete tmp;
}
}
}
它給出如下錯誤:
double free or corruption (out)
Aborted (core dumped)
最大的問題是您實際上沒有鏈表。 您有一個節點結構,並且您正在嘗試將節點串在一起,但是您缺少一個實際的類來為您維護您的數據結構。
自然,當您嘗試刪除數組時,只會刪除每個索引的第一個節點。 您有零個代碼來處理刪除整個列表。
下面是一個鏈表類的簡短示例。 它缺少相當多的功能,但它足以展示一些好的實踐以及它是如何工作的。
#include <iostream>
class IntList {
public:
IntList() = default;
~IntList(); // Rule of 5
IntList(const IntList& other); // Rule of 5
IntList(IntList&& other) noexcept; // Rule of 5
IntList& operator=(IntList other); // Rule of 5
IntList& operator=(IntList&& other); // Rule of 5
void push_back(int value);
void print() const; // Only here for ease of demo
friend void swap(IntList& lhs, IntList& rhs);
private:
struct Node {
int m_key = 0;
Node* m_next = nullptr;
Node(int key) : m_key(key) {}
};
Node* m_head = nullptr;
Node* m_tail = nullptr;
};
IntList::~IntList() {
while (m_head) {
Node* tmp = m_head;
m_head = m_head->m_next;
delete tmp;
}
m_head = nullptr;
m_tail = nullptr;
}
IntList::IntList(const IntList& other) {
if (other.m_head) {
// Set up first node
this->m_head = new Node(other.m_head->m_key);
m_tail = m_head;
Node* otherWalker = other.m_head->m_next;
while (otherWalker) { // Handles the rest of the nodes
m_tail->m_next = new Node(otherWalker->m_key);
m_tail = m_tail->m_next;
otherWalker = otherWalker->m_next;
}
}
}
IntList::IntList(IntList&& other) noexcept : IntList() { swap(*this, other); }
IntList& IntList::operator=(IntList other) {
swap(*this, other);
return *this;
}
IntList& IntList::operator=(IntList&& other) {
swap(*this, other);
return *this;
}
void IntList::push_back(int value) {
Node* tmp = new Node(value);
if (!m_head) {
m_head = tmp;
m_tail = m_head;
return;
}
m_tail->m_next = tmp;
m_tail = tmp;
return;
}
void IntList::print() const {
Node* walker = m_head;
if (!walker) {
std::cout << "Empty List.\n";
}
while (walker) {
std::cout << walker->m_key << (walker->m_next ? ' ' : '\n');
walker = walker->m_next;
}
}
void swap(IntList& lhs, IntList& rhs) {
using std::swap;
swap(lhs.m_head, rhs.m_head);
swap(lhs.m_tail, lhs.m_tail);
}
int main() {
IntList one;
one.push_back(42);
one.push_back(55);
IntList two(one);
IntList three;
three.push_back(350);
three.push_back(240);
three.push_back(609);
IntList four(three);
four.push_back(666);
// While I can appreciate learning, there's no reason for a dynamically
// allocated array. SO trope of use a vector instead applies here. NOTE: a
// vector would not have helped with your code, it just takes away your
// responsibility to delete the array later. You'd still leak memory.
IntList* const container = new IntList[4];
container[0] = one;
container[1] = two;
container[2] = three;
container[3] = four;
for (int i = 0; i < 4; ++i) {
container[i].print();
}
delete[] container;
}
IntList
是一個表示整數單鏈表的類。 數據成員m_head
和m_tail
代表列表的開頭和結尾。 m_tail
是可選的,但我發現如果你知道列表的結尾,它會讓生活更輕松。 當涉及到從中間擦除時,雙向鏈表也讓你的生活變得更輕松,而且它們並沒有那么難寫。
該列表由節點組成,其中一個節點指向下一個節點的位置。 你已經有了這個。
解決您的問題的關鍵函數是析構函數~IntList()
。 仔細檢查該函數。 注意它是如何在你的整個列表中移動的,刪除每個節點。 這就是你所缺少的。 那和實際的列表類來完成所有這些。
因為每個IntList
對象都照顧自己的內存,所以我只需要刪除動態數組。 當數組自毀時,它會調用每個元素的析構函數。 這意味着在每個IntList
元素在其自身之后清除之后,然后刪除數組內存。 沒有泄漏,也沒有雙重釋放。
有助於理解數據結構的最重要的事情就是將其繪制出來。
我提到的良好實踐是 5 函數規則(0/3/5 規則)和復制交換習語。 規則 5 是必要的,因為鏈表類正在管理動態資源。 main 函數充分利用了復制構造函數。 請注意,該數組包含列表的副本。 如果我不想要副本,則必須將數組聲明為雙指針並將指針數組分配給IntLists
。 IntList
將在主函數結束時自行清理。
復制交換習語只是讓生活更輕松並減少代碼重復。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.