2016. 1. 27. 19:56

[문제 제시]

"임의의 문장을 입력 받아 해당 문장에서 한글 단어만 추출하려면 어떻게 해야 할까요?

문장 부호, 공백 문자, 특수 문자 등 한글 이외의 문자를 모두 제외해야 합니다. 

이러한 프로그램을 가장 효율적(빠르거나, 메모리를 적게 쓰거나)으로 동작하게 하려면, 무엇을 고려해야 할까요?"


[프로그램 개발 절차]

위와 같은 문제를 아래의 4단계에 걸쳐 개발하려고 합니다.


분석 > 설계 > 개발 > 성능/기능 테스트


[소프트웨어 개발에서 분석이란? 그리고 어떻게?]

소프트웨어 개발에서 '분석'은 '무엇(what)'을 만들 것인지를 정의(파악)하는 단계입니다. 머리가 좋거나, 지식을 많이 쌓은 사람만이 할 수 있는 것은 아닙니다. 분석이라는 단어부터 어렵게 느껴질 수 있는데, 영어 단어인 analysis의 어원을 살펴봅시다.


analysis는 'ana(up to)'와 'lysis(untie)'가 결합하여 얽히고 뭉쳐 보이지 않던 것을 물러지게(lys) 하면 그 속에 무엇이 있는지'를 알게 됩니다.

출처 - lose 에 대하여


분석 (分析) : 한자로는 '나눌 分', '쪼갤 析' 영어의 어원과 크게 다르지 않습니다. 분석이란, 주어진 과제(혹은 문제)를 좀 더 잘게 쪼개서 문제를 명확히 이해하는 과정입니다. 잘게 쪼개다 보면 미쳐 생각하지 못했던 부분들이 드러나기도 합니다. 그리고 분석 과정에서 새로운 의문점이 드러나기도 합니다. 분석 과정은 문제를 쪼개보고, 의문점이 발생하면 이해를 위해 문제를 다시 검토하거나, 심하면 문제를 재정의합니다. 


개발이나 설계를 하기 전에 분석하는 이유는 "구현"할 수 있는 문제인지를 파악하고, 처음 문제에서 미쳐 드러나지 않은 숨은 위험요소를 찾아내며 구현할 수 없다면 문제를 재정의하거나, 주어진 자원(시간, 비용)으로 풀 수 없다면 전체 계획을 수정하기 위한 작업입니다. 또한, 분석 결과는 설계와 구현하는데 필요한 사양(specification)으로 활용됩니다.


["한글 단어 추출" 문제 분석]

먼저, 주어진 문제를 한 문장씩 나누어 봅니다.


1. 임의의 문장을 입력 받아 해당 문장에서 한글 단어만 추출한다.

2. 문장 부호, 공백 문자, 특수 문자와 한글 이외의 문자를 모두 제외해야 한다.

3. 가장 효율적(빠르거나, 메모리를 적게 쓰거나)으로 동작해야 한다.


다시 쪼갤 수 있다면 쪼개 봅니다. 모호한 것들을 제거해 나갑니다. 새로운 의문점이 드러날 수도 있습니다.


1. 임의의 문장을 입력 받아 해당 문장에서 한글 단어만 추출한다.


: 임의의 문장을 어떻게 입력 받을 것인가? 사람이 직접 입력하는지, 웹 사이트의 주소를 입력 받는지, 아니면 파일을 선택하는지?

: 한글 단어는 정확히 명사를 추출한다는 것인지? 아니면, 문장성분(예를 들어 주어+조사)을 의미하는 것인지?


2. 문장 부호, 공백 문자, 특수 문자 등 한글 이외의 문자를 모두 제외해야 한다.


: 영어, 숫자 문자도 제외하는가?


3. 가장 효율적(빠르거나, 메모리를 적게 쓰거나)으로 동작해야 한다.


: 빠른데 메모리를 많이 쓰거나, 느린데 메모리를 적게 쓴다면 둘 중 어느 쪽이 나은 결과인가?


문제에서 제기되지 않았지만, 다른 의문도 발생할 수 있습니다.


- 입력 텍스트의 다양한 텍스트 인코딩(UTF-8, EUC-KR)을 지원해야 하는가?

- 형태소 분석기를 적용해야 하는가?

- 어떤 언어를 개발해야 하는가?

- 어떤 플랫폼 (웹, PC 어플리케이션, 모바일)에서 동작해야 하는가?

- 처리 결과는 데이터베이스에 저장해야 하는가?


위와 같은 의문점에 대한 답을 구한 후에, 요구사항(세부 문제 항목)을 나열하면 간단한 '요건 분석'을 마쳤다고 할 수 있습니다.


Posted by 곽중선
2015. 5. 11. 01:43

"AlgoSpot DRAWRECT 문제 풀이"에 대한 마지막 코드 예제 입니다. 이번에는 절차지향 방식의 코드를 개선해 XOR 비트 연산자의 원리를 이용해 if 제어문 조차 사용하지 않는 short code를 소개하고자 합니다. XOR 비트 연산자 사용에 대한 아이디어는 이은택님이 제안해 주셨고, 이은택님의 샘플 코드 또한 참고해 보시면 좋겠습니다. XOR 연산자를 활용한 기법을 소개하는 이유는 컴퓨터 하부 구조의 동작 방식 (2진수 기반의 컴퓨터 원리 등)과 수학적 논리(혹은 공식)를 잘 이해할 경우, 더 할 나위 없는 성능을 발휘하는 가장 짧은 코드를 작성할 수 있다는 것을 보여 드리기 위함입니다.


▶ 배타적 논리합


배타적 논리합 (exclusive or)은 수리 논리학에서 주어진 2개의 명제 가운데 1개만 참일 경우를 판단하는 논리 연산입니다. 약칭으로 XOR, EOR, EXOR라고도 씁니다. 연산자는 ⊻ (유니코드: U+22BB)입니다. 혼돈이 되지 않을 경우, XOR, xor ⊕ (유니코드: U+2295), +、≠ 라고도 씁니다. (위키백과 배타적 논리합 참조)


배타적 논리합의 "진리표"는 아래와 같습니다.


 명제 P

명제 Q

 P  Q

 참

 참

 거짓 

 참

 거짓 

 참 

 거짓

 참 

 참 

 거짓

 거짓

 거짓


▶ XOR (Exclusive OR) 비트 연산


XOR 연산은 두 값의 각 자릿 수를 비교해, 값이 같으면 0, 다르면 1을 계산하는 연산입니다. XOR 연산은 비트 단위로 이루어집니다.


0101

XOR    0011

-----------

       = 0110

 

C or C++ 언어에서 XOR 비트 연산자는 ^ (caret) 문자를 사용합니다.


   x = y ^ z;


