数据结构分配

问题描述

我的 CS 类(数据结构)中有一个作业,但我不断收到上述错误。 基本上我需要在 C++ 中编写代码,其中用户给出了一些链表,然后程序获得一个随机链表大小(从 100 到 200)以及一个随机元素(从 0 到 50)来添加链接中列出自己。目标是创建一个名为 output 的最终数组,其中的链表元素至少出现在给定列表的一半或一半以上(每个列表必须对每个元素计数一次)。 我收到一个错误(进程以退出代码 134 结束(被信号 6 中断:SIGABRT) 为什么我收到这个错误? 谢谢。

#include <iostream>
#include <random>
#include <functional>
#include <stdlib.h>
using namespace std;
struct node{
    int data;
    node*next;
};
class linkedlistCreation{
private:node*head,*tail;
public:linkedlistCreation()
    {
        head=NULL;
        tail=NULL;
    }
    void addnode(int random){
        node*tmp=new node;
        tmp->data=random;
        tmp->next=NULL;
        if(head==NULL){
            head=tmp;
            tail=tmp;
        }else{
            tail->next=tmp;
            tail=tail->next;
        }

    }

};


int main() {
    linkedlistCreation a;
    int k;
    int i;
    int j;
    int listsize;
    int element;
    default_random_engine generator;
    uniform_int_distribution<int> list_size_distribution(100,200);
    uniform_int_distribution<int> data_element_distribution(0,50);
    auto random_list_size = bind(list_size_distribution,generator);
    auto random_element = bind(data_element_distribution,generator);
    cout << "Give number of lists:" ;
    cin >> k;
    int NumbersList[50]={0};
    int CheckingList[50]={0};
    for(i=0;i<k;i++){
        listsize=random_list_size();
        CheckingList[50]={0};//Initializing the checking List

        for(j=0;j<=listsize;j++){
            element=random_element();
            cout<<element<<endl;
            a.addnode(element);
            if (CheckingList[element]==0){
                NumbersList[element]=NumbersList[element]+1;
                CheckingList[element]=CheckingList[element]+1;
            }
        }


  

//    for (i=0;i<k;i++){
//        if(NumbersList[i]>=k/2){
//             output[i]=i;
//             cout<<output[i]<<endl;
//
//        }
//
//
//    }
    return 0;






}



解决方法

关于分配值得预先了解的是,当列表大小在 [100,200] 范围内时,范围 [0,50] 中的每个数字都将很容易出现在至少一半的列表中。对于尽可能小的列表,如果我要手动均匀分配数字,我会简单地从 0 开始并写入每个连续的数字。这意味着每个数字将在每个列表中出现一次。让它随机,一个数字有可能永远不会成功,但它很低。所以所需的输出似乎毫无意义。

如果我们只关注所需的输出,链表是一种糟糕的方法。进一步分解:

  • 在 [0,50] 范围内生成 'n' 个随机数序列。
  • 注意每个序列中出现的数字
  • 跟踪某个数字在任何序列中出现的次数
  • 输出出现在至少一半序列中的数字(基本上是每个数字)

我将使用 std::set 代替链表。它是有序的,更重要的是,每个元素都是唯一。使用 std::set 消除了处理重复项的需要。

然后我在 std::map<int,int> 中保持计数,其中键是 [0,50] 范围内的数字,键值是出现在 'n' 个序列中的该数字的计数。

最后,打印很容易。我只是通过地图看看计数是否合格。

#include <iomanip>
#include <iostream>
#include <map>
#include <random>
#include <set>
#include <string>
#include <vector>

int main() {
  std::mt19937 prng(std::random_device{}());
  std::uniform_int_distribution<int> list_size(100,200);
  std::uniform_int_distribution<int> element_range(0,50);

  int num;
  std::cout << "Number: ";
  std::cin >> num;

  std::map<int,int> intCountPerList;
  for (int i = 0; i < num; ++i) {
    int size = list_size(prng);
    std::set<int> s;

    for (int j = 0; j < size; ++j) {
      s.insert(element_range(prng));
    }

    for (auto num : s) {
      ++intCountPerList[num];
    }
  }

  std::cout << "Numbers that appeared in at least half of the 'lists': \n";
  int numLength = std::to_string(num).length();
  for (auto count : intCountPerList) {
    if (count.second >= num / 2) {
      std::cout << std::setw(numLength) << count.first << ": " << count.second
                << " times.\n";
    }
  }
}

如果需要使用链表,程序基本不变。您只需添加生成列表的额外工作,然后将列表中的值添加到 std::set。如果您不想使用 std::set,则需要手动计算每个列表中的每个数字。这只是增加了不必要的中间人工作,但它是可行的。

在我继续之前,我有一个关于太多人在 C++ 中学习链表的方式的小咆哮。这是不对的。如果 C++ 是您的语言,请使用它。创建一个类,添加迭代器,使其成为模板类。链表是 RAII 等 C++ 中许多原则和实践的结晶,但它们都被抛弃了,因为我们将把全局可见的 struct 和一些免费函数称为“数据结构”。这真的很烦人。大吼大叫。

我的列表是双向链接的,主要原因是它的效果大约是原来的两倍 :-P。严肃地说,使用双向链表编写许多操作要容易得多。管理额外的指针需要付出很小的代价。它还具有迭代器,允许预期的遍历。这意味着我可以使用基于范围的 for 循环。此列表并不完整,但我保留了它,主要用于 SO 答案。

#ifndef MY_LIST_HPP
#define MY_LIST_HPP

#include <algorithm>  // std::swap
#include <cstddef>  // std::size_t

/*
 * Pre-declare template class and friends
 */
template <typename T>
class List;

template <typename T>
void swap(List<T>& lhs,List<T>& rhs);

/*
 * List Class Declaration
 */
template <typename T>
class List {
 public:
  List() = default;
  List(T val);
  List(const List& other);
  List(List&& other);
  ~List();

  void push_front(T val);
  void push_back(T val);

  class iterator;
  iterator begin();
  iterator end();
  // iterator find(T val);

  std::size_t size() const;

  iterator erase(iterator toErase);  // Implement
  void clear();
  bool operator=(List other);
  friend void swap<T>(List& lhs,List& rhs);

 private:
  struct Node {
    T data;
    Node* prev = nullptr;
    Node* next = nullptr;

    Node(T val) : data(val) {}
  };

  Node* m_head = nullptr;
  Node* m_tail = nullptr;
  std::size_t m_size = 0;

  // Helper functions
  void make_first_node(T val);
  Node* find_node(T val);
};

/*
 * List Iterator Declaration
 */
template <typename T>
class List<T>::iterator {
 public:
  iterator() = default;
  iterator(List<T>::Node* node);  // minimum
  T& operator*();                 // minimum
  iterator& operator++();         // minimum
  iterator operator++(int);
  iterator& operator--();
  iterator operator--(int);
  bool operator==(const iterator& other);  // minimum
  bool operator!=(const iterator& other);  // minimum
 private:
  Node* m_pos = nullptr;
};

/*
 * List Implementation
 */
template <typename T>
List<T>::List(T val) : m_head(new Node(val)),m_tail(m_head),m_size(1) {}

template <typename T>
List<T>::List(const List<T>& other) {
  m_head = new Node((other.m_head)->data);
  m_tail = m_head;
  m_size = 1;

  Node* walker = (other.m_head)->next;
  while (walker) {
    push_back(walker->data);
    ++m_size;
    walker = walker->next;
  }
}

template <typename T>
List<T>::List(List&& other) : List() {
  swap(*this,other);
}

template <typename T>
List<T>::~List() {
  clear();
}

template <typename T>
void List<T>::push_front(T val)
{
  if (!m_head) {
    make_first_node(val);
    return;
  }

  Node* tmp = new Node(val);
  tmp->next = m_head;
  m_head->prev = tmp;
  m_head = tmp;
  ++m_size;
}

template <typename T>
void List<T>::push_back(T val) {
  if (!m_head) {
    make_first_node(val);
    return;
  }

  Node* tmp = new Node(val);
  tmp->prev = m_tail;
  m_tail->next = tmp;
  m_tail = tmp;
  ++m_size;
}

template <typename T>
typename List<T>::iterator List<T>::begin() {
  return iterator(m_head);
}

template <typename T>
typename List<T>::iterator List<T>::end() {
  return iterator(nullptr);
}

// template <typename T>
// typename List<T>::iterator List<T>::find(T val) {
//   return iterator(find_node(val));
// }

template <typename T>
std::size_t List<T>::size() const {
  return m_size;
}

template <typename T>
typename List<T>::iterator List<T>::erase(typename List<T>::iterator toErase)
{
  Node* node = find_node(*toErase);

  if (node->prev) {
    node->prev->next = node->next;
  } else {
    m_head = node->next;
  }

  if (node->next) {
    node->next->prev = node->prev;
  } else {
    m_tail = node->prev;
  }

  Node* toReturn = node->next;
  delete node;

  return toReturn;
}

template <typename T>
void List<T>::clear() {
  Node* tmp = m_head;
  while (m_head) {
    m_head = m_head->next;
    delete tmp;
    tmp = m_head;
  }
  m_tail = nullptr;
  m_size = 0;
}

template <typename T>
bool List<T>::operator=(List other) {
  swap(*this,other);

  return *this;
}

template <typename T>
void List<T>::make_first_node(T val) {
  m_head = new Node(val);
  m_tail = m_head;
  m_size = 1;
}

template <typename T>
typename List<T>::Node* List<T>::find_node(T val) {
  if (!m_head) {
    return nullptr;
  }

  Node* walker = m_head;
  while (walker != nullptr && walker->data != val) {
    walker = walker->next;
  }

  return walker;
}

template <typename T>
void swap(List<T>& lhs,List<T>& rhs) {
  using std::swap;

  swap(lhs.m_head,rhs.m_head);
  swap(lhs.m_tail,rhs.m_tail);
  swap(lhs.m_size,rhs.m_size);
}

/*
 * List Iterator Implementation
 */
template <typename T>
List<T>::iterator::iterator(Node* node) : m_pos(node) {}

template <typename T>
T& List<T>::iterator::operator*() {
  return m_pos->data;
}

template <typename T>
typename List<T>::iterator& List<T>::iterator::operator++() {
  m_pos = m_pos->next;

  return *this;
}

template <typename T>
typename List<T>::iterator List<T>::iterator::operator++(int) {
  iterator tmp(m_pos);
  ++(*this);

  return tmp;
}

template <typename T>
typename List<T>::iterator& List<T>::iterator::operator--() {
  m_pos = m_pos->prev;

  return *this;
}

template <typename T>
typename List<T>::iterator List<T>::iterator::operator--(int) {
  iterator tmp(m_pos);
  --(*this);

  return tmp;
}

template <typename T>
bool List<T>::iterator::operator==(const iterator& other) {
  return m_pos == other.m_pos;
}

template <typename T>
bool List<T>::iterator::operator!=(const iterator& other) {
  return !(*this == other);
}

#endif

是的。而且还不完整。公平地说,这也不算太远。

这是修改后的 main() 函数:

#include "niceList.hpp"
#include <iomanip>
#include <iostream>
#include <map>
#include <random>
#include <string>
#include <vector>

int main() {
  std::mt19937 prng(std::random_device{}());
  std::uniform_int_distribution<int> list_size(100,int> intCountPerList;
  for (int i = 0; i < num; ++i) {
    int size = list_size(prng);
    List<int> list;

    for (int j = 0; j < size; ++j) {
      list.push_back(element_range(prng));
    }

    int occurences[51]{0};
    for (auto num : list) {
      ++occurences[num];
    }

    for (int idx = 0; idx < 51; ++idx) {
      if (occurences[idx] > 0) {
        ++intCountPerList[idx];
      }
    }

  }

  std::cout << "Numbers that appeared in at least half of the 'lists': \n";
  int numLength = std::to_string(num).length();
  for (auto count : intCountPerList) {
    if (count.second >= num / 2) {
      std::cout << std::setw(numLength) << count.first << ": " << count.second
                << " times.\n";
    }
  }
}

如果您只是并排比较 main() 函数,您可以看到这个函数所做的毫无意义的额外工作。我再次被诱惑跳过列表并直接进入计数数组。链表对于这个任务绝对是浪费时间和精力。如果您需要自己编写列表,我们讨论的是 40 行程序与至少 2-3 行的程序。而且启动效率要低得多。

,

SIGABRT 被许多库用于在发生严重或致命错误(在运行时产生)时中止程序。但是,在您的情况下,问题出在“CheckingList”上。一个非常简单的解决方法是在块之外定义它。