- Merge Sort



정렬할 배열을 재귀적으로 정확히 반으로 나누면서 정렬과 병합을 반복하는 형식으로 정렬하는 방법


pseudo code


mergeSort(A[], p, r) {            // A[] : 정렬할 원 배열, p: 현재 함수에서 가리키는 배열의 처음 위치, r: 배열의 마지막 위치

if(p<r) {                       // p가 r보다 작을 경우. 즉, 더 이상 나눌 수 없을 때 까지 분할을 실행

q = (p+r) / 2;         // 배열의 위치 p와 r을 이용해서 중간 값 q를 구함

mergeSort(A, p, q);        // 반으로 나눈 왼쪽 재귀적 실행

mergeSort(A, q+1, r);     // 반으로 나눈 오른쪽 재귀적 실행

merge(A, p, q, r);           // 왼쪽과 오른쪽을 병합

}

}


동작 예)



- Quick Sort


정렬할 배열을 재귀적으로 나누되, 기준점(pivot)을 설정하여 더 큰 값과 작은 값으로 나눠서 정렬하는 방법


pseudo code


quickSort(A[], p, r) {                    // A[] : 정렬할 원 배열, p: 현재 함수에서 가리키는 배열의 처음 위치, r: 배열의 마지막 위치

if(p<r) {                             // p가 r보다 작을 경우. 즉, 더 이상 나눌 수 없을 때 까지 분할을 실행

q = partition(A, p, r);       // pivot을 기준으로 왼쪽과 오른쪽 부분배열로 분할

quickSort(A, p, q-1);        // pivot의 왼쪽 부분배열 재귀적 실행

quickSort(A. q+1, r);        // pivot의 오른쪽 부분배열 재귀적 실행

}

}


동작 예)


기준점(pivot)은 어떤 값으로 해도 상관 없으나, 현재는 각 분할의 가장 오른쪽 값으로 설정했을 경우


i : 기준점보다 작은 값들의 마지막 배열 위치

j : 현재 확인중인 배열 위치

x : 기준점


1. 배열의 처음부터 j번째의 값과 기준점의 값 x를 비교하여 A[j]가 같거나 크면 pass, 적으면 A[i+1] 값과 A[j] 값을 치환한 다음 i를 1 더해줌

(i 앞의 값들은 모두 기준값보다 작고 뒤의 값들은 모두 크도록 만듬)


2. 배열의 값을 전부 확인한 경우에 A[i+1] 값과 A[x] 값을 치환 

(기준값을 기준값보다 작은 부분배열과 기준값보다 큰 부분배열의 사이에 위치시킴)




Merge Sort 보다 Quick Sort가 빠른 이유


- 병합 과정에서 유리함


Merge Sort는 병합 과정의 왼쪽과 오른쪽 데이터를 합치는 동작에서 정렬을 한 번 더 진행해야 한다.

또한, 해당 정렬을 진행하는 과정에서 임시 배열을 하나 생성해야 함.


하지만 Quick Sort의 경우에는 원 배열을 부분배열로 분할하기는 하지만 병합이라는 과정이 없기 때문에

임시 배열을 만들거나 병합 시에 데이터를 재 정렬할 필요가 없음.

Fragment란, 어플리케이션에서 화면에 직접 보이는 공간인 Activity내에서


분할시키고 다른 화면으로 전환할 수 있는 화면 공간의 단위입니다.


Fragment를 이용하려면, 그 상위에 있는 Activity에서 출력할 layout을 제어해줘야 합니다.


하지만 Fragment내부에서 다른 Fragment로 이동하는 것은 그 Fragment가 자신의 하위레벨이 아니기 때문에


내부에서 직접 제어할 수 없으므로, 상위 레벨인 Activity를 호출하여 제어하는 형태가 되어야 합니다.



MainActivity 아래에 A, B, C 라는 3개의 Fragment를 만들었다고 가정 시,


A, B, C Fragment의 내부에서 서로 다른 Fragment로 전환하는 방법입니다.


먼저 MainActivity의 onCreate() 메소드에서 기본적으로 사용할 Fragment공간과 초기 Fragment의 Instance를 전달합니다.


- MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// 화면 전환 프래그먼트 선언 및 초기 화면 설정
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.ContentLayout, StudyFragment.newInstance()).commit();
}


그 다음, 다른 Fragment로 전환할 때 이용할 메소드를 정의합니다.


- MainActivity.java

public void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.ContentLayout, fragment).commit();      // Fragment로 사용할 MainActivity내의 layout공간을 선택합니다.
}

MainActivity에서든 Fragment 내부에서든 Fragment를 전환할 때 이 메소드를 이용할 예정입니다.



그리고 Fragment 내부에서 다른 Fragment로 전환할 event를 정의합니다.



- StudyFragment.java (study_fragment.xml Layout 이용)

public class StudyFragment extends Fragment {

// 각각의 Fragment마다 Instance를 반환해 줄 메소드를 생성합니다.
public static StudyFragment newInstance() {
return new StudyFragment();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstaceState) {
View view = inflater.inflate(R.layout.study_fragment, null); // Fragment로 불러올 xml파일을 view로 가져옵니다.
Button button1 = (Button)view.findViewById(R.id.study_button); // click시 Fragment를 전환할 event를 발생시킬 버튼을 정의합니다.

button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

// getActivity()로 MainActivity의 replaceFragment를 불러옵니다.
((MainActivity)getActivity()).replaceFragment(NewFragment.newInstance());    // 새로 불러올 Fragment의 Instance를 Main으로 전달
}
});

return view;
}
}

참고로 Activity 하위의 모든 Fragment들이 newInstance() 메소드를 가지고 있어야 화면 전환이 가능합니다.


이걸로 생각보다 간단하게 해결했습니다.

제가 작성하고 있는 앱의 경우 service를 이용하고 있기 때문에


종료되지 않고 폰이 켜져있는 한 계속 실행되고 있습니다.


여기서 Thread를 동작시키고, 앱을 이용하고 있을 때만 Thread를 동작시키고 앱이나 화면이 꺼지면 Thread를 중지시키려 합니다.


하지만 Thread.stop() 기능이 deprecated되었기 때문에 (더 이상의 API에서 지원을 하지 않는 기능이기 때문에)


다른 방법을 찾아보았습니다.



- while( )의 조건을 이용

=> 쓰레드가 동작하는 조건을 결정하는 boolean변수를 하나 만들어 쓰레드의 동작을 제어합니다.


private boolean condition = true;


@Override

public void onDestroy( ) {

super.onDestroy( );

condition = false;

}


MyThread th = new MyThread( );

th.start( );


class MyThread extends Thread( ) {

public void run( ) {

while(condition) {

 . . .

}

}

}


- Thread.interrupt( )를 이용

=> 앞의 방식과 기능은 유사하나 쓰레드의 인터럽트 함수를 사용하는 경우입니다.


MyThread th = new MyThread( );

th.start( );


@Override

public void onDestroy( ) {

super.onDestroy( );

th.interrupt( );

}


class MyThread extends Thread( ) {

public void run( ) {

while(!isInterrupted()) {

 . . .

try {

. . .

} catch (InterruptedException e) {

Thread.currentThread( ).interrupt( );

} catch (Exception e) {

e.printStackTrace( );

}

}

}

}

+ Recent posts