220 likes | 380 Views
Chapter 3. 일괄데이터로 작업하기 WORKING WITH BATCHES OF DATA. 3 장에서는 …. 1-2 장에서는 하나의 문자열을 읽어 들이고 그것을 출력하고 , 약간의 장식을 추가한 정도 대부분 문제는 이보다 훨씬 복잡하다 . 복잡해지는 원인은 여러 개의 유사한 데이터를 처리해야 하기 때문 3 장에서 다루는 문제는 , 학생의 시험성적과 과제성적을 읽어 들여 , 최종성적을 계산 (3.1 절 ) 입력된 성적을 저장해야 하는 경우 , vector 클래스 사용 (3.2 절 )
E N D
Chapter 3 일괄데이터로 작업하기WORKING WITH BATCHES OF DATA
3 장에서는… • 1-2 장에서는 • 하나의 문자열을 읽어 들이고그것을 출력하고, 약간의 장식을 추가한 정도 • 대부분 문제는 이보다 훨씬 복잡하다. • 복잡해지는 원인은 여러 개의 유사한 데이터를 처리해야 하기 때문 • 3 장에서 다루는 문제는, • 학생의 시험성적과 과제성적을 읽어 들여, 최종성적을 계산(3.1절) • 입력된 성적을 저장해야 하는 경우, vector 클래스 사용 (3.2절) • 일련의 데이터를 처리하는 다양한 방법 • 얼마나 많은 성적들이 있는지 미리 알지 못해도, 저장할 수 있는 방법
3.1 학생 성적 계산하기 • 기말 40% 중간 20% 과제의 평균이 40% 일 때 최종 성적 계산하는 과정 1) 이름 읽어 들이기 2) 중간고사와 기말고사 성적 읽어 들이기 3) 과제성적 읽어 들이기 • 몇 개를 과제점수를 읽어 들였는지 저장 • 현재까지 읽어 들인 과제 점수의 합계 저장 4) 과제성적 평균 계산하기 5) 최종 성적 계산하기 • 최종 = 중간 * 0.2 + 기말 * 0.4 + 과제 평균 * 0.4
학생 성적 계산 – 과제성적 평균 #include <iomanip> #include <ios> #include <iostream> #include <string> using namespace std; // using std::setprecision; using std::streamsize; int main() { // ask for and read the student's name cout << "Please enter your first name: "; string name; cin >> name; cout << "Hello, " << name << "!" << endl; // ask for and read the midterm and final grades cout << "Please enter your midterm and final exam grades: "; double midterm, final; cin >> midterm >> final;
// ask for the homework grades cout << "Enter all your homework grades, " "followed by end-of-file: "; // the number and sum of grades read so far int count = 0; double sum = 0; // a variable into which to read double x; // invariant: we have read `count' grades so far, and // `sum' is the sum of the first `count' grades while (cin >> x) { ++count; sum += x; } // write the result streamsize prec = cout.precision(); cout << "Your final grade is " << setprecision(3) << 0.2 * midterm + 0.4 * final + 0.4 * sum / count << setprecision(prec) << endl; return 0; }
성적 읽어 들이기 cout <<“Enter your midterm and final …: ”; double midterm, final; cin >> midterm >> final; • 실수형 • float (단일 정밀도 부동소수점 타입):6자리유효 숫자 • double (double-precision floating point): 최소 10자리 유효 숫자 • 부동소수점 연산에는 항상 double을 써라. • 보다 정확하고, 하드웨어 발전으로속도도 느리지 않다. • 입력 연산자 >> • 읽어 들인 후, 왼쪽 연산자를 결과 값으로 리턴함 • cin>>midterm>>final; // cin>>midterm; // cin>>final;
문자열 리터럴 cout << "Enter all your homework grades, " "followed by end-of-file: "; • 공백문자만으로 구분된 둘 또는 그 이상의 문자열 리터럴은 자동적으로 합쳐진다 cout << "Enter all your homework grades, followed by end-of-file: ";
초기화 하기 int count=0; double sum=0; // 자동으로 형 변환 일어남: sum=0.0; • 명시적으로 초기화하지 않으면, • 기본 타입의 지역 변수들은 정의되지 않은(undefined)상태 • 쓰레기 값을 가지므로, 이 상태로 사용하면 위험 초래 • 클래스 타입의 변수는 디폴트 초기화(default-initialization) • 예, string 타입 변수는 빈 문자열로 초기화 됨 • 초기화 할지 말지 어떻게 판단? • 프로그래머의 책임 • 위 프로그램에서, 왜 name과 x는 초기화 안하지? 왜 count와 sum은 초기화 하지?
입력의 끝 테스트하기 // 불변식: 지금까지 count개의 성적을 읽어 들였고 // sum은 처음 count개의 성적의 합이다. while ( cin>>x ) { ++count; sum += x; } • while 문의 condition에 cin>>x 등장 • 가장 최근의 입력 요청(즉, cin >> x )이 성공하면, 조건식이 성공 • cin>>x에서 >> 연산자는 왼쪽 피연산자 cin을 리턴하는데, cin 값은 true/false로 자동 변환 • 아래 경우에 cin>> x가 false가 됨 (보다 구체적인 원리는 12.5절) • 파일 끝 입력 (키보드에서 Ctrl-Z 또는 Ctrl-D) • 변수형과 호환되지 않는 값 입력. 예) int형 입력에 숫자외 입력 • 입력장치에 대한 하드웨어 오류 감지
출력에서 정밀도 정해주기 streamsize prec = cout.precision(); cout << "Your final grade is " << setprecision(3) << 0.2*midterm + 0.4*final + 0.4*sum / count << setprecision(prec) << endl; • setprecision(3) • 주요 자리수 세자리 출력: 소수점 앞에 두 자리, 뒤에 한 자리 • 출력 후 cout의 정밀도를 바꾸기 이전 상태로 돌려주기 • 정밀도 바꾸기 이전 상태 보관: streamsize prec = cout.precision(); • 정밀도를 바꾸기 이전 상태로 돌려주기: setprecision(prec);
3.2 평균 대신 중앙 값 사용하기 • 중앙값(median)과 평균값(average) • 입력이 55 80 12 70 65 라면, • 평균값:(55+80+12+70+65)/5=56.4 • 중앙값:65 • 중앙값은 어떻게 구할까? • Sorting(오름차순 또는 내림차순)후 가운데 있는 값을 취함 • 입력 값들의 개수가 짝수이면: 가운데 두 개의 평균 • 중앙값을 사용하기로 한다면 프로그램은? • 앞의 프로그램처럼, 읽은 값을 저장하지 않아도 될까? • 저장해야 한다면 어디에 어떻게? • 중앙값을 계산하기 위해 • 값을 한번에 하나씩 읽어 저장, 끝까지 다 읽은 후에 값들을 정렬, 중간에 위치한 값(들)을 구함
vector에 일련의 데이터 저장 • 표준 라이브러리는 vector 타입을 제공 • vector 타입은 주어진 타입에 대한 여러 개의 값들을 저장 • 필요한 때에 크기가 커지며, 개별 값들을 효과적으로 접근 가능 • vector 타입의 객체에 저장하기 // 이전 것과 비교해보자. int count=0; double sum=0; double x; while(cin>>x) { ++count; sum+=x; } double x; vector<double> homework; while (cin>>x) homework.push_back(x);
vector타입 vector<double> homework; homework.push_back(x); • vector 는 일련의 값을 저장하는 컨테이너(container) • 값을 여러 개 저장할 수 있는 타입을 컨테이너라 한다. • vector 타입은 템플릿 클래스(template class)로 정의되어 있음 • ‘객체’의 타입이 매개변수화 되어 있음. <>안에 명시 • vector<double>은 double 타입의 객체를 담는다 • vector<string>은 string 타입의 객체를 담는다 • push_back(x) 멤버 함수 • vector의 끝에 새로운 요소를 추가하는함수 • 즉, vector의 뒤(back)에 밀어 넣음 (push) • 자연히 vector의 크기는 하나 증가됨 • 몇 개의 요소를 담고 있는지는 어떻게 알지? • vector의 효율:요소가많아지면 효율이 떨어지나? • 템플릿 클래스를 정의하는 방법은 11장에서!!
vector크기 vector<double>::size_type size = homework.size(); • vector크기 알아내기 • size()라는 멤버함수 사용. homework.size(); • vector의 크기를 저장할 변수 • vector의 size_type을 사용. vector<double>::size_type size; • typedef은 해당 타입에 대한 동의어를 정의 typedef vector<double>::size_type vec_sz vec_sz size = homework.size(); • typedef에 의해 size_type과 vec_sz는 동의어가 됨 • size_type을 여러 군데에서 사용하는 경우유용함
오류 처리 • 오류 처리는 매우 중요하다. “어제까지는 됐는데…” “컴퓨터가 이상하네. 되다 안되다 하네.” • 모든 입력 사례(instance)를 고려해라! • 현재 문제에서는, size가 0일 경우와그렇지 않은 경우 if(size==0) { cout << endl <<“You must enter your grades, ” “Please try again.” << endl; return 1; } • 운영체제에게 1을 리턴 하여 실행 실패를 알림 • main이 0을 리턴하면 프로그램이 성공했다고 가정함 • 오류 처리를 해주지 않으면 어떤 일이 생길까?
정렬하기 sort(homework.begin(), homework.end()); • sort() 함수 • 컨테이너에 들어있는 값들을 오름차순(nondecreasing)으로 정렬 • 정렬된 결과를 담을 새 컨테이너를 생성하는 것이 아니라, 원래 컨테이너의 요소들의 값을 서로 바꿈 • 효율: n log(n)알고리즘 사용. • C++의 표준 라이브러리는 꽤 효율적이다 • begin()과 end()는 vector의 멤버 함수 • homework.begin()는 첫번째 요소, homework.end()는 마지막 요소를 나타냄. • homework의 첫 번째와 마지막 요소는 homework[0]과 homework[size-1]
중앙값 찾기 vec_sz mid = size/2; double median; median = size%2==0?(homework[mid]+homework[mid-1])/2: homework[mid]; 나머지 연산자 %, 조건부 연산자 ?: • size가 짝수일 때, • size가 홀수일 때, // 홀수 개 일 때 // 짝수 개 일 때
학생 성적 계산 – 과제성적 중앙값 #include <algorithm> #include <iomanip> #include <ios> #include <iostream> #include <string> #include <vector> using namespace std; int main() { // ask for and read the student's name cout << "Please enter your first name: "; string name; cin >> name; cout << "Hello, " << name << "!" << endl; // ask for and read the midterm and final grades cout << "Please enter your midterm and final exam grades:"; double midterm, final; cin >> midterm >> final; // ask for and read the homework grades cout << "Enter all your homework grades, “ "followed by end-of-file: “;
vector<double> homework; double x; // invariant: `homework' contains all the homework grades read so far while (cin >> x) homework.push_back(x); // check that the student entered some homework grades typedef vector<double>::size_type vec_sz; vec_sz size = homework.size(); if (size == 0) { cout << endl << "You must enter your grades. Please try again." << endl; return 1; } // sort the grades sort(homework.begin(), homework.end()); // compute the median homework grade vec_sz mid = size/2; double median; median = size%2==0 ? (homework[mid] + homework[mid-1])/2 : homework[mid]; // compute and write the final grade streamsize prec = cout.precision(); cout << "Your final grade is " << setprecision(3) << 0.2 * midterm + 0.4 * final + 0.4 * median << setprecision(prec) << endl; return 0; }
벡터의 원소 접근하기 vector<int> v; v.push_back(100); // 100 v.push_back(10); // 100 10 v.push_back(1); // 100 10 1 cout << v[0] << endl; // prints 100 cout << v[1] << endl; // prints 10 cout << v[2] << end; // prints 1 cout << v[3] << endl; // ERROR! No element at this position. for(unsigned int i=0; i != v.size(); ++i){ cout << v[i] << endl; }
출력: 소수점 3자리 지정 • 소수점 3자리까지 출력하는 방법 cout.setf(ios::fixed, ios::floatfield); cout.precision(3);
벡터 초기화 • 정수형의 빈 벡터(empty vector) 생성 vector<int> a; • 100개의 double형 벡터 생성, 각 요소의 초기값은 3.14로 설정 int n = 100; vector<double> b( 100, 3.14 ); • 10,000개의 정수를 저장하는 벡터 생성 vector<int> c( n*n ); • 벡터 b를 복사한 벡터 d생성 vector<double> d( b ); vector<double> e( b ); // ERROR; e는 double형, b는 int형 cout << a.size() << endl << b.size() << endl << c.size() << endl << d.size() << endl;