Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
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
Archives
Today
Total
관리 메뉴

TIL

2021 05 27 (목) 본문

2021/일일 기록

2021 05 27 (목)

ililillllllliilli 2021. 5. 28. 13:31

20210527(목)



1. 학습 날짜 : 20210527(목)


2. 학습 시간 : 14:00 ~ 17:00, 17:30 ~ 21:30


3. 학습 주제 : push_swap 알고리즘 생각해내기, 명령어 집합 구현


4. 동료 학습 방법 :


5. 학습 목표 :

  • Push_swap 명령어 집합 구현
  • Push_swap pop() 오류 수정.
    • 잘하면 연결리스트 전체 구조를 되돌아봐야 할 수 도 있을 것 같다.
      • mental - 코드를 갈아 엎는게 왜 힘들까.
  • Push_swap 명령어 집합 구현
    • sa, sb, ss, pa, pb, ra, rb, rr, rra, rrb, rrrRReverse 계열 : head에 있는 것을 top으로 옮긴다.
    • Reverse 계열 : top에 있는 것을 head로 옮긴다
  • quicksort 사용해서 배열을 만들어서 인자들을 정렬한다. - 5시까지 완성
  • stderror에 Error\n를 출력해야한다. !!!!!!

6. 학습 내용 :



./push_swap 1 2 3 4 5 6 7 8 9 10
initialized
10    9    8    7    6    5    4    3    2    1
10    9    8    7    6    5    4    3    2    1    200
popped
popped data : 200
10    9    8    7    6    5    4    3    2    1    200

# push(200) 후 pop(200)을 했는데 200이 계속 남이있는 상황.

1차 예상 :

        *data = l_list->tail->data;
        aux_node = l_list->tail;
        l_list->tail->prev->next = l_list->head;
        l_list->head->prev = l_list->tail->prev;
        l_list->tail = aux_node->prev;        //여기에서 문제가 생긴 것으로 추정.
                                                                            //왜..?
                                                                            //
        free(aux_node);

2차 예상 :

int        linked_list_push(t_ll **ab_arr, int    num_stack, int data)
{
    t_node    *new_node;
    t_ll    *l_list;

    l_list = ab_arr[num_stack];
    new_node = (t_node *)malloc(sizeof(t_node));
    if (!new_node)
        return (ft_print_error());
        //malloc 에러 시 t_ll, 안의 모든 노드들 삭제하고 프로그램 종료.
    new_node->data = data;
    if (l_list->size == 0)
    {
        l_list->head = new_node;
        l_list->tail = new_node;
    }
    else
    {
        l_list->tail->next = new_node;
        l_list->head->prev = new_node;
        l_list->tail = new_node;    //
    }
    new_node->next = l_list->head;
    new_node->prev = l_list->tail;
    l_list->size++;
    return (1);
}

Push 하는 부분에서 문제가 생긴 것이 확실해보인다.

정확히는 push()의 else부에서 문제가 생겼다.

    else
    {
        l_list->tail->next = new_node;
        l_list->head->prev = new_node;
        l_list->tail = new_node;    // 이 부분에서 바꾸어준 tail을 
    }
    new_node->prev = l_list->tail; //변경된 tail을 다시 바꾸어서 사용하려고 했기 때문에 new_node->prev = new_node를 가리키고 있었다.

해당 문제를 고치니 해결되었다.



Push_swap 명령어 집합 구현

sa, sb, ss, pa, pb, ra, rb, rr, rra, rrb, rrr


swap 실험 성공

    swap_ab(ab_array, STACK_A);
    traverse_list(ab_array, STACK_A);
    traverse_list(ab_array, STACK_B);
    swap_ab(ab_array, STACK_A);
    traverse_list(ab_array, STACK_A);
    traverse_list(ab_array, STACK_B);
/push_swap 1 2
initialized
1    2
empty stack
2    1
empty stack
./push_swap 1 2 3 4 5 6 7
initialized
7    6    5    4    3    1    2
empty stack
7    6    5    4    3    2    1
empty stack

