퀵정렬 처럼, 합병정렬은 분할 정복 알고리즘입니다.

주어진 배열을 두개로 나누고, 두개의 배열을 인자로 합병정렬 함수 호출을 합니다. 그리고 정렬된 두 배열을 병합합니다.

merge() 함수는 두개의 배열을 합병하는데 사용됩니다.

merge(arr, left, middle, right)은 arr[left ... middle]과 arr[middle+1 ... right]이 정렬되었다는 가정하에 두개의 서브배열을 합병합니다.

 

mergeSort(arr[], left, right)

if( right > left)

1. 중간 지점을 찾아서 두개로 나눕니다.

   middle = (left+right)/2

2. 왼쪽 부분 배열로 mergeSort를 호출합니다.

  mergeSort(arr, left, middle)

3. 오른쪽 부분 배열로 mergeSort를 호출합니다.

  mergeSort(arr, middle+1, right)

4. 두개의 부분 배열을 합병합니다.

   merge(arr, left, middle, right)

#include<stdlib.h> 
#include<stdio.h> 
#include<cstring>
#include<iostream>
using namespace std;

void printArray(int A[], int size);

//두개의 배열을 합병합니다.
//left~middle, middle+1~right 까지
void merge(int arr[], int left, int middle, int right) 
{ 
	int left_size = middle - left + 1; 
	int right_size = right - middle; 

	/* 임시 배열을 만듭니다. */
	int Left[left_size], Right[right_size]; 

	/* 왼쪽 오른쪽 배열에 값을 복사합니다. */
	memcpy(Left, &arr[left], left_size*sizeof(int));
	memcpy(Right, &arr[middle+1], right_size*sizeof(int));

	/* Merge the temp arrays back into arr[l..r]*/
	int i=0;
	int j=0;
	int k = left; // Initial index of merged subarray 
//	둘다 합병이 끝나지 않은경우 
	while (i < left_size && j < right_size) 
	{ 
		//작은 값을 먼저 넣는다. 
		if (Left[i] <= Right[j]) 
		{ 
			arr[k] = Left[i]; 
			i++;
		} 
		else
		{ 
			arr[k] = Right[j]; 
			j++; 
		} 
		k++; 
	} 

	/* 왼쪽에 값이 남은경우 */
	if(i < left_size) 
	{ 
		memcpy(&arr[k], &Left[i], (left_size - i)*sizeof(Left[0]));
	} 

	/* 오른쪽 배열에 값이 남은경우 */
	if (j < right_size) 
	{ //인덱스 - 인덱스가 아닌 갯수에서 j를 빼는 거라 +1할 필요가 없다 
		memcpy(&arr[k], &Right[j], (right_size - j)*sizeof(Right[0]));
	} 
} 

//정렬하려는 배열의 왼쪽, 오른쪽 인덱스를 넣어준다. 
void mergeSort(int arr[], int left, int right) 
{ 
	if (left < right) //오른쪽 인덱스가 더 큰경우만 시행 
	{ 
		//(left+right)/2랑 같으나 오버플로우를 막기 
		int middle = left+(right-left)/2; 

		//배열을 나누어 재귀함수 호출한다. 
		mergeSort(arr, left, middle); 
		mergeSort(arr, middle+1, right); 
		
		//나눈 배열들을 합병한다. 
		merge(arr, left, middle, right);
		
	} 
} 

void printArray(int A[], int size) 
{ 
	int i; 
	for (i=0; i < size; i++) 
		cout<<A[i]<<" "; 
	cout<<endl;
} 

int main() 
{ 
	int arr[] = {12, 11, 13, 5, 6, 7}; 
	int arr_size = sizeof(arr)/sizeof(int); 

	cout<<"Given array is"<<endl; 
	printArray(arr, arr_size); 

	mergeSort(arr, 0, arr_size - 1); 

	cout<<endl<<"Sorted array is"<<endl; 
	printArray(arr, arr_size); 
	return 0; 
} 

 

시간복잡도

O(n log(n))

 

제자리 정렬이 아니며, 안정정렬이다

 

"주어진 배열을 최대한으로 나눈 뒤 합병하면서 정렬시키는 방식이다."

'알고리즘 > 지식' 카테고리의 다른 글