▶ XOR 비트 연산을 이용한 동일 값 제거


XOR 비트 연산자를 활용하면, 여러 개의 값 중에서 동일한 값들을 제거할 수 있습니다. 예를 들어, 3개의 값이 존재하고 그 중에서 2개의 값이 동일하고 나머지 하나의 값이 다른 경우, XOR 비트 연산 2번을 통해 나머지 하나의 다른 값을 추출할 수 있습니다. 예를 들어, 십진수 12, 7, 7 등 3개의 값을 2번에 걸쳐 XOR 연산을 수행하는 과정과 그 결과는 다음과 같습니다. 연산 순서에 상관없이 하나의 다른 값이 얻게 되는 것을 확인할 수 있습니다.


▶ XOR 비트 연산을 short code 예시

#include <stdio.h>
#include <stdlib.h>

/* x,y 좌표를 표현하는 점(point) 구조체를 정의한다. */ 
typedef struct {
   int x;
   int y;
} point;
 

int main(int argc, char *argv[]) {
	
	// 테스트 케이스 반복 횟수 및 좌표 변수 생성 및 초기화 
	int cnt = 0;
	point p1 = {0, 0};
	point p2 = {0, 0};
	point p3 = {0, 0};
	point p4 = {0, 0};
	
	// 테스트 케이스 반복 횟수 입력. 
	int testCaseCount;
	printf("Input test case number : ");
	scanf("%d", &testCaseCount); 
	
	// 입력 받은 테스트 케이스 수만큼 반복 처리... 
	for(cnt=0; cnt<testCaseCount; cnt++) {
		
		// ----- pt, p3, p3 등 3개의 좌표 값 입력 -----
		printf("Input p1 (x, y) : ");
		scanf("%d %d", &p1.x, &p1.y);
		printf("p1.x = %d, p1.y = %d\n", p1.x, p1.y);
		
		printf("Input p2 (x, y) : ");
		scanf("%d %d", &p2.x, &p2.y);
		printf("p2.x = %d, p2.y = %d\n", p2.x, p2.y);
		
		printf("Input p3 (x, y) : ");
		scanf("%d %d", &p3.x, &p3.y);
		printf("p3.x = %d, p3.y = %d\n", p3.x, p3.y);
		
		// ----- 4번째 좌표 계산 및 출력 ----- 

		// p4.x 좌표 계산 
		p4.x = p1.x ^ p2.x ^ p3.x;
		// p4.y 좌표 계산 
		p4.y = p1.y ^ p2.y ^ p3.y;

		// p4 좌표 출력 
		printf("\nResult p4.x = %d, p4.y = %d", p4.x, p4.y );
	}
	
	return 0;
}


Posted by 곽중선
2015. 5. 10. 03:39

"AlgoSpot DRAWRECT 문제 풀이"에 대한 2가지 코드를 준비해 봤습니다. 그중에서 두번째로 객체지향적으로 문제를 풀어보는 코드입니다. 객체지향 프로그래밍의 목표는 컴퓨터가 최대한 효율적으로 문제를 해결할 수 있도록 코드를 작성하는 것이 아니라, 인간이 세상을 바라보는 시각에 근접하게끔 코드를 작성하는 것입니다. 따라서, 절차지향적 코드에 비해 코드의 분량이 좀 더 길어지거나, 상대적으로 비효율적으로 느껴질 수 있습니다. 그러나, 하드웨어의 성능 발전, 컴파일러 기술의 향상 등으로 인해 조금 더 길어진 코딩이라고 할지라도 전체적인 성능 상의 차이는 두드러지게 나타나지는 않는 편입니다. (참고 : 절차지향 코드 버전)


더불어, 객체지향 기법을 적용하는 분야(혹은 도메인)에서는 기계 보다는 인간의 관점을 중시하는 경향이 있습니다. 객체지향 혹은 절차지향 중 어느 한 쪽이 우월한가를 따지는 것은 별 의미가 없습니다. 객체지향과 절차지향은 각각의 장점과 단점을 가지고 있고, 해결해야할 문제가 일상생활(실세계)의 문제에 가까울수록 객체지향 기법으로 설계하고 코딩했을 때 얻을 수 있는 이득이 많습니다. 이점을 염두에 두시고, 이어지는 설명과 구현 절차를 읽으셔야 합니다.  


▶ 객체지향 철학 그리고 5대 개념


문제 풀이에 앞서 객체지향 철학 및 5대 개념을 먼저 읽어보시는 것을 권합니다.



▶ UML(Unified Model Language)


객체지향으로 설계 및 구현할 때는 플로우 챠트가 아니라, 가급적 UML(Unified Modeling Language)을 이용해 설계합니다. (플로우 차트를 절대 사용하지 말아야 한다는 것은 아닙니다. 객체지향 코드 내에서도 논리적인 흐름이 발견되고 논리적인 흐름을 표현하는데는 플로우 차트가 유용합니다.) UML 에서는 다양한 다이어그램을 이용해 소프트웨어의 모델을 설계하는데, 그중에서 유스 케이스(Use Case), 클래스 다이어그램(Class Diagram) 그리고, 시퀀스 다이어그램(Sequence Diagram)을 가장 많이 사용하게 됩니다. "UML: 클래스 다이어그램과 소스코드 매핑" 문서를 읽어보시면 도움이 될 듯 합니다.


UML 중에서 유스 케이스(Use Case)는 가장 직관적이면서 이해하기 쉽고, 가장 먼저 작성하게 됩니다. 사용자(actor)가 컴퓨터(소프트웨어 혹은 하드웨어)를 이용해 어떤 작업들을 수행하는가? 소프트웨어가 어떤 기능을 제공하는가? 라는 질문에 대해 가장 포괄적이고, 직관적으로 보여주는 다이어그램입니다. 아래 그림을 보시면, 논리적인 흐름이나 기술적인 정보는 아무것도 표현하지 않습니다. 객체지향 설계의 접근 방식의 모토(motto)는 바로 인간의 시선에서부터 시작하자는 것입니다.


유스 케이스 다이어그램의 목적은 시스템 혹은 소프트웨어에 대한 요약(brief), 개요(outline or overview)를 제공하는 것입니다. 소프트웨어를 구현함에 있어서 가장 핵심적인 기능은 무엇인가? 좀 더 세세한 설계를 진행하기에 앞서 시스템을 최대한 간략히 묘사함으로써 개발자/기획자/설계자 등 프로젝트에 참여하는 모든 사람들이 공통의 목표를 명확히 공유할 수 있도록 하는 것이 목표입니다.


DRAWRECT를 정의하는 유스 케이스는 매우 단순합니다. 3개의 좌표를 제시하고, 사각형의 4번째 좌표를 계산하는 것입니다. 유스 케이스 다이어그램으로 표현하면 아래와 같습니다.




