How We Coding

http://boj.kr/9184


- 메모이제이션만 하면 된다.


< 소스코드 >


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
 
int d[21][21][21];
 
int w(int a, int b, int c)
{
    if(a <= 0 || b <= 0 || c <= 0return 1;
 
    if(a > 20 || b > 20 || c > 20
        return w(202020);
    
    if(d[a][b][c]) return d[a][b][c];
    
    if(a < b && b < c)
        return d[a][b][c] = w(a, b, c-1+ w(a, b-1, c-1- w(a, b-1, c);
    
    return d[a][b][c] = w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1- w(a-1, b-1, c-1);
}
 
int main()
{
    while(1) {
        int a, b, c;
        scanf("%d%d%d"&a, &b, &c);
        if(a == -1 && b == -1 && c == -1break;
        
        printf("w(%d, %d, %d) = %d\n", a, b, c, w(a, b, c));
    }
    return 0;
}
 
cs


>> 12 라인을 9번 라인보다 먼저 써서 런타임에러가 발생했었다...

>> 배열의 각 차원의 크기는 21인데, a, b, c 중 20보다 큰 값이 들어오면 저 코드를 먼저 실행하게 

     되어 런타임 에러가 발생하는 듯 하다.

'BOJ > DP' 카테고리의 다른 글

[2216] 문자열과 점수  (0) 2018.02.21
[11048] 이동하기  (0) 2018.02.18
[2302] 극장 좌석  (0) 2018.02.05
[1937] 욕심쟁이 판다  (0) 2018.02.01
[1309] 동물원  (0) 2018.02.01



# Day_02_02_list.py


- Collection 

[] : list

() : tuple

{} : set/dictionary

<> : not used



- list


1
2
3
4
5
6
= [135]
print(a)    # [1, 3, 5]
print(a[0], a[1], a[2])     # 1 3 5
 
a[0= 99
print(a)    # [99, 3, 5]
cs


>> 1 : list 의 선언

>> python 에서는 array 가 없다고 함.

>> 3 : 인덱스를 통한 접근

>> 5 : 값의 변경



- 반복문을 통한 접근


1
2
for i in range(len(a)):
    print(a[i])
cs


>> len(a) : list 의 갯수를 리턴해준다.



- 문제

- 100 보다 작은 난수 10개로 이루어진 리스트를  반환하는 함수 만들기


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def makeRandom1():
    a = [0000000000]
    for i in range(10):
        a[i] = random.range(100)
    return a
 
 
def makeRandom2():
    a = [0]*10
    for i in range(10):
        a[i] = random.range(100)
    return a
 
 
def makeRandom3():
    a = []
    for i in range(10):
        a.append(random.randrange(100))
    return a
cs


>> makeRandom3() 에서 처럼 append() 를 많이 쓴다고 한다.

>> 하지만 느리다고 한다.

>> append() 는 리스트의 맨 뒤에 내용을 추가.



- 문제

- 리스트를 거꾸로 뒤집는 함수 만들기


1
2
3
4
5
def reverseList(c):
    size = len(c)
    for i in range(size//2):
       c[i], c[size-1-i] = c[size-1-i], c[i]
    return c
cs




1
2
for i in a:
    print(i, end=' ')
cs


>> 여기서 a는 리스트

>> i는 인덱스가 아닌, 리스트의 각 요소



- range() 와 리스트의 타입


1
2
3
print(type(range(5)), type(a))  
 
# <class 'range'> <class 'list'>
cs


>> range, list 는 utterable 객체



- reversed(obj)


1
2
3
4
5
6
7
8
9
for i in a:
    print(i, end=' ')
print()
# 37 67 44 50 25 65 15 66 5 86 
 
for i in reversed(a):
    print(i, end=' ')
print()
# 86 5 66 15 65 25 50 44 67 37
cs


>> list 가 뒤집어진 상태로 진행이 된다.


1
2
3
4
for i in reversed(range(len(a))):
    print(a[i], end=' ')
print()
# 86 5 66 15 65 25 50 44 67 37 
cs


>> 이런식으로도 가능하다.



- enumerate()


1
2
3
4
for i in enumerate(a):
    print(i, end=' ')
print()
# (0, 37) (1, 67) (2, 44) (3, 50) (4, 25) (5, 65) (6, 15) (7, 66) (8, 5) (9, 86) 
cs


>> i는 (index, value) 의 형태를 갖는다. 데이터 타입은 튜플..!!

>> 특정 데이터가 몇번째 데이터인지 알고 싶을 때 enumerate() 을 사용


1
2
3
4
for i in enumerate(a):
    print(i[0], i[1], end=' ')
print()
# 0 37 1 67 2 44 3 50 4 25 5 65 6 15 7 66 8 5 9 86 
cs


>> 괄호를 없애고 싶을 땐 인덱스를 활용한다.



- 튜플(tuple)은 리스트의 상수버전...

- 리스트와 사용방법이 동일하다. 다만, 내용을 바꿀수 없을 뿐..!!


1
2
3
= (123)
t[0= 99
# TypeError: 'tuple' object does not support item assignment
cs

 

>> 튜플은 보통 파이썬이 사용한다.

>> 매개변수를 전달하거나, 반환값을 전달할 때.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def sumOfOddEven():
    odd, even = 00
    for i in range(1100):
        if i%2 == 1: odd  += i
        else :       even += i
 
    return odd, even
 
 
s1, s2 = sumOfOddEven()
print(s1, s2)       # 2500 2450
 
= sumOfOddEven()
print(s)            # (2500, 2450)
print(type(s))      # <class 'tuple'>
cs


>> 13 : s 의 타입은 튜플이다.


1
2
3
= 12
print(t)            # (1, 2)
print(type(t))      # <class 'tuple'>
cs



- 그래서 enumerate() 이런식으로 사용한다.


1
2
3
for i, k in enumerate(a):
    print(i, k, end=' ')
print()
cs




- list 로 강제 캐스팅하기


1
2
= list(range(0102))
print(a)    # [0, 2, 4, 6, 8]
cs



- 레퍼런스

 

1
2
3
4
5
6
7
= list(range(0102))
print(a)    # [0, 2, 4, 6, 8]
 
= a;
a[0= 99
print(a)    # [99, 2, 4, 6, 8]
print(b)    # [99, 2, 4, 6, 8]
cs


>> 6 번 라인의 결과는 명확하다.

>> 7 번 라인의 결과는..???

    레퍼런스 개념으로 a와 b는 같은 리스트를 가리킨다..!!

>> 4 번 라인을 얕은복사 라고 한다. (shallow copy)

>> 데이터가 같이 바뀌므로 주의해야한다.



- 데이터의 복사 (깊은복사)


1
2
3
4
5
6
7
= list(range(0102))
print(a)    # [0, 2, 4, 6, 8]
 
= a.copy();
a[0= 99
print(a)    # [99, 2, 4, 6, 8]
print(c)    # [0, 2, 4, 6, 8]
cs


>> copy() 를 사용한다.



- 음수 인덱스


1
2
3
= list(range(0102))
print(a)    # [0, 2, 4, 6, 8]
print(a[0], a[-1])      # 0 8
cs


>>  파이썬은 음수 인덱스를 지원한다. -1은 마지막 값, -2은 뒤에서 두번째 값

< 숙제 review >


1) 팰린드롬인지 판단한는 함수 재귀함수로 구현하기


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <string.h>
 
int isP(char str[], int s, int e)
{
    if(s >= e) return 1;
    return str[s]==str[e] ? isP(str, s+1, e-1) : 0;
}
 
int main()
{
    char str[100];
    scanf("%s", str);
    isP(str, 0, strlen(str)-1) ? puts("True") : puts("False");
    return 0;
}
 
cs


>> 첫번째 인덱스와 마지막 인덱스의 문자가 같을때, 그 안의 문자열이 팰린드롬이면 팰린드롬이다.



2) 리스트의 내용을 모두 출력하는 함수 만들기


1
2
3
4
5
6
7
8
void printList(List *list)
{
    Node *= list->head;
    while(p != NULL) {
        printf("%d\n", p->data);
        p = p->next;
    }
}
cs




< Tutoring >


< 연결리스트의 전체노드 삭제 >


1
2
3
4
5
6
7
8
9
10
void deleteList(List *list)
{
    Node *= list->head;
    while(p != NULL) {
        Node *tmp = p;
        p = p->next;
        free(tmp);
    }
    init(list);
}
cs


>> 위 예제의 응용에 불과하다고 생각함.

>> 동적할당으로 생성된 변수는 free() 를 통해 해제를 시킬 수 있다.

>> 9번은 다 지우고 난 다음 초기화를 다시 해주는 역할 정도..



< 연결리스트에서 특정 노드의 삭제 >


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void deleteNode(List *list, int pos)
{
    int k = 1;
    Node *prev, *cur = list->head;
    if(pos == 1) {
        list->head = list->head->next;
        free(cur);
        return ;
    }
    
    while(k < pos) {
        k++;
        prev = cur;
        cur = cur->next;
    }
    prev->next = cur->next;
    free(cur);
}
cs


>> 11~14 에서 첫번째 노드가 1번 노드라고 할 때, k번째 노드는 cur 가 가리키게 된다.

>> 하지만 위의 코드는 pos 의 값이 노드의 갯수보다 큰 값이 들어오면 에러가 발생한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void deleteNode2(List *list, int pos)
{
    int k = 1;
    Node *prev, *cur = list->head;
 
    if(cur == NULL)
        return ;
 
    if(pos == 1) {
        list->head = list->head->next;
        free(cur);
        return ;
    }
    
    while(cur != NULL && k < pos) {
        k++;
        prev = cur;
        cur = cur->next;
    }
 
    if(cur == NULL) {
        puts("Position does not exist.");
        return ;
    }
 
    prev->next = cur->next;
    free(cur);
}
cs



>> 어떤 부분들이 바뀌었는지 비교해봐 얘들아.. ㅎㅎ

>> 그외 List 주머니에 사이즈 관련 변수 하나 만들어서 노드의 개수를 카운트 해나가면서

     pos 값이 그 사이즈 안에 있는 값인지 체크하는 방법으로 해도 되고, 상황에 맞게 하면 될듯.!!



< 원형연결리스트의 삽입 (앞에) >


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <stdio.h>
#include <stdlib.h>
 
typedef struct node {
    int data;
    struct node *next;
} Node;
 
typedef struct list {
    Node *head;
} List;
 
void init(List *list)
{
    list->head = NULL;
}
 
void CircularListAdd(List *list, int data)
{
    Node *p, *newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
 
    if(list->head == NULL) {
        list->head = newNode;
        newNode->next = newNode;
        return ;
    }
 
    p = list->head;
    while(p->next != list->head)
        p = p->next;
 
    p->next = newNode;
    newNode->next = list->head;
    //list->head = newNode;
}
 
void printCircularList(List *list)
{
    Node *cur = list->head;
 
    if(cur == NULLreturn ;
 
    do {
        printf("%d\n", cur->data);
        cur = cur->next;
    } while(cur != list->head);
}
 
int main()
{
    List list;
    init(&list);
    
    CircularListAdd(&list, 1);
    CircularListAdd(&list, 3);
    CircularListAdd(&list, 7);
    CircularListAdd(&list, 5);
 
    printCircularList(&list);    
 
    return 0;
}
cs


>> 18 : 원형 연결리스트의 데이터를 삽입하는 함수.

>> 38 : 원형 연결리스트의 데이터를 출력하는 함수


>> 60 의 결과는 1, 3, 7, 5

>> 35 의 주석을 해제했을 때, 60의 결과는 5, 7, 3, 1

>> 즉 35가 없으면 뒤로 삽입, 있으면 앞으로 삽입을 하는 결과가 만들어진다.


>> 다만 위의 코드에서는 삽입을 할때, 항상 맨 마지막 노드를 찾아야 하는 번거로움(?)이 있다.

     하지만 헤드포인터를 테일이라고 생각하고 코드를 작성하면 그럴필요가 없어진다..!!


1
2
3
4
5
6
7
8
9
10
11
12
13
void CircularListAdd2(List *list, int data)
{
    Node *newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    if(list->head == NULL) {
        list->head = newNode;
        newNode->next = newNode;
        return ;
    }
    newNode->next = list->head->next;
    list->head->next = newNode;
    //list->head = newNode;
}
cs


>> head 를 tail 이라고 생각하면 된다.

>> 12 가 없으면 앞으로 삽입, 12가 있으면 뒤로 삽입하는 코드가 된다.



< 원형연결리스트의 노드들 중 홀수의 갯수 세기 >


- printCircularList() 에서 홀수인지만 판단한는 조건만 추가하고 계산 후 그 값을 리턴하면 된다.

- 그러니 우리는 if(cur->data & 1) 이라는 표현에 대해 알아보자.


>> & 는 비트 연산자로 각 비트별 AND 연산을 수행한다.

>> 참고로 모든 홀수의  마지막 비트(2^0)은 항상 1 이다.

     모든 짝수의 마지막 비트는 항상 0 이다.

>> 1 은 8비트 기준 00000001 이다.

>> 그러므로 1과 & 연산을 하면, 마지막 비트를 제외한 비트는 1이든 0이든 AND 연산의 결과는

    0이 나온다. 그렇기 때문에 홀수와 1에 대해 &(AND) 연산을 하면 항상 1이 나온다.

>> 조건식에서 1은 참을 의미한다..



cf) -1 은 비트로 표현하면 1로만 구성이 된다. 8비트라면 11111111 이 된다.

>> 1을 더하면 0이 되므로 증명 끝..

>> -2는 -1에서 1을 빼면 된다. 그러므로 -2는 8비트기준 11111110 이 된다.

>> -3은 -1에서 2를 빼면 된다. 그러므로 -3은 8비트 기준 11111101 이 된다.


>> 작은 수들은 굳이 2의 보수 취하지 않고도 이런식으로 구할 수 있다.



< 양방향 연결리스트의 삽입 >


- 우리가 지금까지 했던 연결리스트는 한방향으로만 연결이 되어 있다.

  하지만, 양방향 연결리스트는 말 그대로 양방향으로 연결이 되어 있다. 그러므로 prev 같은 노드 

  포인터가 필요없어진다.

- 노드에 대한 디자인도 새로 해야한다.


1
2
3
4
5
typedef struct node {
    int data;
    struct node *next;
    struct node *prev;
} Node;
cs


>> 4 : 이전 노드를 가리키기 위한 포인터가 추가되었다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void insertNode(List *list, int data)
{
    Node *newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = NULL;
    newNode->prev = NULL;
 
    if(list->head == NULL)
        list->head = newNode;
    else {
        newNode->next = list->head;
        list->head->prev = newNode;
        list->head = newNode;
    }
}
cs


>> 앞으로 삽입하는 코드. 

>> 6, 12번 줄이 추가가 된다.



< 더미노드를 이용한 양방향 연결리스트의 삽입 >


- 더미노드를 사용하면 list->head 가 가리키는 노드가 바뀌는 것에 대한 염려를 안해도 된다.

- 더미노드를 사용하면 init() 함수를 수정해주어야 한다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void init(List *list)
{
    list->head = (Node*)malloc(sizeof(Node));;
    list->head->prev = NULL;
    list->head->next = NULL;
}
 
void insertNode(List *list, int data)
{
    Node *newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
 
    newNode->next = list->head->next;
    list->head->next = newNode;
    newNode->prev = list->head;
}
cs


>> 그리고 삽입코드는 위와 같이 쓸 수 있다.




< 숙제 >

- 복습잘하기

- 이중연결리스트에서 position 값이 주어졌을 때, 해당 위치에 노드를 삭제하는 함수 만들기


- 양의 정수를 입력 받았을 때, 3자리 마다 , 를 찍어서 출력해주는 함수(재귀로)

   input : 1000000 >> output : 1,000,000


- 스택, 중위식을 후위식으로 표기하는 방법, 후위식을 계산하는 방법 예습해오기


How To Play "River Flows In You" On Guitar (arranged by Sunga Jung) (guitar lesson / tutorial) Part 2


튜토리얼 영상 : http://www.goliathguitartutorials.com/riverflows-part-2.html



open : 3


4F4S : 4


open : 3, 6 together


2F5S, 2F4S(Em) : 5 then 4


open 3 then hammer up to the 2F3S


3F5S : 2, 5 together 


2F4S : 4, 3 then 4, 3, 2 and hammering 1F2S


3F2S, 3F6S : 2, 6 together


4, 3 again.


1F2S : 2 and pull off


2F3S : 4, 3



intro one more time but slight different.


3F1S, 2F4S : 1, 4 together


2F1S, 2F4S : 1, 3 together


3F1S : 1


2F4S : 4 then 2


2F1S : 1, 3 together


3F1S : 1


3F1S,  3F2S, 3F5S : 5 then 3 then 2 then 1


1F2S, 3F4F : 5 then 3 then 2




3F3S, 3F6S : 3, 6 together


4F3S : 3


1F2S : 2 (index finger)


3F2S : 4, 3, 2, toghether quickly


2


2F3S : 4, 3 together


7F1S : 1


5F1S : 1, 4 together


open 4


3F2S, 5F1S  : 1, 2 together and 

     then hammer up to the 7F1S and pull off


3F1S : 1


2F1S : 1


2F1S : 1, 6


2F4S : 4, 3 


open 3 and then hammer up


3F5S : 2, 5


2F4S : 4, 3 


open : 2 then 4, 3, 2 and hammering 1F2S


3F2S, 3F6S : 2, 6 together


4, 3 again.


1F2S : 2 and pull off


2F3S : 4, 3








- C언어에서는 다른 함수에있는 변수에 접근하기 위해 포인터를 사용했다.

- C++ 에서는 레퍼런스 라는 것을 통해 가능하다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <cstdio>
 
typedef struct arr100 {
    int arr[100];
} Arr100;
 
void c_Swap(int *a, int *b)
{
    int t = *a;
    *= *b;
    *= t;
}
 
void ref_Swap(int &a, int &b)
{
    int t = a;
    a = b;
    b = t;
}
 
int sum(Arr100 &t) // Decreasing memory overhead.
{
    int Sum=0;
    for(int i=0; i<100; i++)
        Sum += t.arr[i];
    return Sum;
}
 
int main()
{
    int x = 3;
    int y = 5;
 
    // int &ref; => impossible
    // &ref = x; => impossible
    int &ref = x; 
    printf("%d %d\n", x, ref);      // 3 3
    printf("%p %p\n"&x, &ref);    // 0x7ffee122ca68 0x7ffee122ca68
 
    c_Swap(&x, &y);
    printf("%d %d\n", x, y);        // 5 3
 
    ref_Swap(x, y);
    printf("%d %d\n", x, y);        // 3 5
 
        
    Arr100 A;
    for(int i=0; i<100; i++)
        A.arr[i] = 100-i;
 
    int Sum = sum(A); 
    printf("%d\n", Sum);        // 5050
 
    return 0;
}
 
cs


>> 34 : 선언과 동시에 초기화가 필요하다.

>> 35 : 한번 가리킨 대상을 바꿀 수 없다.

>> 36 : 레퍼런스의 선언. 변수이름 앞에 &를 붙인다. 

     자료형 &변수명 = 참조할 변수명; 의 형태를 가진다.

>> 37 : x와 x를 reference 로 하는 ref 는 같은 값을 갖는다.

>> 38 : 역시 같은 주소를 갖는다. 즉 어떤 변수에 새로운 이름을 부여한다고 생각하면 된ㄷ

>> 40 : c 언어에서의 swap 함수이다. 포인터를 사용

>> 43 : 레퍼런스를 이용한 swap 으로, 매개변수를 전달할 때 주소를 전달하지 않으며,

            14 라인에서 보듯이 매개변수를 참조형으로 선언해서 전달받는다.

>> 51, 21 :  이렇게 참조형으로 매개변수를 전달 받으면, 메모리 오버헤드를 줄일 수 있다. 

  매개변수도 일종의 지역변수 이므로 그만큼의 메모리를 차지하지만, 참조형으로 전달 

  받으면 그렇지 않다. 재귀함수에서 변하지 않는 객체를 넘길 경우에서 유용하다.



- 그 외 상수값으로 초기화 할 수 없다. 바인딩을 할 수 없다는 컴파일 에러 발생


1
int &refConstant = 10;
cs


error: non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'

    int &refConstant = 10;



- 그 외 레퍼런스로 이루어진 배열을 만들 수 없다고 한다.



- 기본적인 내용은 이정도 이며, 나중에 참조형이 참 재미있는(?) 기능임을 알게 될 것이다. 

  (함수의 리턴형이 참조형인 경우)



- 또한, 래퍼런스의 필요성은 [] 등 오퍼레이터 오버로딩에서 나타난다고 한다.

  *vec[10] = 3; 같은 이상한 표현을 쓰지 않아도 된다고 하는데, 

  이 글을 작성하고 있는 시점에서 아직 은 모르는 내용이다.....



- '레퍼런스로 이루어진 배열'(int &arr[10])은 만들 수 없지만, '배열의 레퍼런스'(int (&arr)[10])은 

   만들 수 있다고 한다.. 함수의 인자로 넘겨서 항상 특정 길이를 가진 배열만을 받게 할 수도 있지만, 

  그러느니 그냥 std::array나 std::vector 쓰는 게 낫다고 함.




출처 : http://kks227.blog.me/60204949464


'Language > C++' 카테고리의 다른 글

<3> namespace (네임스페이스)  (0) 2018.02.22
<1> C++ 에서 확장된 기능  (0) 2018.02.12

- 변수를 생성과 동시에 초기화 하는 방법 추가.


1
2
3
4
5
int a = 5;
int a(5);
 
int a=2, b=3;
int a(2), b(3);
cs


>> 모든 자료형에 적용 가능.

>> 배열은 초기화 방법이 다르므로 이런식으로는 불가능



- for 문의 초기식에서 변수 선언 가능


1
2
for(int i=0; i<n; i++)
    scanf("%d"&k);
cs


>> 여기서 i 의 스코프(scope)는 해당 for 문의 안쪽이 된다.



- bool 타입의 자료형 추가.


1
2
bool isTrue = true;
bool isFalse = false;
cs



- 형변환(type casting) 의 추가.


1
2
3
4
5
double d = 3.14;
int n = (int)d;
 
double f = 3.141592;
int k = static_cast<int>(f);
cs


>> static_cast<자료형>(값) 의 형태를 가지고 있다.


>> 용도는 추후 포스팅..



- c 언어의 헤더파일 사용방법


1
2
3
4
5
#include <stdio.h> // C 
#include <stdlib.h> // C
 
#include <cstdio> // C++
#include <cstdlib> // C++
cs


>> 뒤의 .h 를 없애고, 앞에 c를 붙인다.





출처 : http://kks227.blog.me/60204924344


'Language > C++' 카테고리의 다른 글

<3> namespace (네임스페이스)  (0) 2018.02.22
<2> 레퍼런스 (reference)  (0) 2018.02.12

( https://developer.artik.io/documentation/artik/getting-started/up-to-date.html )


# apt-key add /var/lib/apt/keyrings/artik-platform-keyring.gpg

>> 이전에 안 했을 경우..


# sudo apt-get update


# apt-get upgrade




# apt install build-essential


# apt-get install aptitude


# aptitude install mplayer 

  (N – Y - Y)


>> 안되면 될때까지..!!

>> wifi 로 할 경우 여러번 실패하였다.
>> 하지만 랜선을 꼽고 했더니 한번에 되버렸다.........


'Etc. > G2C' 카테고리의 다른 글

[ARTIK530] ubuntu로 시작하기  (0) 2018.01.31

< 재귀함수 숙제 review >


- 1부터 n까지의 숫자중 홀수/짝수의 합 구하기


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
 
int oddSum(int n)
{
    if(n < 1return 0;
    if(n%2 == 0) n--;
    return n + oddSum(n-2);
}
 
int evenSum(int n)
{
    if(n < 1return 0;
    if(n%2 == 1) n--;
    return n + evenSum(n-2);
}
 
int main()
{
    int n = 100;
    printf("%d\n", oddSum(n)); 
    printf("%d\n", evenSum(n)); 
    return 0;
}
cs


>> 6번째 줄을 if(!(n%2)) 로 쓸 수도 있다.

>> 13번째 줄은 if(n&1) 로 쓸 수 있다.



- 배열의 요소들 중에서 최대값 구하기.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
 
int f(int arr[], int n)
{
    int k;
    if(n == 0return arr[0];
    k = f(arr, n-1);
    return k > arr[n] ? k : arr[n];    
}
 
int main()
{
    int arr[] = {10230115033};
 
    printf("%d\n", f(arr, 5));
    return 0;
}
cs



- 배열의 요소들 중에서 두번째 최대값 구하기.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
 
int max;
 
int f2(int arr[], int n)
{
    int k;
    if(n == 1) {
        max = arr[n] > arr[n-1] ? arr[n] : arr[n-1];
        return arr[n] > arr[n-1] ? arr[n-1] : arr[n];
    }
    k = f2(arr, n-1);
    
    if(arr[n] < k) return k;
    if(arr[n] > max) { int t=max; max=arr[n]; return t; }
    return arr[n];
}
 
int main()
{
    int arr[] = {50102301133};
 
    printf("%d\n", f2(arr, 5));
    return 0;
}
cs


>> n 은 마지막 인덱스



< 연결리스트 >




- 노드 디자인 하기


1
2
3
4
typedef struct node {
    int data;
    struct node *next;
} Node;
cs


>> 자기참조 구조체

>> typedef 의 역할 // ex) typedef int INT;

>> 구조체는 자료형이다. 사용자 정의 자료형. 즉, 우리가 만든 자료형이다.



- List 주머니(?) 디자인 하기.


1
2
3
typedef struct list {
    Node *head;
} List;
cs



- 리스트 생성 후 초기화 하기


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
 
typedef struct node {
    int data;
    struct node *next;
} Node;
 
typedef struct list {
    Node *head;
} List;
 
void init(List *list)
{
    list->head = NULL;
}
 
int main()
{
    List list;
    init(&list);
 
    return 0;
}
cs


>> 19 : List 타입의 list 변수 생성

>> 20 : list 를 초기화 하는 코드. C++에서 생성자를 수동으로 실행시킨다고 생각하면 될 것 같다.



- 데이터 삽입하기.


1
2
3
4
5
6
7
8
9
10
11
12
13
void insertNode(List *list, int data)
{
    Node *newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = NULL;
 
    if(list->head == NULL)
        list->head = newNode;
    else {
        newNode->next = list->head;
        list->head = newNode;
    }
}
cs

 

>> 3 : 동적할당으로 #include <stdlib.h> 헤더파일이 필요하며, 

   결과 값으로 이름없는 변수의 주소값을 리턴한다. 그리고 그 주소를 newNode 에 저장.


>> 3, 5, 1 순으로 삽입을 하면 (head)->(1)->(5)->(1)->NULL 모양의 리스트가 만들어 진다.

     즉, 앞쪽으로 데이터가 삽입이 된다.

     (그림은 머릿속으로.....)


>> newNode->data : newNode가 가리키는 변수의 멤버 data (고요속의 외침..ㅎㅎ)


>> 아래와 같이 분기를 하지 않아도 될 것 같다.


1
2
3
4
5
6
7
void insertNode(List *list, int data)
{
    Node *newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = list->head;
    list->head = newNode;
}
cs


>> 검증은 못해봄. 누가 테스트 해보고 결과좀 알려줘. ㅎ



- 데이터 뒤로 삽입하기. 

1) 리스트 주머니 수정하지 않고 해보기.

2) 리스트 주머니를 수정해서 해보기.



1) 의 경우


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void insertNodeBack(List *list, int data)
{
    Node *prev, *newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = NULL;
 
    if(list->head == NULL) {
        list->head = newNode;
    }
    else {
        prev = list->head;
        while(prev->next != NULL)
            prev = prev->next;
        prev->next = newNode;
    }
}
cs


>> 12-13 : prev 를 통해 맨 마지막 노드를 찾는 코드이다. 

>> 14 : 맨 마지막 노드를 찾았으면, 거기에 새 노드를 연결하면 될 듯.




### 자료구조 공부할 때, 특히 포인터등이 헷갈릴때는 그림을 그려가면서 해봐 얘들아 ㅎㅎ



### 숙  제 ###


- 복습 잘하기.

- 어떤 문자열이 주어졌을 때, 해당 문자열이 팰린드롬(회문)인지 판단하는 함수 재귀함수로 만들기

- 리스트의 내용을 모두 출력하는 함수 만들기

- 양방향 연결4리스트, 환형 연결리스트 예습해오기.

< 180130 튜터링 >

 

1 재귀함수 만들기.

>> 함수를 잘 정의하고, 그 정의를 그대로 활용하기

>> 어떻게 쪼갤지 생각하기..

>> 언제까지??(재귀의 종료, 탈출조건)

>> 점화식을 알고 있다면 그대로 표현하기.

 

- 팩토리얼 계산하는 함수

- 1부터 n까지의 합 구하는 함수

- 1 부터 n 까지 출력하는 함수

- n 부터 1까지 거꾸로 출력하는 함수

- a n (파워함수)을 구하는 함수

- 배열 요소들의 합 재귀함수로 구하기.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <stdio.h>
 
int sum(int n)
{
    if(n < 1return 0;
    return n+sum(n-1);
}
 
int evenSum(int n)
{
    if(n < 1return 0;
    if(n%2 != 0) n--;
    return n+evenSum(n-2);
}
 
void print1(int n)
{
    if(n < 1return ;
    print1(n-1);
    printf("%d\n", n);
}
 
void print2(int n)
{
    if(n < 1return ;
    printf("%d\n", n);
    print2(n-1);
}
 
 
int main()
{
    int n;
    scanf("%d"&n);
 
    printf("%d\n", sum(n));
    printf("%d\n", evenSum(n));
    print1(n); // 1 to n
    puts("");
    print2(n); // n to 1
}
 
cs



2. 함수의 호출과정

- 하노이 타워 코드가 왜 그렇지 구현되어 있는지.

(이해 안되면, Hanoi(3, ‘A’, ‘B’, ‘C’); 손으로 써가면서 따라가봐 ㅎㅎㅎㅎ)

 

- 아래 세 함수의 결과는 같지만, 호출 순서가 어떻게 다른지 생각해보기

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void f(int n)
{
    if(n == 0return ;
    f(n-1);
    f(n-1);
    printf(“*”);
}
 
void f(int n)
{
    if(n == 0return ;
    f(n-1);
    printf(“*”);
    f(n-1);
}
 
void f(int n)
{
    if(n == 0return ;
    printf(“*”);
    f(n-1);
    f(n-1);
}
cs



 

3. 동적 프로그래밍

- 피보나치 함수를 구해주는 함수에서 전달값이 크면 왜 느려지는지 생각해보기.

- 이를 해결하기 위한 방법 중 하나를 소개 했지만, 어려우면 넘어가도 됨.

  (메모이제이션)

 

### 숙제 ###

- 복습 잘 하기.

- 1부터 n 까지의 수 중 홀수(혹은 짝수)의 합 구하는 함수 구하기(재귀)

- 배열의 요소들 중 최대값(혹은 최소값) 재귀함수로 구하기.(재귀)

- 배열의 요소들 중 두번째 최대값 재귀함수로 구하기. (재귀)

(힌트가 필요하면 갠톡으로..)

- 연결리스트 개념 공부해오기

동영상 강의 : http://pythonkim.tistory.com/notice/77


# Day_02_01_loop.py



# 제어문과 반복문의 연결고리


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 문제
# count 에 0~3 사이의 숫자를 입력 받아서
# 입력받은 숫자 만큼 아침인사를 해봅니다.
# 2가지 종류의 코드를 만들어보기.
 
 
def ans1():
    count = int(input('count : '))
 
    if count == 1:
        print("Good Morning!")
    elif count == 2:
        print("Good Morning!")
        print("Good Morning!")
    elif count == 3:
        print("Good Morning!")
        print("Good Morning!")
        print("Good Morning!")
 
 
def ans2():
    count = 2
    if count >= 1:
        print("Good Morning!")
    if count >= 2:
        print("Good Morning!")
    if count >= 3:
        print("Good Morning!")
 
 
def ans3():
    count = 2
    i = 0
    if i < count:
        print("Good Morning!")
        i += 1
        if i < count:
            print("Good Morning!")
            i += 1
            if i < count:
                print("Good Morning!")
                i += 1
                if i < count:
                    print("Good Morning!")
                    i += 1
                    if i < count:
                        print("Good Morning!")
                        i += 1
 
 
def ans():
    count = 3
    i = 0
    while i < count:
        print("Good Morning!")
        i += 1
 
cs




- 규칙


# 규칙을 찾는 것이 중요. (시작, 종료, 증감)

# 1 3 5 7 9     1~9 까지 2칸씩 건너뛴다.

# 0 1 2 3 4     0~4 까지 1칸씩 건너뛴다.

# 5 4 3 2 1     5~1 까지 -1칸씩 건너뛴다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def rule1():
    i = 1                   # 시작
    while i <= 9:           # 종료
        print("Hello")
        i += 2              # 증감
 
 
def rule2():
    i = 0
    while i <= 4:
        print("Hello")
        i += 1
 
 
def rule3():
    i = 5
    while i >= 1:
        print("Hello")
        i -= 1
cs


>> Python 에서는 i++ 과 같은 증감 연산자를 제공하지 않는다고 한다. ㅜㅜ

>> 세 개 모두 "Hello" 를 5번 출력한다.



- 줄이 바뀌지 않게 하기


1
2
3
4
5
rint('Hello', end=' ')
print('python')
 
# 실행결과 
# Hello python
cs


>> end 파라미터를 사용하면 된다.


- end 파라미터의 또 다른 예시.


1
2
3
4
5
print('Hello', end='***')
print('python')
 
# 실행결과
# Hello***python
cs



-  문제


# 0 ~ 99 까지 출력하는 함수를 만드시오.


1
2
3
4
5
def show100():
    i = 0
    while i <= 99:
        print(i, end=' ')
        i += 1
cs




- for in 문 


1
2
3
4
5
6
7
8
9
10
11
12
13
for i in range(0101):
    print(i, end=' ')
print()
 
for i in range(010):
    print(i, end=' ')
print()
 
for i in range(10):
    print(i, end=' ')
print()
 
# 0 1 2 3 4 5 6 7 8 9 
cs


>> 시작 : 0, 종료 : 10, 증감 : 1

>> 시작, 종료, 증감이 명확한 경우 for 문을 사용한다.

>> 증감의 기본은 1, 시작의 기본은 0



# 문제

# count 에 0~3 사이의 숫자를 입력 받아서

# 입력받은 숫자 만큼 아침인사를 해봅니다.

# 2가지 종류의 코드를 만들어보기.


1
2
3
4
5
6
7
8
9
10
11
def sumOfOddEven():
    odd, even = 00
    for i in range(1100):
        if i%2 == 1: odd  += i
        else :       even += i
 
    return odd, even
 
 
s1, s2 = sumOfOddEven()
print(s1, s2)       # 2500 2450
cs



# 난수


1
2
3
4
5
import random
 
print(random.randrange(10))
print(random.randrange(1020))
print(random.randrange(10202))
cs


>> random 모듈을 import 한다.

>> randrange() 는 range() 와 같이 3가지의 종류의 파라미터를 갖는다.

>> 5 줄의 경우 [10, 20) 에서 2씩 증가하는 수들 중에서 난수가 발생함.



# placeholder


1
2
for _ in range(5):
    print(random.randrange(10), end=' ')
cs


>> for i in range(5): 라고 썼을 때, i 를 사용하지 않는다.

>> 하지만 i 를 지우면 에러.

>> 필요가 없는 변수로 의미를 약화시킬 수 있음. _ 로 표현 (placeholder)

>> _ 는 변수이지만 변수로 사용하지 않겠다는 의미..



# random.seed(1)


1
2
3
random.seed(1)
for _ in range(5):
    print(random.randrange(10), end=' ')    # 2 9 1 4 1
cs


>> 난수값을 고정시킬 수 있다.

>> seed 가 1이 되고 나서의 첫번째 숫자, 두번째 숫자 ...

>> 프로그램 처음에 딱 한번 호출해서 사용한다.



1
2
3
4
5
next = 1
def rand():
    global next
    next = next * 1103515245 + 12345
    return int(next // 65536) % 32768
cs


>> seed() 의 원리 같은 코드라고 한다.