수업 출처) 숙명여자대학교 소프트웨어학부 수업 "자료구조", 유석종 교수님

 

1. 재귀호출

- 함수가 실행 중에 자기 자신을 다시 호출하는 것이다.

- 같은 작업을 반복하는데 조금씩 상황이 바뀌는 경우에 사용한다.

 

- 함수에 반드시 종결 조건이 있어야 한다.

- Divide & Conquer 전략에 사용된다.

- 재귀 호출문은 if-else나 while문을 활용한 반복문으로 바꿀 수 있다.

- 컴파일러의 관점에서 재귀 호출은 새로운 함수를 호출하는 것과 같다.

- 따라서 함수를 호출할 때마다 함수의 지역 변수, 복귀 주소 등 컨텍스트 정보를 활성 레코드에 저장해야 한다.

 

- 장점 : 알고리즘을 깔끔하게 표현할 수 있다.

- 단점 : 함수를 실행할 때마다 메모리에 환경 변수를 저장하기 때문에 메모리의 소모가 일어난다.

 

2. 팩토리얼 예제

- n! = 1 x 2 x ... x (n-1) x n = (n-1)! x n

 

- 같은 일 (곱셈) 을 반복하면서 n = 0이면 n! = 1 이라는 종결 조건이 포함되어있기 때문에 재귀 호출을 사용할 수 있다.

 

long factorial (int n)
{
    if (n == 0)
        return 1;
    else 
        return n * factorial (n-1);
}

이와 같이 n = 0 이면 1을, n > 0 이면 n * (n-1)! 을 반환하는 형식으로 표현할 수 있다.

 

3. 최대공약수 (GCD) 예제

- 공통으로 나누는 수 중 가장 큰 수 

 

- 조건 (by 유클리드 호제법)

    - gcd (x, y) = gcd (y, x % y)  (if (y > 0))

    - gcd (x, 0) = x

 

ind gcd (x, y)
{
    if (y == 0)
        return x;
    else return gcd (y, x % y);
}

 

4. Binary Search 이진 탐색

- 정렬된 항목 리스트에 대해서 중간값과 크기를 비교하고 그 결과에 따라 가능성이 있는 절반의 리스트에 대해서만 과정을 반복하는 탐색 알고리즘이다.

 

- 한 번 비교할 때마다 탐색 대상 원소의 수가 절반으로 감소한다.

- 원소의 수가 n개일 때 이진탐색은 총 log₂ⁿ 번의 비교 횟수를 요구한다. 따라서 순차 탐색보다 속도가 빠르다.

- 조건은 리스트 안에 겹치는 숫자가 없어야 한다는 것이다. 

 

-while문과 if문을 이용한 이진탐색

#include <stdio.h>
int binsearch (int mylist[], int item, int left, int right);

void main()
{
    int pos, maxnum = 12, item = 60;
    int mylist[] = {5, 8, 9, 11, 13, 17, 23, 42, 45, 52, 60, 72};
    pos = binsearch(mylist, item, 0, maxnum - 1);
    printf("position = %d", pos);
}