▶ 객체 후보 정하기 


절차지향 프로그램은 고유한 기능을 수행하는 함수(혹은 서브루틴)들을 프로그래머가 지정한 절차에 따라 연속적으로 실행시켜 결과를 얻는 방식입니다. 공장의 컨베이너 벨트처럼 잘 짜여진 흐름에 따라, 연쇄적으로 하나씩 작업들이 이어가는 것이죠. 따라서, 소프트웨어 개발자 혹은 설계자는 각각의 작업을 마친 후에 다음 작업이 무엇이 실행되어야 하고, 각 단계에서 가공된 데이터를 다음 단계의 함수로 어떻게 전달할 것인가? 동적인 흐름을 하나씩 따져가며 문제를 풀어야 합니다.


반면에 객체지향 프로그래밍은 객체라는 형태의 부품들을 먼저 정의 혹은 추출합니다. 이것은 사람이 현실 세계를 이해하는 방식에서 비롯된 것입니다. 우리는 움직이는 자동차를 바라볼 때 자동차의 가속, 감속, 회전 등의 동작(behavior)과 자동차 자체의 형태, 무게, 차종 등의 상태 정보(status)를 구분해서 인식하지 않습니다. 그냥 자동차 자체는 동작과 상태를 함께 지니고 있다고 받아들입니다. 이러한 인간의 사고 방식을 따르는 객체지향 프로그램에서 객체라는 요소는 행위(behavior)와 상태(status)를 함께 가지고 있는 소프트웨어 부품(parts, component)입니다. 객체지향 설계에서는 문제를 푸는 절차에 앞서, 해결하고자 하는 문제 자체에 포함된 다양한 객체를 먼저 식별(identify or extract)하고, 각 객체들이 서로 어떻게 연결되고, 함께 상호 작용하는지를 파악합니다.


DRAWRECT 문제에서 객체(혹은 클래스)로 구분지을 수 있는 후보군은 다음과 같습니다. 후보군이라고 말하는 것은 설계하는 사람의 관점에 따라 객체 혹은 클래스가 아니라고 볼 수도 있다는 말입니다. 정확히 어떤 방식으로 설계해야 하고 어떤 클래스들을 정의해야 한다는 엄격한 기준은 없습니다.


 객체(클래스) 후보

 행위 (behavior)

상태(status) 

 뷰포인트

 입력 좌표 값의 정상 유무 검증

 최소, 최대 좌표 허용 범위 

 좌표

 X축, Y축 값 저장 및 조회

 X축 및 Y축 좌표 값

 사각형

 p1, p2, p3 등 3개의 좌표 저장

 p4 좌표 계산

 p1, p2, p3 등의 좌표 정보


 

▶ 객체 간의 정적 관계 설계 (클래스 다이어그램)


객체 간의 정적인 관계는 클래스 다이어그램을 이용해 정의합니다. 관계(relation)를 통해 객체 혹은 클래스들이 서로 간에 어떤 의미(역할)을 가지는지를 나타내게 됩니다. 자동차의 부품들이 서로 아무런 상관없이 존재하거나, 독립적으로 동작하는 것이 거의 없는 것처럼 객체지향 프로그램에서도 프로그램의 부품에 해당하는 객체들에 각각의 역할과 의미가 부여되어야 합니다. 클래스 다이어그램을 통해서 각 클래스 간의 상속, 합성, 연관 등의 정적인 관계를 파악합니다. 이러한 관계 부여는 실제 코딩으로 이어지기 때문에 의미 없는 문서화 작업으로 치부해서는 안됩니다.


- 사각형(Rectangle)은 좌표(Point)를 포함합니다. 이를 소유 관계(has-a relation)라고 합니다.

- 뷰포인트(Viewpoint)는 좌표(Point)를 검증합니다. 이를 연관(association)이라 합니다.




▶ 객체 간의 상호 동작 설계 (시퀀스 다이어그램)


객체 혹은 클래스들이 함께 동작하는 과정에서 어떤 기능을 호출하는지와 어떤 정보를 주고 받는지를 표현하는 것이 시퀀스 다이어그램입니다. 시퀀스 다이어그램은 기능의 흐름을 표현한다는 점에서 플로우 차트와 유사하나, 논리적인 판단(if 조건 등)을 기술하지 않는다는 점은 플로우 차트와 다릅니다. 앞서 말한 것처럼 객체지향 설계에서는 세밀한 논리적 흐름보다는 큰 얼개(구조)를 표현하는데 집중합니다.




▶ 객체지향 코드 작성


위와 같은 설계를 바탕으로 구현된 코드는 아래와 같습니다.


[Point.java]
package algospot.exam.drawrect;

/**
 * 점(point) 클래스.
 * 
 */
public class Point {
	// X 축 좌표.
	private int xCoord;
	// Y 축 좌표.
	private int yCoord;
	
	/**
	 * 생성자와 getter 메소드만을 제공하는 이유는 최초 값 설정 후에 잘못 변경되는 것을 막기 위함이다.
	 * 
	 * @param xCoord X 좌표
	 * @param yCoord Y 좌표
	 */
	public Point(int xCoord, int yCoord) {
		this.xCoord = xCoord;
		this.yCoord = yCoord;
	}
	
	public int getXCoord() {
		return xCoord;
	}
	
	public int getYCoord() {
		return yCoord;
	}
	
	public String toString() {
		return String.format("(x = %d, y = %d)", xCoord, yCoord);
	}
}
[Viewport.java]
package algospot.exam.drawrect;

public class Viewport {
	private static final int MIN_COORDINATE = 1;
	private static final int MAX_COORDINATE = 1000;

	public static boolean validatePoint(Point point) {
		return point.getXCoord() >= MIN_COORDINATE && point.getXCoord() <= MAX_COORDINATE &&
				point.getYCoord() >= MIN_COORDINATE && point.getYCoord() <= MAX_COORDINATE;
	}
}
[Rectangle.java]
package algospot.exam.drawrect;

/**
 * 직사각형 클래스
 * @author "Sunny Kwak"
 *
 */
public class Rectangle {
	private Point p1;
	private Point p2;
	private Point p3;
	
	public Rectangle(Point p1, Point p2, Point p3) {
		this.p1 = p1;
		this.p2 = p2;
		this.p3 = p3;
	}
	
