[분할 정복 알고리즘(Divide and conquer algorithm)]


-  그대로 해결할 수 없는 문제를 작은 문제로 분할하여 문제를 해결하는 방법(알고리즘)

-  즉, 한번에 해결하기 어려운 문제를 작은 단위의 문제들로 나누어 해결하는 방법이다.

-  정복(conquer)이 들어가는 이유는 재밌게도 나폴레옹과 관련이 있다.1805년 12월 2일 아우스터리츠 

   전투에서 프랑스의 황제(皇帝) 나폴레옹은 숫자면에서 우세했던 연합군을 물리치기 위해서 나폴레옹은 

   연합군의 중앙으로 쳐들어가 그들의 병력을 둘로 갈라 놓았고, 둘로 나누어진 병력은 개별적으로는 

   나폴레옹의 군대보다 숫자가 적었기 때문에 전투는 나폴레옹의 승리로 끝나게 되었다. 분할정복법은 위와 

   같은 사례를 프로그램에 이용한 것이다.


분할정복법을 구현하기 위한 순서는 다음과 같다.
  1. 분할(Divide) : 분할이 가능한 경우, 큰 문제를 하나 이상의 작은 문제로 분할한다.
  2. 정복(Conquer) : 분할이 가능하다면 계속 분할한다. 분할이 불가능하다면 나눈 작은 문제를 각각 해결한다.
  3. 결합(Combine) : 정복된(해결된) 해답을 모아 큰 문제의 답이 되도록 결합(병합)한다.
분할 정복 알고리즘은 문제를 쪼개는 과정이 가장 핵심적인 기능이며 효율적인 분할을 하는 것이 중요하다.
문제 분할만 잘해도 그것을 해결(정복)한 뒤 병합하는 과정은 간단하기 때문이다. 하지만, 분할정복법의 경우 
대다수가 재귀호출을 통해 구현되기 때문에 그만큼 많은 부담을 갖게 된다.
 

[분할 정복 알고리즘을 이용한 대표적인 알고리즘]

  • 퀵 정렬 (Quick Sort)
  • 병합 정렬 (Merge Sort)
  • 피보나치 수열 (Fibonacci Sequence)
  • 거듭 제곱 (Exponentiation)
  • 고속 푸리에 변환 (Fast Fourier Transform, FFT)

참고 블로그 

http://debugnote.com/algorithm/2015/07/06/quick-sort/



Posted by sungho88
,

선택 정렬은 오히려 버블 정렬보다도 쉽고 간단한 알고리즘이다. 

1. 주어진 리스트 중에 최소값을 찾은 후, 

2. 그 값을 리스트 맨 앞에 위치한 값과 교체(교환)한다.

3. 맨 처음 위치를 제외하고(이미 최소값이므로) 나머지 리스트를 같은 방법으로 반복한다.

딱, 세가지만 생각하면 된다. 



① 주어진 리스트 중에 최소값을 찾는 방법

위와같은 배열a[]가 존재할 때, 리스트 중 가장 작은 요소의 인덱스값을 구하기 위해서는 어떻게 할까?

int[] arr = {3,5,1,7,9,2,6};

int min_index = 0;

for (int i = 1; i < arr.length; i++) {

if(arr[min_index]>arr[i]) min_index = i;

System.out.println(arr[min_index] +" "+arr[i]);

}

요런식으로 하면 인덱스 0(값6)이후의 값부터 비교해가며 최소값의 인덱스를 찾을 수 있다. 

min_index = 2일 것이다.


② 리스트 맨 앞 요소와 위치를 교환한다.

for (int i = 1; i < arr.length; i++) {

if(arr[min_index]>arr[i]) min_index = i;

System.out.println(arr[min_index] +" "+arr[i]);

//아래 부분이 추가됨.

temp = arr[0];

arr[0] = arr[min_index];

arr[min_index]= temp;

}


이러면 될까? 되긴 한다. 그렇지만 어떻게 나올까? 

1 5 3 7 9 2 6 

뭐야 이게? 뭐가 되긴 됐는데? 그렇다. 최소값 1이 맨 앞 3과 자리가 바꼈다....

근데. ㅡ_ㅡ;;;다른건 움직이지 않았다. 위 그림에서 보면 두번째 그림과 같다는 것을 알수 있다.

그래서 우리는 반복을 해주어 계속 정렬을 해야한다.


③ 리스트 맨 앞 요소를 제외한 리스트 전체를 위 과정을 반복실행 한다.

맨 앞 즉, 0번째 인덱스 정렬은. 끝났다. 1번째 인덱스부터 새롭게 시작한다. 그러면

min_index값은 어떻게 될까? 당연히.. 1부터다. 

즉, (배열의 크기-1)만큼 돌려야 모든 요소들이 비교를 해가면서 정렬이 완성될 것이다.(그림 참조)