push 실험

    push_ab(ab_array, STACK_B);

    push_ab(ab_array, STACK_B);

    push_ab(ab_array, STACK_B);

    push_ab(ab_array, STACK_B);

    push_ab(ab_array, STACK_B);

    push_ab(ab_array, STACK_B);

    push_ab(ab_array, STACK_B);

    traverse_list(ab_array, STACK_A);
    traverse_list(ab_array, STACK_B);
./push_swap 1 2 3 4 5 6 7
initialized
7    6    5    4    3    2    1
empty stack

7    6    5    4    3    2
1

7    6    5    4    3
1    2

7    6    5    4
1    2    3

7    6    5
1    2    3    4

7    6
1    2    3    4    5

7
1    2    3    4    5    6

empty stack
1    2    3    4    5    6    7

*rev, rev 실험 : *

./push_swap 1 2 3 4 5 6 7
initialized
7    6    5    4    3    2    1
empty stack

1    7    6    5    4    3    2
empty stack

2    1    7    6    5    4    3
empty stack

3    2    1    7    6    5    4
empty stack

rrev도 동일



명령어 집합 구현 성공


인자로 들어온 숫자들을 숫자 배열에 넣은 뒤 오름차 순으로 정렬하기

  • 정수 배열을 위한 포인터를 main에 선언,
  • argument들을 받아 배열에 저장한다.
    • 동적할당.
    • 배열에 저장할 때, STACK_A를 traversing하면서 배열에 저장해야됨.
  • 배열을 "오름차순으로 정렬한다." Using quicksort. - 5시까지
  • 집에 가면 QuickSort, MergeSort 다시 짜보고, 설명 할 수 있을 때 까지 설명해보기..
  • TEST : 인자가 한개, 두개, 세개, 10개일 때 정렬이 제대로 되는가?

중간 평가

📦push_swap
 ┣ 📂includes
 ┃ ┣ 📜linked_list.h
 ┃ ┗ 📜push_swap.h
 ┣ 📂libft
 ┣ 📂srcs
 ┃ ┣ 📜arg_input.c
 ┃ ┣ 📜custom.c
 ┃ ┣ 📜inst.c
 ┃ ┣ 📜inst_2.c                #명령어 집합 위한 inst, inst_2 추가. 
 ┃ ┣ 📜linked_list.c    #linked_list 의 push 수정.
 ┃ ┣ 📜main.c
 ┃ ┣ 📜utils.c                #init_arg_arr, quicksort구현
 ┣ 📜.gitignore
 ┣ 📜Makefile
 ┣ 📜README.md
 ┗ 📜push_swap



타 카뎃의 push_swap 정리 글 보기


의문점 :

⁉️ 이렇게 해야 [3]을 정렬한 다음에 바로 [2]를 정렬할 수 있습니다.

​ ..?정렬하는 순서가 중요한 이유...?

⁉️ 세 그룹은 3등분되어 크기가 비슷할 것이므로 rrr을 반복한 후에 ra 또는 rb를 한 번 더 호출해서 되감기를 끝마칩니다.

💡3등분되어 크기가 비슷하므로, rrr를 실행한 뒤, ra 또는 rb가 필요한 스택에 있어서, ra 와 rb를 몇번 더 호출한다.


⁉️ 두 함수 조합하기 ?

​ 원소를 덜어내다 ?

⁉️ 스택 B를 정렬하는 과정에서 [2]가 올라가버리고 나면 [3]은 정렬을 할 수가 없습니다.


약간 하노이의 탑 방식으로 전개하신듯 하다.

로직도 그렇고, 하노이의 탑 방식을 따른 듯 한데..


