[Sort] MergeSort
개요
합병 정렬(MergeSort)이란?
=> 분할 정복 알고리즘중 하나로 일반적으로 사용되는 정렬방식.
구현했을때 안정 정렬에 속한다.
—
분할 정복 방법
- 문제를 작은 2개의 문제로 분리하고 각각을 해결한 다음, 결과를 모아서 원래의 문제를 해결하는 전략
-
대개 순환 호출을 이용하여 구현한다.
정렬하는 과정
- 분할(Devide) : 입력 배열을 같은 크기의 2개으 ㅣ부분 배열로 분할 한다.
- 정복(Conquer) : 부분배열을 정렬한다. 부분 배열의 크기가 충분히 작지 않으면 순환 호출을 이용하여 다시 분할 정복 방법을 적용한다.
- 결합(Combine) : 정렬된 부분 배열들을 하나의 배열에 합병한다.
(이미지 출처 :https://medium.com/@paulsoham/merge-sort-63d75df76388)
- 장점
- 항상 동일한 시간이 소요되기 때문에 어떤 경우에도 좋은 성능을 보장받을 수 있다.
- 단점
- 정렬할 데이터의 양이 많은 경우에는 그만큼 이동횟수가 많아지므로 시간적 낭비도 많아지게 된다.
- 정렬할 데이터의 양이 많은 경우에는 그만큼 이동횟수가 많아지므로 시간적 낭비도 많아지게 된다.
유니티에서 예제
소스코드
아래는 유니티를 기준으로 작성하였으나 기본적으로 C#이기때문에 숫자를 입력하고 출력하는 부분 외에는 바로 참고하셔도 무방합니다.
[초기화 및 출력함수]
#region private
[SerializeField] InputField m_input_txt;
[SerializeField] Text m_answer_txt;
string[] m_split_text;
string m_input_text, m_output_text;
List<int> split_number_list;
#endregion
public override void Awake()
{
m_input_text = null;
m_output_text = null;
split_number_list = new List<int>();
}
/// <summary>
/// splite number and add in to list
/// </summary>
private void InitList()
{
m_input_text = m_input_txt.GetComponent<InputField>().text;
// split text of inputfield
m_split_text = m_input_text.Split(',');
// add splited text into int list(split_number_list)
for (int count = 0; count < m_split_text.Length; count++)
{
split_number_list.Add(int.Parse(m_split_text[count]));
}
}
/// <summary>
/// Show number list
/// </summary>
private void ShowText(List<int> _list_data)
{
for (int count = 0; count < _list_data.Count; count++)
{
m_output_text += _list_data[count].ToString() + " ";
}
// Display result of Sort
m_answer_txt.text = m_output_text;
}
[초기와 및 마지소트 실행]
/// <summary>
/// activate when press enter
/// </summary>
private void OnclickEnter()
{
InitList();
ShowText(Devide(split_number_list));
}
[정렬]
private List<int> Merge(List<int> _left_list, List<int> _right_list)
{
//_left_list.Sort((a, b) => { return a > b ? 1 :-1; });
List<int> mergedList = new List<int>();
int leftIndex = 0;
int rightIndex = 0;
while((leftIndex < _left_list.Count) && (rightIndex < _right_list.Count))
{
if (_left_list[leftIndex] <= _right_list[rightIndex]) {
mergedList.Add(_left_list[leftIndex]);
leftIndex++;
} else {
mergedList.Add(_right_list[rightIndex]);
rightIndex++;
}
}
if(_left_list.Count > leftIndex) {
for (int count = leftIndex; count < _left_list.Count; count++) {
mergedList.Add(_left_list[count]);
}
} else if(_right_list.Count > rightIndex) {
for (int count = rightIndex; count < _right_list.Count; count++) {
mergedList.Add(_right_list[count]);
}
}
return mergedList;
}
private List<int> Devide(List<int> _list)
{
if (_list.Count <= 1) return _list;
int _middle_point = _list.Count / 2;
List<int> _left_list = _list.ToList();
List<int> _right_list = _list.ToList();
_left_list.RemoveRange(_middle_point, (_list.Count - _middle_point));
_left_list = Devide(_left_list);
_right_list.RemoveRange(0, _middle_point);
_right_list = Devide(_right_list);
return Merge(_left_list, _right_list);
}
[전체 코드]
public class MergeSortManager : BaseTemplateClass
{
#region private
[SerializeField] InputField m_input_txt;
[SerializeField] Text m_answer_txt;
string[] m_split_text;
string m_input_text, m_output_text;
List<int> split_number_list;
#endregion
public override void Awake()
{
m_input_text = null;
m_output_text = null;
split_number_list = new List<int>();
}
/// <summary>
/// splite number and add in to list
/// </summary>
private void InitList()
{
m_input_text = m_input_txt.GetComponent<InputField>().text;
// split text of inputfield
m_split_text = m_input_text.Split(',');
// add splited text into int list(split_number_list)
for (int count = 0; count < m_split_text.Length; count++)
{
split_number_list.Add(int.Parse(m_split_text[count]));
}
}
/// <summary>
/// Show number list
/// </summary>
private void ShowText(List<int> _list_data)
{
for (int count = 0; count < _list_data.Count; count++)
{
m_output_text += _list_data[count].ToString() + " ";
}
// Display result of Sort
m_answer_txt.text = m_output_text;
}
private List<int> Merge(List<int> _left_list, List<int> _right_list)
{
//_left_list.Sort((a, b) => { return a > b ? 1 :-1; });
List<int> mergedList = new List<int>();
int leftIndex = 0;
int rightIndex = 0;
while((leftIndex < _left_list.Count) && (rightIndex < _right_list.Count))
{
if (_left_list[leftIndex] <= _right_list[rightIndex]) {
mergedList.Add(_left_list[leftIndex]);
leftIndex++;
} else {
mergedList.Add(_right_list[rightIndex]);
rightIndex++;
}
}
if(_left_list.Count > leftIndex) {
for (int count = leftIndex; count < _left_list.Count; count++) {
mergedList.Add(_left_list[count]);
}
} else if(_right_list.Count > rightIndex) {
for (int count = rightIndex; count < _right_list.Count; count++) {
mergedList.Add(_right_list[count]);
}
}
return mergedList;
}
private List<int> Devide(List<int> _list)
{
if (_list.Count <= 1) return _list;
int _middle_point = _list.Count / 2;
List<int> _left_list = _list.ToList();
List<int> _right_list = _list.ToList();
_left_list.RemoveRange(_middle_point, (_list.Count - _middle_point));
_left_list = Devide(_left_list);
_right_list.RemoveRange(0, _middle_point);
_right_list = Devide(_right_list);
return Merge(_left_list, _right_list);
}
/// <summary>
/// activate when press enter
/// </summary>
private void OnclickEnter()
{
InitList();
ShowText(Devide(split_number_list));
}
}