for (int i = 0; i < arr.length; i++) {

for (int j = i+1; j < arr.length; j++) {

if(arr[min_index]>arr[j]) min_index = j;

temp = arr[i];

arr[i] = arr[min_index];

arr[min_index]= temp;

}

}


일단, 에 나오는 for문을 감싸는 for문을 하나 더 삽입해서 이중for문이 되도록 해야 한다.

기존에 i변수를 j로 바꾸고 0번째 인덱스를 의미하는 0을 지우고 j를 넣는다.

왜냐하면 j가 하나하나 증가되면서 값을 저장하기 때문이다. 따라서,다음과 같이 정렬이 된다.

1 2 3 5 6 7 9 




선택 정렬의 성능평가 

버블 정렬과 성능상 큰 차이가 없다. 선택 정렬의 빅-오 역시 O(n^2) 

이 둘을 비교하는 것은 도토리 키재기..라고 할 수 있다.


Posted by sungho88
,

버블 정렬은 정렬하면 가장 먼저 떠오르는 간단한 정렬방법이다.

버블 정렬은 이름 그대로 앞에서부터 순서대로 비교하고 교환하는 과정이 마치 거품이 일어나는 모습에

비유되어 버블 정렬이라는 이름이 지어진 것이다.

그만큼 이해하기도, 구현하기도 쉽고 간단하다. 물론 구현이 쉬운만큼 성능적으로는 매우 떨어진다.

만약, 오름차순으로 정렬을 하려고 한다. 아래와 같은  배열 6 1 2 3 4 5이 있다면, 

위 그림에서 보듯, 버블 정렬은 인접한 두 개의 데이터를 비교해가면서 정렬을 진행하는 방식이다.

두 개의 데이터를 비교하여, 정렬순서상 위치가 바뀌어야 할 경우에는 두 데이터의 위치를 바꿔나간다.

즉, 정렬의 우선순위가 가장 낮은, 제일 큰 값을 맨 뒤로 보내는 것을 반복하는게 바로 이 정렬의 핵심이다.

위 사진의 경우에는 6만 보내면 해결됐지만, 만약 6 5 4 3 2 1이라면 모든 값을 비교 후 이동함으로 최악이다.

먼저, 하나의 요소와 그 뒷 요소를 비교해서 앞이 뒤보다 크다면 앞.뒤의 위치를 변경하는 코드를 구현하면,

