퀵 정렬: (퀵 정렬) 세 가지 재귀적 구현 방법(hoare, pointer, digging) 및 비재귀적 방법(C 언어 구현)


머리말

퀵 정렬에서 가장 중요한 것은 벤치마크 값 키를 비교 기준으로 선택하는 것입니다
. 상대적이 됩니다. 예전에는 더 질서정연했습니다. 이 아이디어에 따르면 여러 번 재귀하고 빠른 정렬을 사용하기만 하면 됩니다.

다음은 벤치마크 값 키를 찾는 방법이며 중간 요소를 찾는 데 사용합니다.

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);
}

Supongo que te gusta

Origin blog.csdn.net/m0_74774759/article/details/130649917
Recomendado
Clasificación