Как мне прочитать массив структур из файла и отсортировать его?

0

Предисловие: рекомендации, установленные профессором, я должен использовать массив, а не какую-либо другую структуру данных. Его psuedo-код (который не очень краток) метода, которым мы должны следовать:

name and grade are read into a temporary location
loop from the end of the filled part of the array down to beginning {
if (new last name < current last name) {
   copy current name and grade down
}
else if (new/current last names are equal and new first name < current first name) {
   copy/assign current name and grade down
}
else {
   found right place, break out of loop
}
}
now that you've made room, insert (copy) new name into correct sorted position

Я вижу, что я, вероятно, нарушаю границы массива, пытаясь прочитать позицию массива [-1], но я не могу придумать, как избежать этого, поскольку я рассчитываю назад от количества элементов, которые у меня есть, и мне приходится сравнивать их.

Я читаю строки из текстового файла и сохраняю фрагменты каждой строки в структуре. Затем я использую алгоритм insert-sort-esque для хранения структур в алфавитном порядке. Тем не менее, мой массив, похоже, не заполняет первые строки линии новыми строками, просто перезаписывая предыдущие строки... Как будто один из моих тестов сравнения терпит неудачу, так как моя позиция копии никогда не меняется, хотя это может быть связано с тем, что начальное заполнение массива в некотором роде терпит неудачу. Я чувствую себя глупо, мне, должно быть, не хватает чего-то простого... Также мой модуль DisplayList, по-видимому, никогда не получает массив, который был заполнен чем угодно. Я неправильно изменяю массив?

Вот модуль с проблемой:

bool sortInput(ifstream &infile, StudentType students[], int size)
{
   StudentType temp;
   int copyToHere;

   if(size == 0)
   {
      infile >> temp.last >> temp.first >> temp.grade;
      strcpy(students[0].last, temp.last);
      strcpy(students[0].first, temp.first);
      students[0].grade = temp.grade;
      size++;
   } 

   while(infile)
   {
      infile >> temp.last >> temp.first >> temp.grade;
      //cout << "TEST" << temp.last << temp.first << temp.grade << endl;

      for(int i = size; i > 0; i--)
      {       
         if(strcmp(temp.last, students[i-1].last) < 0)
         {
            students[i] = students[i-1];
            students[i-1] = temp;
         }
         else if(strcmp(temp.last, students[i].last) == 0 && strcmp(temp.first, students[i].first) < 0)
         {
            students[i] = students[i-1];
         }
         else
         {
            break;
         }

         copyToHere = i;
      }

      cout << "Size = " << size << " and copy position = " << copyToHere << endl;
      students[copyToHere] = temp;
      size++;

      //test to see if array is populated properly
      for(int i = 0; i < size; i++)
      {
         cout << "Name is " << students[i].first << " " << students[i].last << " and grade is " << students[i].grade << endl;
      }

      cout << "DONE" << endl;

   } //end while loop

   return true;
}

Вот полный код (если необходимо по какой-либо причине или дальнейшему контексту):

// ----------------------------------------------------------------------------
// You write meaningful doxygen comments and assumptions

#include <string.h>
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;

int const MAXSIZE = 100;            // maximum number of records in total
int const MAXLENGTH = 31;           // maximum string length 
int const MAXGRADE = 100;           // highest possible grade
int const LOWGRADE = 0;             // lowest possible grade
int const GROUP = 10;               // group amount
int const HISTOGRAMSIZE = (MAXGRADE-LOWGRADE)/GROUP + 1;    // grouped by GROUP

struct StudentType  {               // information of one student
   int grade;                       // the grade of the student
   char last[MAXLENGTH];            // last name (MAXLENGTH-1 at most)
   char first[MAXLENGTH];           // first name (MAXLENGTH-1 at most)
};

// prototypes go here
bool sortInput(ifstream &, StudentType [], int);
void displayList(StudentType [], int);
/*setHistrogram();
displayHistogram();
findAverage();*/

//------------------------------- main ----------------------------------------
int main()  {
   StudentType students[MAXSIZE];   // list of MAXSIZE number of students
   int size = 0;                    // total number of students
   int histogram[HISTOGRAMSIZE];    // grades grouped by GROUP
   int average = 0;                 // average exam score, truncated

   // creates file object and opens the data file
   ifstream infile("data1.txt");
   if (!infile)  { 
      cout << "File could not be opened." << endl; 
      return 1;  
   }

   // read and sort input by last then first name
   bool successfulRead = sortInput(infile, students, size);              

   // display list, histogram, and class average 
   if (successfulRead)  {
      displayList(students, size);
     // setHistogram(... you figure parameters ...);
     // displayHistogram(... you figure parameters ...);
     // average = findAverage(... you figure parameters ...);
      cout << "Average grade: " << average << endl << endl;
   }
   return 0;
}

