경고 : 최신판이 아닙니다. 이 문서의 오래된 판을 편집하고 있습니다. 이것을 저장하면, 이 판 이후로 바뀐 모든 편집이 사라집니다. 로그인하고 있지 않습니다. 편집하면 당신의 IP 주소가 공개적으로 기록됩니다. 계정을 만들고 로그인하면 편집 시 사용자 이름만 보이며, 위키 이용에 여러 가지 편의가 주어집니다.스팸 방지 검사입니다. 이것을 입력하지 마세요!{{쉽게 알 수 있다 시리즈|이 문서는 정말 쉽습니다.|문서의 내용이 너무 쉬워서 오늘부터 프로그래밍 할 수 있을 것 같습니다.}} [[분류:컴퓨터_프로그래밍]] {{토막글}} == 들어가기 전 == 빨간 컵에 [[칠성사이다]]가 담겨져 있고 파란 컵에 [[스프라이트]]가 담겨져있다. 여기서 파란 컵에 칠성사이다를 넣고 빨간 컵에 스프라이트를 넣을려면 어떻게 해야 될까? 해답은 간단하다. 다른 컵(여기선 노란 컵이라 하겠다.)에 빨간 컵의 칠성사이다를 노란 컵에 붓고 빨간 컵이 비게 되면 파란 컵의 스프라이트를 빨간 컵에 붓고 파란 컵이 비게 되면 노란 컵에 담았던 칠성사이다를 파란 컵에 부으면 된다. 갑자기 노란 컵이 튀어나와서 쌩뚱맞다고 생각하는 사람이 있을 수 있겠지만 다른 컵을 쓰면 안된다고는 안했다. 알고리즘은 문제를 해결하기 위한 것이지 [[수수께끼]]나 [[넌센스]] 문제가 아니다. 이 이야기가 왜 나왔냐면 프로그래밍을 할 때 아래 소스 처럼 2개의 변수 값을 서로 바꿀 경우 변수 2개 가지고 끙끙 거리지 말고 간단하게 변수 하나 더 사용해서 쉽게 해결하면 되기 때문이다. <del>이제 제 3의 변수를 쓰지 않고 변수 2개의 값을 맞바꾸는 알고리즘을 생각해보자.</del> {| class="collapsible collapsed" |- ! 의사코드 펼치기 |- | 1 '''function''' 바꾸기(''첫번째컵'', ''두번째컵''): 2 ''잠시담아둘컵'' ← ''첫번째컵'' 3 ''첫번째컵'' ← ''두번째컵'' 4 ''두번째컵'' ← ''잠시담아둘컵'' 5 '''end function''' 6 7 '''function''' 지금상황(): 8 ''파란컵'' ← "칠성사이다" 9 ''빨간컵'' ← "스프라이트" 10 바꾸기(''파란컵'', ''빨간컵'') 11 '''print''' ''파란컵'' 12 '''print''' ''빨간컵'' 13 '''end function''' |- |} <source lang="csharp" class="mw-collapsible mw-collapsed"> using System; namespace 사이다컵바꾸기 { class Program { static void Main(string[] args) { // 빨간 컵과 파란 컵에 칠성사이다와 스프라이트가 담겨져 있다. string 빨간컵 = "칠성사이다"; string 파란컵 = "스프라이트"; Console.WriteLine("=====바꾸기 전====="); Console.WriteLine("빨간컵 : {0}", 빨간컵); Console.WriteLine("파란컵 : {0}", 파란컵); // 새롭게 준비한 노란 컵 string 노란컵; // 스프라이트를 빨간 컵에 붓기 위해 칠성사이다를 노란컵에 붓는다. // 그 다음 파란 컵의 스프라이트를 빨간 컵에 붓는다. // 그 다음 노란 컵에 임시로 담아둔 칠성 사이다를 파란 컵에 붓는다. 노란컵 = 빨간컵; 빨간컵 = 파란컵; 파란컵 = 노란컵; Console.WriteLine("=====바꾼 후====="); Console.WriteLine("빨간컵 : {0}", 빨간컵); Console.WriteLine("파란컵 : {0}", 파란컵); } } } </source> 여담으로, 위 취소선의 답은 의외로 간단하다. 정수가 저장되어 있는 a와 b가 있을 때, a와 b를 더한 다음 a에 저장한다. 그 다음 a에서 b를 뺀 값을 b에 저장한다. 그 다음 a에서 b를 뺀 값을 a에 저장하면 된다. <del>숫자가 아니고 객체면?</del> <del>[[우린 안될 거야 아마|포인터 주소값을 더하고 빼면... ...]]</del> 사실 덧셈보다 더 빠른 방법은 XOR 회로를 사용하는법이 있다. 값이 같지 않으면 a=a^b b=a^b a=a^b를 넣어두면 정수가 아니더라도, 산술적 연산이 아니라 비트 배열 자체가 바뀌기 때문에 값이 교환된다.<s>하지만 병렬 프로그래밍에서는 무리DA☆ZE★</s> == 알고리즘의 시간 복잡도 == 어떤 알고리즘이 실행될 때에 입력과 알고리즘의 실행 시간의 함수 관계를 의미한다. 입력에 따라 알고리즘의 속도가 차이가 난다. 입력되는 숫자의 정렬 작업을 하는 알고리즘 a와 b가 있다고 할 때, 숫자의 개수 등에 따라서 a가 b보다 더 빠르게 정렬 작업을 끝마칠 수도 있고 b가 a보다 더 빠르게 정렬 작업을 끝마칠 수도 있다는 의미이다. 이러한 속도는 알고리즘의 계산 횟수에 따라 달라지는데, 이를 정확히 측정하는 것은 매우 어렵다. 그러므로 보통 이를 나타내는데는 [[Big O 표기법]]으로 대략의 시간을 표시한다. 입력된 자료의 수가 <math>n</math>일 때 계산 횟수가 <math>3n+4</math>이면 <math>O(n)</math>, <math>2n^3+n^2</math>면 <math>O(n^3)</math>등으로 나타내는 방식. 이 시간 복잡도가 <math>O(2^n)</math>이런 모습이나, <math>O(n!)</math>이런 모습으로 나오면 풀이시간에 답이 없어진다. 예를 들어 소수와 소수의 곱을 [[소인수 분해]]하는 것이다. 77같이 작은 수는 7 * 11로 쉽게 할 수 있지만, 4,951,760,154,835,678,088,235,319,297를 소인수 분해하라고 하면 일단 좌절한다. <del>[[엔리코 푸치|이럴 때는 마음을 안정시키고 소수를 세는거다]]</del> 여담으로 답은 2,305,843,009,213,693,951 * 2,147,483,647이다. 하지만 반대로 답이 2,305,843,009,213,693,951 * 2,147,483,647 확인하는 것은 쉽다. 이에 관한 것은 [[P-NP 문제]] 참고. == 알고리즘의 정당성 증명 == == 알고리즘을 설계하는 일반적인 방법 == 아래 나오는 모든 코드는 '''[[C(프로그래밍 언어)|C언어]]'''를 기본으로<ref>일단 C언어로는 작성을 해 두자.</ref><ref>C언어의 문법(특히 포인터)은 미리 공부를 해 두자.</ref>, 다른 언어들은 알아서 추가해주길 바란다. == 플로우 차트 == === 기호 === == 자료구조 == === 선형 자료구조 === ==== 선형 랜덤 접근 가능 ==== ===== 배열 ===== 가장 쉬운 자료구조이자 가장 언어에 따라 달라지는 자료구조. c언어에서는 대괄호를 사용한다. <source lang="C"> int array1[]; //int *array1과 비슷함. int array2[10]; //크기를 가지는 배열 int array3[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; //초기화한 배열 </source> ===== 해시 ===== 해시는 해시 함수로 구현한다. 해시 함수는 마치 배열처럼, 어떤 자료를 찾을 때 O(1)의 시간만을 소요한다. 해시함수에 키 값을 넣어 주소값을 얻고, 그 주소에 위치한 버킷에 저장된 데이터를 가져오는 방식을 사용한다. 하지만, 언제나 O(1)이 보장되는 것은 아니다. 자세한 것은 [[해시 테이블]] 참고. ==== 선형 랜덤 접근 불가능 ==== ===== 스택 ===== 후입선출(後入先出) 자료구조 스택이다. push 함수와 pop 함수를 갖는 게 정석이며, 추가로 옵션함수(empty, full 등)을 가질 수 있다. 아래는 배열로 구현한 스택이다.<ref>C++ STL의 그것보다 빠를 것이다. 다만 확장이 어려울 뿐.</ref> <source lang="C"> //헤더 부분 void push(int); //push 함수 정의 int pop(); //소스 부분 int array[500]; //스택의 최대 크기는 500 int top = -1; //스택의 현재 크기는 0; void push(int n) { array[++top] = n; } int pop() { return array[top--]; } </source> 사용법은 스택에 넣고 싶은 것을 push로 넣고, pop로 빼면 된다. <source lang="c"> push(1), push(2), push(3); printf("%d %d %d", pop(), pop(), pop()); </source> 출력 결과는 3 2 1과 같을 것이다. ===== 큐 ===== 선입선출(先入先出) 자료구조 큐이다. put 함수와 get 함수를 가진다. 밑의 큐는 [[연결 리스트]]로 구현된 큐이다. 배열로 하는 경우에는 보통 순환 큐라고 해서 맨 끝과 앞을 연결(나머지 연산자 % 이용)하는 방식으로 구현한다. 소스는 다음과 같다. <source lang="C"> void put(int); int get(); struct linkedList { int value; struct linkedList *next; }; struct linkedList *front; struct linkedList *rear; //포인터가 있어서 이해하기 힘들지만 찬찬히 뜯어보면 그리 어렵지 않은 내용이다. void put(int n) { if(front == NULL) { *front = {n, NULL}; rear = front; } else { rear -> *next = {n, NULL}; rear = rear -> next; } int get() { int res = front -> value; front = front -> next; return res; } </source> ===== 데크 ===== ===== 링크드 리스트 ===== 연결 리스트라고도 불린다. 값과 다음 노드를 가지고 있다.<ref>옵션으로는 이전 노드, 끝 노드의 다음이 시작 노드인 등일 수 있다.</ref> 가장 간단하게 구현한 것은 위의 [[큐]](...). 다시 한 번 뜯어보고 옵션을 넣어본다면 실력 향상에 도움이 될 것이다. === 비선형 자료구조 ===<!-- 아니 이 인간이 순서를 이상하게 해 놓았어 --> 아래 참조 ===== 그래프 ===== ===== 트리 ===== ====== 힙 ====== === 문자열 === == 분할 정복 == == 동적 계획법 == === 제귀적 방법 === === 반복적 방법 === == 정렬 알고리즘 == 크기순, 사전순과 같이 정렬하는 알고리즘을 말한다. 효율적인 알고리즘들 중 대부분은 데이터가 사전에 정렬되어 있을 것을 요구하는 것이 많다. {{YouTube|kPRA0W1kECg}} 일단 이걸 보고 뭘 배우면 좋을 지 생각해보자. === 안정 정렬 === 비교한 값이 같을 때 서로 바뀌지 않는 정렬법을 안정 정렬이라고 한다. ==== 거품(Bubble) 정렬 ==== 세상에서 가장 만만한 정렬(...). 바로 뒤의 원소와 비교해 더 크다면 뒤로 간다. 뒤에서부터 차례차례 정렬돼가는 것을 보면…. 하지만 가능하면 쓰지는 말자. 성능으로 치면 가장 구린 정렬. 캐시 히트 레이트로나 여러가지 면으로 매우 좋지 않지만 워낙 알고리즘 자체가 간단하기 때문에 보통 입문용으로 가르치곤 하지만... <source lang="C"> int arr[] = {5, 3, 7, 8, 6, 4, 2, 1, 0, 9}; void sort() { int i, j; for(i = 0; i < 10; i++) for(j = i; j < 9; j++) if(arr[j] > arr[j + 1]) //j번째 원소가 다음 원소보다 크다면 바꾼다. { arr[j] = arr[j] ^ arr[j + 1]; arr[j + 1] = arr[j] ^ arr[j + 1]; arr[j] = arr[j] ^ arr[j + 1]; } } </source> ==== 병합(Merge) 정렬 ==== 분할정복기법의 대표적 예이다. 소스는 은근 쉽다.<!-- 에러 수정바람 --> <source lang="C"> int arr[] = {5, 3, 7, 8, 6, 4, 2, 1, 0, 9}; int tmparr[10]; void sort(int, int); void merge(int, int); void sort(int start, int end) { if(end > start) { sort(start, (start + end) / 2); sort((start + end) / 2 + 1, end); } merge(start, end); } void merge(int start, int end) //여기가 진짜다. { int i = start, j = (start + end) / 2 + 1; int count = start; while(i <= (start + end) / 2 && j <= end) { if(arr[i] > arr[j]) { tmparr[count++] = arr[j++]; } else { tmparr[count++] = arr[i++]; } } while(i <= (start + end) / 2) { tmparr[count++] = arr[i++]; } while(j <= end) { tmparr[count++] = arr[j++]; } for(i = start; i <= end; i++) { arr[i] = tmparr[i]; } } </source> === 불안정 정렬 === 비교한 값이 같을 때 서로 바뀌는 정렬법을 불안정 정렬이라고 한다. ==== 선택(Selection) 정렬 ==== ==== 삽입(Insertion) 정렬 ==== ==== 퀵(Quick) 정렬 ==== 정렬의 왕이다. 평균 <math>O(n \log n)</math>인 정렬 알고리즘들 중 가장 빠르다. 피봇을 잡고 하는 건 너무 어렵고, 예를 들어 설명하자면 5, 3, 7, 8, 6, 4, 2, 1, 0, 9가 있을 때, 5를 기준으로 일단 정렬한다. 사람이 한다면 아마 3, 4, 2, 1, 0, '''5''', 7, 8, 6, 9가 될 것이다. 이 상태에서 5의 앞을 다시 정렬한다. 2, 1, 0, '''3''', 4와 '''5'''와 7, 8, 6, 9가 남았다. 이 때, 4는 3 뒤에 있는 오직 한 개의 수이므로 정렬이 되었다고 본다. 이런 식으로 하다 보면 0, 1, 2, 3, 4, 5, 6, 7, 8, 9의 올바른 순열이 나올 것이다. 소스는 다음과 같다.<ref>물론 최적화는 되어 있지 않다.</ref> <source lang="C"> int arr[] = {5, 3, 7, 8, 6, 4, 2, 1, 0, 9}; void sort(int, int); void sort(int start, int end) { int i = start + 1; int j = end; if(end < start) return; while(i < j) { while(arr[i] <= arr[start]) { i++; } while(arr[j] >= arr[start]) { j--; } if(i < j) { arr[i] = arr[i] ^ arr[j]; arr[j] = arr[i] ^ arr[j]; arr[i] = arr[i] ^ arr[j]; } } if(arr[start] > arr[j]) { arr[start] = arr[start] ^ arr[j]; arr[j] = arr[start] ^ arr[j]; arr[start] = arr[start] ^ arr[j]; } sort(start, j - 1); sort(j + 1, end); } </source> ==== 힙(Heap) 정렬 ==== === 그 밖의 정렬 알고리즘 === ==== 버킷(Bukket) 정렬 ==== ==== 자릿수(Radix) 정렬 ==== == 탐욕법 == 그리디 알고리즘 또는 욕심쟁이 알고리즘 등으로도 불리운다. 현재 봤을 때 가장 최적해같아 보이는 것을 선택하는 알고리즘이다. 근사해를 구할 때 쓰이면 가장 좋으나, 최적해를 구할 때에는 역추적을 해야만 한다. 가장 사람을 잘 흉내내는 알고리즘이다.{{--|이런 욕심쟁이들.}} == 조합 탐색 == == 수치해석 == == 정수론 == == 계산 기하 == == 트리 == === 구현과 순회 === === 이진 검색 트리 === 이진 검색 트리는 고급 자료구조를 위해서 다양하게 활용되기도 한다. 그에 관해서는 다음 문서를 참고. * [[이진 색인 트리]] * [[레드 블랙 트리]] === 힙 === 힙은 트리의 일종으로 부모 노드 값이 항상 자식 노드 값보다 큰 트리를 말한다. {{--|힙소트 할때 쓰는 트리이다.}} 보통 이진트리로 구현한다. 힙에 새 원소를<!-- 중딩이 원소까지 알아야겠어? --> 넣고 빼는 데에는 [[big-O 표기법|<math>O(n \log n)</math>]]의 시간 복잡도를 가진다. {{--|뭔가 힙보다 힙정렬이 더 앞에 있는 것 같은 건 눈의 착각이다.}} C로 힙을 구현하는 방법은 크게 두 가지, 배열과 포인터가 있다. 포인터로 하는 방법은 직관적이지만 많은 자원(메모리 또는 시간)이 소모된다. 하지만 배열은 힙의 각 노드를 배열의 어떤 인덱스에 대응시킬지 고민해야 하지만 훨씬 자원을 효율적으로 사용할 수 있다. === 구간 트리 === === 트라이 === == 그래프 == 수학, 과학 시간에 많이 보던 그 그래프와는 [[사뭇]] 다르다. 알고리즘을 배우다 보면 어쩌면 가장 많이 나오는 부분일 지도 모른다. 주로 노드와 엣지로 표현된다. {{--|왠지 노드는 동그라미이고 엣지는 선이다.}} '그래프 구조'로 검색하면 그런 그림을 볼 수 있다. 간단한 구조체를 만들어 보자. <source lang="C"> struct Edge //노드보다는 엣지로 나타내는 편이 대부분의 경우에 더 좋다. { int snode; //시작 노드 int enode; //종료 노드 //int cost; //가중치를 가지는 엣지에 사용된다. }; </source> struct Edge가 하나 이상 있는 것이 바로 그래프이다. === 순회 알고리즘 === ==== 깊이 우선 탐색 ==== Depth First Search, DFS ==== 너비 우선 탐색 ==== Breadth First Search, BFS === 최단 경로 === ==== 플로이드-워셜(Floyd-Warshall) 알고리즘 ==== ==== 데이크스트라(Dijkstra) 알고리즘 ==== {{--|이거 왜 그리디에 없고 여기 있냐}} 최단거리를 찾는 알고리즘이다. 움짤이 여럿 돌아다니니 한 번 보자. [[File:Shortest path Dijkstra vs BellmanFord.gif|thumb|Shortest path Dijkstra vs BellmanFord]] {{--|c부터 조사하지 않는 게 수상하긴 하지만 }}윗 것은 데이크스트라, 아랫 것은 벨먼 포드 알고리즘이다. 이것만 보고도 이해할 수 있다면 참 좋겠다. <!-- 다음은 그 소스이다. c로 구현하기 힘든데...--> ==== 벨먼-포드(Bellman-Ford) 알고리즘 ==== === 위상 정렬 === === 최소 비용 스패닝 트리 === ==== 크러스컬(Kruskal) 알고리즘 ==== ==== 프림(Prim) 알고리즘 ==== === 네트워크 플로우 === == 문자열 알고리즘 == ==== 문자열 검색 ==== ===== KMP 알고리즘 ===== ===== 보이어-무어 알고리즘 ===== ===== <s>최종병기</s> 접미사 트리 ===== [[추가바람]] {{각주}} {{쉽게 배우는 프로그래밍 입문}} 요약: 리브레 위키에서의 모든 기여는 크리에이티브 커먼즈 저작자표시-동일조건변경허락 3.0 라이선스로 배포됩니다(자세한 내용에 대해서는 리브레 위키:저작권 문서를 읽어주세요). 만약 여기에 동의하지 않는다면 문서를 저장하지 말아 주세요. 글이 직접 작성되었거나 호환되는 라이선스인지 확인해주세요. 리그베다 위키, 나무위키, 오리위키, 구스위키, 디시위키 및 CCL 미적용 사이트 등에서 글을 가져오실 때는 본인이 문서의 유일한 기여자여야 하고, 만약 본인이 문서의 유일한 기여자라는 증거가 없다면 그 문서는 불시에 삭제될 수 있습니다. 취소 편집 도움말 (새 창에서 열림) | () [] [[]] {{}} {{{}}} · <!-- --> · [[분류:]] · [[파일:]] · [[미디어:]] · #넘겨주기 [[]] · {{ㅊ|}} · <onlyinclude></onlyinclude> · <includeonly></includeonly> · <noinclude></noinclude> · <br /> · <ref></ref> · {{각주}} · {|class="wikitable" · |- · rowspan=""| · colspan=""| · |} {{lang|}} · {{llang||}} · {{인용문|}} · {{인용문2|}} · {{유튜브|}} · {{다음팟|}} · {{니코|}} · {{토막글}} {{삭제|}} · {{특정판삭제|}}(이유를 적지 않을 경우 기각될 가능성이 높습니다. 반드시 이유를 적어주세요.) {{#expr:}} · {{#if:}} · {{#ifeq:}} · {{#iferror:}} · {{#ifexist:}} · {{#switch:}} · {{#time:}} · {{#timel:}} · {{#titleparts:}} __NOTOC__ · __FORCETOC__ · __TOC__ · {{PAGENAME}} · {{SITENAME}} · {{localurl:}} · {{fullurl:}} · {{ns:}} –(대시) ‘’(작은따옴표) “”(큰따옴표) ·(가운뎃점) …(말줄임표) ‽(물음느낌표) 〈〉(홑화살괄호) 《》(겹화살괄호) ± − × ÷ ≈ ≠ ∓ ≤ ≥ ∞ ¬ ¹ ² ³ ⁿ ¼ ½ ¾ § € £ ₩ ¥ ¢ † ‡ • ← → ↔ ‰ °C µ(마이크로) Å °(도) ′(분) ″(초) Α α Β β Γ γ Δ δ Ε ε Ζ ζ Η η Θ θ Ι ι Κ κ Λ λ Μ μ(뮤) Ν ν Ξ ξ Ο ο Π π Ρ ρ Σ σ ς Τ τ Υ υ Φ φ Χ χ Ψ ψ Ω ω · Ά ά Έ έ Ή ή Ί ί Ό ό Ύ ύ Ώ ώ · Ϊ ϊ Ϋ ϋ · ΐ ΰ Æ æ Đ(D with stroke) đ Ð(eth) ð ı Ł ł Ø ø Œ œ ß Þ þ · Á á Ć ć É é Í í Ĺ ĺ Ḿ ḿ Ń ń Ó ó Ŕ ŕ Ś ś Ú ú Ý ý Ź ź · À à È è Ì ì Ǹ ǹ Ò ò Ù ù · İ Ż ż ·  â Ĉ ĉ Ê ê Ĝ ĝ Ĥ ĥ Î î Ĵ ĵ Ô ô Ŝ ŝ Û û · Ä ä Ë ë Ï ï Ö ö Ü ü Ÿ ÿ · ǘ ǜ ǚ ǖ · caron/háček: Ǎ ǎ Č č Ď ď Ě ě Ǐ ǐ Ľ ľ Ň ň Ǒ ǒ Ř ř Š š Ť ť Ǔ ǔ Ž ž · breve: Ă ă Ğ ğ Ŏ ŏ Ŭ ŭ · Ā ā Ē ē Ī ī Ō ō Ū ū · à ã Ñ ñ Õ õ · Å å Ů ů · Ą ą Ę ę · Ç ç Ş ş Ţ ţ · Ő ő Ű ű · Ș ș Ț ț 이 문서에서 사용한 틀: 틀:-- (원본 보기) (준보호됨)틀:YouTube (원본 보기) (준보호됨)틀:YouTube/styles.css (편집) 틀:Youtube (편집) 틀:ㅊ (원본 보기) (준보호됨)틀:각주 (원본 보기) (준보호됨)틀:고지 상자 (원본 보기) (보호됨)틀:쉽게 알 수 있다 시리즈 (편집) 틀:인용문2 (원본 보기) (준보호됨)틀:취소선 (원본 보기) (준보호됨)틀:탭 (원본 보기) (준보호됨)틀:탭/styles.css (편집) 이 문서는 다음의 숨은 분류 1개에 속해 있습니다: 분류:유튜브 영상이 포함된 문서