	/**
	 * 3개의 사각형 좌표 값을 이용해 마지막 좌표를 계산한다.
	 * @return
	 */
	public Point calculateP4() {
		int x = 0, y = 0;
		
		if(p1.getXCoord() == p2.getXCoord()) {
			x = p3.getXCoord();
		} else if(p1.getXCoord() == p3.getXCoord()) {
			x = p2.getXCoord();
		} else if(p2.getXCoord() == p3.getXCoord()) {
			x = p1.getXCoord();
		}
		
		if(p1.getYCoord() == p2.getYCoord()) {
			y = p3.getYCoord();
		} else if(p1.getYCoord() == p3.getYCoord()) {
			y = p2.getYCoord();
		} else if(p2.getYCoord() == p3.getYCoord()) {
			y = p1.getYCoord();
		}
		
		return new Point(x, y);
	}
}
[AlgoSpotDrawRect.java]
package algospot.exam.drawrect;

import java.util.Scanner;

/**
 * 직사각형의 3개 좌표를 입력 받아 4번째 좌표를 계산하는 프로그램.
 *  
 * @author "Sunny Kwak"
 */
public class AlgoSpotDrawRect {

	public static void main(String[] args) {

		Scanner scanner = new Scanner(System.in);
		
		// 테스트 케이스 반복 횟수 입력.
		System.out.print("Input test case number : ");
		int loopCnt = scanner.nextInt();
		
		// 입력 받은 테스트 케이스 수만큼 반복 처리... 
		for (int cnt = 0; cnt < loopCnt; cnt++) {

			// pt, p3, p3 등 3개의 좌표 값 입력 
			Point p1 = readPoint(scanner);
			Point p2 = readPoint(scanner);
			Point p3 = readPoint(scanner);

			// 직사각형 객체 생성 및 4번째 좌표 계산 
			Rectangle rectangle = new Rectangle(p1, p2, p3);
			Point p4 = rectangle.calculateP4();
			
			// 정상적으로 계산된 경우, 4번째 좌표 출력 
			System.out.printf("%d %d\n", p4.getXCoord(), p4.getYCoord());
		}

		scanner.close();
	}

	/*
	 * x, y 좌표 입력 및 정상 좌표 유무 검사.
	 * 정상 좌표인 경우, Point 객체를 생성한 후 반환.
	 */
	private static Point readPoint(Scanner scanner) {
		System.out.print("Input p1 (x, y) : ");
		int xCoord = scanner.nextInt();
		int yCoord = scanner.nextInt();
		Point point = new Point(xCoord, yCoord);

		if (Viewport.validatePoint(point)) {
			return point;
		} else {
			throw new IllegalArgumentException("Invalide coordinate : " + point);
		}
	}

}


Posted by 곽중선
2015. 5. 9. 19:29

"AlgoSpot DRAWRECT 문제 풀이"에 대한 2가지 코드를 준비해 봤습니다. 그중에서 첫번째로 절차지향적으로 문제를 풀어보는 코드입니다. 알고리즘 자체를 코드로 변환하는 방법에 대해서 익숙하지 않거나, 사람이 인식할 수 있는 코드를 작성하는 방법을 잘 모르시는 분들을 위해 준비한 것입니다.


컴퓨터가 이해하는 코드는 어느 바보나 다 짤 수 있다. 훌륭한 프로그래머는 사람이 이해할 수 있는 코드를 짠다.

- 마틴 파울러 : Martin Fowler (리팩토링 저자).


▶ 주 플로우 챠트 작성 (Draw main flow chart)


앞서 알고리즘 문제 풀이에서 기술한 흐름을 순서도(flow chart)로 작성해 봅니다. 논리 전개에 익숙하지 않은 분들은 가급적 바로 코딩에 뛰어들지 마시고, 귀찮더라고 문제를 풀 때마다 플로우 차트를 그리는 연습을 해야 합니다. 그리고 가급적이면, 파워포인트 혹은 플로우 챠트 그리는 도구를 사용하지 말고, 직접 종이에 그려 보는 것을 권장합니다. 그래야 좀 더 논리적인 전개에 집중할 수 있습니다. 플로우 차트를 도구 없이도 머리 속에서 그릴 수 있게 되면, 그 다음에는 종이나 파워포인트 없이 바로 코딩을 시작해도 됩니다.




▶ 서브루틴 플로우 챠트 작성 (Draw subroutine flow chart)