int binsearch (int list[], int item, int left, int right)
{
    int mid;
    while (left <= right) {
        mid = (left + right) / 2;
        if (list[mid] == item)
            return mid;
        else {
            if (item < list[mid]
                right = mid - 1;
            else
                left = mid + 1;
        }
    }
    return -1;
}

 

- 재귀호출 형식의 이진탐색

#include <stdio.h>
int rbinsearch (int mylist[], int item, int left, int right);

void main()
{
    int pos, maxnum = 12, item = 60;
    int mylist[] = {5, 8, 9, 11, 13, 17, 23, 42, 45, 52, 60, 72};
    pos = binsearch(mylist, item, 0, maxnum - 1);
    printf("position = %d", pos);
}

int rbinsearch (int list[], int item, int left, int right)
{
    int mid;
    if (left <= right)
    {
        mid = (left + right) / 2;
        if (item == list[mid] 
            return mid;
        else if (list[mid] < item)
            return rbinsearch(list, item, mid + 1, right);
        else 
            return rbinsearch (list, item, left, mid - 1);
     }
     return -1;
 }
        

 

5. 하노이 타워 예제

- 세 개의 기둥과 크기가 다양한 원판이 존재한다. 

- 해결할 문제는 한 기둥에 꽂힌 원판들을 그 순서 그대로 다른 기둥으로 옮기는 것이다.

- 조건

    - 한 번에 하나의 원판만 옮길 수 있다.

    - 큰 원판이 작은 원판 위에 놓일 수 없다.

 

- 알고리즘

    - 세 개의 기둥 A, B, C 가 있고, A에서 B로 n개의 원판을 옮긴다.

    1) A에서 (n-1)개의 원판을 C로 옮긴다.

    2) A에 남은 1개의 원판을 B로 옮긴다.

    3) C에 있는 (n-1)개를 B로 옮긴다. 

 

- 기둥 a = 1, b = 2, c = 6 - a - b // a, b 제외한 빈 기둥이 c

- 총 이동횟수 : 2ⁿ - 1

 

#include <stdio.h>
void htower(int n, int a, int b);

int count = 0;

void main()
{
    int n;
    count = 0;
    printf("Enter disc number = ");
    scanf("%d", &n);
    htower(n, 1, 2);
    printf("# move for %d discs : %d\n", n, count);
}

void htower (int n, int a, int b)
{
    int c;
    count ++;
    if (n == 1)
        printf("Disc %d, moved from Pole (%d) to (%d)\n", n, a, b);
        
    else {
        c = 6 - a - b;
        htower(n-1, a, c);
        printf("Disc %d, moved from Pole (%d) to (%d)\n", n, a, c);
        htower(n-1, c, b);
    }
}

 

- Time complexity 시간 복잡도 

    - t(1) = 1 : 하나의 디스크 옮기는데 필요한 시간

    - time to move n disks : t(n)

        - t(n) = 2 t(n-1) + 1

                 = 2 (2 t(n-2) + 1) + 1

                 = ...

                 = 2ⁿ⁻¹ + 2² + ... + 2¹ + 2⁰

                 = 2ⁿ - 1 ≅ 2

    - t(n) = O(2ⁿ) 

    → n 이 크면 사용하지 않는 것이 좋다.

 

6. Permutation 순열

- 순서를 다르게 나열하는 방법의 수

 

- {a, b, c, d}  → ₄P₄ = 4! = 24

a) (a, Perm (b, c, d))  →  Perm(b, c, d) = (b, Perm (c, d)), (c, Perm (b, d)), (d, Perm (b, c)) 

b) (b, Perm (a, c, d))

c) (c, Perm (a, b, d))

d) (d, Perm (a, b, c))

 

// i : start index of range
// n : end index of range

void perm(char list[], itn i, int n)
{
    int j;
    if (i == n)      // list print
    { 
        for (j = 0; j <= n; j++)
            printf("%c", list[j]);
        printf("   ");
    }
    else {
        for (j = i; j <= n; j++) {
            Swap(list[i], list[j]);    // 두 수 교환
            perm(list, i + 1; n);
            Swap(list[i], list[j]);
        }
    }
}
    

'Software > Data Structures' 카테고리의 다른 글

[자료구조] 연결 리스트  (0) 2021.04.20
[자료구조] 선형 자료구조  (0) 2021.04.18
[자료구조] 알고리즘 성능 분석  (0) 2021.04.17
[자료구조] C언어 기초  (0) 2021.04.17
[자료구조] Introduction  (0) 2021.04.17

수업 출처) 숙명여자대학교 소프트웨어학부 수업 "자료구조", 유석종 교수님

 

1. Structure 구조체

- 자료형이 상이한 여러 멤버들을 하나의 자료로 묶어서 처리할 수 있는 복합 자료형

 

1-1. 구조체 변수 선언

// ex1

struct student
{
    int age;
    int grade;
    char major[20];
} kim, lee;

