[Data Structure] - Sort - Quick Sort

 


Quick sort is a commutative sorting method of binary tree structure proposed by Hoare in 1962.

Basic idea :

Any element in the sequence of elements to be sorted is taken as the reference value , and the set to be sorted is divided into two subsequences according to the sorting code . All elements in the left subsequence are smaller than the reference value, and all elements in the right subsequence are greater than the reference value. The process is then repeated for the leftmost subsequence until all elements are arranged in their corresponding positions.

 Common ways to divide the interval into left and right halves according to the reference value:  Hoare method, digging method, front and rear pointer method .


1. Hoare version

Animation understanding:

 options:

1. When the leftmost key is selected, the right side goes first. --> When left and right meet, it is smaller than the key.

2. When selecting the rightmost key as the key, the left side goes first. --> When left and right meet, it is bigger than the key.

Core idea:

Select the left value as the key, go right first, find a value smaller than the key and stop (skip the larger one), then go left and find a larger value than the key and stop (skip the smaller one). Swap the values ​​of left and right until left and right meet. The value of the encounter point is exchanged with the key value.


int Partion1(int* a, int left, int right)
{
	// 三数取中 -- 面对有序最坏情况,变成选中位数做key,变成最好情况
	int midi = GetMidIndex(a, left, right);
	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]);

	return left;
}

Notice:

 Quick sort optimization: taking the middle of three numbers to select the key: taking the median of three numbers will not make the largest or smallest key

 

 

 


2. Digging method

Animation understanding:

 

options:

1. When the leftmost key is selected, the right side goes first.

2. When selecting the rightmost key as the key, the left side goes first.

Core idea:

Find the small value on the right, put the value smaller than the key into the pit, and form a new pit on the right; find the large value on the left and throw it into the pit, and form a new pit on the left.

// 挖坑法
int Partion2(int* a, int left, int right)
{
	// 三数取中 -- 面对有序最坏情况,变成选中位数做key,变成最好情况
	int midi = GetMidIndex(a, left, right);
	Swap(&a[midi], &a[left]);

	int key = a[left];
	//坑
	int pivot = left;
	while (left < right)
	{
		// 右边找小, 放到左边的坑里面
		while (left < right && a[right] >= key)
		{
			--right;
		}

		a[pivot] = a[right];
		pivot = right;

		// 左边找大,放到右边的坑里面
		while (left < right && a[left] <= key)
		{
			++left;
		}
		a[pivot] = a[left];
		pivot = left;
	}

	a[pivot] = key;
	return pivot;
}

Notice:

First fill in the value of the pit, and then change the position of the pit.

 

 


3. Front and back pointer method:

Animation understanding:

 options:

Core idea:

When cur finds a value smaller than the key, stop, ++prev, and then swap the values ​​of the prev and cur positions.

prev is either immediately followed by cur, or followed by a sequence larger than key.

// 推荐掌握这个 -- 思想三种大家都要掌握
int Partion3(int* a, int left, int right)
{
	// 三数取中 -- 面对有序最坏情况,变成选中位数做key,变成最好情况
	int midi = GetMidIndex(a, left, right);
	Swap(&a[midi], &a[left]);

	int keyi = left;
	int prev = left;
	int cur = prev + 1;
	while (cur <= right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			Swap(&a[cur], &a[prev]);
		}

		++cur;
	}

	Swap(&a[prev], &a[keyi]);
	return prev;
}

Quick sort optimization
1. Select the key by taking the middle of the three numbers
2. When recursing to a small subinterval, you can consider using insertion sort

void QuickSort(int* a, int left, int right)
{
	if (left >= right)
		return;

	// 小区间优化,当分割到小区间时,不再用递归分割思路让这段子区间有序
	// 对于递归快排,减少递归次数
	if (right - left + 1 < 10)
	{
		InsertSort(a + left, right - left + 1);
	}
	else
	{
		//类似二叉树遍历,根左右
		int keyi = Partion(a, left, right);
		// [left, keyi-1] keyi [keyi+1, right]
		QuickSort(a, left, keyi - 1);
		QuickSort(a, keyi + 1, right);
	}
}

Non-recursive method:

Use the stack structure to process ranges.

// 递归深度太深的程序,只能考虑改非递归
void QuickSortNonR(int* a, int left, int right)
{
	ST st;
	StackInit(&st);
	StackPush(&st, left);
	StackPush(&st, right);

	while (!StackEmpty(&st))
	{
		int end = StackTop(&st);
		StackPop(&st);

		int begin = StackTop(&st);
		StackPop(&st);

		int keyi = Partion3(a, begin, end);
		// [begin, keyi-1] keyi [keyi+1, end]
		if (keyi + 1 < end)
		{
			StackPush(&st, keyi + 1);
			StackPush(&st, end);
		}

		if (begin < keyi - 1)
		{
			StackPush(&st, begin);
			StackPush(&st, keyi - 1);
		}
	}

	StackDestroy(&st);
}

Guess you like

Origin blog.csdn.net/m0_51866180/article/details/121985605