주된 흐름을 플로우 차트로 작성한 후에는 서브루틴(subroutine)에 대한 플로우 차트를 작성합니다. 플로우 차트 하나에 모든 논리(logic0을 담을 수 없습니다. 달리 말해서, 하나의 플로우 차트에 단계가 10~20개 정도가 좋은 것이고 그 보다 많은 단계를 하나의 플로우 차트에 그려 넣는다는 것은 플로우 차트를 쪼갤 필요가 있다는 얘기가 됩니다. 문제를 한 눈에 알아보고, 전체 흐름을 파악할 수 있을 정도가 되어야 버그(bug)를 최대한 방지할 수 있습니다. 또한 플로우 차트를 쪼개는 과정에서 부수적으로 서브루틴(subroutine) 혹은 함수(function)를 도출해낼 수 있다는 점도 플로우 차트를 권장하는 이유입니다.




▶ 절차적 코드 작성


절차적 프로그래밍 패러다임을 적용하기 위해 C 언어로 작성하였습니다. 아래 코드를 보시면, 여러 개의 좌표를 저장하기 위해 구조체(struct)를 사용하신 것을 확인할 수 있습니다. 논리(logic)도 중요하지만, 프로그래밍 언어들에서 제공하는 구조체 등을 활용하면 보다 사람이 이해하기 좋은 코드 (직관적이고, 가독성 높은)를 작성하실 수 있습니다.


#include <stdio.h>
#include <stdlib.h>

/* x,y 좌표를 표현하는 점(point) 구조체를 정의한다. */ 
typedef struct {
   int x;
   int y;
} point;

int main(int argc, char *argv[]) {
	
	// 테스트 케이스 반복 횟수 및 좌표 변수 생성 및 초기화 
	int cnt = 0;
	point p1 = {0, 0};
	point p2 = {0, 0};
	point p3 = {0, 0};
	point p4 = {0, 0};
	
	// 테스트 케이스 반복 횟수 입력. 
	int testCaseCount;
	printf("Input test case number : ");
	scanf("%d", &testCaseCount); 
	
	// 입력 받은 테스트 케이스 수만큼 반복 처리... 
	for(cnt=0; cnt<testCaseCount; cnt++) {
		
		// pt, p3, p3 등 3개의 좌표 값 입력 
		printf("Input p1 (x, y) : ");
		scanf("%d %d", &p1.x, &p1.y);
		printf("p1.x = %d, p1.y = %d\n", p1.x, p1.y);
		
		printf("Input p2 (x, y) : ");
		scanf("%d %d", &p2.x, &p2.y);
		printf("p2.x = %d, p2.y = %d\n", p2.x, p2.y);
		
		printf("Input p3 (x, y) : ");
		scanf("%d %d", &p3.x, &p3.y);
		printf("p3.x = %d, p3.y = %d\n", p3.x, p3.y);
		
		// 4번째 좌표 계산  (p1 ~ p3는 입력, p4 는 출력 용도의 인자[argument]) 
		int returnCode = calculateP4(&p1, &p2, &p3, &p4);
		
		// 정상적으로 계산된 경우, 네번째 좌표 출력 
		if(returnCode == 0) {
			printf("Result p4.x = %d, p4.y = %d", p4.x, p4.y );
		} 
		// 잘못된 입력 좌표가 존재할 경우, 에러 메시지 출력 및 프로그램 종료. 
		else {
			printf("Error : Invalid coordinate");
			return 1;
		}
		
	}

	return 0;
}

/*
 * p1, p2, p3 등 3개의 좌표 값을 입력받아, p4 좌표 계산.
 *
 * 만일, 잘못된 자표가 입력된 경우 -1 반환, 정상적으로 좌표를 계산한 경우 0 반환. 
 */
int calculateP4(point *p1, point *p2, point *p3, point *p4) {

	// p4.x 좌표 계산 
	if(p1->x == p2->x) {
		p4->x = p3->x;
	} else if(p1->x == p3->x) {
		p4->x = p2->x;
	} else if(p2->x == p3->x) {
		p4->x = p1->x;
	} else {
		return -1;
	}
	
	// p4.y 좌표 계산 
	if(p1->y == p2->y) {
		p4->y = p3->y;
	} else if(p1->y == p3->y) {
		p4->y = p2->y;
	} else if(p2->y == p3->y) {
		p4->y = p1->y;
	} else {
		return -1;
	}
	
	return 0;
}


▶ 실행 결과


위와 같은 코드의 실행 결과(예시)는 아래와 같습니다.


Input test case number : 1

Input p1 (x, y) : 10 30

p1.x = 10, p1.y = 30

Input p2 (x, y) : 45 30

p2.x = 45, p2.y = 30

Input p3 (x, y) : 10 65

p3.x = 10, p3.y = 65


Result p4.x = 45, p4.y = 65


Posted by 곽중선
2015. 5. 4. 16:05

AlgoSpot Quiz '사각형 그리기 (DRAWRECT)' 문제 풀이.


▶ DRAWRECT 문제 분석


- input       : 입력의 첫 행은 T 값이며, 테스트 케이스(test case)의 갯수이다. 

                 나머지 입력은 x, y 좌표 값을 공백으로 구분한 행들이며, 3 * T 갯수 만큼 입력된다.

- processing : T 만큼 반복하면서, 3개의 2차원 좌표를 이용해 마지막 좌표를 계산한다.

- output     : 계산된 마지막 좌표를 출력한다.


입력 값의 범위와 유형은 아래와 같이 표현할 수 있습니다.




▶ 문제 분할

문제 자체가 복잡하지 않기 때문에 세밀한 문제 분할은 필요가 없습니다.


▶ 핵심 논리 구성

4개의 점 중에서 하나가 누락될 경우, 3개의 점으로 구성할 수 있는 경우의 수를 구해 봅니다. 수학의 '조합(combination)'을 활용하면 되겠습니다. 조합(Combination)이란, 서로 다른 개 중 순서를 무시하고 개를 택하는 것이며,  기호로 나타냅니다.



조합을 이용해 4개의 점 중에서 3개의 점을 순서를 구분하지 않고 선택하는 경우의 수를 계산하면, 아래와 같습니다.



4개의 경우의 수를 표 형태로 표현해 보면 다음과 같습니다.


 조합

 Case #1

Case #2 

Case #3 

Case #4 

 좌표

 p1 (x1, y1)

 p2 (x2, y1)

 p3 (x1, y2)

 p1 (x1, y1)

 p2 (x2, y1)

 p4 (x2, y2)

 p1 (x1, y1) 
 p3 (x1, y2)
 p4 (x2, y2)
 p2 (x2, y1)
 p3 (x1, y2)
 p4 (x2, y2)

 비고

 p4 제외

 p3 제외 

 p2 제외  p1 제외 


위 표를 통해 얻을 수 있는 핵심 논리는 아래와 같습니다.


직사각형의 3개의 점(point)가 입력되었을 때, x와 y 좌표는 항상 2개는 같고 나머지 하나는 다르다.

다른 값을 가지는 2개의 x, y 좌표 값을 결합하면 4번째 좌표를 얻을 수 있다.


▶ 플랫폼 문제 해결

본 문제는 플랫폼 문제를 해결할 필요가 없습니다.


▶ 핵심 정리

알고리즘 문제 해결을 위해 가장 좋은 도구는 '수학'입니다. 또한, 문제를 풀기 위해서 좌표계 등의 시각적인 도구를 활용하면, 직관적으로 문제를 이해하는데 있어 큰 도움이 됩니다.

Posted by 곽중선
2015. 5. 2. 00:30

AlgoSpot Quiz 'ENDIANS' 문제 풀이 과정을 통한 소프트웨어 설계 연습.


▶ 소프트웨어 설계 연습 서론

소프트웨어 문제를 풀이를 할 때, "어떤 절차 혹은 방식"으로 프로그램을 작성해야 하는 것인지 감이 잘 잡히지 않는 분들이 더러 있습니다. 여러분의 머리가 나쁘기 때문에 그런 것이 아니라, 논리적으로 문제를 푸는 연습(혹은 훈련)이 부족하기 때문에 어렵게 느껴지는 것입니다.


달리기를 잘하고 싶다면, 달리기 연습부터 해야 합니다. 걷지도 못하는 아이가 뛰려고 하면 넘어질 뿐이죠. 자전거를 타고 싶다고 당장 안장에 올라타서 패달부터 밟으면 어찌 되겠습니까? 논리적으로 사고하는 능력도 훈련이 필요한 것입니다. 대한민국에서 고등학교 수준의 교육을 정상적으로 이수했다면 프로그래밍을 하는데 있어서 필요한 '학습 능력'이 부족한 것이 아닙니다. 다만, 여러분이 논리 문제를 풀어 본 적이 별로 없다는 점이 여러분의 프로그래밍을 힘들게 만드는 것입니다. 단순한 예제를 풀어가는 과정을 통해 논리로 문제를 푸는 연습을 해보고자 합니다.


 ENDIANS 문제 분석 및 논리 전개

알고스팟 왕초보 문제 "ENDIANS" 에 제시된 문제를 먼저 읽어보시기 바랍니다.


문제를 읽고 나서, 별거 아닌데? 생각하고 바로 코딩부터 하려는 분도 있을 수 있습니다. 잠시 그 손을 멈추시기 바랍니다. 운동할 때, 100 미터쯤 대충 달리는 거 문제가 아닙니다. 그런데, 왜 운동 선수들을 매일 똑같은 달리기를 반복할까요? 그저 내달리기만 하는 것은 아닐 겁니다. 멀리 오래도록 달리기 위해서는 달리는 자세와 호흡법, 페이스 조절 능력 등이 함께 필요한 법입니다.


보다 복잡하고, 어려운 문제를 풀기 위해서는 작은 문제를 풀 때도 좀 더 차분하게 접근할 필요가 있다는 얘기입니다. 저는 아래에 서술하는 내용을 일단, 종이에 적어가면서 천천히 음미하고 반추하는 시간을 가졌습니다. 그리고, 이제 키보드를 치며 다시 문서로 정리하고 그런 연후에 코드를 작성할 것입니다.  여러분도 좀 더 여유를 가지고 프로그래밍에 임하셨으면 좋겠습니다.


제 방식이 무조건 옳다라고 말씀 드리기는 어렵지만, 제가 프로그램을 작성하는데 있어 가급적 지키고 있는 절차는 다음과 같습니다.


  1. 문제 분석 (problem analysis)
    : 주어진 문제를 논리 흐름(logical flow)에 따라 다시 정리합니다. 가장 쉬운 방법은 입력, 처리, 출력 3단계로 문제를 재정의하는 것입니다.

  2. 문제 분할 (break down problem) 
    : 문제를 해결하기 쉽도록 보다 작은 문제로 쪼개 봅니다. (분할 및 정복 :devide & conquor 라고도 합니다.)

  3. 핵심 논리 구성 (composite core logic) 
    : 대다수의 문제는 쉬운 부분을 제외하고 나면, 한 두개의 어렵거나 까다로운 부분이 드러나게 됩니다.

  4. 플랫폼 문제 해결 (solving platform issue)
    : 플랫폼이라 함은 하드웨어, 운영체제, 프로그래밍 언어, 라이브러리 및 프레임워크 등 어플리케이션 프로그램을 작성하는데 있어서 의존해야 하는 모든 것을 말합니다. 풀어내고자 하는 문제를 해결하기 위해 어떤 API를 사용해야 하는지? 하드웨어 어떤 기능을 이용해야 하는지에 대한 문제를 해결합니다. 이미 알고 있는 지식이라면 쉽게 해결되지만 잘 모르거나, 처음 접하는 문제라면 적극적으로 검색 기술을 활용합니다.

  5. 코딩 (coding)
    : 이제, 코딩할 수 있습니다.!

"ENDIANS" 문제에 대한 분석 및 논리 구성 과정 사례는 아래와 같습니다.

  1. 문제 분석
    소프트웨어는 거의 "입력, 처리, 출력" 등 3단계의 흐름을 설계할 수 있습니다.

    - input         : n개의 32 bit unsigned int 값이 한 줄(line)에 하나씩 있는 텍스트 파일을 읽어들인다.
    - processing   : 엔디언 변환(endian conversion)을 수행한다.
    - output       : 변환한 숫자를 출력한다.

  2. 문제 분할
    문제를 해결하기 쉽도록 좀 더 작은 문제들(혹은 자세한 절차)로 쪼개 봅니다.

    1) 텍스트 파일을 연다.
    2) 한 줄의 텍스트 문자열을 읽어들인다.
    3) 읽어들인 문자열을 32 bit unsigned int 형 값으로 변환한다.
    4) 엔디언 변환(endian conversion)을 수행한다.
    5) 변환 결과를 출력한다.
    6) 더 이상 읽어들일 라인이 없을 경우, 파일을 닫고 프로그램을 종료한다.
    7) 아니면, 다음 행을 읽어들이기 위해 2) 단계로 이동한다.

  3. 핵심 논리 구성
    위와 같은 흐름에서 가장 중요한 (혹은 어려운) 문제는 32 bit 부호없는 정수 값의 엔디언을 변환하는 것입니다.

    1) 입력된 32 bit 부호없는 정수 값을 4 byte 배열 형태로 분리(혹은 변환)한다.
    2) 바이트 배열에 담긴 데이터를 역순(reverse order)으로 재배치 한다.
    3) 재배열된 바이트 배열을 다시 부호 없는 정수 값으로 변환한다.
    4) 변환된 정수 값을 출력한다.

  4. 플랫폼 문제 해결
    문제를 코드로 작성할 때 다양한 기술적 문제를 고려할 필요가 있습니다.

    프로그래밍 언어, 운영체제, 하드웨어, 라이브러리 등 어플리케이션 프로그램 자체에서 직접 구현하는 것이 아니라, 
    어플리케이션 하위에 위치한 (혹은 어플리케이션이 의존하고 있는) 시스템에서 제공 받는 기능들을 활용하고자 한다면, 원하는 기능이 있는지 코딩하기 전에 확인할 필요가 있고, 최악(?)의 경우에는 직접 구현해야 하는 경우도 발생합니다.

    ENDIANS 문제를 자바로 구현하고자 할 경우에 다음과 같은 문제들을 고려할 필요가 있습니다.

    텍스트 파일을 열고, 한줄 씩 읽어들이는 방법은 무엇인가?
    : java.io.File 클래스와 InputStream, BufferedReader 등 JDK에서 제공하는 API를 활용하면 됩니다.

    자바 언어에서 '부호없는 32 bit 정수' 타입을 지원하는가?
    자바는 부호 없는 정수형 타입을 지원하지 않습니다. 그러나, 64 bit 정수형인 long 타입을 사용하면 32 bit unsigned int 값을 저장할 수 있습니다.

    바이트 배열과 32 bit 정수 값을 상호 변환하는 방법은 무엇인가?
    우리에게는 구글과 StackOverflow가 있습니다. StackOverflow 참조 : 정수와 바이트 배열 간의 상호 변환 

 핵심 정리

