머리말
퀵 정렬에서 가장 중요한 것은 벤치마크 값 키를 비교 기준으로 선택하는 것입니다
. 상대적이 됩니다. 예전에는 더 질서정연했습니다. 이 아이디어에 따르면 여러 번 재귀하고 빠른 정렬을 사용하기만 하면 됩니다.
다음은 벤치마크 값 키를 찾는 방법이며 중간 요소를 찾는 데 사용합니다.
int GetMidNumi(int* a, int left, int right) {
int mid = (right + left) / 2;//
//中间的元素的下标
if (a[left] < a[mid]) {
if (a[mid] < a[right]) {
return mid;
}
else if (a[left] > a[right]) {
return left;
}
else {
return right;
}
}
else {
if (a[mid] > a[right]) {
return mid;
}
else if (a[left] < a[right]) {
return left;
}
else {
return right;
}
}
//最终返回left,right,mid为下标的元素中
//中间值的下标
}
1. 재귀적 방법(일반적으로 사용됨)
1. 호어 방법:
한 가지만 기억하세요: 키를 왼쪽으로 만들고 오른쪽으로 먼저 이동합니다.
삽입 정렬은 최적화에 사용할 수 있지만 물론 사용할 수 없으며 모두 빠른 정렬
삽입 정렬을
사용합니다. 이 링크에는 내 콘텐츠가 포함되어 있습니다. 삽입 정렬
void QuickSort1(int* a, int left, int right) {
if (left >= right) {
return;
//退出此次函数调用
}
if (right - left + 1 > 10) {
//记住一点:左边做key,右边先走
int begin = left;
int end=right;
//保存左右边界值
int midi = GetMidNumi(a, left, right);
//获取中间元素下标
if (midi != left) {
Swap(&a[midi], &a[left]);
}
//把中间位置的数据与最左边进行交换
int keyi = left;
//存储基准值的下标
while (left < right) {
while (left < right && a[right]>=a[keyi]) {
right--;
//右边找小
}
while (left < right && a[left] <= a[keyi]) {
left++;
//左边找大
}
Swap(&a[left], &a[right]);
}
Swap(&a[left], &a[keyi]);
//此时left==right
//left此时的位置就是key的正确位置,让其进行交换
keyi = left;
//以keyi的下标作为分界点,因为其已经在正确位置了
//不需要在进行递归了
//【begin,keyi-1】keyi【keyi+1,end】
QuickSort1(a, begin, keyi - 1);
QuickSort1(a, keyi + 1, end);
}
else {
InsertSort(a + left, (right - left + 1));
//对快排进行优化,数据少的时候就用插入
//当然你也可以if (right - left + 1 > 10)不要
//也不用插入,全进行快排
}
}
2. 파기 방법:
void QuickSort2(int* a, int left, int right) {
if (left >= right) {
return;
}
if ((right - left + 1) > 10) {
int begin = left;
int end = right;
int midi = GetMidNumi(a, left, right);
if (midi != left) {
Swap(&a[midi], &a[left]);
}
int key = a[left];
//保存基准的值
int hole = left;
//让最左边为坑
while (left < right) {
while (left < right && a[right] >= key) {
right--;
//右边找小
}
a[hole] = a[right];
//把其放在坑位
hole = right;
//坑位更新,此时右边为坑
while (left < right && a[left] <= key) {
left++;
//左边找大
}
a[hole] = a[left];
hole = left;
//同上
}
a[hole] = key;
//最后hole就是left==right的位置
//也就是key的正确位置
//【begin,hole-1】hole【hole+1,end】
QuickSort1(a, begin, hole - 1);
QuickSort1(a, hole + 1, end);
}
else {
InsertSort(a + left, (right - left + 1));
}
}
3. 전후 포인터 방법:
void QuickSort3(int* a, int left, int right) {
if (left >= right) {
return;
}
if ((right - left) > 10) {
int begin = left;
int end = right;
int midi = GetMidNumi(a, left, right);
if (midi != left) {
Swap(&a[midi], &a[left]);
}
int keyi = left;
int prev = left;
//cur找到比a【keyi】小的值,++prev,cur与prev位置交换
//cur++
//cur找到比a【keyi】大的值,cur++
//也就是无论怎样,cur一定++;
int cur = prev + 1;
while (cur <= right) {
//把比a【keyi】小的值往左翻
//prev要么紧跟着cur
//要么prev与cur之间间隔着一段比a【keyi】
//大的区间
if (a[cur] < a[keyi] && ++prev != cur) {
Swap(&a[cur], &a[prev]);
}
cur++;
}
Swap(&a[prev], &a[keyi]);
//prev为a【keyi】的正确位置
keyi = prev;
//【begin,keyi-1】keyi【keyi+1,end】
QuickSort2(a, begin, keyi - 1);
QuickSort2(a, keyi + 1, end);
}
else {
InsertSort(a + left, (right - left + 1));
}
}
둘, 비재귀적
비재귀는 실제로 간격을 나누는 빠른 정렬의 아이디어이지만 순환 방식으로 만 가능합니다.
따라서 간격 스택의 기본 동작을 제어하려면 스택을 사용해야 합니다 .
스택을 이해하지 못하는 경우 이 기사를 먼저 읽으십시오.
int PartSort(int* a, int left, int right) {
int midi = GetMidNumi(a, left, right);
if (midi != left) {
Swap(&a[midi], &a[left]);
}
int prev = left;
int cur = prev + 1;
int keyi = left;
while (cur<= right) {
if (a[cur] < a[keyi] && ++prev != cur) {
Swap(&a[cur], &a[prev]);
}
cur++;
}
Swap(&a[prev], &a[keyi]);
keyi = prev;
//这个其实就是快排的一部分,找到key的正确位置返回
return keyi;
}
void QuickSortNonR(int* a, int left, int right) {
ST st;
STInit(&st);
STPush(&st, right);
//栈先进先出,
//所以【0,9】
//先入右边的【9,0】
//0先出
STPush(&st, left);
while (!STEmpty(&st)) {
int begin = STTop(&st);
STPop(&st);
int end = STTop(&st);
STPop(&st);
int keyi = PartSort(a, begin, end);
if (keyi + 1 < end) {
STPush(&st, end);
STPush(&st, keyi + 1);
}
if (begin < keyi - 1) {
STPush(&st, keyi - 1);
STPush(&st, begin);
}
}
STDestroy(&st);
}