정리필요2

실습8

ShineWithMe 2008. 9. 1. 23:24

#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//#define COMPARE(x, y) (((x)<(y)) ? -1:((x)==(y)) ? 0:1)
const int MAXNAME = 20;
const int MAXSIZE = 10;

class StudentRecord
{
private:
 int sno;
 string sname; // 또는 char sname[MAXNAME] 사용
 float score;
public:
 StudentRecord() {;}
 StudentRecord(int no, string name, float s) {sno=no, sname=name, score=s;}
 void setSno(int no) {sno = no;}
 void setSname(string name) {sname = name;}
 void setScore(float s) {score = s;}
 int getSno() const {return sno;}
 string getSname() const {return sname;}
 float getScore() const {return score;}
 void readFromFile(fstream&);
 void writeToFile(fstream&);
 void printRecord(ostream&);
 int size();
};
void StudentRecord::writeToFile(fstream& BinOut)// 이진파일에 쓰기
{
 BinOut.write((char*) &sno, sizeof(int));    // 4
 int namelen = (int)sname.length();     
 BinOut.write((char*) &namelen, sizeof(int));   // 4
 BinOut.write(sname.c_str(), (std::streamsize)namelen); // sname.length()
 BinOut.write((char*) &score, sizeof(float));   // 4
}

void StudentRecord::readFromFile(fstream& Bin)// 이진파일 읽기
{
 int len;
 Bin.read((char*) &sno, sizeof(int));  // 4
 Bin.read((char*) &len, sizeof(int));  // 4
 char* name = new char[len+1];
 Bin.read(name, (std::streamsize)len);  // sname.length()
 name[len] = '\0';
 sname = name;
 Bin.read((char*) &score, sizeof(float)); // 4
}

void StudentRecord::printRecord(ostream&)// 화면에 출력
{
 // 채워야 할 부분
 cout << sno <<'\t'<< sname <<'\t'<< score <<endl;
}

int StudentRecord::size()
{
 return sizeof(sno) + sizeof(int) + (int)sname.length() + sizeof(score);
}

class KeyIndex
{
private:
 int key;
 int Offset;
 //int RRN;
public:
 KeyIndex() {;}
 KeyIndex(int k, int r) {key = k, Offset = r;}
 void Set(int k, int r) {key = k, Offset = r;}
 int getKey() const {return key;}
 int getOffset() const {return Offset;}
 void readFromFile(fstream& Bin);
};
void KeyIndex::readFromFile(fstream& Bin)// 이진파일 읽기
{
 // 가변길이로
 Bin.read((char*) &key, sizeof(int));  // 4
 Bin.read((char*) &Offset, sizeof(int));  // 4
}


template <class Type>
class Sort
{
private:
 void exchange(Type &a, Type &b);
public:
 void bubble(StudentRecord *data, int n);
};

template <class Type> //버블소트로 인덱스정렬
void Sort<Type>::bubble(StudentRecord *data, int n)
{

 int i=0, j=0;
  for(i=0; i<n; i++)
   for(j=0; j<n; j++)
    if(data[i].getSno() < data[j].getSno())
     exchange(data[i], data[j]);
}

template <class Type> // 교환함수
void Sort<Type>::exchange(Type &a, Type &b)
{
 Type c;
 c=a;
 a=b;
 b=c;
}

int compare(int x, int y)
{
 if(x < y) return -1;
 else if (x==y) return 0;
 else return 1;
}

int binarySearch(fstream& index, int key, int smax)
{
 //KeyIndex *R = new KeyIndex[smax];
 KeyIndex R[MAXSIZE];
 for(int i=0; i<smax; i++)
  R[i].readFromFile(index);

 int middle, left, right;
 int offset=0;

 left=0;
 right=smax-1;
 
 while(left <= right)
 {
  middle = (left+right)/2;
  switch (compare(R[middle].getKey(), key))
  {
  case -1 : left = middle + 1;
   break;
  case 0 : return R[middle].getOffset(); 
  case 1 : right = middle - 1;
  }
 }
 return -1;
}



int main(int argc, char* argv[])
{
 StudentRecord S[MAXSIZE], R[MAXSIZE];
 string sname; // 레코드저장할임시변수
 int sno;
 float score;

 // 루프 변수

 ifstream textin(argv[1]);

 if(!textin.is_open())
 {
  cout << "파일을 열수 없습니다. " << endl;
  return 0;
 }

 int i=0, n=0;
 // student 파일에서 레코드 읽어 배열에 저장
 while (textin.good() && textin.peek() != EOF)
 {
  textin >> sno >> sname >> score;
  textin.ignore(300, '\n');
  S[i] = StudentRecord(sno, sname, score);
  i++;
 }
 
 textin.close();
 fstream DataFile("student.bin", ios::in | ios::out | ios::trunc | ios::binary);
 fstream IndexFile("index.bin", ios::in | ios::out | ios::trunc | ios::binary);

 // 배열에 있는 레코드를 정렬한후 출력
 Sort<StudentRecord> sort;
 sort.bubble(S, i);

 cout << "---------[student.bin]---------" << endl;
 cout << "Sno    " <<'\t' << "Sname" << '\t' << '\t' << "Score" << endl;
 cout << "-------" <<'\t' << "-----" << '\t' << '\t' << "-----" << endl;
 for (n=0; n<i; n++)
  S[n].printRecord(cout);

 // 이진파일 생성했다.

 KeyIndex *K = new KeyIndex; // 인덱스정렬 할 배열
 for(int j=0; j<i; j++)
 {
  K->Set(S[j].getSno(), DataFile.tellp());
  S[j].writeToFile(DataFile);
  IndexFile.write((char*) K, sizeof(*K));
 }

 // 인덱스 파일 출력
 IndexFile.clear();
 IndexFile.seekg(0, ios::beg);
 cout << "---------[index.bin]---------" << endl;
 cout << "sno       " << '\t' << "address" << endl;
 cout << "----------" << '\t' << "-------" << endl;
 for (n = 0; n < i; n++)
 {
  IndexFile.read((char*) K, sizeof(*K));
  cout << K->getKey() << "\t\t" << K->getOffset() << endl;
 }

 IndexFile.clear();
 IndexFile.seekg(0, ios::beg);
 int key;
 StudentRecord s;
 char command;
 cout << "Do you want to retrieve a student record? y(es) or n(o): ";
 cin >> command;

 while (command != 'n')
 {
  IndexFile.clear();
  IndexFile.seekg(0, ios::beg);
  cout << "Enter sno : ";
  cin >> key;

  // 레코드가 인덱스 파일에 있으면 주소 값 반환, 없으면 -1 반환
  int offset = binarySearch(IndexFile, key, i);
  if (offset == -1)
   cout << "No such sno" << endl;
  else
  {
   // 데이터 파일의 get 포인터를 가져올 레코드에 위치시킴
      DataFile.seekg(offset);
   s.readFromFile(DataFile); // 레코드를 s에 갸져옴
   cout << "Sno    " <<'\t' << "Sname"
        << '\t' << '\t' << "Score" << endl;
   cout << "-------" <<'\t' << "-----" << '\t' << '\t'
                             << "-----" << endl;
   s.printRecord(cout);
  }

  cout << "Do you want to retrieve a student record? y(es) or n(o): ";
  cin >> command;
 }

 DataFile.close();
 IndexFile.close();

 return 0;
}