간혹 어디까지가 알고리즘인가? 라는 의문이 들 때가 있습니다. 예를 들자면, 정수형 데이터와 바이트 배열 간에 상호 변환하는 과정도 알고리즘의 일부가 아니냐는 질문을 받습니다. 이런 과정을 직접 생각해야지 검색해서 남의 해법을 참고하는 것은 '편법' 혹은 틀린 자세는 아닌가 라는 의견을 접하고는 합니다. 소프트웨어 구현 과정의 모든 것을 스스로 해야 한다면, 파일을 읽고 쓰는 자바 API와 운영체제 까지도 직접 작성해야 하지 않을까 라는 반문을 해봅니다. 제가 정의하는 알고리즘은 '문제를 이해하고 논리적인 절차를 정의하는 것'이며, 구현 방안(방식)은 알고리즘의 본질이 아니라고 생각합니다.



Posted by 곽중선
2015. 5. 1. 15:11

알고리즘(수학적 논리), 영어 그리고 인문과 역사에 대한 이야기를 좀 해볼까 합니다.


"알고스팟'이라는 컴퓨터 알고리즘 수련 사이트에 올라온 문제를 풀이하는 스터디를 진행 중입니다. 우선 알고스팟의 튜터리얼 (왕초보) 문제를 풀고 있는데, 두번째 문제의 시험 문제가 영문이네요. 스터디에 참여하시는 분들이 문제 해석부터 난관에 부딧친 상황입니다.


