C++删除链表数组

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)

最大的问题是你实际上没有链表。你有一个节点结构,你正试图将节点串在一起,但你缺少一个实际的 class 来为你维护你的数据结构。

当然,当您尝试删除数组时,只会删除每个索引的第一个节点。您有零代码来处理删除整个列表。

下面是一个链表的简短示例 class。它缺少相当多的功能,但足以展示一些良好的实践及其工作原理。

#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 是一个 class,表示整数的单链表。数据成员 m_headm_tail 分别表示列表的开头和结尾。 m_tail 是可选的,但我发现如果您知道列表的结尾位置,它会让生活变得更轻松。当涉及到从中间擦除时,双向链表也让你的生活变得更容易,而且它们也没有那么难写。

列表由节点组成,其中一个节点指向下一个节点的位置。你已经知道了。

解决您问题的关键函数是析构函数,~IntList()。仔细检查该功能。注意它是如何在你的整个列表中移动的,随着它的移动删除每个节点。 这就是您所缺少的。 那,以及完成所有这些的实际列表 class。

因为每个IntList对象都有自己的内存,所以我只需要删除动态数组。当数组销毁自身时,它会调用每个元素的析构函数。这意味着在每个 IntList 元素自己清理完之后,数组内存就会被删除。没有泄漏,也没有双重释放。

有助于理解数据结构的最重要的事情就是把它画出来。

我提到的良好做法是 5 函数法则(Rule of 0/3/5)和复制交换惯用语。 5 的规则是必要的,因为链表 class 正在管理动态资源。主要功能是充分利用复制构造函数。请注意,该数组包含列表的副本。如果我不想要副本,我必须将数组声明为双指针并分配一个指向 IntLists 的指针数组。 IntList 将在主函数结束时自行清理。

copy-swap 惯用语只会让生活更轻松并减少代码重复。