bool sortInput(ifstream &infile, StudentType students[], int size)
{
   StudentType temp;
   int copyToHere;

   if(size == 0)
   {
      infile >> temp.last >> temp.first >> temp.grade;
      strcpy(students[0].last, temp.last);
      strcpy(students[0].first, temp.first);
      students[0].grade = temp.grade;
      size++;
   } 

   while(infile)
   {
      infile >> temp.last >> temp.first >> temp.grade;
      //cout << "TEST" << temp.last << temp.first << temp.grade << endl;

      for(int i = size; i > 0; i--)
      {       
         if(strcmp(temp.last, students[i-1].last) < 0)
         {
            students[i] = students[i-1];
            students[i-1] = temp;
         }
         else if(strcmp(temp.last, students[i].last) == 0 && strcmp(temp.first, students[i].first) < 0)
         {
            students[i] = students[i-1];
         }
         else
         {
            break;
         }

         copyToHere = i;
      }

      cout << "Size = " << size << " and copy position = " << copyToHere << endl;
      students[copyToHere] = temp;
      size++;

      //test to see if array is populated properly
      for(int i = 0; i < size; i++)
      {
         cout << "Name is " << students[i].first << " " << students[i].last << " and grade is " << students[i].grade << endl;
      }

      cout << "DONE" << endl;

   } //end while loop

   return true;
}

void displayList(StudentType students[], int size)
{
   cout << "List of names sorted:" << endl;

   for(int i = 0; i < size; i++)
   {
      cout << " " << students[i].grade << " " << students[i].last << " " << students[i].first << endl;
   }
}

// ----------------------------------------------------------------------------
// functions with meaningful doxygen comments and assumptions go here
Теги:
arrays
insertion-sort

2 ответа

1
Лучший ответ

Ваша сортировка вставки действительно не вставляется правильно. Давайте рассмотрим одну часть вашего основного цикла вставки:

   if(strcmp(temp.last, students[i-1].last) < 0)
     {
        students[i] = students[i-1];
        students[i-1] = temp;
     }

Намерение этого, очевидно, заключается в том, чтобы вставить temp в массив в позиции i-1. Вы меняете элемент на i-1 на i но что случилось с другими элементами массива? Вам нужно переместить их на одну позицию, чтобы освободить место для вставленного элемента. Что-то вроде:

memmove(students + i, students + i - 1, sizeof(students[0]) * size - i - 1);

У вас также есть другие проблемы в коде. copyToHere потенциально неинициализирован. Вы копируете temp в массив несколько раз (students[i-1] = temp; и students[copyToHere] = temp; не нужны оба). После того, как вы сделали вставку во внутреннем цикле, вы должны выйти. Ваша специальная обработка, когда список пуст, действительно не требуется, и так далее.

Посмотрите на псевдокод для алгоритма сортировки вставки и посмотрите, можете ли вы упростить и переписать свой код для устранения проблем.

  • 0
    Ура думаю, что я нашел решение. Идея этого оператора if заключается в том, что, поскольку я начинаю с конца моего текущего списка элементов, он будет сдвигать каждый элемент, который необходимо сместить, чтобы освободить место для текущего временного элемента. Я понял, что оператор else - это то, где должна быть фактическая вставка, и поэтому я ломаю, потому что в этот момент я сохранил temp, куда она должна идти. Я отправил свой новый код ниже в качестве ответа, если вы хотите критиковать, но, похоже, он работает должным образом, поскольку массив заполняется всеми именами (хотя он удваивает фамилию).
  • 0
    Одна проблема, которую я не решил, состоит в том, что мой массив не передается другим модулям, правильно заполненным ... кажется, он заполняется только в этом модуле сортировки. Есть идеи для этого?
Показать ещё 6 комментариев
0

Решение моей собственной проблемы ха-ха. Я был глуп, потому что не выполнил другое выражение должным образом. Теперь я работаю над повторением моих сопоставлений с именами, поскольку что-то кажется неправильным, так как он не упорядочивает одинаковые фамилии в алфавитном порядке.

УРОК УЗНАЙТЕ: Уберите все, прежде чем думать, что вы раздвоены. Теперь я действительно чувствую себя идиотом, надеюсь, не тратил много времени на поиски.

  for(int i = size; i > 0; i--)
  {       
     if(strcmp(temp.last, students[i-1].last) < 0)
     {
        students[i] = students[i-1];
        students[i-1] = temp;
     }
     else if(strcmp(temp.last, students[i].last) == 0 && strcmp(temp.first, students[i].first) < 0)
     {
        students[i] = students[i-1];
        students[i-1] = temp;
     }
     else
     {
        students[i] = temp;
        break;
     }

     insertHere = i;
  }

Ещё вопросы

Сообщество Overcoder
Наверх
Меню