SlideShare une entreprise Scribd logo
1  sur  26
자료구조01


조별 프로젝트 #2




     말(馬)의 여행




             조장 : 09 김창헌
             조원 : 09 김정훈
                 11 김정무
                 11 김종진
                 11 김지환
-Index-
-개인별 업무
-일정계획
-회의록
-기본자료
-알고리즘
-초안
-문제점 & 해결방안
-최종소스
-결과분석
-참고문헌 및 출처
※개인별업무
09김창헌     조장 : 회의록작성 및 보고서 작성, 일정 계획



09김정훈         관련사항 조사 및 복잡도계산



11김정무         관련사항 조사 및 복잡도계산



11김종진        프로그램 설계 및 알고리즘 구상



11김지환        프로그램 설계 및 알고리즘 구상




        ※일정계획

3월27일            업무분담 및 문제파악




3월29일           조사내용 정리 및 이해




4월 3일   프로그램 설계 문제점 파악 해결방안 모색 및 초안작성




4월 7일      최종 프로그램 설계 및 최종 보고서 작성
※회의록
회의일시    2012년 3월 27일(화)                조    C1        작성자   09김창헌

참석자     09김창헌, 09김정훈, 11김정무, 11김종진, 11김지환




         내용                                           비고




        1.조원별 업무분담
        조장과 프로그램설계 2명, 관련사항 조사 2명으로 팀을 구성했다.
        2.일정 계획
        다음 회의시간까지 자신이 맡은 업무를 수행해 와서 서로 어떻게 문제를 풀어나
        갈 것 인지 토의하기로 함
        3.보고서 계획
 회의내용   소집단보고서작성 및 자신들이 참고한 자료들과 출처를 조장에게 보내주기로 함.
        조장이 종합해서 보고서 초안 작성하기로 함.
        4.알고리즘 계획
        다음 회의시간에 서로 맡은 업무에 충실히 연구를 하여 어떻게 알고리즘을 짤 것
        인지에 대해 토의하기로 함.
회의일시    2012년 3월 29일(목)                조    C1         작성자   09김창헌

참석자     09김창헌, 09김정훈, 11김정무, 11김종진, 11김지환




         내용                                            비고




        1.조원별 업무 파악
        각자 맡은 업무에 대해 조장이 자료들을 확인하여 프로젝트를 어떤 방향으로 진
        행해야할지 초안에 대해 토의함.
        2.일정 확인
        회의시간이 끝나고 설계조원들이 초안을 작성한 뒤 주말에 모여서 프로젝트를 진
        행하기로 함.
        3.문제점 파악/해결법 토의
 회의내용   스택, 큐, 백트래킹의 기본적 내용만 알고 있어서 어떻게 프로그램에 적용시킬 것
        인지에 대해 많은 연구가 필요할 것 같다.
        자료조사 하는 조원이 오늘밤까지 스택, 큐, 백트래킹의 종류와 적용법등을 조사
        하여 온라인으로 설명을 해주기로 했다.
        4.보고서 초안 토의
        개인 소집단 보고서와 자료조사내용 및 출처와 프로그램 초안과 알고리즘, 프로
        그램 설계중 문제점과 해결법을 추가하여 보고서 초안을 만들기로 토의함.
회의일시    2012년 4월 3일(화)                 조    C1       작성자   09김창헌

참석자     09김창헌, 09김정훈, 11김정무, 11김종진, 11김지환




        내용                                           비고




        1.조원별 업무 파악
        자료조사 조원들은 임무를 거의 다 수행하여, 설계조원의 임무를 같이 도와주기
        로 하였음.
        2.일정 확인
        이번 회의 마치고 설계 조원이 소스를 마무리하면 주말에 모여서 최종보고서 및
 회의내용   소스파악 하기로 함.
        3.문제점 파악 / 해결법 토의
        스택을 사용하지 않고 소스를 설계해서 관련사항 조원들과 함께 어떤 식으로 접
        목시켜야 할지 이야기 하기로 함.
        4.보고서 확정
        최종 소스 마무리 되고 나서 조원들과 모여 조장이 쓴 최종보고서를 읽어보고
        수정 할 부분 수정 하고 최종보고서 확정 짓기로 함
※기본자료
스택의 개념
스택의 구조는 매우 간단합니다. 스택은 밑이 막혀있는 긴 통이라고 보면 됩니다. 즉, 입구
와 출구가 같은 긴 통이므로 먼저 들어간 것은 밑에 있게 되고, 나중에 들어간 것은 제일
먼저 나오게 됩니다. 그래서 스택을 LIFO(Last In First Out)구조라 고 합니다.




스택을 조작하는 방법(연산이라고 합니다.) 은 두가지가 있습니다. 하나는 스택에 값을 집
어 넣는 연산인 push이고 다른 하나는 스택에서 값을 빼내는 pop 동작입니다. 위 그림을
보면 쉽게 이해가 될 것입니다.
배열로 스택 구현하기
배열을 이용하여 스택을 구현하는 것은 위의 그림과 같은 모양이 됩니다. 우선 스택의 긴
통을 정의 하고 스택의 마지막 데이터의 위치인 상단을 top이라는 배열 인덱스를 이용하겠
습니다.
배열의 성격상 스택 이라는 통의 크기는 정해 놓아야 합니다. 일단 10이라고 잡겠습니다.
스택에 들어갈 데이터는 정수형이라고 가정하면 다음과 같이 정의 할 수 있습니다.
#define MAXSIZE 10 // 스택의 크기 정의
int stack[MAXSIZE]; // 스택의 긴 통
int top; // 스택의 상단
여기서 top의 위치를 정확히 규정해 봅니다. 어떤 경우는 top이 스택의 가장 위 데이터가
아니라 그 위, 즉, 다음에 들어갈 데이터 저장 공간을 가리키기도 합니다. 여기서는 가장 위
의 데이터를 가리키는 것으로 정하겠습니다. 스택을 정의 할 때 두가지 중 하나를 선택해서
사용하여야 하며, 혼용되어서는 안됩니다.
그리고, 스택연산을 정의 할 때, 극단적인 경우, 즉, 데이터가 하나도 없을 때와 꽉 차있을
때에 약간 주의를 해야 합니다.
먼저, 스택이 비어 있는 경우 top은 -1의 값을 가져야 합니다. C에서 배열의 인덱스는 0
부터 시작하므로, top이 0이라면 스택에 데이터가 하나 있다는 의미입니다. 스택이 비어있
는 경우는 초기 스택이 생성되었을 때도 마찬가지 이므로 스택을 초기화 하려면 top을 -1
로 설정하면 됩니다.
push를 위해서는 값이 있어야 하므로 push의 함수 인자로 val이라는 양의 정수형을 사용하
겠습니다. 그 후 push는 top을 하나 증가시키고 배열의 인덱스 top에 val을 넣으면 됩니다.
그런데, 앞서 말씀드렸듯이 스택이 꽉차있는 경우에 push를 하게 되면 스택이 넘쳐나게 됩
니다. 이를 스택 오버플로우(Stack Overflow)라고 합니다. 그러므로 배열의 인덱스인 top이
MAX-1이 되었을 때 스택이 꽉차있는 경우이므로 예외 처리를 해야 합니다.



[[ 스택의 용도 ]]
컴퓨터에서 스택이 사용되는 가장 대표적인 부분은 바로 연산이다.
연산에는 우선 순위라는 것이 있기 때문에 연산 도중에 우선 순위가 높은 연산을 만나게 되면 그 동
안의 연산 결과를 잠시 보관해두고
우선 순위가 높은 연산을 먼저 처리하게 되는데 이때 또다시 더 높은 순위의 연산을 만나면 또 스택
에 보관해두고 현재의 연산을 한다.
그리고 순위가 높은 연산이 끝나면 다시 스택에서 그 전에 하던 연산을 가져와서 계속해서 연산을 수
행해 나가는 것이다.
이 것 이외에도 함수의 호출시에도 메인 함수에서 함수를 호출하게 되면 메인 함수에서 사용되던 지
역 변수들이 모두 스택에 저장된다.
그리고 해당 함수의 작업을 진행하게 되고 또 그 함수에서 다른 함수의 호출이 있게 되면 그 동안 사
용되던 모든 정보를 스택에 저장하고
다시 함수를 호출하여 작업을 수행하다가 그 함수가 종료되면 스택에서 그 전의 모든 정보를 가져와
함수 호출 다음의 작업을 재개한다.
이런 식의 작업들을 수행하기 위해서는 스택이라는 후입 선출의 기억 장치가 꼭 필요한 것이다.


큐의 개념
 큐는 스택과 비슷한 모양을 하고 있지만, 조작방식은 다릅니다. 큐의 구조도 간단한데, 스
택과 달리 앞 뒤가 뚫린 통이라고 보시면 됩니다. 이 통은 뒤에서 뭔가를 집어넣고 앞에서
빼냅니다. 즉, 먼저 들어온 것은 먼저 나오는 구조로 FIFO(First In First Out)이라고 부릅니
다.




 큐의 연산은 put과 get이 있습니다. 큐에 자료를 집어 넣을 때는 뒤(rear)에서 처리하고,
이를 put이라고 합니다. 반대로 큐에서 자료를 빼낼 때는 앞(front)에서 처리하고 이를 get
이라고 합니다.
배열로 큐 구현하기
 배열을 이용한 큐의 구현은 스택의 구현과 비슷한 난이도일 것 같지만, 조금 더 생각해보
