정렬 [데이터 구조] 빠른 사랑에 빠지게

텐 고전적인 정렬 알고리즘!
그림 삽입 설명 여기

머리말

제발확인이것 좀 봐 : 정렬 알고리즘은 + 코드 환경 준비 - 지식 사전 .

위의 내용이 준비가되면,의 신속 종류의를 시작하자!

빠른 정렬

구현 과정 :

  • ①에서 시퀀스를 선택 피벗 포인트 소자 (피벗)
    소자 지점의 축선의 각각의 선택 엘리먼트 0의 위치를 가정
  • ② 피벗 (2)의 서브 시퀀스로 분할
    피벗 요소 (왼쪽) 전면에 피봇보다 작은
    백 피봇 요동 소자 (우측)보다 클 것이다
    방전 소자 측 캔 피봇 등전위
  • ① ② ③ 서브 동작 시퀀스
    없이 재분할 (시퀀스에서 단지 하나 개의 요소)까지

그림 삽입 설명 여기
빠른 정렬의 본질은 그림 쇼 :

  • 각 요소는 점진적으로 피봇 포인트 요소로 변환 될

구성 피벗 포인트

. (6) 시퀀스 {들어 . 8 . 8 B 2 ,. 6 B ., 4 ,. 9 ,. 5 ,. 7} 구성된 축점 :

  • 첫째로 백업 엘리먼트 0의 위치, 피벗 포인트 소자 ;

그림 삽입 설명 여기

  • 궁극적 인 목적은 구성하는 중심 요소 서열로 피봇 점 :
    좌측 절반은 이하 피벗 점 요소 이외서열 ;
    우측은 피벗 지점 소자 초과서열 ,
    다음과 같다 :

그림 삽입 설명 여기

어떻게 당신이 그것을 구조화합니까?
제 위치 시퀀스 시작

  • 덜 축 요소보다 사이트 요소를 찾고, 오른쪽에서 왼쪽으로 스캔
    나중에 발견 , 위치로 시작, 시작 ++, 다음 찾을 역 ;
  • 축 부재보다 큰 점 요소를 찾고, 왼쪽에서 오른쪽으로 스캔,
    뒷부분의 최종 위치로, 최종하고 찾을 역방향 ;
  • 좌우 한 다음, 위에 설명되어 스캔하면 == 단부 시작 백업 개시 중앙으로 소자의 피벗 점 .

이 과정은 조금 때까지, 나중에 찾을 왼쪽에서 오른쪽으로 왼쪽으로 오른쪽 볼 필요가, 프로세스의주기를 혼란 요소의 왼쪽 절반에 피벗 포인트보다 작은 모든 요소 , 피벗 포인트 이상의 모든 요소보다 큰 요소의 오른쪽 절반으로 피벗 점의 완전한 건설.
그림 삽입 설명 여기
그림 삽입 설명 여기

구성 피벗 포인트 -에 대한 코드

어떻게 코드를 구현하는 바로 스캔 왼쪽에서왼쪽 스캔 오른쪽에서 교류 그것? 코드를 살펴는 이유를 이해할 수있을 것이다. . .

/**
 * 构造出 [begin, end) 范围的轴点元素
 * @return 轴点元素的最终位置
 */
private int pivotIndex(int begin, int end){	
	// 备份begin位置的元素
	T pivot = array[begin];
	// end指向最后一个元素
	end--;
	while(begin < end){
		while(begin < end){	// 从右往左扫描
			if(cmp(pivot, array[end]) < 0){ // 右边元素 > 轴点元素
				end--;
			}else{ // 右边元素 <= 轴点元素
				array[begin++] = array[end];	
				break;
			}
		}
		while(begin < end){ // 从左往右扫描
			if(cmp(pivot, array[begin]) > 0){ // 左边元素 < 轴点元素
				begin++;
			}else{ // 左边元素 >= 轴点元素
				array[end--] = array[begin];
				break;
			}
		}
	}
	// 将轴点元素放入最终的位置
	array[begin] = pivot;
	// 返回轴点元素的位置
	return begin; // begin==end
}