어느 스터디 멤버 분의 고민 :


"해석은 얼추 했는데 정확히 문제가 원하는게 무엇인지 잘 모르겟네요."


문제를 해석하는데 있어서 가장 큰 문제는 영어와 인문학적 경험입니다. 아래 문장을 보시죠.


"People from Lilliput are called little-endians, since they open eggs at the small end. People from Blefuscu are called big-endians, since they open eggs at the big end."


'small end'와 'big-end'라는 표현이 대체 무슨 뜻일까요? 걸리버 여행기를 한글 책으로 읽어 본 경험이 있는 사람이라면, 금새 이해할 수 있습니다. 아래는 제가 번역한 문장입니다.


"릴리퍼트 사람들은 리틀 엔디언(little-endians)이라 불리며, 달걀의 뾰족한 끝(little-end)을 깨고 먹는다. 블레퍼스큐 사람들은 빅 엔디언(big-endians)이라 불리며, 뭉툭한 끝(big-end)을 깨고 먹는다."


그런데, 이제 또 다른 벽이 나타납니다. 알고리즘 문제 내용의 일부를 보겠습니다.


"이런 식의 논쟁은 그들의 아침식사 문제 뿐만 아니라, 컴퓨터에서도 발생하고 있다. 릴리퍼트와 블레퍼스큐의 컴퓨터는 정수(integers) 값을 저장하는 방식이 다른데 바이트(bytes) 데이터들을 서로 다른 순서로 저장하는 것이다. 릴리퍼트(리틀 엔디언)의 컴퓨터는 LSB(least significant byte)부터 MSB(most significant byte) 순서로 정렬하고, 블레퍼스큐의 컴퓨터는 정확히 반대로 동작한다.


따라서, 블레퍼스큐와 릴리퍼트의 컴퓨터 간에 정보를 주고 받을 필요가 있다면, 어떤 식이건 변환 절차가 필수적이다. 아무도 데이터를 보내면서 변환하는 것을 원하지 않기 때문에, 수신자들이 항상 변환 작업을 수행해야만 한다."


스터디 내에서 이런 식의 문제가 왜 필요한가? 어디에 쓰이는 건가? 라는 질문이 나옵니다. 컴퓨터의 발전 역사에 대한 지식이 없으면, 출제 의도를 전혀 이해할 수 없습니다. 다음 링크 "위키피디아, 엔디언이란?"을 참고하시면, 아오지탄광(알고스팟의 별칭)의 출제자들이 왜 이런 문제를 냈는가를 이해할 수 있습니다. 우리가 사용하는 모든 컴퓨터는 늘상 네트워크를 통해 데이터를 주고 받고 과정에서 엔디언 문제와 씨름하고 있습니다. 단지, 눈에 띄지 않을 뿐이지요.


정리하자면, "알고리즘"을 공부하는데 있어서 수학적 재능과 노력만 필요한 게 아닙니다. 영어, 상식 그리고 (컴퓨터) 역사 등의 배경 지식과 이론이 없으면 앞으로 나아가기 어렵습니다. 컴퓨터 소프트웨어의 목표는 현실 세계의 문제를 가상의 세계 (cyberspace)로 이식하는 것입니다. 그런데, 현실 세계의 문제들을 이해조차 하기 어렵다면, 어떻게 문제를 풀 수 있겠습니까? 자, 이래도 어쨋건 코딩만 잘하면 (빨리 빨리 코드를 만들어 내기만 하면) 되는 걸까요?


문제 출처 : "AlgoSpot : ENDIAN Quiz" 



Posted by 곽중선
2015. 5. 1. 11:50

알고스팟 (통칭 아오지탄광) 문제풀이 스터디를 진행 중입니다.

지원자 12명 중에서 11명이 튜터리얼 중에서 가장 쉬운 첫번째 문제를 풀이한 상태이며,

초보자들이 지나치기 쉬운 잘못된 코딩 습관을 통계내 봤습니다.

참고 하시기 바랍니다.


분류 유형
코드
좋은 않은 코딩 스타일 코드 예시 설명 (진지하게 읽지 마세요.) 발생
건수
발생
빈도
Bad B1 무의미한 제어문 사용
(불필요한 논리)
while ( flag ) { break; } if 조건 없이 break 실행 2 18%
B2 의미 없거나 불필요한 변수 사용 flag = true; 사용 안하는 변수 선언 1 9%
Not
Good
N1 루트 패키지 사용 패키지 선언 없음 9 82%
N2 입력 값 범위 체크 안함 if( inputNum < 10 ) { … } 음의 정수를 입력할 수 있으나,
그러지 않기를 바래요.
8 73%
N3 불분명하거나
의미없는 클래스 명칭
Main { … } 어떤 기능을 수행하는지 알 수 없음.
(내 마음 알고 싶나요? 나도 몰라요.)
6 55%
N4 불명확한 변수 명칭 int num; 데이터 타입은 알 수 있으나,
용도는 파악 안됨
4 36%
N5 들여쓰기 일관성 없음 석봉아 이제 불을 끄자꾸나…
어머니는 떡을 써시고, 나는 코딩을…
3 27%
N6 연산자와 조건문의 결함  while( i-- > 0 ) { ... } 로직을 한눈에 파악하기 어려움. 2 18%
N7 패키지 명칭에 대문자 사용 package KingBeginner; 그런데, 번역이 맞습니까? 1 9%
N8 Camel Case와 Snake Case 혼용 int input_Num; 엎어 치던가.. 매치던가.. 하나만.. 1 9%
N9 API 에 대한 불충분한 이해 exit(0); 오류가 발생했으나, 정상 종료 처리함 1 9%
N10 불필요한 주석 표기 // input number 코드만 보고 충분히 이해할 수 있음에도
주석을 쓰려면 차라리 한글로 쓰시는게?
1 9%
N11 주석에 적힌 파일명과
실제 파일명칭 불일치
gistfile1.cpp != main.cpp 암 유발자…. ? 1 9%
N12 소스 주석에 한글 영어 혼용 Copyright (c) 2015년 암 유발자…. ? (2) 1 9%
N13 잘못된 주석 위치 unsigned int inputVal;
// unsigned int로 선언
난 네가 이미 읽고 이해한 것,
그것 조차 설명하겠다!
1 9%
N14 값 비교 시, 작은 값 부터
비교하는 것을 권장함
if(n <= 10 && n > 0) 큰 것이 좋아? (응?) 1 9%
총 참가자 수  11




