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로 정렬 후 배열
3 12 19 23 35 43 45 51
기본 게이트웨이를 사용할 수 없음 Windows 10 2019
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 정렬에 대해 자세히 설명합니다.
추천 도서