[data structure] recursive implementation of quick sorting_ Detailed explanation of three methods + optimization

Keywords: Algorithm data structure

There are eight common sorting algorithms, so it is estimated that they will be divided into several periods. Interested friends may wish to click a collection column. ღ (´ᴗᴗღ) comparison Center

OJ link

Quick sort is an exchange sort method with binary tree structure proposed by Hoare in 1962. Its basic idea is:

Any element in the element sequence 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 less than the reference value, and all elements in the right subsequence are greater than the reference value, and then the process is repeated in the leftmost and leftmost subsequences until all elements are arranged in corresponding positions.

Common ways to divide the interval into left and right parts according to the benchmark value: Hoare method, pit excavation method and front and rear pointer method.

Fast scheduling can be realized by recursive and non recursive methods.

Hoare method

Core ideas

  1. When selecting the value on the left as the key, go first on the right.
  2. When you select the value on the right as the key, go first on the left.

This document is arranged in ascending order by default, as shown in the figure. The value on the left is key. Go first on the right, find a value smaller than the key and stop, then go again on the left, find a value larger than the key and stop. Swap the left and right values until the left and right meet. The value of the encounter point is exchanged with the key value.

Legend analysis


Single trip procedure

// Quick sort hoare version
int PartSort1(int* a, int left, int right)
{
	// Select key on the left and start walking on the right
	int keyi = left;
	while (left < right)
	{
		// When left = right, meet break
		// Go first on the right and find the little girl
		while (left < right && a[right] >= a[keyi])
		{
			// Avoid subscript overruns and dead loops
			--right;
		}
		// Go left and find the big one
		while (left < right && a[left] <= a[keyi])
		{
			++left;
		}
		// The value of the encounter is exchanged with the key
		Swap(&a[left], &a[keyi]);
	}
	return left;
}

Excavation method

Hoare version deformation.

Core ideas

1. Similarly, select the value on the left as the key, and go first on the right;
2. Select the value on the right as the key, and go first on the left.

Find the smaller value on the right, put the value smaller than key into the pit, and form a new pit on the right; Find a big one on the left and throw it into the pit. A new pit will be formed on the left.

Excavation method code

// Quick sequencing excavation method
int PartSort2(int* a, int left, int right)
{
	// Select the value on the left as the key, and go first on the right
	int key = a[left];
	int keyi = left;
	while (left < right)
	{
		// Go first on the right and find the little girl
		while (left < right && a[right] >= key)
		{
			--right;
		}
		// Find the small one and put the small one in the pit
		a[keyi] = a[right]; // a[right] < key
		keyi = right;

		// Go left and find the big one
		while (left < right && a[left] <= key)
		{
			++left;
		}
		// Find the big one and put the big one in the pit
		a[keyi] = a[left];
		keyi = left;
	}
	// left = right
	// Put the keyi value back in the pit
	a[keyi] = key;
	return keyi;
}

Front and back pointer method

The positions of prev and cur are different with different key selections.

When the value on the left is the key, cur finds a value smaller than the key, stops when it finds a value smaller than the key, + prev, and exchanges the values of prev and cur.

Front and back pointer method program

// Quick sort before and after pointer method
int PartSort3(int* a, int left, int right)
{
	// key in left position
	int keyi = left;
	int prev = left, cur = left + 1;
	while (cur <= right)
	{
		// Cur looks back for the small one, finds the small one, + prev, and then exchanges with cur
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			Swap(&a[prev], &a[cur]);
		}
		++cur; //cur, keep looking back
	}
	// Exchange the values of prev and key. Prev is a smaller value than key at this time
	Swap(&a[prev], &a[keyi]);
	return prev;
}

Fast scheduling analysis + optimization

For the ideal fast platoon, the reference value of each time is as follows:

The time complexity is O(N*logN)

But when the array is ordered:

Fast sorting degenerates into bubble sorting.

resolvent:
1. Random key value
2. Triple median.

However, if the array elements are the same in triple fetching, it will become invalid.

Three data fetching:

int GetMidValIndex(int* a, int left, int right)
{
	int mid = left + ((right - left) >> 1);
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		else if (a[left] > a[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
	else // a[left] > a[mid]
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		else if (a[left] < a[right])
		{
			return left;
		}
		else
		{
			return right;
		}
	}
}

Fast row recursive implementation

The recursive implementation of quick sort is similar to the preorder traversal process of binary tree.

Firstly, Hoare, pit digging method or front and back pointer method are used for single pass sorting, and then the left interval and right interval are processed respectively by recursion.

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

	// Inter cell optimization
	if (right - left + 1 < 10)
	{
		InsertSort(a + left, right - left + 1);
	}
	else
	{	
		int keyi = PartSort3(a, left, right);
		QuickSort(a, left, keyi - 1);
		QuickSort(a, keyi + 1, right);
	}
}

Space complexity: O(logN)

Posted by Brad on Sat, 27 Nov 2021 17:21:23 -0800