quick sort c with examples
일러스트레이션이있는 C ++의 Quicksort.
Quicksort는 '피벗'이라는 특정 요소를 선택하고이 피벗 s0을 기준으로 정렬 할 배열 또는 목록을 두 부분으로 분할하는 널리 사용되는 정렬 알고리즘입니다. 피벗보다 작은 요소는 목록의 왼쪽과 요소입니다. 피벗보다 큼은 목록 오른쪽에 있습니다.
따라서 목록은 두 개의 하위 목록으로 분할됩니다. 동일한 크기에 하위 목록이 필요하지 않을 수 있습니다. 그런 다음 Quicksort는 자신을 재귀 적으로 호출하여이 두 하위 목록을 정렬합니다.
=> 여기에서 완벽한 C ++ 교육 가이드를 확인하십시오.
학습 내용 :
- 소개
- 일반 알고리즘
- Quicksort의 의사 코드
- 삽화
- C ++ 예제
- 자바 예
- Quicksort 알고리즘의 복잡성 분석
- 3 방향 Quicksort
- 무작위 빠른 정렬
- Quicksort vs. Merge Sort
- 결론
- 추천 도서
소개
Quicksort는 더 큰 배열이나 목록의 경우에도 효율적으로 작동합니다.
이 튜토리얼에서는 Quicksort 알고리즘의 몇 가지 프로그래밍 예제와 함께 Quicksort의 작동에 대해 자세히 알아 봅니다.
피벗 값으로 첫 번째, 마지막 또는 중간 값 또는 임의의 값을 선택할 수 있습니다. 일반적인 아이디어는 배열의 다른 요소를 왼쪽이나 오른쪽으로 이동하여 궁극적으로 피벗 값이 배열의 적절한 위치에 배치된다는 것입니다.
일반 알고리즘
Quicksort의 일반적인 알고리즘은 다음과 같습니다.
quicksort(A, low, high) begin Declare array A(N) to be sorted low = 1st element; high = last element; pivot if(low 이제 Quicksort 기술에 대한 의사 코드를 살펴 보겠습니다.
Quicksort의 의사 코드
//pseudocode for quick sort main algorithm procedure quickSort(arr(), low, high) arr = list to be sorted low – first element of array high – last element of array begin if (low 분할 알고리즘의 작동은 예제를 사용하여 아래에 설명되어 있습니다.
이 그림에서는 마지막 요소를 피벗으로 사용합니다. 배열에 단일 요소가있을 때까지 배열이 피벗 요소를 중심으로 연속적으로 분할되는 것을 볼 수 있습니다.
이제 우리는 개념을 더 잘 이해하기 위해 아래에 Quicksort의 그림을 제시합니다.
삽화
퀵 정렬 알고리즘의 예를 살펴 보겠습니다. 마지막 요소가 피벗 인 다음 배열을 고려하십시오. 또한 첫 번째 요소는 낮음으로 표시되고 마지막 요소는 높음으로 표시됩니다.
4 년 경력의 qtp 인터뷰 질문 및 답변
그림에서 우리는 배열의 양쪽 끝에서 포인터를 위아래로 이동하는 것을 볼 수 있습니다. 낮은 지점이 피벗보다 큰 요소를 가리키고 높은 지점이 피벗보다 작은 요소를 가리킬 때마다 이러한 요소의 위치를 교환하고 각각의 방향으로 낮은 포인터와 높은 포인터를 전진시킵니다.
이것은 낮은 포인터와 높은 포인터가 서로 교차 할 때까지 수행됩니다. 서로 교차하면 피벗 요소가 적절한 위치에 배치되고 배열이 두 개로 분할됩니다. 그런 다음이 두 하위 배열은 모두 퀵 정렬을 재귀 적으로 사용하여 독립적으로 정렬됩니다.
C ++ 예제
다음은 C ++에서 Quicksort 알고리즘을 구현 한 것입니다.
#include using namespace std; // Swap two elements - Utility function void swap(int* a, int* b) { int t = *a; *a = *b; *b = t; } // partition the array using last element as pivot int partition (int arr(), int low, int high) { int pivot = arr(high); // pivot int i = (low - 1); for (int j = low; j <= high- 1; j++) { //if current element is smaller than pivot, increment the low element //swap elements at i and j if (arr(j) <= pivot) { i++; // increment index of smaller element swap(&arr(i), &arr(j)); } } swap(&arr(i + 1), &arr(high)); return (i + 1); } //quicksort algorithm void quickSort(int arr(), int low, int high) { if (low < high) { //partition the array int pivot = partition(arr, low, high); //sort the sub arrays independently quickSort(arr, low, pivot - 1); quickSort(arr, pivot + 1, high); } } void displayArray(int arr(), int size) { int i; for (i=0; i < size; i++) cout< 산출:
입력 배열
12 23 3 43 51 35 19 45
빠른 정렬로 정렬 된 배열
3 12 19 23 35 43 45 51
여기에는 배열을 분할하고 파티션을 정렬하기 위해 quicksort를 재귀 적으로 호출하는 데 사용되는 루틴, 기본 quicksort 함수 및 배열 내용을 표시하고 그에 따라 두 요소를 교체하는 유틸리티 함수가 있습니다.
먼저 입력 배열로 quicksort 함수를 호출합니다. quicksort 함수 내에서 파티션 함수를 호출합니다. 분할 함수에서 마지막 요소를 배열의 피벗 요소로 사용합니다. 피벗이 결정되면 배열이 두 부분으로 분할 된 다음 quicksort 함수가 호출되어 두 하위 배열을 독립적으로 정렬합니다.
quicksort 함수가 반환되면 피벗 요소가 올바른 위치에 있고 피벗보다 작은 요소가 피벗 왼쪽에 있고 피벗보다 큰 요소가 피벗 오른쪽에 있도록 배열이 정렬됩니다.
다음으로, 우리는 자바에서 퀵 정렬 알고리즘을 구현할 것입니다.
자바 예
// Quicksort implementation in Java class QuickSort { //partition the array with last element as pivot int partition(int arr(), int low, int high) { int pivot = arr(high); int i = (low-1); // index of smaller element for (int j=low; j 산출:
입력 배열
12 23 3 43 51 35 19 45
Quicksort로 정렬 후 배열
기본 게이트웨이를 사용할 수 없음 Windows 10 2019
3 12 19 23 35 43 45 51
Java 구현에서도 C ++ 구현에서 사용한 것과 동일한 로직을 사용했습니다. 피벗 요소를 적절한 위치에 배치하기 위해 배열에서 피벗 및 퀵 정렬이 수행 될 때 배열의 마지막 요소를 사용했습니다.
Quicksort 알고리즘의 복잡성 분석
quicksort에서 배열을 정렬하는 데 걸리는 시간은 입력 배열과 파티션 전략 또는 방법에 따라 다릅니다.
k가 피벗보다 적은 요소 수이고 n이 총 요소 수이면 퀵 정렬에 걸리는 일반적인 시간은 다음과 같이 표현할 수 있습니다.
T (n) = T (k) + T (n-k-1) + O (n)
여기서 T (k)와 T (n-k-1)은 재귀 호출에 걸리는 시간이고 O (n)은 파티셔닝 호출에 걸리는 시간입니다.
Quicksort에 대한이 시간 복잡성을 자세히 분석해 보겠습니다.
# 1) 최악의 경우 : 퀵 정렬 기법의 최악의 경우는 배열에서 가장 낮은 요소 또는 가장 높은 요소를 피벗으로 선택할 때 주로 발생합니다. (위의 그림에서는 가장 높은 요소를 피벗으로 선택했습니다). 이러한 상황에서 정렬 할 배열이 이미 오름차순 또는 내림차순으로 정렬 된 경우 최악의 경우가 발생합니다.
따라서 총 소요 시간에 대한 위의 표현은 다음과 같이 변경됩니다.
T (n) = T (0) + T (n-1) + O (n) 그 결심 의 위에두)
# 2) 최상의 사례 : 퀵 정렬의 가장 좋은 경우는 선택한 피벗 요소가 배열의 중간 일 때 항상 발생합니다.
따라서 최상의 경우의 반복은 다음과 같습니다.
소프트웨어 테스트의 버그 유형
T (n) = 2T (n / 2) + O (n) = O (nlogn)
# 3) 평균 사례 : 퀵 정렬의 평균 사례를 분석하려면 모든 배열 순열을 고려한 다음 각 순열에 걸리는 시간을 계산해야합니다. 간단히 말해서 퀵 정렬의 평균 시간도 O (nlogn)가됩니다.
다음은 Quicksort 기술의 다양한 복잡성입니다.
최악의 시간 복잡성 O (n 2) 안정 동일한 값을 가진 두 요소가 동일한 순서로 배치되지 않으므로 불안정합니다. 안정적 – 동일한 값을 가진 두 요소가 정렬 된 출력에서 동일한 순서로 나타납니다. 최상의 경우 시간 복잡성 O (n * log n) 평균 시간 복잡성 O (n * log n) 공간 복잡성 O (n * log n)
피벗 요소 (중간, 첫 번째 또는 마지막)의 선택을 변경하는 것만으로 여러 가지 방법으로 퀵 정렬을 구현할 수 있지만 퀵 정렬의 경우 최악의 경우는 거의 발생하지 않습니다.
3 방향 Quicksort
원래 퀵 정렬 기법에서는 일반적으로 피벗 요소를 선택한 다음이 피벗 주위의 하위 배열로 배열을 분할하여 하나의 하위 배열이 피벗보다 작은 요소로 구성되고 다른 하위 배열은 피벗보다 큰 요소로 구성됩니다.
그러나 피벗 요소를 선택하고 배열에 피벗과 동일한 요소가 두 개 이상 있으면 어떻게 될까요?
예를 들어 다음 어레이 {5,76,23,65,4,4,5,4,1,1,2,2,2,2}를 고려하십시오. 이 배열에 대해 간단한 퀵 정렬을 수행하고 피벗 요소로 4를 선택하면 요소 4의 발생 하나만 수정하고 나머지는 다른 요소와 함께 분할됩니다.
대신 3 방향 퀵 정렬을 사용하면 배열 (l… r)을 다음과 같이 세 개의 하위 배열로 나눕니다.
- Array (l… i) – 여기서 i는 피벗이고이 배열은 피벗보다 작은 요소를 포함합니다.
- Array (i + 1… j-1) – 피벗과 같은 요소를 포함합니다.
- Array (j… r) – 피벗보다 큰 요소를 포함합니다.
따라서 배열에 중복 요소가 두 개 이상있을 때 3 방향 퀵 정렬을 사용할 수 있습니다.
무작위 빠른 정렬
퀵 정렬 기법은 난수를 사용하여 피벗 요소를 선택할 때 무작위 퀵 정렬 기법이라고합니다. Randomized quicksort에서는 'central pivot'라고하며 각 측면이 최소 ¼ 요소를 갖도록 배열을 분할합니다.
무작위 퀵 정렬의 의사 코드는 다음과 같습니다.
// Sorts an array arr(low..high) using randomized quick sort randomQuickSort(array(), low, high) array – array to be sorted low – lowest element in array high – highest element in array begin 1. If low >= high, then EXIT. //select central pivot 2. While pivot 'pi' is not a Central Pivot. (i) Choose uniformly at random a number from (low..high). Let pi be the randomly picked number. (ii) Count elements in array(low..high) that are smaller than array(pi). Let this count be a_low. (iii) Count elements in array(low..high) that are greater than array(pi). Let this count be a_high. (iv) Let n = (high-low+1). If a_low >= n/4 and a_high >= n/4, then pi is a central pivot. //partition the array 3. Partition array(low..high) around the pivot pi. 4. // sort first half randomQuickSort(array, low, a_low-1) 5. // sort second half randomQuickSort(array, high-a_high+1, high) end procedure
위의 'randomQuickSort'코드에서 2 단계에서 중앙 피벗을 선택합니다. 2 단계에서 선택한 요소가 중심 피벗이 될 확률은 ½입니다. 따라서 2 단계의 루프는 2 번 실행될 것으로 예상됩니다. 따라서 무작위 퀵 정렬의 2 단계에 대한 시간 복잡도는 O (n)입니다.
루프를 사용하여 중앙 피벗을 선택하는 것은 무작위 퀵 정렬을 구현하는 이상적인 방법이 아닙니다. 대신 요소를 무작위로 선택하고 중앙 피벗이라고 부르거나 배열 요소를 다시 섞을 수 있습니다. 무작위 퀵 정렬 알고리즘에 대해 예상되는 최악의 경우 시간 복잡도는 O (nlogn)입니다.
Quicksort vs. Merge Sort
이 섹션에서는 빠른 정렬과 병합 정렬의 주요 차이점에 대해 설명합니다.
비교 매개 변수 빠른 정렬 병합 정렬 분할 배열은 피벗 요소를 중심으로 분할되며 항상 두 개의 절반으로 나뉘지는 않습니다. 어떤 비율로도 분할 할 수 있습니다. 배열은 두 개의 절반 (n / 2)으로 분할됩니다. 최악의 경우 복잡성 O (n 2) – 최악의 경우 많은 비교가 필요합니다. O (nlogn) – 평균 케이스와 동일 데이터 세트 사용 더 큰 데이터 세트에서는 잘 작동 할 수 없습니다. 크기에 관계없이 모든 데이터 세트에서 잘 작동합니다. 추가 공간 현재 위치 – 추가 공간이 필요하지 않습니다. 제자리에 있지 않음 – 보조 어레이를 저장할 추가 공간이 필요합니다. 분류 방법 내부 – 데이터가 주 메모리에 정렬됩니다. 외부 – 데이터 배열을 저장하기 위해 외부 메모리를 사용합니다. 능률 작은 크기의 목록에 대해 더 빠르고 효율적입니다. 더 큰 목록에 빠르고 효율적입니다. 배열 / 연결된 목록 어레이에 더 선호됩니다. 연결 목록에 적합합니다.
결론
이름 자체에서 알 수 있듯이 quicksort는 다른 정렬 알고리즘보다 목록을 빠르게 정렬하는 알고리즘입니다. 병합 정렬과 마찬가지로 빠른 정렬도 분할 및 정복 전략을 채택합니다.
이미 살펴본 것처럼 빠른 정렬을 사용하여 피벗 요소를 사용하여 목록을 하위 배열로 나눕니다. 그런 다음 이러한 하위 배열이 독립적으로 정렬됩니다. 알고리즘이 끝나면 전체 배열이 완전히 정렬됩니다.
Quicksort는 더 빠르고 효율적으로 데이터 구조를 정렬합니다. Quicksort는 널리 사용되는 정렬 알고리즘이며 병합 정렬 알고리즘보다 선호되는 경우도 있습니다.
다음 자습서에서는 Shell 정렬에 대해 자세히 설명합니다.
추천 도서