[정렬 알고리즘] 힙 정렬  (0) 2020.03.04
[정렬 알고리즘] 퀵 정렬  (0) 2020.03.04
[정렬 알고리즘] 삽입 정렬  (0) 2020.03.03
[정렬 알고리즘] 버블 정렬  (0) 2020.03.03
[정렬 알고리즘] 선택 정렬  (0) 2020.03.02

삽입정렬은 우리가 카드를 정렬하듯 작동하는 간단한 정렬 알고리즘입니다.

 

8 7 1 2 9 6,   시작

7 8 1 2 9 6,   7은 8보다 앞에 오므로 그 앞에 삽입

1 7 8 2 9 6,   1은 8보다, 7보다 앞에 오므로 그 앞에 삽입

1 2 7 8 9 6,   2는 8보다, 7보다 앞에 오므로 그 앞에 삽입

1 2 7 8 9 6,   9는 8보다 크므로 그대로

1 2 7 6 8 9,   6은 9보다 8보다 작으므로 그 앞에 삽입

 

#include <bits/stdc++.h> 
using namespace std; 

void insertionSort(int arr[], int n) 
{ 
	for(int i=1; i<n; i++){
		int key = arr[i];
		
		int j=i-1;
		//key가 들어갈 자리를 찾는다 
		while(j>=0 && arr[j] > key){
			arr[j+1] = arr[j];
			j--;			
		}
		//그 자리에 삽입한다. 
		arr[j+1]=key;
	}
} 

void printArray(int arr[], int n) 
{ 
	int i; 
	for (i = 0; i < n; i++) 
		cout << arr[i] << " "; 
	cout << endl; 
} 

int main() 
{ 
	int arr[] = { 12, 11, 13, 5, 6 }; 
	int n = sizeof(arr) / sizeof(int); 

	insertionSort(arr, n); 
	printArray(arr, n); 

	return 0; 
}

 

시간복잡도: O(n^2)

제자리정렬이며 안정정렬이다.

 

"정렬할 원소가 들어갈 자리를 찾아 삽입한다. 1번 인덱스 원소부터 마지막 인덱스 원소까지 실시한다."

'알고리즘 > 지식' 카테고리의 다른 글

[정렬 알고리즘] 퀵 정렬  (0) 2020.03.04
[정렬 알고리즘] 합병 정렬  (0) 2020.03.03
[정렬 알고리즘] 버블 정렬  (0) 2020.03.03
[정렬 알고리즘] 선택 정렬  (0) 2020.03.02
[기본] 정렬 알고리즘  (0) 2020.03.02

버블정렬은 가장 간단한 알고리즘입니다.

인접한 원소를 비교하고 반복적으로 재배열 하면서 작동합니다.

 

예:

(5 1 4 2 8)->(1 5 4 2 8), 처음 두 원소를 비교하고 5와 1을 바꿉니다.

(1 5 4 2 8)->(1 4 5 2 8), 5와 4를 바꿉니다.

(1 4 5 2 8)->(1 4 2 5 8), 5와 2를 바꿉니다.

(1 4 2 5 8)->(1 4 2 5 8), 순서가 올바르기에 5와 8은 바꾸지 않습니다. pass

 

(1 4 2 5 8)->(1 4 2 5 8)pass

(1 4 2 5 8)->(1 2 4 5 8), 4와 2 교환

(1 2 4 5 8)->(1 2 4 5 8)pass

(1 2 4 5 8)->(1 2 4 5 8)pass

 

이제 정렬이 되었지만 알고리즘 내에서는 완료 되었는지 알 수 없기에, 전부 pass될 때 까지 반복합니다.

(1 2 4 5 8)->(1 2 4 5 8)pass

(1 2 4 5 8)->(1 2 4 5 8)pass

(1 2 4 5 8)->(1 2 4 5 8)pass

(1 2 4 5 8)->(1 2 4 5 8)pass

 

#include <bits/stdc++.h> 
using namespace std; 

void swap(int *xp, int *yp) 
{ 
	int temp = *xp; 
	*xp = *yp; 
	*yp = temp; 
} 