구성 피벗 포인트 - 최적화

균일 피벗 점뿐만 아니라, 주위의 요소의 수를 비교하면 가장 경우 :

  • T (N) = 2 * T (N / 2) + O (N) = O (nlogn)

피벗 점 주위의 요소의 수는 매우 고르지 않은 경우, 최악의 경우 :

  • T (N) = t (N - 1) + O (N) = O (N 2 )

접근 방식은 일반적으로 촬영되는 최악의 경우의 확률을 줄이기 위해 :

  • 임의로 선택된 피벗 포인트 소자
    피벗 점 요소 이전에 백업 될 수 있고, 임의의 요소들의 시퀀스의 요소는 교환 위치로 시작한다.
// 随机选择轴点元素, 将 begin 位置的元素与序列中的随机元素交换一下
swap(begin, begin + (int)Math.random()*(end - begin));

// 备份begin位置的元素
T pivot = array[begin];
.....

생각? 피벗 포인트 소자 같

시퀀스의 모든 요소가 피벗 점의 요소와 동일한 경우 , 상기 알고리즘을 이용하여 , 상기 샤프트 부재는 두 개의 서브 시퀀스로 균일 점 열 수있다
그림 삽입 설명 여기

생각 : 위의 코드, 판사의 CMP 위치는 어떤 영향을 할 것이다 ≥, ≤ 바뀌었다?
그림 삽입 설명 여기
결과 :

  • 시퀀스 피벗 포인트 요소는 매우 불균등 분할
  • 시간 복잡도 O에서 최악의 결과 (N- 2 )

그림 삽입 설명 여기

퀵 전체 코드

/**
 * 快速排序
 */
public class QuickSort<T extends Comparable<T>> extends Sort<T> {

	@Override
	protected void sort() {
		sort(0, array.length);
	}
	/**
	 * 对 [begin, end) 范围的元素进行快速排序
	 */
	private void sort(int begin, int end){
		if(end - begin < 2) return;
		
		// 确定轴点位置 O(n)
		int mid = pivotIndex(begin, end);
		// 对子序列进行快速排序
		sort(begin, mid);
		sort(mid + 1, end);
	}
	/**
	 * 构造出 [begin, end) 范围的轴点元素
	 * @return 轴点元素的最终位置
	 */
	private int pivotIndex(int begin, int end){
		// 随机选择轴点元素
		swap(begin, begin + (int)Math.random()*(end - begin));
		// 备份begin位置的元素
		T pivot = array[begin];
		// end指向最后一个元素
		end--;
		while(begin < end){
			while(begin < end){	// 从右往左扫描
				if(cmp(pivot, array[end]) < 0){ // 右边元素 > 轴点元素
					end--;
				}else{ // 右边元素 <= 轴点元素
					array[begin++] = array[end];	
					break;
				}
			}
			while(begin < end){ // 从左往右扫描
				if(cmp(pivot, array[begin]) > 0){ // 左边元素 < 轴点元素
					begin++;
				}else{ // 左边元素 >= 轴点元素
					array[end--] = array[begin];
					break;
				}
			}
		}
		// 将轴点元素放入最终的位置
		array[begin] = pivot;
		// 返回轴点元素的位置
		return begin; // begin==end
	}
	
}

20000 값은 [1, 10000] 난수 생성 분류된다 :
그림 삽입 설명 여기

복잡성과 안정성

복잡성 및 빠른 정렬의 안정성 :

  • 바람직하게는, 평균 시간 복잡도 : O (nlogn)
  • 최악의 시간 복잡도 : O (N- 2 )
  • 의 때문에 재귀 이유는 호출, 공간 복잡도 : O (logn)
  • 에 속하는 불안정 정렬
게시 된 170 개 원래 기사 · 원 찬양 47 ·은 20000 +를 볼

추천

출처blog.csdn.net/weixin_43734095/article/details/105156039