NephalemGuard
NephalemGuard

Reputation: 1

How can I make a sorted structure in C++ when I have more input data in more than one array?

I need to make a sorted list/struct by years, but i dont know how to make it. Here is some data, for example the first data from each array: year: 2010 month: 1 and the temp was -10.4C. I just start learning the C++, but it caught me. Btw. sorry for my Eng.

#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

const int LENGTH = 24;

struct list
{
    int year;
    int month;
    double temp;
    list *next;
};

int main()
{
    int year[LENGTH]={2010, 2010, 2011, 2011, 2011, 2017, 2017, 2016, 2016, 2016, 2015, 2015, 2013, 2013, 2012, 2011, 2015, 2016, 2017, 2011, 1013, 2014, 2015, 2016 };
    int month[LENGTH]={1 , 2 , 1 , 2 , 3 , 7, 8, 2, 6, 7, 3, 5, 10, 11, 12, 5, 6, 10, 10, 11, 12, 4, 11, 12 };
    double temp[LENGTH]={-10.4,-2.8, -5.1,-2.1, 3.5 , 30.9, 35.7, -7.3, 20.3, 34.2, 6.2, 15.4,10.13, 1.56,-12.7, 15.8, 16.2, 0.21, 9.9, 4.4, -3.3, 4.7, 0, 20.4 };

//i can only make this

list *pStart = NULL, *pNext;
list *p;

for (int index = 0; index<LENGTH; index++) {
     p->year = year[index];
     p->month = month[index];
     p->temp = temp[index];
     p = p->next;
}

//and here need to print it after sort
//Just an idei sort(years) and after it upload/fill the struct or do you know a better way?
}

Upvotes: 0

Views: 85

Answers (1)

BitTickler
BitTickler

Reputation: 11875

Starting to learn a new language is always quite some work. With C++, the heritage of C adds to the learning curve, as there is the old (C) way and a newer (C++) way to do things. Yes, you can write C++ programs which are quite C-like. But then you do not reap the benefits of what C++ has to offer.

Namely:

  • A much more comprehensive standard library.
  • Less need for dangerous stuff like pointers.
  • A bunch of useful out-of-the-box data types (collections, ...).

If it is not part of an assignment (e.g. homework), the default collection type a C++ programmer considers first is a std::vector<T>. Unless you know it is always fixed and same size and you need that extra dose of performance. Then you would use std::array<T,N>, probably. Only for special cases and when you have good reason and probably profiling data to back up the decision, would you consider list based containers, instead. (std::dequeue,...).

As for the sorting, there is std::sort() in the algorithm header file at your disposal, which comes in a bunch of overloads. One of the overloads lets you specify the comparison function to apply during the sorting. Given you want to sort your data just by year, while there is more data in the struct, this is what you want.

Below, please find the code I came up with which - I hope - does what you want.

#include <iostream>
#include <cstdint>
#include <vector>
#include <algorithm>

template <class T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& value) {
  os << "vector(" << value.size() << "):" << std::endl << "{";
  if (value.size() > 0) {
    os << value[0];
  }
  for ( size_t i = 1; i < value.size(); ++i) {
    os << ", " << value[i];
  }
  os << "}";
  return os;
}

struct DataPoint {
  uint16_t year;
  uint8_t month;
  double temp;
  DataPoint( uint16_t y, uint8_t m, double t)
    : year{y}
    , month{m}
    , temp{t}
  {}
  DataPoint(const DataPoint& other)
    : year{other.year}
    , month{other.month}
    , temp{other.temp}
  {}
};

std::ostream& operator<<(std::ostream& os, const DataPoint& value) {
  os << "DataPoint: {"
     << value.year << ", "
     << (int)value.month << ", " // cast needed because iostream stupid.
     << value.temp << "}";
  return os;
}

using DataSet = std::vector<DataPoint>;

bool initDataSet(DataSet& target) {
  constexpr size_t LENGTH = 24;
  target.clear();
  target.reserve(LENGTH);
  uint16_t year[LENGTH]=
    {2010, 2010, 2011, 2011, 2011, 2017, 2017, 2016, 2016,2016,
     2015, 2015, 2013, 2013, 2012, 2011, 2015, 2016, 2017, 2011,
     1013, 2014, 2015, 2016 };
  uint8_t month[LENGTH]=
    {1 , 2 , 1 , 2 , 3 , 7, 8, 2, 6, 7,
     3, 5, 10, 11, 12, 5, 6, 10, 10, 11,
     12, 4, 11, 12 };
  double temp[LENGTH]=
    {-10.4,-2.8, -5.1,-2.1, 3.5 , 30.9, 35.7, -7.3, 20.3, 34.2,
     6.2, 15.4,10.13, 1.56,-12.7, 15.8, 16.2, 0.21, 9.9, 4.4,
     -3.3, 4.7, 0, 20.4 };
  for (size_t i=0; i < LENGTH; ++i) {
    target.push_back(DataPoint(year[i], month[i], temp[i]));
  }
  return true;
}

int main(int argc, const char* argv[]) {
  DataSet data;
  if (initDataSet(data)) {
    std::cout
      << "Before sorting"
      << std::endl
      << data << std::endl;

    std::sort(data.begin(),data.end(),
          [](const DataPoint& a, const DataPoint& b) -> bool {
        return a.year < b.year;
          });

    std::cout
      << "After sorting"
      << std::endl
      << data << std::endl;
  }
  return 0;
}

It also shows the standard way to make ìostream output your data types in whatever deems you appropriate.

As an exercise, you can try to re-write this code to use a std::forward_list<T> instead of the vector. You cannot use std::sort(), then because a singly linked list only has a forward iterator and not a random access iterator. But luckily, you will find, that std::forward_list<T> has a member function named sort(). So, the rewrite will be rather minimal.

Upvotes: 1

Related Questions