1 / 81

CHAPTER 10 . 포인터

CHAPTER 10 . 포인터. 포인터의 기본 개념과 특징을 이해한다 . 포인터 선언과 간접 참조를 통한 포인터 사용 방법을 배운다 . 포인터의 증감 연산을 통한 다양한 포인터 활용법을 배운다 . 포인터와 배열의 연관성을 배운다 . 함수의 인수 전달에서 포인터의 역할 및 사용 방법을 배운다 . 포인터를 이용한 문자열 처리에 대해 배운다. 10.0 개요 p.448. 일반 변수 프로그램에서 사용하는 데이터를 저장 포인터 변수 데이터가 저장된 주기억장치의 주소만 저장

xandy
Télécharger la présentation

CHAPTER 10 . 포인터

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CHAPTER 10. 포인터 포인터의 기본 개념과 특징을 이해한다. 포인터 선언과 간접 참조를 통한 포인터 사용 방법을 배운다. 포인터의 증감 연산을 통한 다양한 포인터 활용법을 배운다. 포인터와 배열의 연관성을 배운다. 함수의 인수 전달에서 포인터의 역할 및 사용 방법을 배운다. 포인터를 이용한 문자열 처리에 대해 배운다.

  2. 10.0 개요 p.448 • 일반 변수 프로그램에서 사용하는 데이터를 저장 • 포인터 변수 데이터가 저장된 주기억장치의 주소만 저장 (간단히 포인터(pointer)라고도 함) • 포인터의 장점 • 직접 참조할 수 없는 변수를 포인터를 이용 간접적으로 참조 가능 • 기억 공간의 효율적 사용 • 프로그램 성능 개선

  3. 10.1.1 주기억장치의 주소 p.449 • 주기억장치(main memory) • CPU가 실행할 명령어 코드와 처리할 데이터를 저장하는 기억장치 • 실행 프로그램은 반드시 주기억장치에 적재되어야 함 • 주기억장치의 주소(address) • 주기억장치의 일정 크기마다 붙인 일련번호 • [표 10-1]처럼 건물의 사무실 호수나 아파트 단지의 동과 호수와 같은 개념

  4. 10.1.1 주기억장치의 주소 p.450 • 주소 부여 단위 설치된 운영체제에 의해 결정되는데 대부분은 1바이트마다 부여 • 그림 10-2 2GB 주기억장치에 char ch = ‘A’;로 선언된 변수 ch에 할당된 기억장소 • 용량이 2GB라면 주소의 범위는? 1G(Giga) =230 →2G(Giga) =2*230 → 0~ 2* 230 -1번지를 사용 주소 주기억장치 ch

  5. 10.1.2 포인터 변수의 필요성 p.451 • 실생활에서의 포인터 예

  6. 10.1.3 포인터 훑어보기 프로그램 p.452 • 포인터 사용 3단계(필요한 내용) p.452 ① 포인터 변수 선언 ② 포인터 변수가 특정 기억장소를 가리키기  가리키고 싶은 기억장소의 주소를 포인터 변수에 대입 ③ 포인터를 사용한 간접 참조  특별 연산자인 간접연산자 ‘*’를이용

  7. 10-1 포인터 변수 ptr을 이용해 var을 참조하는 예 p.452 3 intmain() 4 { 5 intvar = 100; 6 int*ptr; // int형 값 가리킬 포인터 변수 ptr선언 7 8 ptr= &var; // ptr이 변수 var을 가리키게 함 9

  8. 10-1 포인터 변수 ptr을 이용해 var을 참조하는 예 p.452 10 // 변수 var에 저장된 값을 직접 참조하여 출력하기 11 printf("변수 var의 값: %d \n", var); 12 13 // ptr을 이용해 var에 저장된 값을 간접적으로 참조하여 출력하기 14 printf("var의 간접 참조 (*ptr) 결과 값: %d \n\n", *ptr); 15 16 // 변수 var의 주기억장치 주소와 포인터 변수 ptr에 저장된 주소 출력하기 17 printf("변수 var의 주소:%u(%p) \n", &var, &var); 18 printf("변수 ptr에 저장된 주소:%u(%p) \n", ptr, ptr); 19 20 return 0; 21 }

  9. 10.2.1 포인터 변수 선언 p.455 • 포인터 변수의 선언 자료형 *포인터변수명; • ㈜ • int* ptr1, ptr2; → ptr1만 포인터 변수 • int*ptr1, *ptr2; → 둘 다 포인터 변수 char *p ‘Y’ 포인터변수가 가리키는 곳에 저장될 자료형 나중에 포인터가 가리키는 곳에 자료가 저장된 경우의 그림 int *pi 1024

  10. 10.2.2 주소 연산자 &와 주소 대입 p.457 • 변수의 주소 구하기 &변수명 • 주소의 대입 포인터변수가 해당 주소의 기억장소를 가리키게 됨 포인터변수명= &변수명; 주소 연산자 (scanf에서사용) 포인터 변수가 오른쪽의 변수를 가리키게 됨 포인터변수 변수명

  11. 10.2.2 주소 연산자 &와 주소 대입 p.457 주소 주기억장치 • 예 1 intvar; 2 int *ptr; 3 4 ptr = &var; 주소 주기억장치 1310588 4행 결과의축약 그림 var ptr

  12. 10.2.2 주소 연산자 &와 주소 대입 p.457 • 주의 • int*ptr = &var;의미 • 주소 출력 변환 명세 p.458 • %u: 10진수로 출력, %p: 16진수로 출력 • 예 • printf("변수 var의 주소: %u (16진수: %p) \n", &var, &var); → 변수 var의 주소: 1310588 (16진수: 0013FF7C) • printf("포인터 변수 ptr의 주소: %u (16진수: %p) \n", &ptr, &ptr); → 포인터 변수 ptr의 주소: 1310576 (16진수: 0013FF70) • int *ptr; • ptr = &var; • int *ptr; • *ptr = &var;

  13. 10.2.3 간접 연산자 * p.458 • [그림 10-8] 일반 변수의 직접 참조 p.459 1 var = 100; 2 printf("변수 var에 저장된 값: %d", var); • [그림 10-9] 포인터 변수의 직접 참조 1 intvar = 100; 2 int *ptr; 3 4 ptr = &var; 5 printf("포인터 변수 ptr의 주소:%u \n", ptr); Q) ptr이 가리키는 기억장소(var)를 변수명var을 사용하지 않고 참조하려면? →간접 참조 연산자 *를 사용해야 함 변수 var 100 주소:1310588번지 ptr = &var 결과 • 포인터 변수 ptr 변수 var 1310588 100 주소:1310588번지

  14. 10.2.3 간접 연산자 * p.459 • 포인터를 통한 간접 참조 * 포인터변수명 • 포인터변수에 저장된 주소에 해당하는 기억장소를 참조 → 포인터를 통해 다른 기억장소를 간접적으로 참조 • 쉽게 ‘포인터 변수가 가리키는 곳’으로 해석 • 선언문 int *ptr; 의 의미→ ptr이 가리키는 곳(*ptr)에는 int형 자료가 저장됨을 의미 • 예 1 intvar = 100; 2 int *ptr; 3 4 ptr = &var; 5 printf("ptr이 가리키는 곳에 저장된 값:%d \n", *ptr); • 포인터 변수 ptr 변수 var 1310588 100 주소:1310588번지

  15. 10.2.3 간접 연산자 * p.459 • 간접 연산자의 강력함 p.460 Q) output 함수에서 main 함수의지역변수를 참조할 수 있을까? printf(“%d”, m_var); (X) → m_var은 main의지역변수이므로 참조 불가 m_var

  16. 변수의 l-value와 r-value p.460 • 일반 변수의 l-value와 r-value intsum= 0; sum = sum + 1; 변수의 r-value 변수(기억장소)에 저장된 값 그림 10-11 변수의 두 가지 의미: 기억장소와 저장된 값 변수의 l-value 변수의기억장소 주소 주기억장치 0 변수 sum에 저장된 값 변수 sum에 할당된 기억장소

  17. 변수의 l-value와 r-value p.461 • 포인터 변수의 l-value와 r-value • intsum= 0; • int*ptr = ∑ • *ptr = *ptr + 1; • printf(“ptr이 가리키는 곳에 저장된 값: %d", *ptr); l-value 즉기억장소 ptr이 가리키는 곳(*ptr) 기억장소 r-value즉 기억장소에 저장된 값 ptr이 가리키는 곳(*ptr)에 저장된 값 주소 주기억장치 식에 해당하므로 r-value 즉저장된 값 1이 출력 ptr 0 + 1 (b) *ptr= *ptr + 1; 결과 • 정리) • sum = sum + 1; → sum값을 1 증가→ sum++; • *ptr = *ptr + 1; → ptr이 가리키는 곳의 값을 1 증가 → (*ptr)++

  18. 10.2.5 변수간의 교환과 포인터 간의 교환 비교 p.462 • 두 변수의 값교환 방법 두 가지 a와 b 두 값을 직접 교환 vs. 두 변수를 가리키는 포인터 p1과 p2 교환→ ‘소대원들의 교환 vs. 소대장의 교환’에 비유 가능 : [그림 10-14] → 어느 쪽이 효율적일까? 100 200 a b p1 &a p2 &b

  19. 10-2 두 포인터 변수가 가리키는 곳의 값을 교환하기 p.463 3 intmain() 4 { 5 inta = 100, b = 200, temp; 6 int *p1, *p2, *p_temp; 7 8 p1 = &a; // p1은 a를 가리키게 함 9 p2 = &b; // p2는 b를 가리키게 함 10 printf(" a = %d, b = %d\n", a, b); 11 printf("*p1 = %d, *p2 = %d\n", *p1, *p2); 12 13 printf("\n>> p1과 p2가 가리키는 곳에 저장된 값을 직접 바꾸기 \n"); 14 temp = *p1; 15 *p1 = *p2; 16 *p2 = temp; 17 18 printf(" a = %d, b = %d\n", a, b); 19 printf("*p1 = %d, *p2 = %d\n", *p1, *p2); 100 p1 1310588 a p2 1310576 200 b 100 temp 100 200 p1 1310588 a p2 1310576 200 100 b

  20. 10-2 두 포인터 변수가 가리키는 곳의 값을 교환하기 p.463 21 printf("\n>> 포인터 p1과 p2에 저장된 주소를 바꾸기 \n"); 22 a = 100, b = 200; // 원래 a와 b의 값으로 초기화 23 p_temp= p1; 24 p1 = p2; 25 p2 = p_temp; 26 27 printf(" a = %d, b = %d\n", a, b); 28 printf("*p1 = %d, *p2 = %d\n", *p1, *p2); 29 30 return 0; 31 } p_temp 1310588 100 p1 1310588 1310576 a p2 1310576 1310588 200 b • Q) 어느 쪽이 효율적일까? • 포인터가가리키는 곳의 자료가 정수 1개가 아니라 문자열 또는 11장의 구조체와 같이 많은 자료가 있는 곳이라면 포인터를 교환하는 것이 훨씬 효율적

  21. 10.3 포인터의 덧셈과 뺄셈 p.465 • 주소는 4바이트의 정수형 상수 → 포인터에 대한 덧셈과 뺄셈이 가능 ㈜ 곱셈과 나눗셈은 불가능, 실수와의 연산은 불가능 • 포인터 + 1 실제로 1이 아니라 포인터 변수 선언 시 명시한 자료형의기억장소 크기만큼 더한다.

  22. 10-3 ‘포인터 변수+1’과 ‘포인터 변수-1’의 결과 p.465 6 intvi = 123, *pi; 10 pi = &vi; // pi는 vi를 가리키게 함 12 14 printf("\n pi-1 = %u, pi = %u, pi+1 = %u", pi-1, pi, pi+1); 주소 주기억장치 pi - 1 포인터 변수 pi 1310564 123 14행의 pi + 1 pi + 1 pi에 저장된 값 1310564 int형의 크기 4 1310568

  23. 10-4 포인터 개념을 확인하기 위한 프로그램 p.467 5 inta = 100, b = 200; 6 int*p1, *p2; // int형 포인터 변수 선언 7 8 p1 = &a; // p1이 a를 가리키게 함 9 printf("p1 = &a 후: a = %d, *p1 = %d \n", a, *p1); 10 11 *p1 = *p1 + 1; // p1이 가리키는 곳의 값을 1 증가 12 printf("(*p1)++ 후: a = %d, *p1 = %d \n", a, *p1);

  24. 10-4 포인터 개념을 확인하기 위한 프로그램p.467 14 p2 = p1; // p2도 p1이 가리키는 곳을 가리키게 함 15 printf("p2 = p1 후: a = %d, *p1 = %d, *p2 = %d \n", a, *p1, *p2); 16 17 (*p2)++; // *p2 = *p2 + 1; p2가 가리키는 곳의 값을 1 증가 18 printf("(*p2)++ 후: a = %d, *p1 = %d \n\n", a, *p1); 19 20 printf("&a = %u, &b = %u, b = %d \n", &a, &b, b); 21 printf("p1 = %u, p1-1 = %u, *(p1-3) = %d \n", p1, p1-1, *(p1-3)); ㈜ ‘debug’ 모드가아닌‘release’ 모드로 실행하면 변수가 차지하는 기억장소 위치가 다르므로 다른 값이 나온다.

  25. 10.4 포인터와 배열은 친구 p.469 • 포인터의 가감 연산은 어디에서 사용될까? • 배열명은배열의 시작 주소인포인터 상수→ 배열명에 대한 가감 연산이 가능 • 배열 원소 참조는? • 배열명(배열 시작 주소)과첨자에 대한 덧셈 연산과 간접 연산자를 이용 → arr배열의 두 번째 원소: arr[1] 또는 *(arr+1)

  26. 10.4.1 배열명은 배열의 시작주소 p.470 • 배열명은 배열 시작 주소(포인터 상수) • 배열은 동일한 자료형의 많은 자료를 주기억장치의 연속된 기억장소에 저장 • intarr[5]={1, 2, 3, 4, 5};에서 배열명arr == 배열 시작 주소 == 첫 원소 시작 주소 &arr[0] == arr+0 • intarr[5]={1, 2, 3, 4, 5};에서 • *(arr + 0) 또는 *arr →arr[0] • *(arr + 1) : arr이 가리키는 곳 보다 하나 뒤→ arr[1] • *(arr + 2) : arr이 가리키는 곳 보다 두개 뒤→ arr[2] ⇒ *(arr + i) : arr이 가리키는 곳 보다 i개 뒤 → arr[i]

  27. 10.4.1 배열명은 배열의 시작주소 p.470 • 배열 원소 참조 ‘배열명[첨자]’ 컴파일러에 의해 ‘*(배열명+첨자)’ 포인터 연산으로 처리됨

  28. 10-5 [프로그램 7-1]의 수정 p.471 1 #include <stdio.h> 2 #include <conio.h> // getch함수를 위한 헤더 파일 3 #define SIZE 5 4 5 intmain() 6 { 7 intquiz[SIZE]; 8 inti, count, sum; 9 double ave; 10 11 printf("%d명의 점수를 순서대로 입력하세요.\n\n", SIZE); 12 for (i=0; i<SIZE; i++) 13 { 14 printf("%d번의 퀴즈 점수는? ", i+1); 15 scanf("%d", (quiz + i)); // scanf("%d", &quiz[i]); 16 } 17 18 sum = 0; 19 for (i=0; i<SIZE; i++) 20 sum = sum + *(quiz+i); // sum = sum + quiz[i]; 21 22 ave= (double)sum / SIZE;

  29. 10-5 [프로그램 7-1]의 수정 p.471 23 24 count = 0; 25 for (i=0; i<SIZE; i++) 26 if (*(quiz+i) < ave) // if (quiz[i] < ave) 27 count++; 28 29 printf("\n결과를 보려면 아무키나 누르세요. \n"); 30 getch(); // 키보드로부터 문자 한 개 입력. 일시 정지 효과 31 32 printf("\n===============\n"); 33 printf("평균: %.1lf점 \n", ave); 34 printf("평균 미만: %d명 \n", count); 35 printf("===============\n"); 36 37 return 0; 38 }

  30. 10.4.2 포인터 변수를 이용한 배열 참조 p.472 • 포인터 변수를 이용한 배열 원소 참조 포인터 변수에 배열 시작 주소를 저장하면→ 포인터 변수를 배열명처럼 사용 가능 배열명[첨자] → *(배열시작주소+첨자) → *(포인터변수+첨자) → 포인터변수[첨자] • 예) intarr[5], *p; p = arr; p[1] = 10; → arr[1]=10;과 동일 printf("%d", arr[1]);→ 10 • 주의) intarr[5]; int*p = arr; // int*p; p=arr; arr= p; // 배열명은 상수므로 다른 값을 대입하여 변경할 수 없다.

  31. 10-6 다양한 배열 원소 참조 방법 p.473 2 #define SIZE 5 4 int main() 5 { 6 int i, arr[SIZE] = {1, 2, 3, 4, 5}; // 배열 선언 7 int *ptr; // 포인터 선언 8 9 ptr = arr; // ptr에 배열 arr의 시작 주소를 대입하여 arr 배열을 가리키게 하기 10 11 // 배열명[첨자]를 사용해 배열 원소에 저장된 값 출력하기 12 for (i=0; i<SIZE; i++) 13 printf("arr[%d] = %d \n", i, arr[i]); 14 printf("\n"); 15 : 33 return 0; 34 } • 20 행의 *(arr + i) • 25 행의 *(ptr + i) • 30 행의 ptr[i] • 와 동일

  32. 10-6 다양한 배열 원소 참조 방법 p.473

  33. 10.5 포인터와 함수 p.475 • 함수 간 인수 전달과 포인터 • 값에 의한 호출 함수는 자신을 호출한 함수의 변수를 참조하여 수정할 수 없다. • 주소에 의한 호출 포인터를 이용 자신을 호출한 함수의 변수를 간접적으로 참조하여 수정 가능→포인터의 필요성, 유용성, 강력함 • ‘주소에 의한 호출’ 인수 전달 방식 • 호출 함수: 인수의 주소를 전달 • 피호출 함수: 전달된 주소를 포인터 매개변수에 저장→ 포인터를 통해 인수를 간접적으로 참조하여 수정 가능

  34. 10.5.1 포인터를 이용한 주소에 의한 호출 p.475 • 주소에 의한 호출 인수 전달 형식 함수 호출 • 함수명 ( &인수명 ); 함수 정의 인수의 주소가 전달되어 저장됨 → 포인터는 자신을 호출한 함수의 인수를 가리키게 됨 • 반환값형 함수명(자료형 *포인터변수명) • { ‘*포인터변수명’으로 인수를 참조 }

  35. 10-7 값에 의한 호출과 주소에 의한 호출 비교 p.476 3 void swap_value(int x, int y); // 값에 의한 호출 방식 4 void swap_address(int *x, int *y); // 주소에 의한 호출 방식 6 int main() 7 { 8 int x = 100, y = 200; 9 10 printf("In main: x=%d, y=%d \n\n", x, y); 11 12 swap_value(x, y); // 값에 의한 호출: x와 y의 값을 전달 13 printf("In main: x=%d, y=%d (swap_value(x, y) 호출 후)\n\n", x, y); • 22 void swap_value(int x, int y) • 23 { • 24 int temp; • 25 • 26 temp = x; • 27 x = y; • 28 y = temp; • 29 printf("In swap_value: x=%d, y=%d \n", x, y); • 30 } main의 x, y가 아니라 자신의 x, y를 참조하므로 main의 x, y는 변경되지 않는다.

  36. 10-7 값에 의한 호출과 주소에 의한 호출 비교 p.476 4 void swap_address(int *x, int *y); // 주소에 의한 호출 방식 6 int main() 7 { 8 int x = 100, y = 200; 15 swap_address(&x, &y); // 주소에 의한 호출: x와 y의 주소를 전달 16 printf("In main: x=%d, y=%d (swap_address(&x, &y) 호출 후)\n\n", x, y); 17 19 } • 33 void swap_address(int *x, int *y) // x, y를 포인터 변수로 선언 • 34 { • 35 int temp; // 임시 대피 장소 • 37 temp = *x; // x가 가리키는 곳의 값을 temp에 대입 • 38 *x = *y; // y가 가리키는 곳의 값을 x가 가리키는 곳에 대입 • 39 *y = temp; // temp의 값을 y가 가리키는 곳에 대입 • 40 printf("In swap_address: *x=%d, *y=%d \n", *x, *y); • 41 } 33행에서 x, y대신 다른 포인터 변수명을 선언하여 이 포인터에 간접참조연산자를 사용해도 된다.

  37. 10.5.1 포인터를 이용한 주소에 의한 호출 p.477

  38. 10.5.2 배열을 함수의 매개변수로 사용하는 경우 p.479 • 함수간 배열 전달: 포인터 이용 • 함수 정의시 배열을 선언하는 방법은 p.349 8.11.2에서 소개 • 포인터를 이용하는 방법: 배열 원소 자료형에 맞는 포인터 매개변수 선언 함수 호출 • 함수명 ( 배열명); 함수 정의 • 반환값형함수명(자료형*포인터변수명) • { • ‘*(포인터변수명+첨자)’ 또는 ‘포인터변수명[첨자]’로 배열원소 참조 } 배열의 시작 주소가 전달되어 저장됨 → 포인터는 자신을 호출한 함수의 배열 시작 위치를 가리키게 됨

  39. 10.5.2 배열을 함수의 매개변수로 사용하는 경우 p.479 • [프로그램 10-8] 인기도 조사 결과 배열을 백분율로 변환하는 [프로그램 8-15]를 포인터를 사용해 변경

  40. 10-8 배열을 포인터로 전달받아 처리하기 p.489 [프로그램 8-15] 인기도조사 →[프로그램 10-8]: 포인터를 사용해 변경 1 #include <stdio.h> 2 #define N 4 3 4 void print_arr(int *arr); // void print_arr(int arr[N]); 5 void percentage(int *arr); // void percentage(int arr[N]); 6 7 int main() 8 { 9 int count[N] = {42, 37, 83, 33}; 10 11 printf("인원수: "); 12 print_arr(count); // count 배열을 전달해 출력하기 13 14 percentage(count); // count 배열을 전달해 백분율로 변환하기 15 16 printf("\n백분율: "); 17 print_arr(count); // count 배열을 전달해 출력하기 18 19 return 0; 20 }

  41. 10-8 배열을 포인터로 전달받아 처리하기 p.489 : 12 print_arr(count); : 22 void print_arr(int *arr) // void print_arr(int arr[N]) 23 { 24 int i; 26 for (i=0; i<N; i++) 27 printf("%3d", *(arr + i)); // printf("%3d", arr[i]); 28 }

  42. 10-8 배열을 포인터로 전달받아 처리하기 p.489 30 void percentage(int *arr) // void percentage(int arr[N]) 31 { 32 int i, total = 0; 34 for(i=0; i<N; i++) 35 total += *(arr + i); // total += arr[i]; 36 37 for (i=0 ;i<N; i++) 38 *(arr + i) = (int) ((double) *(arr + i) / total * 100); 39 // arr[i] = (int) ((double) arr[i] / total * 100); 40 }

  43. 10.6.1 다양한 정렬 알고리즘 p.483 • 정렬(sort 혹은 sorting) • 순서 없이 나열된 값들을 특정 순서대로 나열하는 것 • 오름차순 정렬 / 내림차순 정렬

  44. 10.6.1 다양한 정렬 알고리즘: 교환 정렬 p.484 • 교환 정렬(exchange sort) • 첫 원소 자리부터 순서대로 정렬이 완료된 상태의 값이 저장되도록 함 • for (i=0; i<SIZE-1; i++) • a[i]에 (i+1)번째로 작은 값을 저장하기; i가 0일 때: a[0]에 제일 작은 값을 저장하기 i가 1일 때: a[1]에 둘째로 작은 값을 저장하기 i가 2일 때: a[2]에 셋째로 작은 값을 저장하기 i가 3일 때: a[3]에 넷째로 작은 값을 저장하기 → 원소수가 5개이므로 a[3]에 넷째로 작은 값을 저장하면 a[4]에는 제일 큰 값이 저장됨

  45. 10.6.1 다양한 정렬 알고리즘: 교환 정렬 p.484 • a[i]에 (i+1)번째로 작은 값을 저장하는 방법은? i가 0일 때: a[0]과 나머지 a[1]~a[SIZE-1]까지의 두 원소를 차례로 정렬 • i가 0일 때 a[0]에제일 작은 값을 저장하기(①~ ④를 반복) • for (j=i+1; j<SIZE; j++) • if (a[i] > a[j]) • { • a[i]와a[j] 교환; • } ① a[0]과 a[1]을정렬 • 교환 발생 ② a[0]과 a[2]를정렬 • 교환 발생 ③ a[0]과 a[3]를 정렬 • 교환 발생 ④a[0]과 a[4]를 정렬 • → [그림 10-18]과 같은 방식으로a[i]와 ~ a[i+1]~a[SIZE-1]을 비교하여 정렬하는 과정을 i가 0일 때부터 3까지 반복하면 정렬이 완료됨 a[0]에 제일 작은 값 저장

  46. 10.6.1 다양한 정렬 알고리즘: 교환 정렬 • 교환 정렬 • [그림 10-18]과 같은 방식으로 a[i]와 ~ a[i+1]~a[SIZE-1]을 비교하여 정렬하는 과정을 i가 0일 때부터 3까지 반복하는 코드로 작성 가능 1 // 교환 정렬 2 for (i=0; i<SIZE-1 ; i++) 3 for (j = i+1; j<SIZE; j++) 4 if (a[i] > a[j]) 5 { 6 temp = a[i]; 7 a[i] = a[j]; 8 a[j] = temp; 9 }

  47. 10.6.1 다양한 정렬 알고리즘: 선택 정렬 p.485 • 선택 정렬 • 교환 정렬과 같이 배열 원소 자리 순서대로 정렬을 완료해감 • 두 원소 간의 교환 작업 횟수를 줄이기 위해 정렬 안된 두 원소를 무조건 교환하지 않고 a[i] 자리에 와야 할 원소(a[index])를 선택(selection)한 후 a[i]와 자리바꿈을 함 • for (i=0; i<SIZE-1; i++) • a[i]에 (i+1)번째로 작은 값 a[index]를 선택하여 저장하기; for문 본체 실행 마다 한 번의 교환만 발생 → 교환 정렬보다 훨씬 효율적

  48. 10.6.1 다양한 정렬 알고리즘: 선택 정렬 p.485 • a[i]에 i+1번째로 작은 값을 선택하여 저장하는 과정 선택정렬 알고리즘 for (i=0; i<SIZE-1; i++) { index ←a[i]~a[SIZE-1] 중최솟값의 배열 첨자 a[i]와 a[index]를교환하기 } i가 0일 때: a[0]과 a[0]~a[4] 중최솟값과 교환 • 교환 발생 i가 1일 때: a[1]과 a[1]~a[4] 중최솟값과 교환 • 교환 발생 i가 2일 때: a[2]와 a[2]~a[4] 중최솟값과 교환 • 교환 발생 a[3]과a[3]~a[4] 중최솟값과 교환 i가 3일 때: • 교환 발생

  49. 10.6.1 다양한 정렬 알고리즘: 선택 정렬 p.485 • 1 // 선택 정렬 • 2 for (i=0; i<SIZE-1; i++) • 3 { • 4 min = a[i]; // 일단 최솟값을 a[i]~a[SIZE-1] 중 첫 값으로 초기화 • 5 index = i; // index도 현재 min의 배열 첨자로 초기화 • 7 // 나머지 a[i+1]~a[SIZE-1] 원소와 비교하여 min 구하기 • 8 for (j=i+1; j<SIZE; j++) • 9 if (min > a[j]) • 10 { • 11 min = a[j]; • 12 index = j; // min이 수정되었으므로 index도 수정 • 13 } • 14 // 현재 정렬 위치인 a[i]와 최솟값 a[index]를 교환 • 15 temp = a[i]; • 16 a[i] = a[index]; • 17 a[index] = temp; • 18 } • a[i]~a[SIZE-1] 중 최솟값과 최솟값의 배열 첨자 index는 어떻게? 4~13행과 같이 min 변수가 새로운 최솟값으로 수정될 때마다 index 또한 최솟값의 배열 첨자로 수정됨

  50. 10.6.1 다양한 정렬 알고리즘: 선택 정렬 p.485 • 4~13행의 단순화 • 15~17행에서 정렬할 a[i]와 교환할 원소는 첨자 index 정보만 있으면 a[index]로 참조할 수 있으므로 4~13행에서 굳이 min을 구할 필요가 없다.  4~13행은 다음과 같이 줄일 수 있다. • index = i;// 일단 a[i]를 최솟값이라고 가정하고 index를 i로 초기화하기 • for (j=i+1; j<SIZE; j++) • { • if (a[index] > a[j]) • index = j; • }

More Related