Posted by 곽중선
2015. 4. 30. 21:17

Quiz LINK


Posted by 곽중선
2015. 3. 17. 02:11

▶  온라인 저지 (Online Judge)

프로그래밍 문제를 풀고 온라인으로 채점받을 수 있는 곳


▶  알고리즘 추천 도서


▶  정구진님 추천 사이트

  • https://algospot.com/calendar/ 
    알고스팟 사이트 자체도 괜찮구요. 캘린더 들어가 보시면 알고리즘 대회 스케쥴이 있어요. 가볍게 참가 해 보시면 어느새 열정적으로 하고 있는 자신을... 주로 스케쥴 잡혀있는게 코드포스 랑 탑 코더 인데 둘다 굉장히 짧은 주기로 자주 열고 있습니다. (2-3주) 시차 감안해서 시간 될 때 얼마든지 참가 가능하구요. 코드포스는 제가 알기론 러시아 사이트 인데 문제 풀 때 번역기를 돌려도 이해가 좀 어렵지만 탑코더도 문제가 영어라 문제 이해를 하는데 시간이 조금 걸리더라구요.

  • http://www.topcoder.com/
    탑코더는 정말 유명하죠. 스폰하고 있는 기업만 보더라도 그 위치가 어느정도 인지 알수 있습니다. 들어가자마자 뜨는 합격 수기 같은거 보면 살짝 흥분도 되죠. 디자인하고 소프트웨어, 머신러닝 세가지 주제로 운영중이고 재밌는게 SW 클라우드 소싱을 제공합니다. 이 안에서 할수 있는게 굉장히 많죠. 말씀하신 알고리즘도 안에 있어서 이 안에서 오래 머물 수 있습니다. 알고리즘 하다 지겨우시면 클라우드 소싱을 통해 직접 돈도 버실수 있죠. 능력에 따라 벌수 있는 돈은 천지차이로 나열되어 있습니다. 이 자체로도 충분한 동기부여가 될수 있죠. 

  • https://www.hackerrank.com/contests
    이전에 페이스북 개발자 채용에 한 과정이였는지 확실하지 않은데 페이스북 퍼즐 문제 가 있었습니다 지금은 문을 닫았는데 문을 닫고 내놓은 링크가 이 사이트 입니다. 알고리즘 패턴 별로 굉장히 잘 정리되어 있어서 원하는 유형의 문제를 풀고자 할때 굉장히 좋아요. 사이트 자체 규모가 어느정도 인지는 모르겠으나 한국인은 거의 없는 거 같더군요. 문제별 랭킹도 제공하고 토탈 랭킹도 있습니다. 웹에서 컴파일하고 결과 볼수 있는 사이트들이 많듯이 여기도 원하는 언어로 문제 풀고 바로바로 결과를 피드백 받아볼 수 있어요. 처음하실 때 인풋이 어떻게 들어오는가를 잘 보셔야 합니다. 로컬에서 똑같이 했을 때는 되는데 통과를 못하는 경우가 종종 생기더라구요. 페이스북과 이 사이트의 관계는 잘 모르겠으나 관계 상관없이 정말 좋은 사이트라고 생각됩니다.

  • http://www.comp.nus.edu.sg/~stev.../visualization/index.html
    싱가폴에 한 대학교 에서 만든거 같은데 아예 모르는 경우나 알고 있다가 까먹은 경우나 두가지 모두 유용하게 사용할수 있는 사이트 입니다. 알고리즘 자체도 psuedo code로 간략하게 설명해 놓았고 어떻게 돌아가는지 직접 확인 가능합니다. (첨언 : 아래의 VisualGo 와 동일한 사이트입니다.)

▶  영어 알고리즘 온라인 강의 사이트 ( [출처] 알고리즘 학습 자료 모음|작성자 낙투르 )



▶  PDF / Website


▶  기타 추천 사이트

  • Coding is fun
    장원영 님께서 직접 제작하신 사이트. 알고리즘을 배우기 보다는 한국 정보 올림피아드 기출문제를 푸는 편이라고 합니다.

  • 구글 코드 잼
    구글 코드잼은 구글에서 매년 진행하는 알고리즘 경진대회입니다. 아웃사이더 님의 참가 후기를 읽어 보시는 것을 추천합니다.

  • 프로젝트 오일러
    프로젝트 오일러 (ProjectEuler.net) 는 수학적인 문제들을 컴퓨터 프로그래밍으로 하나씩 해결해가는 퀴즈 풀이 사이트입니다. 프로젝트 오일러 코리아 사이트 (Project Euler @ kr) 에서는 보다 많은 이들이 쉽게 접근해서 즐길 수 있도록 원본 문제를 한국어로 번역해서 제공합니다.

  • VISUALGO
    : VisuAlgo 는 2011년 Steven Halim 박사가 자신이 가르치는 학생들이 데이터 구조와 알고리즘을 좀 스스로 이해하고, 자신만의 학습속도에 따라서 공부할 수 있도록 하기 위해 고안한 것입니다. 싱가폴 국립대학교의 학생들과 함께 간단한 정렬 알고리즘부터 복잡한 그래프 자료구조, 알고리즘, 문자열+위상 알고리즘까지 통합한 시각화된 자료들을 개발했습니다.

  • http://coderbyte.com
    : Coderbyte 는 다양한 프로그래밍 문제 모음을 통해 프로그래밍을 연습하고 기술을 향상할 수 있도록 도와주는 웹 어플리케이션입니다. 문제들은 다양한 난이도로 제공하고 있으며 온라인 어플리케이션 내에서 학습할 수 있도록 되어 있습니다. 아무것도 다운로드 하거나 업로드할 필요가 없습니다. Javascript, Python, Ruby, PHP, Java, C++ 등의 언어로 문제를 풀어볼 수 있습니다.

  • http://www.checkio.org/
    : 알고리즘을 게임 형식으로 좀 더 재미있게 공부할 수 있게 해주는 사이트이며, 한글 인터페이스가 제공됩니다. 문제를 풀면 좀 더 어려운 문제를 푸는 스테이지(stage)가 열립니다.

  • 알고리즘 오픈마켓
    : 알고리즘을 사고 파는 시장!

  • 코딩 도장
    : 코딩 도장은 프로그래밍 문제풀이를 통해서 코딩 실력을 수련(Practice)하는 곳입니다.

  • What makes good programmer
    : 좋은 프로그래머가 되기 위해 알아야 할 것들 (컬럼)

  • API Academy
    : '좋은 API 만드는 방법'을 배우는 온라인 학습 사이트


Posted by 곽중선