면 문제가 아주 많습니다. 먼저 저장할 자료의 앞과 뒤를 가리키는 변수를 선언하여 큐의
구조를 정의해 보겠습니다.
#define MAXSIZE 10 // 큐의 크기
int queue[MAXSIZE];
int front=-1, rear=-1;
 다음으로 put과 get 연산을 정의해 보겠습니다.
int put (unsigned int val) {
if (rear >= MAXSIZE-1) {
    printf (" Queue Overflow");
    return (-1);
    }
    queue[++rear] = val;
}
int get () {
    if (front <= 0) {
    printf (" Queue Underflow");
    return -1;
    }
    return queue[front++];
}
배열의 인덱스로 사용되는 front와 rear가 위 코드에서는 계속 증가하기만 합니다. 결국 몇
번의 연산을 한 후에 rear가 배열의 한계를 넘어 더이상 put연산이 Overflow에러를 발생시
킬 수 있습니다. 그러므로 rear가 배열의 한계에 다다랐을 때에 큐의 데이터를 배열의 앞부
분으로 옮기는 동작이 필요하게 됩니다.
int put (unsigned int val) {
    if (rear >= MAXSIZE-1) {
    if (!(rear-front)) {
    return -1;
    }
    // 여기서 배열의 앞으로 옮겨야 한다.
    memcpy (&queue[0], &queue[front], rear-front+1);
    rear=rear-front;
    front = 0;
    }
    queue[++rear] = val;
}
    지금은 배열의 개수를 10으로 정의 했지만 만약에 5억개라면? 그런 데이터 이동이 put할
때마다 발생한다면? 당연히 비효율적이겠죠.
그래서 해결방법으로 나왔습니다. 환형 (또는 원형) 큐(Circular Queue)를 이용하는 것입니
다. 환형 큐는 뱀이 꼬리를 물고 있는 듯한 모양을 가지고 있습니다. 데이터가 순환하며 저
장되기 때문에 끝이라는 개념도 없습니다. 다음 그림을 보시죠.




[[ 큐의 용도 ]]
큐는 일련의 일들이 순차적으로 진행되는 가운데, 일의 진행이 조금 지체될때 큐에는 다음 일들이 계
속해서 쌓여가는 방식이다.
흔히 버퍼링이라 불리는 스트리밍의 로딩 작업 역시 큐에 자료가 쌓이고 플레이어는 큐의 앞부분부터
플레이를 하게 되는 것이다.
그러다 로딩이 늦어져서 큐에 쌓였던 자료가 모두 사용되고 나면 플레이어는 중지되고 다시 버퍼링
작업을 하게 되는 것이다.
이것 이외에도 프린트 작업을 할때 프린터는 처리 속도에 제한이 있기 때문에 여러가지의 출력을 지
시하게 되면 지시된 순서대로
큐에 자료를 저장하고 하나의 출력이 끝나면 큐에서 다음 자료를 받아와 출력하는 작업을 반복한다.
그러다 큐가 비면 대기 상태가 된다.
이외에도 큐의 용도는 다양하다. 기억할 점은 큐는 순차적인 업무 처리를 위해 다음 할 일을 기억해
두는 장치라는 것이다.
스택은 하던 일을 잠시 접어둘때 사용되는 기억 장치라는 점이 큐와는 다른 점이다.

백트래킹
입력받은 배열의 값에 대해서 가능한 모든 순서조합을 만들어냅니다.
단, 모든 순서조합을 위해서는 최초에 배열의 수가 오름차순으로 정렬되어져 있어야 합니
다.
최종적인 형태는 내림차순정렬이 되어져 있으며, 이때 함수는 더이상 처리를 하지 않고 들
어온 값 그대로 리턴 시켜 버립니다.
내림차순 정렬이 완료 되었으나, 맞는 조합이 없었다면, 해당 문제는 해가 없는 것이 됩니
다.
매번 시도 마다 다음 조합으로 만들어 냅니다. (1차 배열만, 배열의 크기는 무관)
현재 배열의 순서가 답이 될수 없다면, 배열을 다시 백트랙 돌리면 바로 다음 배열 순서의
조합을 만들어냅니다.
1-2-3-4-5-6-7-8-9 의 항이 있었다고 가정할 때, 이 값의 순서가 해당 문제의 답으로서
맞지 않는다면 다음 항으로는 한칸 앞으로 돌아와서 순서를 바꾸어 볼수 있습니다.


입력받은 배열의 값에 대해서 가능한 모든 순서조합을 만들어냅니다.
단, 모든 순서조합을 위해서는 최초에 배열의 수가 오름차순으로 정렬되어져 있어야 합니
다.
최종적인 형태는 내림차순정렬이 되어져 있으며, 이때 함수는 더이상 처리를 하지 않고 들
어온 값 그대로 리턴 시켜 버립니다.


내림차순 정렬이 완료 되었으나, 맞는 조합이 없었다면, 해당 문제는 해가 없는 것이 됩니
다.
매번 시도 마다 다음 조합으로 만들어 냅니다. (1차 배열만, 배열의 크기는 무관)
현재 배열의 순서가 답이 될수 없다면, 배열을 다시 백트랙 돌리면 바로 다음 배열 순서의
조합을 만들어냅니다.
infix, prefix, postfix. (중위표기법, 전위표기법, 후위표기법)

일반적인 수식은 infix이다.
즉, 연산자가 피연산자(보통숫자나 문자)와 피연산자 사이에 존재한다. a + 1과 같은 형태
이다.
기준이 되는 것은 연산자의 위치이다.
+ a 1과 같이 연산자가 피연산자들 앞에 있다면 prefix라고 한다.
반대로 a 1 +과 같은 경우는 당연히 postfix라고 한다.
그럼 infix를 prefix or postfix 로 바꾸는 법을 알아보자.
우선 infix식을 하나 가져온다.


1 + ( a + 2 ) * 5 / 7


아무렇게나 쓴 식이다.
이 식에서 취할 수 있는 모든 괄호를 취해보자.


( 1 + ( ( ( a + 2 ) * 5 ) / 7 ) )


계산상의 순서의 변화는 없을 것이다. 그저 보조괄호를 취한 것뿐이니.
여기서 주목할 것은, 각 괄호 안에는 모두 "피연산자 + 연산자 + 피연산자" 의 구조를 갖고
있다는 것이다.
각 괄호를 기준으로 연산자를 뒤로 빼보자.


( 1 + ( ( ( a 2 )+ * 5 ) / 7 ) )
( 1 + ( ( ( a 2 )+ 5 )* / 7 ) )
( 1 + ( ( ( a 2 )+ 5 )* 7 ) / )
( 1 ( ( ( a 2 )+ 5 )* 7 ) / ) +


각 연산자가 자기 자신이 속해 있는 괄호의 뒤로 빠진 것이다.
이런 식으로 바꾸고 괄호를 모두 삭제해보자.


1 a 2 + 5 * 7 / +


위와 같은 모양의 식이 나오는데, 이게 제대로 만들어 진 건지를 확인해 보기 위해서
이 상태로 앞에서 부터 스택에 넣고 계산해 보자. 연산자를 만나면 스택에서 두개의 피연산
자를 빼서 계산하고 다시 넣는다.


+ : a + 2
* : (a + 2 ) * 5
/ : (a + 2 ) * 5 / 7
+ : 1 + ( a + 2 ) * 5 / 7



잘 된다.
그렇다면 prefix는? 위의 괄호에서 연산자를 앞으로 빼면 된다.
prefix의 경우에는 헝가리 표기법이라고도 한다는데 원래는 명제를 단순하게 표현하기 위해
서 씌였다고 한다.
이를 가지고 스택으로 계산이 불가능한가?
그건 또 아니다. 단지 구현의 차이일뿐.
postfix에서 연산자를 만나면 스택에서 두개의 피연산자를 빼서 더하고 다시 넣어줬다면,
prefix에서는 만약에 스택에 연속 된 두개의 피연산자가 들어오면 두개의 피연산자를 빼주
고 바로 밑의 연산자를 꺼내
계산을 하고 이를 집어 넣어 준다.
예를 보는 게 가장 빠르겠지...


( a + b ) * c + d * k


물론 아무렇게나 쓴 식이다.
괄호로 묶는다.


( ( ( a + b ) * c ) + ( d * k ) )


변환 한다.


( ( + ( a   b ) * c ) + ( d * k ) )
( * ( + ( a b )    c ) + ( d * k ) )
( * ( + ( a b )    c ) + * ( d k ) )
+ ( * ( + ( a b ) c ) * ( d k ) )


괄호 제거...


+ * + a b c * d k


와 같다. 이제 하나씩 넣어보자. 초반에는 연산자만 잔득이나 한번에 넣었다고 하자. 일일이
한줄씩 쓰기 귀찮으니.


+ * + a : b                            -> + * ( a + b )             // 3개의 연산자와 1개의


피연산자가 있는데 추가로 한개의 피연산자 삽입


+ * ( a + b ) : c                     -> +     ( ( a + b ) * c )
+   ( ( a + b ) * c ) : *           -> +     ( ( a + b ) * c ) *
+   ( ( a + b ) * c ) * : d      -> +        ( ( a + b ) * c ) * d
+   ( ( a + b ) * c )    *   d : k -> +      ( ( a + b ) * c )     (d * k) - > ( ( a + b ) *
c ) + (d * k)


잘 된다~


각 표기법을 자료구조를 통해서 바꾸는 법.


<트리 형태>


