프로그래밍 기초/알고리즘

정렬 알고리즘 개요

niamdank 2021. 6. 23. 08:26

  정렬 알고리즘 

정렬이란?

n개의 원소를 순서대로 배열하는 것으로 실생활에 다양하게 사용되는 알고리즘이다. 가령 학생을 키 순서대로 줄을 세운다거나 세무서에서 고지서를 날리기 위해 주민등록 번호순으로 정렬하는 것 등을 예로 들 수 있다.

 

정렬의 종류

정렬에는 여러 종류가 있으며 대표적으로 다음과 같은 정렬이 존재한다.

  • 선택 정렬 가장 큰 원소 또는 가장 작은 원소를 찾아 첫 위치 또는 마지막 위치와 자리를 바꾸는 정렬, 평균 Ο(n²)
  • 버블 정렬 두 개의 원소를 비교하여 정렬 방향에 따라 서로 자리를 바꾸는 연산을 반복하는 정렬, 평균 Ο(n²)
  • 병합 정렬 원소를 두 구역으로 나누는 것을 반복한 뒤 병합하며 자리를 바꾸는 연산을 반복하는 정렬, 평균 Ο(nlogn)
  • 퀵 정렬 특정 값을 기준으로 영역을 나누어 자리를 바꾸는 연산을 반복하는 정렬, 평균 Ο(nlogn)
  • 힙 정렬 최대 힙 또는 최소 힙을 생성하여 원소를 삽입하고 인출하는 정렬, 평균 Ο(nlogn)

 

※ 퀵 정렬이 평균적인 성능이 좋기 때문에 많이 사용된다.

 

정렬 알고리즘 테스트 코드

알고리즘의 효율성 테스트를 위해 1,000,000 개의 난수를 생성하여 텍스트 파일로 저장하는 함수와 해당 파일을 불러오는 함수를 구현한다.

 

Common.h

#pragma once
#include <iostream>
#include <fstream>
#include <ctime>

//#define MAKE_RANDOM_NUMBERS

#ifdef MAKE_RANDOM_NUMBERS
#include <random>
#include <limits>
#endif

namespace Common
{
#ifdef MAKE_RANDOM_NUMBERS
	int* GenerateRandomNumber(int n = 100'000);
	void MakeRandomNumbersFile(int n = 100'000);
#endif

#pragma region 파일 입출력
	int LoadRandomNumbersInFile(int** arr);
#pragma endregion
	
#pragma region 시간 측정
	static std::clock_t startTime;
	static std::clock_t endTime;

	void StartClock();
	void StopClock();
	void PrintElapsedTime();
#pragma endregion
	
	void PrintArray(int arr[], int n);
	void Swap(int arr[], int a, int b);
}

 

Common.cpp

#include "Common.h"

namespace Common
{
#ifdef MAKE_RANDOM_NUMBERS
	/// <summary>
	/// 난수 배열을 생성하여 반환한다.
	/// </summary>
	/// <param name="n">생성할 난수의 개수</param>
	/// <returns>생성된 난수 배열</returns>
	int* GenerateRandomNumber(int n)
	{
		std::default_random_engine randomEngine;
		std::uniform_int_distribution<int> distribution(0, INT_MAX);

		int* arr = new int[n];
		for (int i = 0; i < n; ++i)
		{
			arr[i] = distribution(randomEngine);
		}

		return arr;
	}

	/// <summary>
	/// 난수를 생성하여 파일에 저장한다.
	/// </summary>
	/// <param name="n">생성할 난수의 개수</param>
	void MakeRandomNumbersFile(int n)
	{
		int* arr = GenerateRandomNumber(n);

		std::ofstream ofs("./Randoms.txt");

		ofs << n << ' ';
		for (int i = 0; i < n; ++i)
		{
			ofs << arr[i] << ' ';
		}

		ofs.close();
	}
#endif


#pragma region 파일 입출력
	/// <summary>
	/// 파일에 있는 난수를 불러와 입력된 포인터에 저장한다.
	/// </summary>
	/// <param name="arr">불러온 난수 배열을 반환할 포인터</param>
	/// <returns>불러온 난수의 개수</returns>
	int LoadRandomNumbersInFile(int** arr)
	{
		std::ifstream ifs("./Randoms.txt");

		int n;
		ifs >> n;

		*arr = new int[n];
		for (int i = 0; i < n; ++i)
		{
			ifs >> (*arr)[i];
		}

		ifs.close();

		return n;
	}
#pragma endregion

#pragma region 시간 측정
	/// <summary>
	/// 시간 측정을 시작한다.
	/// </summary>
	void StartClock()
	{
		startTime = std::clock();
	}

	/// <summary>
	/// 시간 측정을 종료한다.
	/// </summary>
	void StopClock()
	{
		endTime = std::clock();
	}

	/// <summary>
	/// 측정한 시간을 계산하여 출력한다.
	/// </summary>
	void PrintElapsedTime()
	{
		std::clock_t elapsed = endTime - startTime;

		double timeSecond = static_cast<double>(elapsed / CLOCKS_PER_SEC);

		std::cout << "total time is " << timeSecond << "s ( " << elapsed << "ms )\n";
	}
#pragma endregion
	/// <summary>
	/// 입력된 배열을 출력한다.
	/// </summary>
	/// <param name="arr">출력할 배열</param>
	/// <param name="n">배열의 길이</param>
	void PrintArray(int arr[], int n)
	{
		for (int i = 0; i < n; i++)
		{
			std::cout << arr[i] << ' ';
		}
		std::cout << '\n';
	}

	/// <summary>
	/// 주어진 인덱스의 값을 서로 바꾼다.
	/// </summary>
	/// <param name="arr">값이 들어있는 배열</param>
	/// <param name="a">첫 번째 인덱스</param>
	/// <param name="b">두 번째 인덱스</param>
	void Swap(int arr[], int a, int b)
	{
		int temp{ arr[a] };
		arr[a] = arr[b];
		arr[b] = temp;
	}
}

 

NadanKim/Algorithm: 알고리즘 학습 및 예제 코드 작성을 위한 저장소 (github.com)

 

GitHub - NadanKim/Algorithm: 알고리즘 학습 및 예제 코드 작성을 위한 저장소

알고리즘 학습 및 예제 코드 작성을 위한 저장소. Contribute to NadanKim/Algorithm development by creating an account on GitHub.

github.com