// ex2

struct
{ 
    int age;
    int grade;
    char major[20];
} kim, lee;

// ex3

struct student
{
    int age;
    int grade;
    char major[20];
};
struct student kim, lee;

 

세 가지 모두 kim과 lee라는 구조체 변수를 선언하는 문장이다.

첫 번째 방식과 같이 구조체의 이름을 줄 수 있고, 두 번째 방식과 같이 구조체 변수를 생성할 수 있다. 세 번째 방식은 구조체 변수를 struct 키워드를 이용해서 선언하는 방식이다. 

 

- 구조체 변수를 통해서 멤버에 값 저장

student.grade = 3;
strcpy(kim.major, "Software Convergence");

이와 같이 "." 연산자를 사용한다.

 

1-2. 구조체 자료형 선언

- 일반적으로 구조체를 사용할 때에는 typedef와 함께 사용되는데, typedef 키워드는 struct student_type{...}와 같이 긴 자료형 이름을 student 로 대체하여 구조체 변수를 선언할 수 있게 해준다.

 

// ex1

typedef struct student_type
{
    char name[10];
    int grade;
    char major[20];
} student;

// ex2

typedef struct
{ 
    char name[10];
    int grade;
    char major[20];
} student;

student kim, lee;

 

이처럼 struct만 쓴다면 } 이후 나오는 것은 그 구조체 자료형을 가진 "변수" 인 반면, typedef struct로 선언을 했을 때 } 뒤에 나오는 것은 구조체 "자료형" 이다.

 

1-3. 구조체 할당과 비교

 

- 할당

    - 동일한 자료형의 구조체 변수 간에 직접적인 할당 명령문은 가능하다.

    - (ex)

    studnet kim, lee;

    kim = lee; 

 