def A_to_B(r)
    if r < 3
        적절히 정렬
        return                            //r이 3보다 작을 때는, 명령어 수를 줄이기 위해서..
    스택A 원소 중에서 "적절한" 피봇을 2개 선택한다
    for r개의 원소에 대해서
        if (스택A의 top) >= 피봇[큰것]        //큰 것은 stack의 head 부로 넘긴다.
            ra명령으로 뒤로 넘긴다        
            ra호출횟수++
        else                                                    //작은 것들은 stack B로 옮기는데, 작은 피벗을 기준으로, 작은 피벗보다 큰                                                                         것은 head로, 작은 피벗보다 작은 것은 tail에 둔다.
            pb명령으로 b로 보낸다
            pb호출횟수++                                    
            if (스택B의 top) >= 피봇 [작은것]
                rb명령으로 뒤로 넘긴다
                rb호출횟수++
    for ra호출횟수, rb호출횟수
        rrr호출 #[3]과 [2]를 스택 앞으로 가져온다
    A_to_B(ra호출 횟수) #[3]                            // A의 3등분한 것 중 큰 chunk - [3] 에 대해서 재귀적으로 정렬해 진행한다.
    B_to_A(rb호출 횟수) #[2]                            // B의 3등분한 것 중 작은 Chunk들에 대해서,재귀적으로 정렬하는데, 
    B_to_A(pb호출 횟수 - rb 호출 횟수) #[1]        // 이 때, [2]를 정렬한 뒤에 [1]을 정렬한다.
                                                                            //재귀적으로, 순서대로 정렬한다.

    출처 : https://www.notion.so/push_swap-c15e6222
def B_to_A(r)
    if r < 3
        적절히 정렬/pa로 보내기
        return
    스택B 원소 중에서 "적절한" 피봇을 2개 선택한다
    for r개의 원소에 대해서
        if (스택B의 top) < 피봇[작은것]
            rb명령으로 뒤로 넘긴다
            rb호출횟수++
        else
            pa명령으로 a로 보낸다
            pa호출횟수++
            if (스택B의 top) >= 피봇 [큰것]
                ra명령으로 뒤로 넘긴다
                ra호출횟수++
    A_to_B(pa호출횟수 - ra호출횟수) #[3]            // 
    for ra호출횟수, rb호출횟수
        rrr호출 #[1]과 [2]를 스택 앞으로 가져온다
    A_to_B(rb호출횟수) #[2]
    B_to_A(ra호출횟수) #[1]

Screen-Shot-2021-05-27-at-8-52-25-PM

QuickSort 와 유사하게 진행되며, 하노이의 탑과 같은, 식으로 진행된다.


""분할 정복" 에서 A_to_B와 B_to_A의 흐름이 조금 다른데, 흐름이 다른 이유는 다음과 같다.

A에는 큰 수를, B에는 작은 수를 두기로 정하며,

따라서, A에는 큰 수를 오름차순으로,

B에는 작은 수를 내림차순으로 둔다. (Stack B에서, )


최종 목표는 top에서부터 오름차순으로 정렬하는게 목표이기 때문에, 그렇게 한다.


Screen-Shot-2021-05-27-at-9-04-38-PM

B에는 top을 기준으로, 내림차순으로(큰 숫자부터 밑으로 작은숫자까지) 정렬되어있어야한다.



Screen-Shot-2021-05-27-at-9-08-29-PM

오늘 이해한 바는 여기까지..

Push_swap 최종 정리 필요


학습에 도움된 사이트 :

주제 페이지
Cadet's notion https://www.notion.so/push_swap-c15e62229b954
보안 이유로 사이트 url을 잘라둠.



오늘 발견한 문제와 해결방안:

  • push_swap 알고리즘의 이해가 필요하다. 지금 한 30%정도 이해한듯하다.
  • 설명할 수 있을 떄 까지 관련 알고리즘을 공부,
  • quicksort도 다시 한 번 정의를 알아야하며, 코딩도 다시 해봐야함.



7. 학습 총평 :

  • 알고리즘부 제외한 구현부분을 구현하는데 이틀 소요. (Testing까지)
  • 알고리즘 공부와 그것의 구현부는 오늘로부터 3일정도 소요기간을 잡아야 할 것 같다.

8. 다음 학습 계획 :

  • 알고리즘의 구현, 디버깅
 

'2021 > 일일 기록' 카테고리의 다른 글

2021 05 31(월)  (0) 2021.06.01
2021 05 28 (금)  (0) 2021.05.31
2021 05 27 (수)  (0) 2021.05.26
2021 05 24(월)  (0) 2021.05.24
2021-04-05 (월) : 데이터 분석  (0) 2021.04.06
Comments