【问题标题】:Data Structures Assignment数据结构分配
【发布时间】:2021-04-15 16:13:07
【问题描述】:

我在我的 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;






}



【问题讨论】:

  • a.cpp:49:9: 错误:'CheckingList' 未在此范围内声明
  • 您在此处显示的代码does not compile。请edit您的问题以显示您正在运行的真实代码。
  • 样式建议:将循环变量保留在循环中。对bind() 的调用不太理想。直接调用分布,或者我们调用 lambda。
  • “是的,我删除了一些行...这不是问题”。通过删除这些行,没有其他人可以重现您的确切问题。请edit 这个问题包括minimal reproducible example。考虑一下您不确定问题出在哪里的可能性。
  • CheckingList[50]={0};//Initializing the checking List 是未定义的行为。它尝试将大小为 50 的数组中的第 51 项设置为 0。它不会将有效元素重置为 0。

标签: c++ data-structures linked-list clion


【解决方案1】:

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

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

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

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

然后我将计数保存在 std::map&lt;int, int&gt; 中,其中键是 [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++ 是您的语言,请使用它。创建一个类,添加迭代器,使其成为模板类。链表是 C++ 中许多原则和实践(如 RAII)的结晶,但由于我们将全局可见的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, 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);
    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 行。而且启动效率要低得多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 2020-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多