void printArray(int arr[], int size) 
{ 
	int i; 
	for (i = 0; i < size; i++) 
		cout << arr[i] << " "; 
	cout << endl; 
} 

void reculsiveBubbleSort(int arr[], int n) 
{ 
    // Base case 
    if (n == 1) 
        return; 
  
    bool all_pass = true;
    for (int i=0; i<n-1; i++) 
        if (arr[i] > arr[i+1]){
        	swap(arr[i], arr[i+1]);
        	all_pass = false;
		}
    printArray(arr, n); 
  	if(all_pass == true){
  		return;
	  }

    reculsiveBubbleSort(arr, n-1); 

void bubbleSort(int arr[], int n) 
{ 
	
	for(int i=0; i<n-1;i++){//원소와 원소 사이마다 한번씩만 반복하면 된다. 그러므로 1회 제거 
		bool all_pass = true;
		for(int j=0; j < n-1-i; j++){//1회 반복 시 제일 뒤의 원소는 정렬이 된 상태가 된다 그러므로 i만큼 빼준다. 
			if (arr[j] > arr[j+1])
			{
				swap(&arr[j], &arr[j+1]);
				all_pass=false;
			}
		}
		printArray(arr, n); 
		if(all_pass == true){
			break;
		}
	}
} 

int main() 
{ 
	int arr[] = {5, 4, 3, 2, 1};
	int n = sizeof(arr)/sizeof(int); 
	bubbleSort(arr, n); 
	cout<<"Sorted array: \n"; 
	printArray(arr, n); 
	return 0; 
} 

 

제자리 정렬이며 안정정렬이다.

최악의 경우 시간복잡도 O(n^2)이다.

 

"인접한 원소를 정렬해나가기 때문에 버블처럼 보인다. 1회 반복때마다 가장 큰 원소는 맨 뒤에 자리하게 된다."

'알고리즘 > 지식' 카테고리의 다른 글

[정렬 알고리즘] 합병 정렬  (0) 2020.03.03
[정렬 알고리즘] 삽입 정렬  (0) 2020.03.03
[정렬 알고리즘] 선택 정렬  (0) 2020.03.02
[기본] 정렬 알고리즘  (0) 2020.03.02
소수 판별  (0) 2019.12.06

선택 정렬 (Selection Sort)

선택정렬은 반복적으로 정렬되지 않은 영역을 찾고, 정렬되지 않은 영역 내부에서 최소(최대)값을 찾아 영역 내의 제일 앞에 배치하여 정렬합니다.

 

이 알고리즘은 주어진 배열을 두개의 영역으로 나누어 사용합니다.

1) 이미 정렬된 영역

2) 아직 정렬되지 않은 영역

 

정렬의 매 순간 마다 정렬되지 않은 영역의 최소(최대) 원소는 선택되어 정렬된 영역으로 이동됩니다.

 

예)

{64, 25, 12, 22, 11}라는 배열이 주어진다면

처음엔 정렬된 영역{}, 정렬되지 않은 영역{64, 25, 12, 22, 11}으로 이루어지고,

오름차순을 가정

 

최소값을 찾아 정렬된 영역으로 이동 시킵니다.

{11}, 그럼 정렬되지 않은 영역에는 {64, 25, 12, 22}이 들어있습니다.

 

두번째엔

{11, 12}, {64, 25, 22}

...

{11, 12, 22}, {64, 25}

{11, 12, 22, 25}, {64}

{11, 12, 22, 25, 64} 순으로 정렬이 됩니다.

 

#include <bits/stdc++.h> 
using namespace std; 

void swap(int *xp, int *yp) 
{ 
	int temp = *xp; 
	*xp = *yp; 
	*yp = temp; 
} 

void selectionSort(int arr[], int n) 
{ 
	for(int i = 0; i<n-1;i++){
		int minidx = i;
		
		for(int j=i+1; j<n;j++){
			if(arr[minidx] > arr[j]){
				minidx = j;
			}
		}
		swap(&arr[i], &arr[minidx]);
	}
} 

void printArray(int arr[], int size) 
{ 	
	for (int i=0; i < size; i++) 
		cout << arr[i] << " "; 
	cout << endl; 
} 