가장 먼저 연산 되는 것부터 리프에서 부터 만들어서 타고 올라온다.
이를 전위 순회를 하면 prefix, 후위 순회를 하면 postfix 중위 순위를 하면 infix가 된다.
형태를 만들면, 스택을 이용하여 가능하다.
<스택과 큐를 사용>


요건 좀 중요한데, 우선 infix을 postfix로 만드는 방법을 보자.
스택과 큐를 사용한다. 스택은 infix를 postfix로 바꾸는 과정에서 연산자를 잠시 저장한다.
알고리즘은 아래와 같다.


 각 연산자의 우선순위는 [ 괄호 < +,- < *,/ ] 의 순이다.


1. '(' 를 만나면 스택에 푸시한다. (푸시 => 저장)
2. ')' 를 만나면 스택에서 '('가 나올때까지 팝하여 큐에 넣고 '('는 팝하여 버린다.
3. 연산자를 만나면 스택에서 그 연산자보다 낮은 우선순위의 연산자를 만날 때까지 팝하
여 큐에 넣고 자신을 푸시한다.
4. 피연산자는 그냥 큐에 넣는다.
5. 모든 입력이 끝나면 스텍에 있는 연산자들을 모두 팝하여 출력한다.



        예)   (2*(3+6/2)+2)/4+3


              문자      큐                    스택(상단->하단)           설명
               (                                                      (
'(' 스택에 푸시 (저장)
               2              2                                       (
숫자는 화면에 출력
               *       2                         * (               '*'
가 '('보다우선순위가 높음
               (       2                         ( * (               '('
는 스택에 푸시( 저장)
               3        2 3                     ( * (            숫자
는 화면에 출력
               +        2 3                     + ( * (          '+'가
'('보다 우선순위가 높음
               6        2 3 6                   + ( * (          숫자
는 화면에 출력
               /       2 3 6                     / + ( * (       '/'가
'+'보다 우선순위가 높음
               2        2 3 6 2                 / + ( * (        숫자
는 화면에 출력
               )       2 3 6 2 / +             * (              '('까지
는 팝하여 출력,'('는무시
               +        2 3 6 2 / + *          + (              '*' 는
'+' 보다 높으므로 팝
               2        2 3 6 2 / + * 2        + (              숫자는
출력
               )       2 3 6 2 / + * 2 +                     '(' 까지 팝
하여 출력
               /       2 3 6 2 / + * 2 +   /                  연산자는
푸시(저장)
4    2 3 6 2 / + * 2 + 4            /     숫자는 출
력
             +    2 3 6 2 / + * 2 + 4 /      +       '/'는 '+'보다
높아서 출력하고'+'는저장
             3    2 3 6 2 / + * 2 + 4 / 3    +         숫자는 출
력
             끝   2 3 6 2 / + * 2 + 4 / 3 +           끝이므로 모두
팝(출력)




이제 큐에 있는 내용을 디큐(dequeue)하면서 스택에 넣으면서 위에 정리한 postfix방법으로
계산을 하면 된다.
※알고리즘
1)장기판 좌표를 정수로 바꾸었을 경우.
①말의 좌표 x, y를 입력한다.
②x*10+y를 통해 각 좌표를 정수로 바꾸고 1차 배열로 구현하고 0으로 초기화한다.
③한 번 간 좌표는 1로 표시하여 중복을 피한다.
④움직일 때 마다 카운트를 올린다.
⑤움직일 곳 없이 모두 막혀 있다면 백트랙킹을 통해 다음 조건을 찾아본다.
⑥반복한다.
⑦카운터가 장기판 크기인 89까지 올라왔다면 처음부터 출력한다.


1-1)장기판 좌표를 정수로 바꾸었을 경우(수정).
①말의 좌표 x, y를 입력한다.
②x*10+y를 통해 각 좌표를 정수로 바꾼다.
③말이 움직인 좌표를 stack 배열에 넣는다.
④움직일 때 마다 카운트를 올린다.
④말이 있는 좌표에서 이동 가능한 전 좌표를 찾는다.
⑥스택 배열에 들어있는 좌표와 ④번에서 찾은 좌표를 처음부터 비교해 순서대로 중복되지
않았다면 첫 번째 좌표를 stack배열에 넣고 계속 반복한다.
⑤움직일 곳 없이 모두 막혀 있다면 백트랙킹을 통해 다음 조건을 찾아본다.
⑥반복한다.
⑦카운터가 장기판 크기인 89까지 올라왔다면 처음부터 출력한다.


1-2)장기판 좌표를 정수로 바꾸엇을 경우(수정).
①말의 좌표 x, y를 입력한다.
②x*10+y를 통해 각 좌표를 정수로 바꾼다.
②stack 2개 잡는다.
③stack1에 시작값을 저장.
④stack2에 이동경로를 저장.
④stack2의 top의 값으로 이동.
⑥stack2의 top의 값의 이동경로에 stack1의 값이 포함되지 않는다면 stack1에 top의 값을
버림.
⑤stack2의 top의 값이 이동경로에 stack1의 값이 포함된다면 stack2의 top의 값을 stack1
에 저장.
⑥stack2의 top의 값을 버림.
⑦stack2에 값이 없을 경우 stack1의 배열을 queue의 형태로 좌표 출력.
⑧stack2에 값이 있을 경우 stack1에 저장된 값과 비교 후 stack1에 없는 이동경로만
stack2에 저장(중복체크)
⑨④번으로 돌아가서 반복


2)장기판을 2차 배열로 구현했을 경우.
①말의 좌표 x, y를 입력한다.
②장기판의 각 점을 좌표라 생각하고 2차 배열로 장기판을 만든다.
③한 번 간 좌표는 1로 표시하여 중복을 피한다.
④움직일 때 마다 카운트를 올린다.
⑤움직일 곳 없이 모두 막혀 있다면 백트랙킹을 통해 다음 조건을 찾아본다.
⑥반복한다.
⑦카운터가 장기판 크기인 89까지 올라왔다면 처음부터 출력한다.
※초안
#include <stdio.h>
#include <stdlib.h>


#define ROW_SIZE 10
#define COL_SIZE 9


#define NUM_WAYS 8
typedef int board_t[ROW_SIZE][COL_SIZE];
int dr[NUM_WAYS] = {-2,-1,1,2,2,1,-1,-2};
int dc[NUM_WAYS] = {1,2,2,1,-1,-2,-2,-1};


void initialize_board(board_t board)
{
         int i,j;
         for(i=0;i<ROW_SIZE;i++)
         {
                    for(j=0;j<COL_SIZE;j++)
                    {
                             board[i][j] = -1;
                    }
         }
}


void print_board(board_t board)
{
         int i,j;
         for(i=0;i<ROW_SIZE;i++)
         {
                    for(j=0;j<COL_SIZE;j++)
                    {
                             printf("%dt",board[i][j]);
                    }
                    printf("n");
         }
}


int is_inside_board(int r, int c)
{
         return r>=0 && r<ROW_SIZE && c>=0 && c<COL_SIZE;
}


int is_available(board_t board, int r, int c)
{
return is_inside_board(r,c) && board[r][c] == -1;
}


int num_next_moves(board_t board, int r, int c)
{
        int i,result=0;
        for(i=0;i<NUM_WAYS;i++)
        {
                   if(is_available(board,r+dr[i],c+dc[i]))
                   {
                            result++;
                   }
        }
        return result;
}


int next_way_of(board_t board, int r, int c)
{
        int i, min = NUM_WAYS, result=0;
        for(i=0;i<NUM_WAYS;i++)
        {
                   if(is_available(board,           r+dr[i],         c+dc[i])   &&
num_next_moves(board,r+dr[i],c+dc[i])<min)
                   {
                            min=num_next_moves(board,r+dr[i],c+dc[i]);
                            result=i;
                   }
        }
        return result;
}


int main()
{
        int r,c,move,next_way;
        board_t board;


        initialize_board(board);
        while(1)
        {
                   printf("input start position r(0~9) c(0~8): ");
                   scanf("%d %d",&r, &c);
                   fflush(stdin);
                   if(is_inside_board(r,c))
                   {
                            break;
                   }
                   printf("Please put them again.n");
        }
        board[r][c] = 0;
for(move=1;move<ROW_SIZE*COL_SIZE;move++)
    {
            if(num_next_moves(board,r,c)==0)
            {
                       printf("Failed.n");
                       print_board(board);
                       system("pause");
                       return 1;
            }
            next_way = next_way_of(board,r,c);
            r=r+dr[next_way];
            c=c+dc[next_way];
            board[r][c]=move;
    }
    print_board(board);
    system("pause");
    return 0;
}
※문제점 & 해결방안
문제점
 체스의 말 이동 소스를 참고해서 수정해 나
갔지만 그것은 장기의 말 이동과는 다른 이동
을 보여주고 스택을 사용하지 않고 공식을 이
용해 문제를 풀어 나갈려고 했다.




해결방안
 스택을 이용한 1차 배열로 바꿔 해결하려고
했다.
※최종소스

#include <stdio.h>
#define STACK_SIZE 8
#define JANG_GI 89
int stack2[STACK_SIZE];
int po[STACK_SIZE47];
void position(int a){
 int n, n1=0;
 stack2[0] = a-21;
 stack2[1] = a-19;
 stack2[2] = a-12;
 stack2[3] = a-8;
 stack2[4] = a+8;
 stack2[5] = a+12;
 stack2[6] = a+19;
 stack2[7] = a+21;
    for(n=0; n<STACK_SIZE; n++){
        if(stack2[n]<=0&&stack2[n]>=89){


if(stack2[n]%10==a%10-2||stack2[n]%10==a%10+2||stac
k2[n]%10==a%10+1||stack2[n]%10==a%10-1){
            po[n1]=stack2[n];
            n1++;
        }
        }
    }
}
void stack(int a){
int stack1[JANG_GI], stack3[JANG_GI];
int count=0, count1, top;
int k;
for(;;){
 if(top==89){
 break;
 }
 stack1[count]=a;
 stack3[count]=a;
 count++;
 top++;
 position(a);
 for(count1=0; count1<=top; count++){
     if(po[0]!=stack1[count1]){
      a=po[0];
      break;
     }
     else if(po[1]!=stack1[count1]){
      a=po[1];
      break;
     }
     else if(po[2]!=stack1[count1]){
      a=po[2];
      break;
     }
     else if(po[3]!=stack1[count1]){
      a=po[3];
      break;
     }
     else if(po[4]!=stack1[count1]){
      a=po[4];
      break;
     }
else if(po[5]!=stack1[count1]){
         a=po[5];
         break;
        }
        else if(po[6]!=stack1[count1]){
         a=po[6];
         break;
        }
        else if(po[7]!=stack1[count1]){
         a=po[7];
         break;
        }
        else{
         top--;
         count=top;
         k=stack1[count+1]-stack3[count];
         for(count1=0; count1<STACK_SIZE; count1++){
            if(stack2[count]==k){
             a = stack3[count]+stack2[count+1];
            }
            else{
             break;
            }
         }
        }
    }
 }
}
int main(){
 int x, y, good;
 int coor;


 printf("input x:");
scanf("%d", &x);
 printf("input y:");
 scanf("%d", &y);
 coor = x*10+y;
 stack(coor);


 for(good=0; good<90; good++){
    printf("<");
    printf("%d", stack1[good]/10);
    printf(",");
    printf("%d", stack1[good]%10);
    printf(">");
 }
return 0;
}
※결과분석

x, y 좌표를 입력 받았지만 stack 함수에서 오류가 나서 프로그램이 작동하지 않는다.
※참고문헌 및 출처
URL
http://winplz.tistory.com/123
http://klsm1229.blog.me/150088201991
http://blog.naver.com/pjy9954?Redirect=Log&logNo=70128954403
http://blog.naver.com/skout123?Redirect=Log&logNo=50135743013
http://blog.naver.com/keloc?Redirect=Log&logNo=40153471559
http://blog.naver.com/dntkrl79?Redirect=Log&logNo=70095768962
http://blog.naver.com/keloc?Redirect=Log&logNo=40153471559
http://blog.naver.com/dntkrl79?Redirect=Log&logNo=70095768962
http://stackoverflow.com/questions/5633248/open-knights-tour-backtracking-algorithm-
in-smlnj
http://www.geeksforgeeks.org/archives/12916
http://blog.naver.com/ryutuna?Redirect=Log&logNo=100122313091
참고서적
-FOUNDATIONS OF ALGORITHMS USING C++ PSEUDOCODE p183~222
Richard Neapolitan/kumarss Naimipour 저
-C언어로 배우는 자료구조 p50~70

Contenu connexe

Tendances

Processing 기초 이해하기_20160713
Processing 기초 이해하기_20160713Processing 기초 이해하기_20160713
Processing 기초 이해하기_20160713Yong Joon Moon
 
Matplotlib 기초 이해하기_20160730
Matplotlib 기초 이해하기_20160730Matplotlib 기초 이해하기_20160730
Matplotlib 기초 이해하기_20160730Yong Joon Moon
 
Python_numpy_pandas_matplotlib 이해하기_20160815
Python_numpy_pandas_matplotlib 이해하기_20160815Python_numpy_pandas_matplotlib 이해하기_20160815
Python_numpy_pandas_matplotlib 이해하기_20160815Yong Joon Moon
 
이산치수학 Project7
이산치수학 Project7이산치수학 Project7
이산치수학 Project7KoChungWook
 
자료구조 Project6
자료구조 Project6자료구조 Project6
자료구조 Project6KoChungWook
 
파이썬정리 20160130
파이썬정리 20160130파이썬정리 20160130
파이썬정리 20160130Yong Joon Moon
 
파이썬 Collections 모듈 이해하기
파이썬 Collections 모듈 이해하기파이썬 Collections 모듈 이해하기
파이썬 Collections 모듈 이해하기Yong Joon Moon
 
파이썬 문자열 이해하기
파이썬 문자열 이해하기파이썬 문자열 이해하기
파이썬 문자열 이해하기Yong Joon Moon
 
Python+numpy pandas 1편
Python+numpy pandas 1편Python+numpy pandas 1편
Python+numpy pandas 1편Yong Joon Moon
 
파이썬 플라스크 이해하기
파이썬 플라스크 이해하기 파이썬 플라스크 이해하기
파이썬 플라스크 이해하기 Yong Joon Moon
 
파이썬+함수 데코레이터+이해하기 20160229
파이썬+함수 데코레이터+이해하기 20160229파이썬+함수 데코레이터+이해하기 20160229
파이썬+함수 데코레이터+이해하기 20160229Yong Joon Moon
 
Python array.array 모듈 이해하기
Python array.array 모듈 이해하기Python array.array 모듈 이해하기
Python array.array 모듈 이해하기Yong Joon Moon
 
Python+numpy pandas 2편
Python+numpy pandas 2편Python+numpy pandas 2편
Python+numpy pandas 2편Yong Joon Moon
 
HI-ARC ACM ICPC TF #5 (ADVANCED DFS)
HI-ARC ACM ICPC TF #5 (ADVANCED DFS)HI-ARC ACM ICPC TF #5 (ADVANCED DFS)
HI-ARC ACM ICPC TF #5 (ADVANCED DFS)Jae-yeol Lee
 
Tensorflow
TensorflowTensorflow
Tensorflowchs71
 
2012 Ds D2 03 Pdf
2012 Ds D2 03 Pdf2012 Ds D2 03 Pdf
2012 Ds D2 03 Pdfkd19h
 
파이썬 문자열 이해하기
파이썬 문자열 이해하기파이썬 문자열 이해하기
파이썬 문자열 이해하기Yong Joon Moon
 
Python Sympy 모듈 이해하기
Python Sympy 모듈 이해하기Python Sympy 모듈 이해하기
Python Sympy 모듈 이해하기Yong Joon Moon
 

Tendances (20)

Processing 기초 이해하기_20160713
Processing 기초 이해하기_20160713Processing 기초 이해하기_20160713
Processing 기초 이해하기_20160713
 
Matplotlib 기초 이해하기_20160730
Matplotlib 기초 이해하기_20160730Matplotlib 기초 이해하기_20160730
Matplotlib 기초 이해하기_20160730
 
Python_numpy_pandas_matplotlib 이해하기_20160815
Python_numpy_pandas_matplotlib 이해하기_20160815Python_numpy_pandas_matplotlib 이해하기_20160815
Python_numpy_pandas_matplotlib 이해하기_20160815
 
이산치수학 Project7
이산치수학 Project7이산치수학 Project7
이산치수학 Project7
 
자료구조 Project6
자료구조 Project6자료구조 Project6
자료구조 Project6
 
파이썬정리 20160130
파이썬정리 20160130파이썬정리 20160130
파이썬정리 20160130
 
파이썬 Collections 모듈 이해하기
파이썬 Collections 모듈 이해하기파이썬 Collections 모듈 이해하기
파이썬 Collections 모듈 이해하기
 
파이썬 문자열 이해하기
파이썬 문자열 이해하기파이썬 문자열 이해하기
파이썬 문자열 이해하기
 
Python+numpy pandas 1편
Python+numpy pandas 1편Python+numpy pandas 1편
Python+numpy pandas 1편
 
파이썬 플라스크 이해하기
파이썬 플라스크 이해하기 파이썬 플라스크 이해하기
파이썬 플라스크 이해하기
 
2012 Ds 06
2012 Ds 062012 Ds 06
2012 Ds 06
 
파이썬+함수 데코레이터+이해하기 20160229
파이썬+함수 데코레이터+이해하기 20160229파이썬+함수 데코레이터+이해하기 20160229
파이썬+함수 데코레이터+이해하기 20160229
 
Python array.array 모듈 이해하기
Python array.array 모듈 이해하기Python array.array 모듈 이해하기
Python array.array 모듈 이해하기
 
Python+numpy pandas 2편
Python+numpy pandas 2편Python+numpy pandas 2편
Python+numpy pandas 2편
 
HI-ARC ACM ICPC TF #5 (ADVANCED DFS)
HI-ARC ACM ICPC TF #5 (ADVANCED DFS)HI-ARC ACM ICPC TF #5 (ADVANCED DFS)
HI-ARC ACM ICPC TF #5 (ADVANCED DFS)
 
Tensorflow
TensorflowTensorflow
Tensorflow
 
Erlang
ErlangErlang
Erlang
 
2012 Ds D2 03 Pdf
2012 Ds D2 03 Pdf2012 Ds D2 03 Pdf
2012 Ds D2 03 Pdf
 
파이썬 문자열 이해하기
파이썬 문자열 이해하기파이썬 문자열 이해하기
파이썬 문자열 이해하기
 
Python Sympy 모듈 이해하기
Python Sympy 모듈 이해하기Python Sympy 모듈 이해하기
Python Sympy 모듈 이해하기
 

En vedette

자료구조1보고서
자료구조1보고서자료구조1보고서
자료구조1보고서KimChangHoen
 
자료구조5보고서
자료구조5보고서자료구조5보고서
자료구조5보고서KimChangHoen
 
이산치6보고서
이산치6보고서이산치6보고서
이산치6보고서KimChangHoen
 
이산치7보고서
이산치7보고서이산치7보고서
이산치7보고서KimChangHoen
 
자료구조4보고서
자료구조4보고서자료구조4보고서
자료구조4보고서KimChangHoen
 
자료구조3보고서
자료구조3보고서자료구조3보고서
자료구조3보고서KimChangHoen
 
자료구조6보고서
자료구조6보고서자료구조6보고서
자료구조6보고서KimChangHoen
 
대학연합 칵테일동아리 COCOK 소개서 _ 코콕
대학연합 칵테일동아리 COCOK 소개서 _ 코콕대학연합 칵테일동아리 COCOK 소개서 _ 코콕
대학연합 칵테일동아리 COCOK 소개서 _ 코콕dagym
 
배달의 민족 브랜드 마케팅 이야기 by 우아한형제들 김봉진 대표
배달의 민족 브랜드 마케팅 이야기 by 우아한형제들 김봉진 대표배달의 민족 브랜드 마케팅 이야기 by 우아한형제들 김봉진 대표
배달의 민족 브랜드 마케팅 이야기 by 우아한형제들 김봉진 대표VentureSquare
 

En vedette (9)

자료구조1보고서
자료구조1보고서자료구조1보고서
자료구조1보고서
 
자료구조5보고서
자료구조5보고서자료구조5보고서
자료구조5보고서
 
이산치6보고서
이산치6보고서이산치6보고서
이산치6보고서
 
이산치7보고서
이산치7보고서이산치7보고서
이산치7보고서
 
자료구조4보고서
자료구조4보고서자료구조4보고서
자료구조4보고서
 
자료구조3보고서
자료구조3보고서자료구조3보고서
자료구조3보고서
 
자료구조6보고서
자료구조6보고서자료구조6보고서
자료구조6보고서
 
대학연합 칵테일동아리 COCOK 소개서 _ 코콕
대학연합 칵테일동아리 COCOK 소개서 _ 코콕대학연합 칵테일동아리 COCOK 소개서 _ 코콕
대학연합 칵테일동아리 COCOK 소개서 _ 코콕
 
배달의 민족 브랜드 마케팅 이야기 by 우아한형제들 김봉진 대표
배달의 민족 브랜드 마케팅 이야기 by 우아한형제들 김봉진 대표배달의 민족 브랜드 마케팅 이야기 by 우아한형제들 김봉진 대표
배달의 민족 브랜드 마케팅 이야기 by 우아한형제들 김봉진 대표
 

Similaire à 자료구조2보고서

자료구조 Project2
자료구조 Project2자료구조 Project2
자료구조 Project2KoChungWook
 
2012 Ds B2 02 Pdf
2012 Ds B2 02 Pdf2012 Ds B2 02 Pdf
2012 Ds B2 02 Pdfkd19h
 
2012 Ds B2 02
2012 Ds B2 022012 Ds B2 02
2012 Ds B2 02chl132435
 
사칙연산 프로그램
사칙연산 프로그램사칙연산 프로그램
사칙연산 프로그램중선 곽
 
자료구조 02 최종 보고서
자료구조 02 최종 보고서자료구조 02 최종 보고서
자료구조 02 최종 보고서pkok15
 
Project#3 How Fast Can We Sort Hwp
Project#3 How Fast Can We Sort HwpProject#3 How Fast Can We Sort Hwp
Project#3 How Fast Can We Sort HwpKimjeongmoo
 
이산치3보고서
이산치3보고서이산치3보고서
이산치3보고서KimChangHoen
 
2012 Dm A0 07 Pdf
2012 Dm A0 07 Pdf2012 Dm A0 07 Pdf
2012 Dm A0 07 Pdfkd19h
 
2012 Dm A0 07 Pdf
2012 Dm A0 07 Pdf2012 Dm A0 07 Pdf
2012 Dm A0 07 Pdfjinwookhong
 
이산치 과제7
이산치 과제7이산치 과제7
이산치 과제7mil23
 
2012 Ds A1 03
2012 Ds A1 032012 Ds A1 03
2012 Ds A1 03seonhyung
 
이산치수학 Project4
이산치수학 Project4이산치수학 Project4
이산치수학 Project4KoChungWook
 
2012 Ds A1 05
2012 Ds A1 052012 Ds A1 05
2012 Ds A1 05seonhyung
 
2012 Ds B1 01
2012 Ds B1 012012 Ds B1 01
2012 Ds B1 01seonhyung
 
자료구조 Project5
자료구조 Project5자료구조 Project5
자료구조 Project5KoChungWook
 

Similaire à 자료구조2보고서 (20)

자구2번
자구2번자구2번
자구2번
 
자료구조 Project2
자료구조 Project2자료구조 Project2
자료구조 Project2
 
2012 Ds B2 02 Pdf
2012 Ds B2 02 Pdf2012 Ds B2 02 Pdf
2012 Ds B2 02 Pdf
 
2012 Ds B2 02
2012 Ds B2 022012 Ds B2 02
2012 Ds B2 02
 
사칙연산 프로그램
사칙연산 프로그램사칙연산 프로그램
사칙연산 프로그램
 
자료구조 02 최종 보고서
자료구조 02 최종 보고서자료구조 02 최종 보고서
자료구조 02 최종 보고서
 
2012 Ds 01
2012 Ds 012012 Ds 01
2012 Ds 01
 
2012 Ds 02
2012 Ds 022012 Ds 02
2012 Ds 02
 
3콤비네이션
3콤비네이션3콤비네이션
3콤비네이션
 
Project#3 How Fast Can We Sort Hwp
Project#3 How Fast Can We Sort HwpProject#3 How Fast Can We Sort Hwp
Project#3 How Fast Can We Sort Hwp
 
이산치3보고서
이산치3보고서이산치3보고서
이산치3보고서
 
2012 Dm A0 07 Pdf
2012 Dm A0 07 Pdf2012 Dm A0 07 Pdf
2012 Dm A0 07 Pdf
 
2012 Dm A0 07 Pdf
2012 Dm A0 07 Pdf2012 Dm A0 07 Pdf
2012 Dm A0 07 Pdf
 
이산치 과제7
이산치 과제7이산치 과제7
이산치 과제7
 
2012 Ds A1 03
2012 Ds A1 032012 Ds A1 03
2012 Ds A1 03
 
자료구조02
자료구조02자료구조02
자료구조02
 
이산치수학 Project4
이산치수학 Project4이산치수학 Project4
이산치수학 Project4
 
2012 Ds A1 05
2012 Ds A1 052012 Ds A1 05
2012 Ds A1 05
 
2012 Ds B1 01
2012 Ds B1 012012 Ds B1 01
2012 Ds B1 01
 
자료구조 Project5
자료구조 Project5자료구조 Project5
자료구조 Project5
 

자료구조2보고서

  • 1. 자료구조01 조별 프로젝트 #2 말(馬)의 여행 조장 : 09 김창헌 조원 : 09 김정훈 11 김정무 11 김종진 11 김지환
  • 2. -Index- -개인별 업무 -일정계획 -회의록 -기본자료 -알고리즘 -초안 -문제점 & 해결방안 -최종소스 -결과분석 -참고문헌 및 출처
  • 3. ※개인별업무 09김창헌 조장 : 회의록작성 및 보고서 작성, 일정 계획 09김정훈 관련사항 조사 및 복잡도계산 11김정무 관련사항 조사 및 복잡도계산 11김종진 프로그램 설계 및 알고리즘 구상 11김지환 프로그램 설계 및 알고리즘 구상 ※일정계획 3월27일 업무분담 및 문제파악 3월29일 조사내용 정리 및 이해 4월 3일 프로그램 설계 문제점 파악 해결방안 모색 및 초안작성 4월 7일 최종 프로그램 설계 및 최종 보고서 작성
  • 4. ※회의록 회의일시 2012년 3월 27일(화) 조 C1 작성자 09김창헌 참석자 09김창헌, 09김정훈, 11김정무, 11김종진, 11김지환 내용 비고 1.조원별 업무분담 조장과 프로그램설계 2명, 관련사항 조사 2명으로 팀을 구성했다. 2.일정 계획 다음 회의시간까지 자신이 맡은 업무를 수행해 와서 서로 어떻게 문제를 풀어나 갈 것 인지 토의하기로 함 3.보고서 계획 회의내용 소집단보고서작성 및 자신들이 참고한 자료들과 출처를 조장에게 보내주기로 함. 조장이 종합해서 보고서 초안 작성하기로 함. 4.알고리즘 계획 다음 회의시간에 서로 맡은 업무에 충실히 연구를 하여 어떻게 알고리즘을 짤 것 인지에 대해 토의하기로 함.
  • 5. 회의일시 2012년 3월 29일(목) 조 C1 작성자 09김창헌 참석자 09김창헌, 09김정훈, 11김정무, 11김종진, 11김지환 내용 비고 1.조원별 업무 파악 각자 맡은 업무에 대해 조장이 자료들을 확인하여 프로젝트를 어떤 방향으로 진 행해야할지 초안에 대해 토의함. 2.일정 확인 회의시간이 끝나고 설계조원들이 초안을 작성한 뒤 주말에 모여서 프로젝트를 진 행하기로 함. 3.문제점 파악/해결법 토의 회의내용 스택, 큐, 백트래킹의 기본적 내용만 알고 있어서 어떻게 프로그램에 적용시킬 것 인지에 대해 많은 연구가 필요할 것 같다. 자료조사 하는 조원이 오늘밤까지 스택, 큐, 백트래킹의 종류와 적용법등을 조사 하여 온라인으로 설명을 해주기로 했다. 4.보고서 초안 토의 개인 소집단 보고서와 자료조사내용 및 출처와 프로그램 초안과 알고리즘, 프로 그램 설계중 문제점과 해결법을 추가하여 보고서 초안을 만들기로 토의함.
  • 6. 회의일시 2012년 4월 3일(화) 조 C1 작성자 09김창헌 참석자 09김창헌, 09김정훈, 11김정무, 11김종진, 11김지환 내용 비고 1.조원별 업무 파악 자료조사 조원들은 임무를 거의 다 수행하여, 설계조원의 임무를 같이 도와주기 로 하였음. 2.일정 확인 이번 회의 마치고 설계 조원이 소스를 마무리하면 주말에 모여서 최종보고서 및 회의내용 소스파악 하기로 함. 3.문제점 파악 / 해결법 토의 스택을 사용하지 않고 소스를 설계해서 관련사항 조원들과 함께 어떤 식으로 접 목시켜야 할지 이야기 하기로 함. 4.보고서 확정 최종 소스 마무리 되고 나서 조원들과 모여 조장이 쓴 최종보고서를 읽어보고 수정 할 부분 수정 하고 최종보고서 확정 짓기로 함
  • 7. ※기본자료 스택의 개념 스택의 구조는 매우 간단합니다. 스택은 밑이 막혀있는 긴 통이라고 보면 됩니다. 즉, 입구 와 출구가 같은 긴 통이므로 먼저 들어간 것은 밑에 있게 되고, 나중에 들어간 것은 제일 먼저 나오게 됩니다. 그래서 스택을 LIFO(Last In First Out)구조라 고 합니다. 스택을 조작하는 방법(연산이라고 합니다.) 은 두가지가 있습니다. 하나는 스택에 값을 집 어 넣는 연산인 push이고 다른 하나는 스택에서 값을 빼내는 pop 동작입니다. 위 그림을 보면 쉽게 이해가 될 것입니다. 배열로 스택 구현하기 배열을 이용하여 스택을 구현하는 것은 위의 그림과 같은 모양이 됩니다. 우선 스택의 긴 통을 정의 하고 스택의 마지막 데이터의 위치인 상단을 top이라는 배열 인덱스를 이용하겠 습니다. 배열의 성격상 스택 이라는 통의 크기는 정해 놓아야 합니다. 일단 10이라고 잡겠습니다. 스택에 들어갈 데이터는 정수형이라고 가정하면 다음과 같이 정의 할 수 있습니다. #define MAXSIZE 10 // 스택의 크기 정의 int stack[MAXSIZE]; // 스택의 긴 통 int top; // 스택의 상단 여기서 top의 위치를 정확히 규정해 봅니다. 어떤 경우는 top이 스택의 가장 위 데이터가 아니라 그 위, 즉, 다음에 들어갈 데이터 저장 공간을 가리키기도 합니다. 여기서는 가장 위 의 데이터를 가리키는 것으로 정하겠습니다. 스택을 정의 할 때 두가지 중 하나를 선택해서 사용하여야 하며, 혼용되어서는 안됩니다. 그리고, 스택연산을 정의 할 때, 극단적인 경우, 즉, 데이터가 하나도 없을 때와 꽉 차있을 때에 약간 주의를 해야 합니다. 먼저, 스택이 비어 있는 경우 top은 -1의 값을 가져야 합니다. C에서 배열의 인덱스는 0 부터 시작하므로, top이 0이라면 스택에 데이터가 하나 있다는 의미입니다. 스택이 비어있 는 경우는 초기 스택이 생성되었을 때도 마찬가지 이므로 스택을 초기화 하려면 top을 -1 로 설정하면 됩니다. push를 위해서는 값이 있어야 하므로 push의 함수 인자로 val이라는 양의 정수형을 사용하 겠습니다. 그 후 push는 top을 하나 증가시키고 배열의 인덱스 top에 val을 넣으면 됩니다. 그런데, 앞서 말씀드렸듯이 스택이 꽉차있는 경우에 push를 하게 되면 스택이 넘쳐나게 됩 니다. 이를 스택 오버플로우(Stack Overflow)라고 합니다. 그러므로 배열의 인덱스인 top이
  • 8. MAX-1이 되었을 때 스택이 꽉차있는 경우이므로 예외 처리를 해야 합니다. [[ 스택의 용도 ]] 컴퓨터에서 스택이 사용되는 가장 대표적인 부분은 바로 연산이다. 연산에는 우선 순위라는 것이 있기 때문에 연산 도중에 우선 순위가 높은 연산을 만나게 되면 그 동 안의 연산 결과를 잠시 보관해두고 우선 순위가 높은 연산을 먼저 처리하게 되는데 이때 또다시 더 높은 순위의 연산을 만나면 또 스택 에 보관해두고 현재의 연산을 한다. 그리고 순위가 높은 연산이 끝나면 다시 스택에서 그 전에 하던 연산을 가져와서 계속해서 연산을 수 행해 나가는 것이다. 이 것 이외에도 함수의 호출시에도 메인 함수에서 함수를 호출하게 되면 메인 함수에서 사용되던 지 역 변수들이 모두 스택에 저장된다. 그리고 해당 함수의 작업을 진행하게 되고 또 그 함수에서 다른 함수의 호출이 있게 되면 그 동안 사 용되던 모든 정보를 스택에 저장하고 다시 함수를 호출하여 작업을 수행하다가 그 함수가 종료되면 스택에서 그 전의 모든 정보를 가져와 함수 호출 다음의 작업을 재개한다. 이런 식의 작업들을 수행하기 위해서는 스택이라는 후입 선출의 기억 장치가 꼭 필요한 것이다. 큐의 개념 큐는 스택과 비슷한 모양을 하고 있지만, 조작방식은 다릅니다. 큐의 구조도 간단한데, 스 택과 달리 앞 뒤가 뚫린 통이라고 보시면 됩니다. 이 통은 뒤에서 뭔가를 집어넣고 앞에서 빼냅니다. 즉, 먼저 들어온 것은 먼저 나오는 구조로 FIFO(First In First Out)이라고 부릅니 다. 큐의 연산은 put과 get이 있습니다. 큐에 자료를 집어 넣을 때는 뒤(rear)에서 처리하고, 이를 put이라고 합니다. 반대로 큐에서 자료를 빼낼 때는 앞(front)에서 처리하고 이를 get 이라고 합니다. 배열로 큐 구현하기 배열을 이용한 큐의 구현은 스택의 구현과 비슷한 난이도일 것 같지만, 조금 더 생각해보 면 문제가 아주 많습니다. 먼저 저장할 자료의 앞과 뒤를 가리키는 변수를 선언하여 큐의 구조를 정의해 보겠습니다. #define MAXSIZE 10 // 큐의 크기 int queue[MAXSIZE]; int front=-1, rear=-1; 다음으로 put과 get 연산을 정의해 보겠습니다. int put (unsigned int val) {
  • 9. if (rear >= MAXSIZE-1) { printf (" Queue Overflow"); return (-1); } queue[++rear] = val; } int get () { if (front <= 0) { printf (" Queue Underflow"); return -1; } return queue[front++]; } 배열의 인덱스로 사용되는 front와 rear가 위 코드에서는 계속 증가하기만 합니다. 결국 몇 번의 연산을 한 후에 rear가 배열의 한계를 넘어 더이상 put연산이 Overflow에러를 발생시 킬 수 있습니다. 그러므로 rear가 배열의 한계에 다다랐을 때에 큐의 데이터를 배열의 앞부 분으로 옮기는 동작이 필요하게 됩니다. int put (unsigned int val) { if (rear >= MAXSIZE-1) { if (!(rear-front)) { return -1; } // 여기서 배열의 앞으로 옮겨야 한다. memcpy (&queue[0], &queue[front], rear-front+1); rear=rear-front; front = 0; } queue[++rear] = val; } 지금은 배열의 개수를 10으로 정의 했지만 만약에 5억개라면? 그런 데이터 이동이 put할 때마다 발생한다면? 당연히 비효율적이겠죠. 그래서 해결방법으로 나왔습니다. 환형 (또는 원형) 큐(Circular Queue)를 이용하는 것입니 다. 환형 큐는 뱀이 꼬리를 물고 있는 듯한 모양을 가지고 있습니다. 데이터가 순환하며 저 장되기 때문에 끝이라는 개념도 없습니다. 다음 그림을 보시죠. [[ 큐의 용도 ]] 큐는 일련의 일들이 순차적으로 진행되는 가운데, 일의 진행이 조금 지체될때 큐에는 다음 일들이 계 속해서 쌓여가는 방식이다. 흔히 버퍼링이라 불리는 스트리밍의 로딩 작업 역시 큐에 자료가 쌓이고 플레이어는 큐의 앞부분부터 플레이를 하게 되는 것이다. 그러다 로딩이 늦어져서 큐에 쌓였던 자료가 모두 사용되고 나면 플레이어는 중지되고 다시 버퍼링 작업을 하게 되는 것이다. 이것 이외에도 프린트 작업을 할때 프린터는 처리 속도에 제한이 있기 때문에 여러가지의 출력을 지 시하게 되면 지시된 순서대로 큐에 자료를 저장하고 하나의 출력이 끝나면 큐에서 다음 자료를 받아와 출력하는 작업을 반복한다. 그러다 큐가 비면 대기 상태가 된다. 이외에도 큐의 용도는 다양하다. 기억할 점은 큐는 순차적인 업무 처리를 위해 다음 할 일을 기억해 두는 장치라는 것이다.
  • 10. 스택은 하던 일을 잠시 접어둘때 사용되는 기억 장치라는 점이 큐와는 다른 점이다. 백트래킹 입력받은 배열의 값에 대해서 가능한 모든 순서조합을 만들어냅니다. 단, 모든 순서조합을 위해서는 최초에 배열의 수가 오름차순으로 정렬되어져 있어야 합니 다. 최종적인 형태는 내림차순정렬이 되어져 있으며, 이때 함수는 더이상 처리를 하지 않고 들 어온 값 그대로 리턴 시켜 버립니다. 내림차순 정렬이 완료 되었으나, 맞는 조합이 없었다면, 해당 문제는 해가 없는 것이 됩니 다. 매번 시도 마다 다음 조합으로 만들어 냅니다. (1차 배열만, 배열의 크기는 무관) 현재 배열의 순서가 답이 될수 없다면, 배열을 다시 백트랙 돌리면 바로 다음 배열 순서의 조합을 만들어냅니다. 1-2-3-4-5-6-7-8-9 의 항이 있었다고 가정할 때, 이 값의 순서가 해당 문제의 답으로서 맞지 않는다면 다음 항으로는 한칸 앞으로 돌아와서 순서를 바꾸어 볼수 있습니다. 입력받은 배열의 값에 대해서 가능한 모든 순서조합을 만들어냅니다. 단, 모든 순서조합을 위해서는 최초에 배열의 수가 오름차순으로 정렬되어져 있어야 합니 다. 최종적인 형태는 내림차순정렬이 되어져 있으며, 이때 함수는 더이상 처리를 하지 않고 들 어온 값 그대로 리턴 시켜 버립니다. 내림차순 정렬이 완료 되었으나, 맞는 조합이 없었다면, 해당 문제는 해가 없는 것이 됩니 다. 매번 시도 마다 다음 조합으로 만들어 냅니다. (1차 배열만, 배열의 크기는 무관) 현재 배열의 순서가 답이 될수 없다면, 배열을 다시 백트랙 돌리면 바로 다음 배열 순서의 조합을 만들어냅니다.
  • 11. infix, prefix, postfix. (중위표기법, 전위표기법, 후위표기법) 일반적인 수식은 infix이다. 즉, 연산자가 피연산자(보통숫자나 문자)와 피연산자 사이에 존재한다. a + 1과 같은 형태 이다. 기준이 되는 것은 연산자의 위치이다. + a 1과 같이 연산자가 피연산자들 앞에 있다면 prefix라고 한다. 반대로 a 1 +과 같은 경우는 당연히 postfix라고 한다. 그럼 infix를 prefix or postfix 로 바꾸는 법을 알아보자. 우선 infix식을 하나 가져온다. 1 + ( a + 2 ) * 5 / 7 아무렇게나 쓴 식이다. 이 식에서 취할 수 있는 모든 괄호를 취해보자. ( 1 + ( ( ( a + 2 ) * 5 ) / 7 ) ) 계산상의 순서의 변화는 없을 것이다. 그저 보조괄호를 취한 것뿐이니. 여기서 주목할 것은, 각 괄호 안에는 모두 "피연산자 + 연산자 + 피연산자" 의 구조를 갖고 있다는 것이다. 각 괄호를 기준으로 연산자를 뒤로 빼보자. ( 1 + ( ( ( a 2 )+ * 5 ) / 7 ) ) ( 1 + ( ( ( a 2 )+ 5 )* / 7 ) ) ( 1 + ( ( ( a 2 )+ 5 )* 7 ) / ) ( 1 ( ( ( a 2 )+ 5 )* 7 ) / ) + 각 연산자가 자기 자신이 속해 있는 괄호의 뒤로 빠진 것이다. 이런 식으로 바꾸고 괄호를 모두 삭제해보자. 1 a 2 + 5 * 7 / + 위와 같은 모양의 식이 나오는데, 이게 제대로 만들어 진 건지를 확인해 보기 위해서 이 상태로 앞에서 부터 스택에 넣고 계산해 보자. 연산자를 만나면 스택에서 두개의 피연산 자를 빼서 계산하고 다시 넣는다. + : a + 2 * : (a + 2 ) * 5 / : (a + 2 ) * 5 / 7 + : 1 + ( a + 2 ) * 5 / 7 잘 된다. 그렇다면 prefix는? 위의 괄호에서 연산자를 앞으로 빼면 된다. prefix의 경우에는 헝가리 표기법이라고도 한다는데 원래는 명제를 단순하게 표현하기 위해 서 씌였다고 한다.
  • 12. 이를 가지고 스택으로 계산이 불가능한가? 그건 또 아니다. 단지 구현의 차이일뿐. postfix에서 연산자를 만나면 스택에서 두개의 피연산자를 빼서 더하고 다시 넣어줬다면, prefix에서는 만약에 스택에 연속 된 두개의 피연산자가 들어오면 두개의 피연산자를 빼주 고 바로 밑의 연산자를 꺼내 계산을 하고 이를 집어 넣어 준다. 예를 보는 게 가장 빠르겠지... ( a + b ) * c + d * k 물론 아무렇게나 쓴 식이다. 괄호로 묶는다. ( ( ( a + b ) * c ) + ( d * k ) ) 변환 한다. ( ( + ( a b ) * c ) + ( d * k ) ) ( * ( + ( a b ) c ) + ( d * k ) ) ( * ( + ( a b ) c ) + * ( d k ) ) + ( * ( + ( a b ) c ) * ( d k ) ) 괄호 제거... + * + a b c * d k 와 같다. 이제 하나씩 넣어보자. 초반에는 연산자만 잔득이나 한번에 넣었다고 하자. 일일이 한줄씩 쓰기 귀찮으니. + * + a : b -> + * ( a + b ) // 3개의 연산자와 1개의 피연산자가 있는데 추가로 한개의 피연산자 삽입 + * ( a + b ) : c -> + ( ( a + b ) * c ) + ( ( a + b ) * c ) : * -> + ( ( a + b ) * c ) * + ( ( a + b ) * c ) * : d -> + ( ( a + b ) * c ) * d + ( ( a + b ) * c ) * d : k -> + ( ( a + b ) * c ) (d * k) - > ( ( a + b ) * c ) + (d * k) 잘 된다~ 각 표기법을 자료구조를 통해서 바꾸는 법. <트리 형태> 가장 먼저 연산 되는 것부터 리프에서 부터 만들어서 타고 올라온다. 이를 전위 순회를 하면 prefix, 후위 순회를 하면 postfix 중위 순위를 하면 infix가 된다. 형태를 만들면, 스택을 이용하여 가능하다.
  • 13. <스택과 큐를 사용> 요건 좀 중요한데, 우선 infix을 postfix로 만드는 방법을 보자. 스택과 큐를 사용한다. 스택은 infix를 postfix로 바꾸는 과정에서 연산자를 잠시 저장한다. 알고리즘은 아래와 같다. 각 연산자의 우선순위는 [ 괄호 < +,- < *,/ ] 의 순이다. 1. '(' 를 만나면 스택에 푸시한다. (푸시 => 저장) 2. ')' 를 만나면 스택에서 '('가 나올때까지 팝하여 큐에 넣고 '('는 팝하여 버린다. 3. 연산자를 만나면 스택에서 그 연산자보다 낮은 우선순위의 연산자를 만날 때까지 팝하 여 큐에 넣고 자신을 푸시한다. 4. 피연산자는 그냥 큐에 넣는다. 5. 모든 입력이 끝나면 스텍에 있는 연산자들을 모두 팝하여 출력한다. 예) (2*(3+6/2)+2)/4+3 문자 큐 스택(상단->하단) 설명 ( ( '(' 스택에 푸시 (저장) 2 2 ( 숫자는 화면에 출력 * 2 * ( '*' 가 '('보다우선순위가 높음 ( 2 ( * ( '(' 는 스택에 푸시( 저장) 3 2 3 ( * ( 숫자 는 화면에 출력 + 2 3 + ( * ( '+'가 '('보다 우선순위가 높음 6 2 3 6 + ( * ( 숫자 는 화면에 출력 / 2 3 6 / + ( * ( '/'가 '+'보다 우선순위가 높음 2 2 3 6 2 / + ( * ( 숫자 는 화면에 출력 ) 2 3 6 2 / + * ( '('까지 는 팝하여 출력,'('는무시 + 2 3 6 2 / + * + ( '*' 는 '+' 보다 높으므로 팝 2 2 3 6 2 / + * 2 + ( 숫자는 출력 ) 2 3 6 2 / + * 2 + '(' 까지 팝 하여 출력 / 2 3 6 2 / + * 2 + / 연산자는 푸시(저장)
  • 14. 4 2 3 6 2 / + * 2 + 4 / 숫자는 출 력 + 2 3 6 2 / + * 2 + 4 / + '/'는 '+'보다 높아서 출력하고'+'는저장 3 2 3 6 2 / + * 2 + 4 / 3 + 숫자는 출 력 끝 2 3 6 2 / + * 2 + 4 / 3 + 끝이므로 모두 팝(출력) 이제 큐에 있는 내용을 디큐(dequeue)하면서 스택에 넣으면서 위에 정리한 postfix방법으로 계산을 하면 된다.
  • 15. ※알고리즘 1)장기판 좌표를 정수로 바꾸었을 경우. ①말의 좌표 x, y를 입력한다. ②x*10+y를 통해 각 좌표를 정수로 바꾸고 1차 배열로 구현하고 0으로 초기화한다. ③한 번 간 좌표는 1로 표시하여 중복을 피한다. ④움직일 때 마다 카운트를 올린다. ⑤움직일 곳 없이 모두 막혀 있다면 백트랙킹을 통해 다음 조건을 찾아본다. ⑥반복한다. ⑦카운터가 장기판 크기인 89까지 올라왔다면 처음부터 출력한다. 1-1)장기판 좌표를 정수로 바꾸었을 경우(수정). ①말의 좌표 x, y를 입력한다. ②x*10+y를 통해 각 좌표를 정수로 바꾼다. ③말이 움직인 좌표를 stack 배열에 넣는다. ④움직일 때 마다 카운트를 올린다. ④말이 있는 좌표에서 이동 가능한 전 좌표를 찾는다. ⑥스택 배열에 들어있는 좌표와 ④번에서 찾은 좌표를 처음부터 비교해 순서대로 중복되지 않았다면 첫 번째 좌표를 stack배열에 넣고 계속 반복한다. ⑤움직일 곳 없이 모두 막혀 있다면 백트랙킹을 통해 다음 조건을 찾아본다. ⑥반복한다. ⑦카운터가 장기판 크기인 89까지 올라왔다면 처음부터 출력한다. 1-2)장기판 좌표를 정수로 바꾸엇을 경우(수정). ①말의 좌표 x, y를 입력한다. ②x*10+y를 통해 각 좌표를 정수로 바꾼다. ②stack 2개 잡는다. ③stack1에 시작값을 저장. ④stack2에 이동경로를 저장. ④stack2의 top의 값으로 이동. ⑥stack2의 top의 값의 이동경로에 stack1의 값이 포함되지 않는다면 stack1에 top의 값을 버림. ⑤stack2의 top의 값이 이동경로에 stack1의 값이 포함된다면 stack2의 top의 값을 stack1 에 저장. ⑥stack2의 top의 값을 버림. ⑦stack2에 값이 없을 경우 stack1의 배열을 queue의 형태로 좌표 출력. ⑧stack2에 값이 있을 경우 stack1에 저장된 값과 비교 후 stack1에 없는 이동경로만 stack2에 저장(중복체크) ⑨④번으로 돌아가서 반복 2)장기판을 2차 배열로 구현했을 경우. ①말의 좌표 x, y를 입력한다. ②장기판의 각 점을 좌표라 생각하고 2차 배열로 장기판을 만든다. ③한 번 간 좌표는 1로 표시하여 중복을 피한다. ④움직일 때 마다 카운트를 올린다.
  • 16. ⑤움직일 곳 없이 모두 막혀 있다면 백트랙킹을 통해 다음 조건을 찾아본다. ⑥반복한다. ⑦카운터가 장기판 크기인 89까지 올라왔다면 처음부터 출력한다.
  • 17. ※초안 #include <stdio.h> #include <stdlib.h> #define ROW_SIZE 10 #define COL_SIZE 9 #define NUM_WAYS 8 typedef int board_t[ROW_SIZE][COL_SIZE]; int dr[NUM_WAYS] = {-2,-1,1,2,2,1,-1,-2}; int dc[NUM_WAYS] = {1,2,2,1,-1,-2,-2,-1}; void initialize_board(board_t board) { int i,j; for(i=0;i<ROW_SIZE;i++) { for(j=0;j<COL_SIZE;j++) { board[i][j] = -1; } } } void print_board(board_t board) { int i,j; for(i=0;i<ROW_SIZE;i++) { for(j=0;j<COL_SIZE;j++) { printf("%dt",board[i][j]); } printf("n"); } } int is_inside_board(int r, int c) { return r>=0 && r<ROW_SIZE && c>=0 && c<COL_SIZE; } int is_available(board_t board, int r, int c) {
  • 18. return is_inside_board(r,c) && board[r][c] == -1; } int num_next_moves(board_t board, int r, int c) { int i,result=0; for(i=0;i<NUM_WAYS;i++) { if(is_available(board,r+dr[i],c+dc[i])) { result++; } } return result; } int next_way_of(board_t board, int r, int c) { int i, min = NUM_WAYS, result=0; for(i=0;i<NUM_WAYS;i++) { if(is_available(board, r+dr[i], c+dc[i]) && num_next_moves(board,r+dr[i],c+dc[i])<min) { min=num_next_moves(board,r+dr[i],c+dc[i]); result=i; } } return result; } int main() { int r,c,move,next_way; board_t board; initialize_board(board); while(1) { printf("input start position r(0~9) c(0~8): "); scanf("%d %d",&r, &c); fflush(stdin); if(is_inside_board(r,c)) { break; } printf("Please put them again.n"); } board[r][c] = 0;
  • 19. for(move=1;move<ROW_SIZE*COL_SIZE;move++) { if(num_next_moves(board,r,c)==0) { printf("Failed.n"); print_board(board); system("pause"); return 1; } next_way = next_way_of(board,r,c); r=r+dr[next_way]; c=c+dc[next_way]; board[r][c]=move; } print_board(board); system("pause"); return 0; }
  • 20. ※문제점 & 해결방안 문제점 체스의 말 이동 소스를 참고해서 수정해 나 갔지만 그것은 장기의 말 이동과는 다른 이동 을 보여주고 스택을 사용하지 않고 공식을 이 용해 문제를 풀어 나갈려고 했다. 해결방안 스택을 이용한 1차 배열로 바꿔 해결하려고 했다.
  • 21. ※최종소스 #include <stdio.h> #define STACK_SIZE 8 #define JANG_GI 89 int stack2[STACK_SIZE]; int po[STACK_SIZE47]; void position(int a){ int n, n1=0; stack2[0] = a-21; stack2[1] = a-19; stack2[2] = a-12; stack2[3] = a-8; stack2[4] = a+8; stack2[5] = a+12; stack2[6] = a+19; stack2[7] = a+21; for(n=0; n<STACK_SIZE; n++){ if(stack2[n]<=0&&stack2[n]>=89){ if(stack2[n]%10==a%10-2||stack2[n]%10==a%10+2||stac k2[n]%10==a%10+1||stack2[n]%10==a%10-1){ po[n1]=stack2[n]; n1++; } } } } void stack(int a){
  • 22. int stack1[JANG_GI], stack3[JANG_GI]; int count=0, count1, top; int k; for(;;){ if(top==89){ break; } stack1[count]=a; stack3[count]=a; count++; top++; position(a); for(count1=0; count1<=top; count++){ if(po[0]!=stack1[count1]){ a=po[0]; break; } else if(po[1]!=stack1[count1]){ a=po[1]; break; } else if(po[2]!=stack1[count1]){ a=po[2]; break; } else if(po[3]!=stack1[count1]){ a=po[3]; break; } else if(po[4]!=stack1[count1]){ a=po[4]; break; }
  • 23. else if(po[5]!=stack1[count1]){ a=po[5]; break; } else if(po[6]!=stack1[count1]){ a=po[6]; break; } else if(po[7]!=stack1[count1]){ a=po[7]; break; } else{ top--; count=top; k=stack1[count+1]-stack3[count]; for(count1=0; count1<STACK_SIZE; count1++){ if(stack2[count]==k){ a = stack3[count]+stack2[count+1]; } else{ break; } } } } } } int main(){ int x, y, good; int coor; printf("input x:");
  • 24. scanf("%d", &x); printf("input y:"); scanf("%d", &y); coor = x*10+y; stack(coor); for(good=0; good<90; good++){ printf("<"); printf("%d", stack1[good]/10); printf(","); printf("%d", stack1[good]%10); printf(">"); } return 0; }
  • 25. ※결과분석 x, y 좌표를 입력 받았지만 stack 함수에서 오류가 나서 프로그램이 작동하지 않는다.
  • 26. ※참고문헌 및 출처 URL http://winplz.tistory.com/123 http://klsm1229.blog.me/150088201991 http://blog.naver.com/pjy9954?Redirect=Log&logNo=70128954403 http://blog.naver.com/skout123?Redirect=Log&logNo=50135743013 http://blog.naver.com/keloc?Redirect=Log&logNo=40153471559 http://blog.naver.com/dntkrl79?Redirect=Log&logNo=70095768962 http://blog.naver.com/keloc?Redirect=Log&logNo=40153471559 http://blog.naver.com/dntkrl79?Redirect=Log&logNo=70095768962 http://stackoverflow.com/questions/5633248/open-knights-tour-backtracking-algorithm- in-smlnj http://www.geeksforgeeks.org/archives/12916 http://blog.naver.com/ryutuna?Redirect=Log&logNo=100122313091 참고서적 -FOUNDATIONS OF ALGORITHMS USING C++ PSEUDOCODE p183~222 Richard Neapolitan/kumarss Naimipour 저 -C언어로 배우는 자료구조 p50~70