if( arr[j] > arr[j+1){ tmp = arr[j]; arr[i] = arr[j+1]; arr[j+1] = tmp; }

import java.util.Scanner;

public class Main {
 public static void main(String[] args) {

  int bubbleSort[] = {6,3,4,5,2,1};

  for (int i = 0; i < bubbleSort.length; i++) {
   System.out.print (bubbleSort[i]+" ");
  }  // 6 3 4 5 2 1 출력
  

BubbleSort(bubbleSort,bubbleSort.length); 


  System.out.println();
  for (int i = 0; i < bubbleSort.length; i++) {
   System.out.print (bubbleSort[i]+" ");
  }  // 1 2 3 4 5 6 출력
 }

 private static void BubbleSort(int[] bubbleSort, int length) {
  
  int temp;
  
  for (int i = 0; i < length-1; i++) {
   for (int j = 0; j < (length-i)-1; j++) {
    if(bubbleSort[j] > bubbleSort[j+1]){
         temp = bubbleSort[j];
         bubbleSort[j] = bubbleSort[j+1];
         bubbleSort[j+1] = temp;
    }
   }
  }
 }
}

위에서 BubbleSort()메소드가 바로 버블 정렬 알고리즘을 구현한 코드이다.

++추가적으로 다른 방법으로 버블 정렬을 구현하였다. 이것이 더욱 간단하지 않을까싶다.

import java.util.Scanner;


public class Main {


public static void main(String[] args) {


Scanner scanner = new Scanner(System.in);

int num1 = scanner.nextInt();

int[] arr = new int[num1];

int flag = 0, temp = 0;

for (int i = 0; i < arr.length; i++) {

arr[i] = scanner.nextInt();

}


for (int i = num1 - 2; i >= 0; i--) {

for (int j = 0; j <= i; j++) {

if (arr[j] > arr[j + 1]) {

temp = arr[j];

arr[j] = arr[j + 1];

arr[j + 1] = temp;

}

}

}

for (int j = 0; j < arr.length; j++) {

System.out.print(arr[j]);

}

}

}

입력 :

7

2 5 11 24 8 1 9

출력 :

1 2 5 8 9 11 24 


성능

정렬 알고리즘의 성능은 두 가지를 근거로 판단한다.  

1. 비교 횟수  : 두 데이터간의 비교연산의 횟수

2. 이동 횟수  : 위치의 변경을 위한 데이터의 이동 횟수.

최선의 경우는 배열이 이미 완벽하게 정렬되어 있는 상태 - 데이터의 이동이 한 번도 일어나지 않음

최악의 경우에는 내림차순.. 즉, 역순으로 정렬되어 있을 경우 비교횟수 = 이동횟수.. 

버블 정렬은 빅오 오브 n^2 (= O(n^2))이므로 매우 좋지 않은, 실제로 사용하지 부담스러운 성능을 보인다.

하지만, 코드가 간단하게 구현할 수 있기 때문에 간단한 배열의 정렬의 경우에는 이 방식을 사용해도 무방하다..

이상으로 버블 정렬에 대한 정리를 마치도록 하겠다. 다음번에는 선택 정렬!!!

 

Posted by sungho88
,

1. 배열(Array)

[배열(Array)이란 무엇인가]

- 거의 모든 언어에서 지원하는 문법이다.

- 배열은 가장 기본적인 자료구조다. 즉, 앞으로 배울 많은 자료구조들이 배열을 부품으로 사용된다.

- 데이터가 적다면 물론 일반 변수를 사용하여 값을 저장하여 사용하면 문제없다.

- 하지만, 데이터가 많아질수록 그룹 관리에 대한 필요성이 생긴다. 이럴 때 배열을 사용하게 된다.

- 즉, 배열은 여러 데이터를 하나의 이름으로 그룹핑해서 관리하기 위한 목적으로 사용하는 자료구조이다.

- element = value + index (value = 저장된 실제 데이터, index는 데이터를 저장 및 조회를 위한 위치 식별자(Index))

- 배열은 반복문과 조합하면 훨씬 더 효율적으로 사용할 수 있다. 

 


 

[배열의 생성 방법]

int[] number = new int[5];

number[0] = 10;

number[1] = 20;

number[2] = 30;

number[3] = 40;

number[4] = 50;

위 코드가 바로 배열을 생성하고, 인덱스에 값을 대입하는 코드이다. 또한 더 간단하게 생성을 하고 싶다면 

int[] number2 = {10,20,30,40,50};

또는 int[] number3 = new int[]{10,20,30,40,50};

모두 같은 의미이다.


[배열 안에 저장된 값을 가져오는 방법(하나의 데이터를 가져올때)]

이를 위해서 인덱스(Index)가 필요하다. 

number[0];   을 호출하면 0번째 인덱스의 값(value)를 가져오게 된다


[배열 안에 저장된 값을 가져오는 방법(하나의 데이터를 가져올때)]

이를 위해서 반복문이 필요하다. while 또는 for문을 통해 0부터 0!부!터! 배열의 크기만큼(number.length) 반복한다.

[배열 안에 저장된 길이를 구하는 방법]

number.length를 작성하여 number라는 배열에 저장된 데이터 길이를 가져올 수 있다. 

[배열의 장점]

작고 가볍다. 또한 단순하다. 그래서 다른 자료구조에서 배열을 부품으로 사용하게 될 것이다.

[배열의 단점 --> 이 단점때문에 ArrayList를 사용한다]

크기가 정해져있기 때문에 데이터 저장이 크기를 초과되면 자동으로 늘어나지 않고 에러를 발생한다.
또한 기능이 없어 단순하다.


2. 리스트(List)

리스트의 특징1. 데이터가 순서대로 저장된다.            2. 중복 데이터를 허용된다.

배열과 리스트의 차이점
(삽입 시)
1. 배열 중간에 데이터를 삽입 시에 덮어쓰기가 되기 때문에 기존의 데이터값은 사라진다!! 
2. 리스트 중간에 데이터를 삽입 시 해당 인덱스 이후 데이터들이 한칸씩 뒤로 이동 후 그 위치에 값 저장                   (데이터 손실이 없다)
(삭제 시)
1. 배열내에 중간에 데이터를 삭제 시 값(value)은 지워지지만 element는 그대로 남아있다(이 경우 null이 나옴..) 
2. 리스트에서 중간에 데이터를 삽입 시 해당 인덱스 삭제 후 데이터들이 한칸씩 앞로 이동하여 빈 공간을 메꿈       (데이터 손실이 없다)
 
즉, 배열은 빈공간이 생길 수 있지만, 리스트는 빈틈(빈공간)을 허용하지 않는다.  

리스트의 기능
- 처음, 끝, 중간에 엘리먼트를 추가/삭제하는 기능
- 리스트에 데이터가 있는지를 체크하는 기능
C언어의 경우 리스트가 없어서 구현해야 하지만, 최근의 언어는 리스트를 기본적으로 지원한다.  

리스트의 생성 방법
ArrayList number = new ArrayList();
number.add(10);
number.add(20);
number.add(30);
number.add(40);
number.add(50);

자바는 리스트와 배열을 모두 지원하며, 둘을 엄격히 구분하여 직접 적절히 선택하여 사용해야한다.
C언어의 경우는 배열만 있고, 리스트는 직접 구현하거나 남의 구현한 리스트를 사용해야한다.
반면, 파이썬. PHP의 경우는 배열과 리스트를그냥 동일한 것으로 간주하여 사용한다. 즉, 리스트를 몰라도 배열을   쓰면 리스트 기능도 묻혀서 사용된다.

자바는 리스트를 두 가지 지원한다. 똑같은 사용방법(메소드) 가지고 있다.

ArrayList의 경우 추가/삭제시 느리지만, 인덱스를 알고 있다면 매우 빠르게 조회할 수 있다.
LinkedList의 경우 추가/삭제 시 빠르지만, 인덱스를 통해 조회하는 속도는 상당히 느리다.
이런 차이를 'Trade-off가 존재한다'
즉, 자기가 구현하고자 하는 것이 무엇이냐에 따라서 배열을쓸지, ArrayList를 쓸지, LinkedList를 쓸지 개발자의 선택에 달렸다....자바는 파이썬. PHP들보다 개발자가 알고 있어야 할것이 더욱더 많지만, 자유도 역시 매우 높다고 할 수 있다. 다시한번 말하지만, 자료구조는 언어마다 다르다. 

 

추가/ 삭제               

 인덱스 조회

 ArrayList

 느림  

빠름 

 LinkedList

빠름 

느림 


리스트 = 완제품 / 배열 = 부품 --> 대비되는 사이가 아니라, 서로서로 비슷비슷 사용된다고 하 수 있다.
자바에서 ArrayList를 사용하는 방법
자바의 경우 컬렉션 프레임워크이라는 곳 안에 ArrayList 자료구조를 기본적으로 내장하고 있기때문에, C언어와 같이 직접 구현을 하지 않아도 된다. 그렇기 때문에 ArrayList 사용방법을 익힌 후 어떻게 구현되는가를 살펴보도록 한다.

[ArrayList 사용방법 - 생성(Create)]
ArrayList<Integer> number = new ArrayList<>();

[ArrayList 사용방법 - 추가(Insert)]

number.add(10);

number.add(20);

number.add(30);

number.add(10);

//ArrayList안에 데이터를 차례대로 저장

또는

number.add(1,10);

//ArrayList안에 인덱스1 위치에 데이터를 끼워서 저장(그 이후 값들은 뒤로 한 칸씩 밀려)



[ArrayList 사용방법 - 삭제(Remove)]

number.remove(2,10);


[ArrayList 사용방법 - 가져오기(Get)]

number.get(2);


[ArrayList 사용방법 - 크기 가져오기(Size)]

number.size();

[ArrayList 사용방법 - 반복(Iteration)]

Iterator it = number.iterator();

// it변수에 iterator 인터페이스 객체를 리턴함.


hasNext() --> 리턴값이 boolean. 해당 엘리먼트 다음 엘리먼트가 존재하는가를 판별

 

Posted by sungho88
,

일단 생활코딩을 보며 정리한 글을 써보려고 한다. 생활코딩 동영상에서 이고잉님이 강의 자료 및 코드는 공용(public)으로 사용해도 된다고 했으므로 안심하고 정리해서 올려보려고 한다.


대부분의 프로그램은 데이터를 처리해서 유용한 정보를 얻기 위해 작성된다.  

그런데 프로그램은 처리하고자 하는 데이터의 구조를 어떻게 구성하느에 따라 성능에 커다란 영향을 미친다.

그렇기 때문에 어떤 상황에 어떤 데이터 구조를 사용하는 것이 바람직한지를 알아야 한다.


먼저, 자료 구조란 무엇인가?

- 자료구조란 프로그램에 의해 쉽게 이용되도록 구성된 데이터들간의 논리적 관계.

- 좋은 프로그램을 작성하기 위해서는 적절한 데이터 구조를 선택하는 것이 중요하다.

- 적절한 데이터 구조란 데이터의 추가,삭제,검색을 효율적으로 수행, 간결하게 표현할 수 있는것을 의미한다.

자료구조는 언어와는 상관없다. 즉, 언어 중립적이다.

- 즉, C JAVA Python등으로도 작성할 수 있다.(이 블로그에서는 자바(Java)로 자료구조를 구현할 것이다)

- 현실을 프로그래밍적으로 표현하는 것이다.  Ex) 배열,트리,그래프 ,리스트, 스택, 큐 등등

- 거대한 데이터를 효율적으로 관리하고 저장하는 것을 의미한다.

- 어렵게 느껴지는 이유 : 실무 경험이 없다. 공감이 안된다. 이해가 안된다.

- 자료구조를 몰라도 프로그램을 만들 수 있다. 하지만, 자료구조를 알면 더욱더 효율적인 

  프로그램을 만들 수 있다.



Posted by sungho88
,