- 비교

    - 구조체 변수 간 직접 비교는 허용되지 않는다.

    - 구조체 멤버 별로 비교해주어야 한다.

    - (ex) 

    if (kim == lee) ...  // 오류 !!

 

    if (strcmp(kim.name, lee.name) ...

    if (kim.age != lee.name) ...

    if (kim.grade == lee.grade) ...

    이런식으로 멤버별로 비교해주면 된다.

 

    - 문자열 비교를 위해 사용된 strcmp 함수는 두 인자 값이 "다를" 경우 1을 반환한다.

 

1-4. 내장형 구조체

- 다른 구조체 변수를 멤버로 갖는 구조체

 

#include <stdio.h>
#include <string.h>

typedef struct Contact_type
{
    char phone[20];
    char email[20];
    char address[20];
} Contact;

typedef struct Student_type
{ 
    char name[20];
    int age;
    char major[20];
    int grade;
    Contact contact;
} Student;

void main() 
{
    Student kim;
    
    strcpy(kim.name, "ChulSoo Kim");
    kim.age = 22;
    strcpy(kim.major, "Software Convergence");
    kim.grade = 3;
    strcpy(kim.contact.phone, "010-3606-0418");
    strcpy(kim.contact.email, "kim@naver.com");
    strcpy(kim.contact.address, "Seoul, Korea");
}

 

student 구조체 안에 contact 구조체를 넣은 형태이다. 

 

2. Pointer 포인터

- 메모리 주소를 값으로 갖는 변수

- 간접 참조를 통해 원본 데이터를 공유하거나 변경할 수 있다.

- call by reference, 연결리스트 동적 메모리 관리 등에 사용된다.

 

2-1. "&" 과 "*"

- &

    - 모든 변수에 붙일 수 있는 "주소" 연산자이다. 

    - 해당 변수의 메모리 주소 값을 반환한다.

 

- *

    - 사용되는 위치에 따라 의미가 달라진다.

    - 반드시 포인터형 변수에만 적용해야 한다.

 

    - int i =3, j;

    - int *p;

 

    - p = &i;

        - i의 주소를 p에 할당한다.

 

    - kim = *p;

        - kim 변수에 p가 가리키는 주소에 저장된 "값"을 대입한다.

 

    - *p = j;

        - p가 참조하는 "공간"에 j의 값을 저장한다.

 

3. Array 배열

- 자료형이 동일한 원소들의 유한집합

- <index, value> → item

- 선언 이후 배열의 크기를 변경할 수 없다.

- 배열의 원소 수가 n개 라면 유효한 배열 인덱스의 범위는 [0, n-1] 이다. 

 

- 배열의 첫 번째 원소인 A[0] 을 "시작 주소 (α)"라고 부른다.   

   이후 원소들은 연속적인 메모리 주소에 저장된다. (α + sizeof(data type))

    - (ex) int → 4bytes 

    α = 100100 → 100104 → 100108 → ...

 

- 배열 이름 A는 시작 주소를 값을 갖고 있는 "포인터 상수"이다. 선언에 사용된 이름은 이후 다른 값(주소)을 가질 수 없다.

 

- A == &A[0]    : A[0]의 주소

- *A == A[0]   : A[0]의 값

 

3-1. 함수에 배열 전달

- 시작 주소를 가지고 있는 "배열 이름"만 전달하면 된다.

- 배열 포인터 관점에서는 call by value이지만, 배열의 관점에서는 call by reference 라고 볼 수 있다.

- int list[] == int *list

 

- 배열 이름 + 정수 → 첫번째 원소에서 정수의 원소 개수만큼 떨어져 있는 원소의 주소

- (ex) oneArray = 100 → oneArray + 1 = 104, oneArray +2 = 108

 

4. Polynomial 다항식

- 항들의 집합

 

- 다항식 추상자료형 연산자

    - Zero()

    - IsZero()

    - Coef (poly, expon)     : 계수 찾기

    - Lead_Exp (poly)     : 최고차항 지수

    - Attach (poly, coef, expon)     : 항 추가

    - Remove (poly, expon)

    - SingleMult (poly, coef, expon)     : 다항식과 단항의 곱셈

    - Add (poly1, poly2)

    - Mult (poly1, poly2)

 

 

- (ex) 다항식 배열 선언

#define MAX_TERMS 50

struct polynomial
{
    float coef;
    int expon;
};

struct polynomial terms[MAX_TERMS];

int avail = 0;

 

www.acmicpc.net/problem/1152

 

1152번: 단어의 개수

첫 줄에 영어 대소문자와 띄어쓰기로 이루어진 문자열이 주어진다. 이 문자열의 길이는 1,000,000을 넘지 않는다. 단어는 띄어쓰기 한 개로 구분되며, 공백이 연속해서 나오는 경우는 없다. 또한

www.acmicpc.net

 

문제 

 

코드

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main() {
    char str[1000001];
    int space = 0;
    int word = 0;
    int len;

    gets(str);
    len = strlen(str);

    for (int i = 0; i < len; i++) {
        if (str[i] == ' ')
            space++;
    }

    word = space +1;

    if (len == space) {
        word = 0;
        printf("%d\n", word);
    }

    else {
        if (isspace(str[0]))
            word--;
        if (isspace(str[len-1]))
            word--;
        printf("%d\n", word);
    }
}

'Software > C' 카테고리의 다른 글

[Baekjoon C] 10828 스택  (0) 2021.02.19
[Baekjoon C] 1259 팰린드롬수  (0) 2021.02.18
[Baekjoon C] 10818 최소, 최대  (0) 2021.02.15
[Baekjoon C] 2753 윤년  (0) 2021.01.31
[Baekjoon C] 2884 알람시계  (0) 2021.01.31

www.acmicpc.net/problem/10828

 

10828번: 스택

첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지

www.acmicpc.net

 

문제

 

코드

#include <stdio.h>
#include <string.h>

int stack[100001];
int count = 0;

void push(int x);
void pop();
void size();
void empty();
void top();

int main() {
    int n, x;
    char order[6];

    scanf("%d", &n);

    for (int i = 0; i < n; i++) {
        scanf("%s", &order);

        if (!strcmp(order, "push")) {
            scanf("%d", &x);
            push(x);
        }

        else if (!strcmp(order, "pop")) pop();
        else if (!strcmp(order, "size")) size();
        else if (!strcmp(order, "empty")) empty();
        else if (!strcmp(order, "top")) top();
        else break;
    }
    return 0;
}

void push(int x) {
    stack[count] = x;
    count++;
}

void pop() {
    if (count != 0) {
        count--;
        printf("%d\n", stack[count]);
        stack[count] = 0;
    }
    else printf("%d\n", -1);
}

void size() {
    printf("%d\n", count);
}

void empty() {
    if (count == 0) printf("%d\n", 1);
    else printf("%d\n", 0);
}

void top() {
    if (count > 0) 
        printf("%d\n", stack[count-1]);
    else printf("%d\n", -1);
}

'Software > C' 카테고리의 다른 글

[Baekjoon C] 1152 단어의 개수  (0) 2021.02.19
[Baekjoon C] 1259 팰린드롬수  (0) 2021.02.18
[Baekjoon C] 10818 최소, 최대  (0) 2021.02.15
[Baekjoon C] 2753 윤년  (0) 2021.01.31
[Baekjoon C] 2884 알람시계  (0) 2021.01.31

www.acmicpc.net/problem/1259

 

1259번: 팰린드롬수

입력은 여러 개의 테스트 케이스로 이루어져 있으며, 각 줄마다 1 이상 99999 이하의 정수가 주어진다. 입력의 마지막 줄에는 0이 주어지며, 이 줄은 문제에 포함되지 않는다.

www.acmicpc.net

 

문제

 

코드

#include <stdio.h>
#include <string.h>

int main() {
    char num[6];
    int len = 0;

    while(1) {
        scanf("%s", &num);

        if (num[0] == '0')
            break;

        if (strlen(num) == 1)
            printf("yes\n");
            len = 0;
            break;

        while (num[len] != '\0') {
            len = strlen(num);
            
            for (int i = 0; i < len/2 ; i++) {
                if (num[i] != num[len - 1 - i]) {
                    printf("no\n");
                    len = 0;
                    break;
                }
                    
                else {
                    if (num[i + 1] == num[len - i - 2]) {
                        printf("yes\n");
                        len = 0;
                        break;
                    }

                    else {
                        printf("no\n");
                        len = 0;
                        break;
                    }
                }
            break;
            }
        break;
        }
    }
    return 0;
}

 

'Software > C' 카테고리의 다른 글

[Baekjoon C] 1152 단어의 개수  (0) 2021.02.19
[Baekjoon C] 10828 스택  (0) 2021.02.19
[Baekjoon C] 10818 최소, 최대  (0) 2021.02.15
[Baekjoon C] 2753 윤년  (0) 2021.01.31
[Baekjoon C] 2884 알람시계  (0) 2021.01.31

www.acmicpc.net/problem/10818

 

10818번: 최소, 최대

첫째 줄에 정수의 개수 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 N개의 정수를 공백으로 구분해서 주어진다. 모든 정수는 -1,000,000보다 크거나 같고, 1,000,000보다 작거나 같은 정수이다.

www.acmicpc.net

 

 

#include <stdio.h>

int main() {
    int n, num;
    int min = 1000001;
    int max = -1000001;
    
    scanf("%d", &n);
    
    for(int i = 0; i < n; i++) {
        scanf("%d", &num);
        if (num > max)
            max = num;
        if (num < min)
            min = num;
    }
    
    printf("%d %d", min, max);
}

'Software > C' 카테고리의 다른 글

[Baekjoon C] 1152 단어의 개수  (0) 2021.02.19
[Baekjoon C] 10828 스택  (0) 2021.02.19
[Baekjoon C] 1259 팰린드롬수  (0) 2021.02.18
[Baekjoon C] 2753 윤년  (0) 2021.01.31
[Baekjoon C] 2884 알람시계  (0) 2021.01.31

+ Recent posts