int main() 
{ 
	int arr[] = {64, 25, 12, 22, 11}; 
	int n = sizeof(arr)/sizeof(int); 
	selectionSort(arr, n); 
	cout << "Sorted array: \n"; 
	printArray(arr, n); 
	return 0; 
}

 

시간복잡도: O(n^2) 2개의 루프문 때문.

불안정 정렬.

추가공간을 사용하지 않기에 제자리 정렬이다.

 

"선택 정렬은 정렬해야하는 원소를 선택해서 정렬된 영역으로 이동시켜 정렬한다."

'알고리즘 > 지식' 카테고리의 다른 글

[정렬 알고리즘] 합병 정렬  (0) 2020.03.03
[정렬 알고리즘] 삽입 정렬  (0) 2020.03.03
[정렬 알고리즘] 버블 정렬  (0) 2020.03.03
[기본] 정렬 알고리즘  (0) 2020.03.02
소수 판별  (0) 2019.12.06

정렬 알고리즘

정렬 알고리즘은 주어진 배열이나 리스트의 원소를 비교 연산자에 따라 재배열하는데 사용됩니다.

비교 연산자는 각 각의 데이터 구조의 원소 순서를 정할때 사용됩니다.

 

정렬 용어

제자리 정렬이란? in-place sorting

제자리 정렬 알고리즘은 정렬하기위해 일정한 추가 공간을 사용합니다..(주어진 배열만 사용)

주어진 리스트에 속한 원소의 순서만 바꿔서 리스트를 정렬합니다.

 

삽입 정렬과 선택 정렬은 추가적인 공간을 사용하지 않기에 제자리 정렬 알고리즘입니다.

합병정렬과 카운팅정렬은 제자리 정렬 알고리즘이 아닙니다.

 

내부정렬과 외부 정렬이란? internal sortring, external sorting

정렬해야할 데이터가 메모리에 한번에 올라올 수 없다면 외부 정렬이라고 합니다.

외부 정렬은 많은 양의 데이터를 정렬할 때 사용합니다.

외부 정렬을 위해 하드디스크, ssd를 사용합니다.

모든 데이터를 메모리에 두는 경우 내부정렬이라고 합니다.

 

안정 정렬이란? stable sorting

 

정렬 알고리즘의 안정성

안정성은 키-값 구조에서 같은 키를 갖는게 가능한 경우 중요합니다.

사람 이름처럼 동명이인이 나오고 그 인물의 데이터는 다른경우.

그리고 이 것을 키로 정렬하고 싶은 경우 알고리즘의 안정성에 신경써야합니다.

 

안정성이란?

같은 키 값을 갖는 원소들이 정렬되기 전의 상대적 위치와 정렬된 후의 상대적 위치가 같은 것을 말합니다.

 

두개의 원소를 갖는 다음과 같은 리스트를 정렬하는 경우

처음 원소로 정렬하기 위해

(1, A), (5, A), (2, A), (3, B), (2, B)를 정렬하는 경우 먼저 앞의 원소로 정렬을 하고

두번째 원소로 정렬하기 위해

(1, A), (2, A), (2, B), (3, B), (5, A) 다시 두번째 원소로 정렬을 합니다.

(1, A), (2, A), (5, A), (3, B), (2, B) 이때 불안정 정렬 알고리즘인 경우 두번째 원소만 신경 써서 배열하여 앞에서 했던 정렬이 무너질 수 있습니다. 이 때 안정 정렬을 사용하면 원하는 값을 얻을 수 있습니다.

 

어떤 정렬이 안정적인가?

버블정렬, 삽입 정렬, 합병정렬, 카운팅 정렬은 안정적입니다.

퀵정렬, 힙정렬은 불안정 정렬입니다.

 

알고리즘 최고 평균 최악 안정/불안정 제자리
선택정렬 Ω(n^2) θ(n^2) O(n^2) 불안정 O
버블정렬 Ω(n) θ(n^2) O(n^2) 안정 O
삽입정렬 Ω(n) θ(n^2) O(n^2) 안정 O
힙정렬 Ω(n log(n)) θ(n log(n)) O(n log(n)) 불안정 O
퀵정렬 Ω(n log(n)) θ(n log(n)) O(n^2) 불안정 O
합병정렬 Ω(n log(n)) θ(n log(n)) O(n log(n)) 안정 X
버킷정렬 Ω(n + k) θ(n + k) O(n^2) 안정 X
래딕스정렬 Ω(nk) θ(nk) O(nk) 안정 X

 

