780 likes | 1.27k Views
자료구조. 제 1 장 기본 개념. ▶ 시스템 생명 주기 (System Life Cycle). 시스템 : Input + Processor + Output 시스템 생명 주기 (System Life Cycle) 시스템 개발을 위한 일련의 단계. ▶ 시스템 생명 주기 (System Life Cycle). ⅰ . 요구조건분석 (Requirement Analysis) 문제에 대한 적절한 해를 구하기 위한 요구조건을 정의
E N D
자료구조 제 1 장 기본 개념
▶ 시스템 생명 주기(System Life Cycle) • 시스템 : • Input + Processor + Output • 시스템 생명 주기(System Life Cycle) • 시스템 개발을 위한 일련의 단계
▶ 시스템 생명 주기(System Life Cycle) ⅰ.요구조건분석(Requirement Analysis) • 문제에 대한 적절한 해를 구하기 위한 요구조건을 정의 • PSL/PSA(Problem Statement Language / Problem Statement Analyzer) • 제약 조건: 필수적, 선택적
▶ 시스템 생명 주기(System Life Cycle) ⅱ.명세(Specification) • define "what the s/w is supposed to do" • 기능적 명세(functional specification) ⑴ 입력/출력 명세: 구문적 제약 조건(비절차적 명세) ⑵ 기능적 명세: 의미적 제약 조건(절차적 또는 비절차적)
▶ 시스템 생명 주기(System Life Cycle) ⅲ.설계(Design) • 명세된 기능을 어떻게 달성하는 가를 기술 : 추상적 언어 • 전체 시스템 설계 - top-down, bottom-up • 추상 데이타 타입 - 데이타 객체와 연산 • 알고리즘 개발
▶ 시스템 생명 주기(System Life Cycle) ⅳ.구현(Implementation) - 코딩 • 구조화 프로그래밍 - assignment, conditional, do-loop • modular 프로그래밍 - one function, one entry/exit point
▶ 시스템 생명 주기(System Life Cycle) ⅴ.검증(verification) i) 검사(test) ⑴ 모듈 검사(단위 검사) ⑵ 통합 검사(그룹 검사) ⑶ 시스템 검사(평가 검사) ii) 정확성(correctness) 증명 iii) debugging - 오류 제거
▶ 시스템 생명 주기(System Life Cycle) ⅵ.운영 및 유지보수(operation and maintenance) • 시스템 설치(installation), 운영, 유지보수 • 새로운 요구조건 - 변경 • 수정 내용의 기록 유지
▶소프트웨어 설계 방법론 ⅰ. 하향식 방법(top-down approach) abstract program(initial solution) : executable by abstract machine decomposition(refinement) concrete programs (in a prog. lang.) : executable by a target machine
▶소프트웨어 설계 방법론 ⅱ. 상향식 방법(bottom-up approach) • modules(subprograms)를 개발 • 상이한 작은 문제를 해결 • 프로그래밍 언어로 직접 개발 • 하나의 기능을 수행 • module 들을 통합 : 시스템 통합 전체 시스템 : 하나의 완전한 프로그램 "divide and conquer"
▶ 객체 지향 설계(Object Oriented Design) • 구조화 프로그래밍 설계와 상이 • 유사점: 분할-정복 기법 (divide and conquer) • 차이점: 분할 방법
▶ 알고리즘적 분해와 객체 지향적 분해 • 알고리즘적 분해 / 기능적 분해 • 전통적 프로그래밍 기법 • 소프트웨어 = 프로세스 • 프로세스의 스텝을 나타내는 모듈로 분해 • 객체 지향적 분해 • 소프트웨어 = 객체의 집합 • 소프트웨어를 객체로 분해 • 재사용성(reusability) • 변경에 유연한 소프트웨어 시스템
▶객체 지향 프로그래밍의 기본적 정의와 개념 • 객체: • 데이타 + 연산 + {Oid} • 데이타 : 애트리뷰트 값 • 객체 지향 프로그래밍: 구현 방법 ⑴ 객체를 기본적인 빌딩 블록 ⑵ 각 객체는 어떤 타입(클래스)의 인스턴스 ⑶ 클래스는 계승(inheritance)으로 연관
▶객체 지향 프로그래밍의 기본적 정의와 개념 • 객체 지향 언어의 요건 ⑴ 객체 지원 ⑵ 모든 객체는 클래스에 소속 ⑶ 계승 지원 • 객체 기반 언어(object-based language): • 객체와 클래스는 지원하되 계승은 지원하지 않는 언어
▶ 프로그래밍 언어의 발전과 C++의 역사 • 고급 프로그래밍 언어 ⑴ 제 1세대 언어 : 수식 계산 • FORTRAN ⑵ 제 2세대 언어 : 알고리즘 표현 • Pascal, C ⑶ 제 3세대 언어 : 추상 데이터 타입(Abstract Data Type) 지원 • Modula, Ada ⑷제4세대언어(객체지향언어) : 계승 지원 • Smalltalk, Objective C, C++
▶ 프로그래밍 언어의 발전과 C++의 역사 • C++ : C plus 객체 지향 개념 • C의 장점 ⑴ 효율성: 하드웨어를 효율화하는 저 수준의 기능을 가지고 있음 ⑵ 유연성: 거의 모든 응용 분야에 사용 ⑶ 가용성: 모든 컴퓨터에 컴파일러 제공
▶ 데이타 추상화와 캡슐화 • 데이타 캡슐화(정보 은닉) • 외부에 대해 데이타 객체의 자세한 구현을 은폐 • 내부 표현을 사용자에게 은폐 • 데이타 추상화 • 데이타객체의명세(specification)와 구현(implementation)을 분리 • 무엇(what)과 어떻게(how)를 독립화
▶ 데이타 추상화와 캡슐화 • C++의 데이타 타입 • 기본 데이타 타입: • char, int, float, double • 타입 수식어: short, long, signed, unsigned • 파생 데이타 타입: • 포인터(pointer) 타입, 참조(reference) 타입 • 데이타 집단화 구조: • 배열(array), 구조(struct), 클래스(class) • 사용자 정의 데이타 타입
▶ 데이타 추상화와 캡슐화 • 타입: 값의 집합 - 정수, 불리언 • 데이타 타입 • 객체들(타입)과 이 객체들에 대해 동작하는 연산의 집합
▶ 데이타 추상화와 캡슐화 • 추상 데이타 타입(Abstract Data Type; ADT) • 객체의 명세와 이들 객체에 대한 연산의 명세를 객체의 표현과 연산의 구현으로부터 분리시킨 데이타 타입 • 명세(specification)와 구현(representation, implementation)의 분리가 핵심개념 • 사용자 정의 데이타 타입 • ADT1.1 : 자연수(NaturalNumber) 추상 데이타 타입
ADTNaturalNumberis • 객체: 순서가 있는 정수의 일부분으로 0부터 해당 컴퓨터의 최대 정수(MAXINT)까지 의 값 • 함수: 모든 x, y ∈ NaturalNumber, TRUE, FALSE ∈ Boolean +, -, <, ==, = 는 일반 정수 연산자 Zero() : NaturalNumber ::= 0 IsZero(x) : Boolean ::= if (x == 0) IsZero= TRUE else IsZero= FALSE Add(x,y):NaturalNumber::= if (x+y <= MAXINT) Add = x+y else Add = MAXINT Equal(x,y):Boolean ::= if (x == y) Equal = TRUE else Equal = FALSE Successor(x):NaturalNumber ::= if (x == MAXINT) Successor = x else Successor = x+1 Subtract(x,y):NaturalNumber ::= if (x<y) Subtract = 0 else Subtract = x-y end NaturalNumber
▶ 데이타 추상화와 캡슐화 • 데이타 추상화와 데이타 캡슐화의 장점 ⑴ 소프트웨어 개발의 간소화: - 복잡한 작업을 부분 작업들로 분해 ⑵ 검사와 디버깅의 단순화: - 부분 작업 ⑶ 재사용성: - 자료 구조가 소프트웨어 시스템에서 별개의 개체로 구현 - 재사용 ⑷ 데이타 타입 표현의 수정: • 데이타 타입의 내부 구현을 직접 접근하는 부분만 변경 필요 - 그 이외 부분에는 무관
▶ 데이타 추상화와 캡슐화 그림 1.1 : 흰색이 검사 대상 부분 (a)에서는 데이터 추상화를 사용, (b)에서는 사용하지 않았음
▶C++ 의 기초 • 프로그램의 구성 • 여러 화일(두가지 타입)로 구성 • 헤더 화일:- .h 접미사 - 선언을 저장 - 시스템/사용자 정의 화일 - 전처리기 명령 #include를 사용 • 소스 화일:- 소스 코드를 저장 - .c 접미사 • 프로그램의 실행 • 소스 화일이 개별적으로 컴파일된 다음, 링크되고, 로드된다.
▶C++에서의 영역(scope) ⑴ 화일 영역 • 함수 정의 또는 클래스 정의에 포함되지 않은 선언 ⑵ 함수 영역 • 레이블 ⑶ 지역 영역 • 블록 안에서 선언된 이름 ⑷ 클래스 영역 • 클래스 정의에 관련된 선언
▶C++ 명령문과 연산자 • C++ 문: C와 같은 문법과 의미 • C++ 연산자: C의 연산자와 동일 • new, delete - 동적 메모리 관리 • C++의 입출력: • 쉬프트 왼쪽/오른쪽 연산자(<<, >>)를 이용 • C와 C++의 중요한 차이점: • 연산자 다중화(operator overloading)
▶C++의 데이타 선언 • 데이타 선언: 어떤 이름을 데이타 타입에 연결 ⑴ 상수값 ⑵ 변수 : 데이타 타입의 인스턴스 ⑶ 상수 변수 : const라는 키워드를 사용하여 선언 ⑷ 열거 타입 : 일련의 정수 상수를 선언 enumBoolean {FALSE, TRUE} ; ⑸ 포인터 : 객체의 메모리 주소를 저장 • int i=25; • int *np; • np= &i;
▶C++의 데이타 선언 ⑹ 참조 타입 : C에 없음 • int i=5; • int& j=i; (j:참조 타입, i에 대한 또 하나의 이름) • i=7; • printf("i=%d, j=%d", i, j); i=7, j=7
▶C++ 주석문 ⑴ 복수행 주석문: • C의 주석문과 동일 • /* --- */ ⑵ 단일행 주석문: • C++에만 있음 • 한 행에서 // 뒤의 모든 텍스트는 컴파일러에 의해 무시
▶C++에서의 입출력 시스템 정의 헤더 화일 iostream.h포함이 필수 • 키워드 cout: • 표준출력장치로 출력 • cout키워드와 출력될 개체는 << 연산자로 분리 ------------------------ #include <iostream.h> void main() { int n=50; float f=20.3; cout<<"n:"<<n<<endl; cout<<"f:"<<f<<endl; 출력 n : 50 } f : 20.3 ------------------------- 프로그램 1.1: C++에서의 출력
▶C++에서의 입출력 • 키워드 cin: • 연산자 >>은 입력 변수들을 구분 • 여백문자(탭, 개행, 공백 문자)로 입력값을 구분 ------------------------- #include <iostream.h> void main() { int a,b; 입력 1 : 5 10<Enter> cin>>a>>b; 입력 2 : 5<Enter> } 10<Enter> ------------------------- 프로그램 1.2: C++에서의 입력
▶C++에서의 입출력 • C++ 입출력 ⑴ 자유 형식 - 포맷 기호가 필요 없음 ⑵ 입출력 연산자도 다중화 가능 • 화일 입출력: - 헤더 화일 fstream.h가 필요
--------------------------------------------- #include <iostream.h> #include <fstream.h> void main() { ofstreamoutFile("my.out", ios::out); if (!outFile) { cerr<< "cannot open my.out" << endl; //표준 에러 장치 return; } int n = 50; float f = 20.3; outFile<< "n: " << n << endl; outFile<< "f: " << f << endl; } --------------------------------------------- 프로그램 1.3 : C++에서 화일 입출력
▶ C++ 함수 - 정규 함수 - 멤버 함수: 특정 클래스와 연관된 함수 • 함수의 구성: • 함수 이름 • 인자 리스트 즉, 시그니쳐(입력) • 반환 타입(출력) • 몸체(함수를 구현한 코드)
▶ C++ 함수 ------------------------ int max(int a, int b) { if (a > b) return a; else return b; } ------------------------- 프로그램 1.4 : 함수의 예 • int : 반환 타입(void : 반환 없음) • max : 함수 이름
▶C++의 매개변수 전달 • call by value : 기본적인 인자 전달 방법 • call by reference : 참조(주소) 타입으로 선언 - 타입 명세자에 &를 첨가 int &a; • 상수 참조(constant reference): 두 매개변수 전달 방법의 이점을 이용 - 인자 변경이 불가 constT& a • Note : 배열은 참조로 전달
▶함수 이름 다중화 • C++ 함수 다중화(function overloading): • 함수의 인자 리스트(시그니쳐)가 다르기만 하면 같은 이름을 가진 함수가 둘 이상 존재 가능 ex) int max(int, int); int max(int, int, int); int max(int*, int); int max(float, int); int max(int, float);
▶ 인라인 함수 • 함수 정의에 키워드 inline을 첨가시켜 선언 - 함수 호출을 줄임 ex) inline int sum(int a, int b) { return a + b; } 만일 i = sum(x,12); 이면 i = x+12; 으로 대체
▶ C++의 동적 메모리 할당 • new / delete 연산자 : 실행 시간 동안 객체에 자유 기억 장소를 할당하거나 반환 • new 연산자 : 원하는 타입의 객체를 생성하고 그에 대한 포인터를 반환- 생성할 수 없으면 0을 반환 • delete 연산자 : new로 생성된 객체에게 할당된 기억 장소를 반환 ex) int *ip= new int; if (ip== 0) cerr<< "Memory not allocated" << endl; . . delete ip;
▶ 알고리즘(Algorithm) • 특정한 일을 수행하기 위한 명령어의 유한 집합 • 알고리즘의 요건(criteria) ⅰ. 입력 : (외부) 원인 0 ⅱ. 출력 : 결과 1 ⅲ. 명백성(definiteness) : 모호하지 않은 명확한 명령 ⅳ. 유한성(finiteness) : 반드시 종료 ⅴ. 유효성(effectiveness) : 기본적, 실행가능 ex. program ≡algorithm flowchart ≠algorithm (명백성과 유효성의 결여)
▶ Description of algorithms • [선택 정렬] : n ≥1 개의 서로 다른 정수의 집합을 정렬하는 프로그램을 작성 "정렬되지 않은 정수들 중에서 가장 작은 값을 찾아서 정렬된 리스트 다음 자리에 놓는다" ----------------------------- for (int i = 0; i < n; i++) { a[i]에서부터 a[n-1]까지의 정수 값을 검사한 결과 a[j]가 가장 작은 값이라 하자; a[i]와 a[j]를 서로 교환; } ----------------------------- 프로그램 1.5 : 선택 정렬 알고리즘
--------------------------------------- 1 void sort(int *a, constint n) 2 // n개의 정수 a[0]부터 a[n-1]까지 비감소 순으로 정렬한다. 3 { 4 for (int i = 0; i < n; i++) 5 { 6 int j = i; 7 // a[i]와 a[n-1] 사이에 가장 작은 정수를 찾는다. 8 for (int k = i + 1; k < n; k++) 9 if (a[k] < a[j]) j = k; 10 // 교환 11 int temp = a[i]; a[i] = a[j]; a[j] = temp; 12 } 13 } --------------------------------------- 프로그램 1.6 : 선택 정렬
▶ Description of algorithms • [이진 탐색] : x = a[j]인 j를 탐색 left, right: 배열(a[0], a[1], ····, a[n-1])의 왼쪽, 오른쪽 끝 지점 초기 값으로 left = 0, right = n-1 list의 중간 위치 middle = (left + right) / 2로 설정 a[middle]과 x를 비교할 경우 3가지 경우 중에 하나를 고려 ⑴ x > a[middle]: left를 middle+1로 설정 ⑵ x < a[middle]: right를 middle-1로 설정 ⑶ x = a[middle]: middle을 반환
▶ Description of algorithms ---------------------------------- char compare(int x, int y) { if (x > y) return '>'; else if (x < y) return '<'; else return '='; // 비교의 끝 } ------------------------------------- 프로그램 1.7: 두 원소의 비교
--------------------------------------- int BinarySearch(int *a, constint x, constint n) // 정렬된 배열 a[0], ..., a[n-1]에서 x를 탐색한다. { for (left와 right를 초기화한다; 원소가 더 있는 한 계속;) { // 가운데 원소를 middle로 설정한다. switch (compare(x,a[middle])) { case '>' : left를 middle + 1로 설정; break; case '<' : right = middle - 1로 설정; break; case '=' : x를 발견; }// switch의 끝 }// for의 끝 not found; }// BinarySearch의 끝 --------------------------------------- 프로그램 1.8 : 이진 탐색의 알고리즘
최종 C++ 함수 --------------------------------------------- 1 int BinarySearch(int *a, constint x, constint n) 2 // 정렬된 배열 a[0], ..., a[n-1]에서 x를 탐색한다. 3 { 4 for (int left = 0, right = n-1; left <= right;){// 원소가 더 있을때까지 5 int middle = (left + right) / 2; 6 switch (comare(x,a[middle])) { 7 case '>' : left = middle + 1; break; // x > a[middle] 8 case '<' : right = middle - 1; break; // x < a[middle] 9 case '=' : return middle; // x == a[middle] 1 }// switch의 끝 11 } // for의 끝 12 return -1; // 발견되지 않음 13 } // BinarySearch의 끝 --------------------------------------------- 프로그램 1.9 : 이진 탐색의 C++ 함수
▶ Algorithm Description • describe algorithm skeleton • abstract language i) assignment(←) ii) conditions if-then-[else] case iii) iteration while do loop for loop repeat until
▶ Algorithm Description iv) function call : return values call by reference(location) call by value call by name ⑴ Call by reference(location) . 실행 시 매개변수의 주소 전달 . 상수의 경우는 저장한 후 그 주소를 전달 ⑵ Call by value . 실제 매개변수의 값을 계산하여 전달 . no return ⑶ Call by name . 실제 매개변수를 계산되지 않은 형태로 전달 . 피호출 프로그램이 계산 시기를 결정
▶ recursive algorithms • 자기 자신을 다시 호출하는 프로시져 (직접, 간접) : 호출 순서 • Factorial(!) : N! = N*(N-1)! int FACT(int N) { if N=0 return (1); else return (N*FACT(N-1)); } N*(N-1)*(N-2)*....*2*1*1 • 실행 과정의 효율적 기술: - 순환적으로 정의된 자료구조 • 실행 효율 저하 - 실행 시간에 순환을 위한 준비 설정이 필요
예제 1.4 [순환적 이진 탐색] -------------------------------------- int BinarySearch(int *a, constint x, constint left, constint right) { // 정렬된 배열 a[left], ..., a[right]에서 x를 탐색 if(left <= right) { int middle = (left + right) / 2; switch(compare(x, a[middle])) { case '>' : return BinarySearch(a, x, middle+1, right); // x > a[middle] case '<' : return BinarySearch(a, x, left,middle-1); // x < a[middle] case '=' : return middle; // x ==a[middle] }// switch의 끝 }// if의 끝 return -1; // 발견되지 않음 } // BinarySearch의 끝 -------------------------------------- 프로그램 1.10 : 이진 탐색의 순환적 구현