'알고리즘 > 지식' 카테고리의 다른 글

[정렬 알고리즘] 합병 정렬  (0) 2020.03.03
[정렬 알고리즘] 삽입 정렬  (0) 2020.03.03
[정렬 알고리즘] 버블 정렬  (0) 2020.03.03
[정렬 알고리즘] 선택 정렬  (0) 2020.03.02
소수 판별  (0) 2019.12.06

https://refactoring.guru/refactoring/what-is-refactoring

 

Clean code

Tired of reading? No wonder, it takes 7 hours to read all of the text we have here. Try our interactive course on refactoring. It offers a less tedious approach to learning new stuff. Let's see...

refactoring.guru

 

'참고 링크 > 개발' 카테고리의 다른 글

플러터 개발  (0) 2020.03.18
[안드로이드] OpenGL 참고용  (0) 2020.03.13
이펙티브 자바  (0) 2020.03.09
코딩 테스트를 위한 Dev C++설치  (0) 2020.01.02
[유니티]너랑나랑개발자 이야기  (0) 2019.12.28

안드로이드는 여러가지 방법으로 앱 데이터를 저장한다.

저장 방법의 선택은 데이터의 크기와 어떤 종류의 데이터를 저장하는지, 개발중인 앱에서만 사용하는 데이터인지 다른 앱이나 사용자가 접근할 수 있는지에 따라 달라진다.

 

내부 파일 저장소: 기기 파일 시스템에 앱에서만 사용할 수 있도록 저장한다.

외부 파일 저장소: 외부 파일 시스템에 파일을 저장한다. 사용자가 접근할 수 있어야하는 경우 사용한다.

공유 기본 설정: 데이터를 키-값으로 저장한다.

데이터베이스: 데이터베이스에 구조화하여 데이터를 저장한다.

 

외부 파일 저장소를 제외하고 다른 방법은 데이터를 다른 앱에서 접근할 수 없다. 공유하고자하는 경우 FileProvider API를 사용해야한다.

 

앱의 데이터를 다른 앱이 사용할 수 있게 하는 경우, ContentProvider를 사용하면 된다. 콘텐츠 프로바이더는 데이터를 저장 방식과 상관없이 다른 앱에서 읽기/쓰기를 제어할 수 있도록 권한을 준다.

 

내부 저장소

개별 어플리케이션에서 사용하는 전용 파일이다.

내부 앱 데이터를 저장하는데 사용된다.

사용자가 앱을 삭제하면 저장된 파일이 삭제된다.

그렇기에 데이터가 앱을 지워도 남게하려면 MediaStore API를 사용해서 적절한 저장소에 저장해야한다.

 

외부 저장소

모든 안드로이드 기기는 파일을 저장하는데 사용할 수 있는 외부 저장소를 가지고 있다.

파일에 접근하기 전에 외부 저장소 디렉토리를 사용할 수 있는지 확인해야한다.

 

다른 앱에서도 접근해야하고 앱 제거 뒤에도 사용해야하는 데이터라면 외부 저장소를 이용하는 것이 좋다.

 

공유 기본 설정 (SharedPreferences)

데이터를 많이 저장하지 않고, 데이터 구조가 필요하지 않는 경우 사용한다.

boolean, float, int, long, string 유형의 데이터를 키-값으로 쓰고 읽을 수 있다.

이것은 XML파일에 작성되고, 앱이 종료되더라도 유지된다.

파일 이름을 직접 지정하거나 액티비티별로 파일을 사용해 데이터를 저장할 수 있다.

 

 

데이터베이스

안드로이드는 SQLite를 완전히 지원한다. 생성한 모든 데이터 베이스는 앱에의해서만 사용이 가능하다.

SQLite API를 직접사용하는 대신 Room 라이브러리로 데이터베이스를 생성하고 관리하는 것이 좋다.

 

Room라이브러리는 SQLite를 완벽하게 활용하는 객체 매핑 추상화 계층을 제공한다.

 

 

+ Recent posts