C language implementation of quick sort and optimization and analysis of quick sort

C language to realize quick sorting and its system optimization and analysis

catalogue

I Implementation of quick sort

1. Implementation ideas

2.QSort implementation

3. Implementation of the function Partition()

4. Complete code

 

II System optimization of quick sort

1. Optimize the selection of keyword pivotkey

2. Optimize unnecessary exchange (turn exchange into assignment)

3. Optimize recursive operation

4.!!!! Optimized complete code!!!!!

III epilogue

I Implementation of quick sort

1. Implementation ideas

The basic idea of quick sorting is: first, find a random number in the array to be sorted (in fact, it is tricky to find this number, which will be discussed later). This number is also called keyword. The array is divided into left and right parts through one sorting. The left part is smaller than the keyword, the middle is the keyword, and the right part is larger than the keyword. Then the left and right parts can continue to sort as just until the whole array is in order.

for example

Unordered array 26,1,7,56,34,23,77,87,22,43,16,66

1. Let's choose a keyword first, for example, 26

2. After the first sorting, the left part is smaller than the keyword, the middle part is the keyword, and the right part is larger than the keyword

I.e. 16 1 7 22 23 26 77 87 34 43 56 66

3. 16 1 7 22 23 is the left part

4. 26 is the keyword, i.e. the middle part

5. 77 87 34 43 56 66 is the right part

6. Then we can continue the operation on the left and right parts, so the core code of quick sorting is how to divide the array into the left and right parts!! Does it sound simple!! Next, let's implement it

2.QSort implementation

void QSort(int* arr, int low,int high)//low is the first subscript of the array, that is, 0; high is the last subscript of the array
{
	int pivot;//Subscript of keyword
	if (low < high)
	{
		pivot = Partition(arr, low, high);//Get the keyword subscript to divide the array into left and right parts
		QSort(arr, low, pivot - 1);//Continue sorting the left part
		QSort(arr, pivot + 1, high);//Continue sorting the right part
	}
}



int main()
{
	int arr[] = { 26,1,7,56,34,23,77,87,22,43,16,66 };

	QSort(arr, 0,(sizeof(arr) / sizeof(arr[0])-1));

	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
}

Here, we define an array int arr [] = {26,1,7,56,34,23,77,87,22,43,16,66}. What we need to do is to get the subscript of the keyword in "pivot = Partition(arr, low, high)" and turn the array into:

1. Keyword in the middle

2. The left side of the keyword is less than or equal to the value of the keyword

3. The right side of the keyword is greater than or equal to the value of the keyword

This is also the function of the function Partition(), so next we need to find a way to implement the function Partition().

3. Implementation of the function Partition()

void swap(int* arr, int x, int y)
{
	int tmp = arr[x];
	arr[x] = arr[y];
	arr[y] = tmp;
}

int Partition(int* arr, int low, int high)
{
	int pivotkey = arr[low];//Pivot key is a keyword. Just find one here. For convenience, we take the first element of the array
	while (low < high)//When low and high are equal, it means that low and high point to the subscript of the keyword at the same time
	{
		while (low < high && arr[high] >= pivotkey)//Start from the right to the left of the array to find if there is anything smaller than the keyword. If there is, jump out of the loop and exchange with the number on the left of the keyword to ensure that the small numbers are on the left of the keyword.
		{
			high--;
		}
		swap(arr, low, high);//Function of exchanging values
		while (low < high && arr[low] <= pivotkey)Start from the left to the right of the array to find out if there is any larger than the keyword. If there is, jump out of the loop and exchange with the number on the right of the keyword to ensure that the large numbers are on the right of the keyword.
		{
			low++;
		}
		swap(arr, low, high);
	}
	return low;//Return keyword subscripts, low and high
}

After Partition() in turn, the array arr [] becomes two parts centered on the first element 26 of the array arr= 16 1 7 22 23 ^ 26 77 87 34 43 56 66. The right part of 26 is larger than 26 and the left part of 26 is smaller than 26. Then continue to recursively sort the left and right sides again, that is, the two sentences of code with a red line in the following figure

4. Complete code

void swap(int* arr, int x, int y)
{
	int tmp = arr[x];
	arr[x] = arr[y];
	arr[y] = tmp;
}


int Partition(int* arr, int low, int high)
{
	int pivotkey = arr[low];//Pivot key is a keyword. Just find one here. For convenience, we take the first element of the array
	while (low < high)//When low and high are equal, it means that low and high point to the subscript of the keyword at the same time
	{
		while (low < high && arr[high] >= pivotkey)//Start from the right to the left of the array to find if there is anything smaller than the keyword. If there is, jump out of the loop and exchange with the number on the left of the keyword to ensure that the small numbers are on the left of the keyword.
		{
			high--;
		}
		swap(arr, low, high);//Function of exchanging values
		while (low < high && arr[low] <= pivotkey)Start from the left to the right of the array to find out if there is any larger than the keyword. If there is, jump out of the loop and exchange with the number on the right of the keyword to ensure that the large numbers are on the right of the keyword.
		{
			low++;
		}
		swap(arr, low, high);
	}
	return low;//Return keyword subscripts, low and high
}


void QSort(int* arr, int low,int high)//low is the first subscript of the array, that is, 0; high is the last subscript of the array
{
	int pivot;//Subscript of keyword
	if (low < high)
	{
		pivot = Partition(arr, low, high);//Get the keyword subscript to divide the array into left and right parts
		QSort(arr, low, pivot - 1);//Continue sorting the left part
		QSort(arr, pivot + 1, high);//Continue sorting the right part
	}
}



int main()
{
	int arr[] = { 26,1,7,56,34,23,77,87,22,43,16,66 };

	QSort(arr, 0,(sizeof(arr) / sizeof(arr[0])-1));

	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
}

Operation effect:

II System optimization of quick sort

1. Optimize the selection of keyword pivotkey

For convenience, we always select the first element of the array as the keyword. There are certain disadvantages if we are so arbitrary. For example, the array to be sorted just now becomes arr [] = {1,26,7,56,34,23,77,87,22,43,16,66}. If we select the first element 1, it is obviously unreasonable to select 1 compared with any other number, So the keywords we just chose have a great impact on our sorting speed.

Therefore, we came up with a way to take a number from the left, middle and right of the array, and then take the one in the middle of the three numbers as the keyword pivot key. This is indeed a good method in small-scale sorting, but its role is also minimal in large-scale arrays. Therefore, in large-scale sorting, sometimes 27 numbers take 9 and then take 3 and then take 1, and 9 take 3 and then take 1. The reason is the same, that is, to find a suitable keyword and speed up sorting.

Therefore, we add these lines of code before determining the keyword pivotkey

    int mid = low + (high - low) / 2;//Determines the subscript of the intermediate element
	if (arr[low] > arr[high])
	{
		swap(arr, low, high);//Exchange data at the left and right ends to keep the left end small
	}
	if (arr[mid] > arr[high])
	{
		swap(arr, high, mid);//Exchange data at the middle right end to ensure that the middle is small
	}
	if (arr[mid] > arr[low])
	{
		swap(arr, mid, low);//Exchange the data of the left and middle ends to ensure that the left end is larger than the middle one, so that the middle of the three numbers will run to the far left
	}

The function partition () becomes like this

int Partition(int* arr, int low, int high)
{
    int mid = low + (high - low) / 2;//Determines the subscript of the intermediate element
	if (arr[low] > arr[high])
	{
		swap(arr, low, high);//Exchange data at the left and right ends to keep the left end small
	}
	if (arr[mid] > arr[high])
	{
		swap(arr, high, mid);//Exchange data at the middle right end to ensure that the middle is small
	}
	if (arr[mid] > arr[low])
	{
		swap(arr, mid, low);//Exchange the data of the left and middle ends to ensure that the left end is larger than the middle one, so that the middle of the three numbers will run to the far left
	}
	int pivotkey = arr[low];//Pivot key is a keyword. Just find one here. For convenience, we take the first element of the array
	while (low < high)//When low and high are equal, it means that low and high point to the subscript of the keyword at the same time
	{
		while (low < high && arr[high] >= pivotkey)//Start from the right to the left of the array to find if there is anything smaller than the keyword. If there is, jump out of the loop and exchange with the number on the left of the keyword to ensure that the small numbers are on the left of the keyword.
		{
			high--;
		}
		swap(arr, low, high);//Function of exchanging values
		while (low < high && arr[low] <= pivotkey)Start from the left to the right of the array to find out if there is any larger than the keyword. If there is, jump out of the loop and exchange with the number on the right of the keyword to ensure that the large numbers are on the right of the keyword.
		{
			low++;
		}
		swap(arr, low, high);
	}
	return low;//Return keyword subscripts, low and high
}

2. Optimize unnecessary exchange (turn exchange into assignment)

We only need to back up a copy of the keywords before dividing the array into the left and right parts, and then in the sorting process, the exchange between numbers is directly changed to assignment, which will reduce a lot of exchange steps

	int pivotkey = arr[low];
	int tem = pivotkey;//Backup keyword
	while (low < high)
	{
		while (low < high && arr[high] >= pivotkey)
		{
			high--;
		}
		arr[low] = arr[high];//Assignment rather than exchange
		while (low < high && arr[low] <= pivotkey)
		{
			low++;
		}
		arr[high] = arr[low];//Assignment rather than exchange
	}
	arr[low] = tem;//Return the value of the keyword to its location

The principle is the same. Find a small number on the right, assign it to the left, find a large number on the left, and assign it to the right. Anyway, in the end, low and high will point to the subscript of the keyword at the same time, and then return the value of the keyword to it.

After the above operations, our Partition() function becomes like this

int Partition(int* arr, int low, int high)
{
    int mid = low + (high - low) / 2;//Determines the subscript of the intermediate element
	if (arr[low] > arr[high])
	{
		swap(arr, low, high);//Exchange data at the left and right ends to keep the left end small
	}
	if (arr[mid] > arr[high])
	{
		swap(arr, high, mid);//Exchange data at the middle right end to ensure that the middle is small
	}
	if (arr[mid] > arr[low])
	{
		swap(arr, mid, low);//Exchange the data of the left and middle ends to ensure that the left end is larger than the middle one, so that the middle of the three numbers will run to the far left
	}

	int pivotkey = arr[low];//Pivot key is a keyword. Just find one here. For convenience, we take the first element of the array
    int tem = pivotkey;//Backup keyword

	while (low < high)//When low and high are equal, it means that low and high point to the subscript of the keyword at the same time
	{
		while (low < high && arr[high] >= pivotkey)//Start from the right to the left of the array to find if there is anything smaller than the keyword. If there is, jump out of the loop and exchange with the number on the left of the keyword to ensure that the small numbers are on the left of the keyword.
		{
			high--;
		}
		arr[low] = arr[high];//Assignment rather than exchange
		while (low < high && arr[low] <= pivotkey)Start from the left to the right of the array to find out if there is any larger than the keyword. If there is, jump out of the loop and exchange with the number on the right of the keyword to ensure that the large numbers are on the right of the keyword.
		{
			low++;
		}
		arr[high] = arr[low];//Assignment rather than exchange
	}
    arr[low] = tem;//Return the value of the keyword to its location
	return low;//Return keyword subscripts, low and high
}

3. Optimize recursive operation

Let's change the function of QSort() to

void QSort(int* arr, int low,int high)
{
	int pivot;
	while (low < high)//if becomes while
	{
		pivot = Partition(arr, low, high);
		QSort(arr, low, pivot - 1);
		low = pivot + 1;//When low is used up, it will not be used anyway, and it will become the original qsort (arr, pivot+1, high); pivot+1, continue to sort recursively
	}
}

In this way, we reduce the number of recursion and greatly improve the speed!!

4.!!!! Optimized complete code!!!!!

void swap(int* arr, int x, int y)
{
	int tmp = arr[x];
	arr[x] = arr[y];
	arr[y] = tmp;
}


int Partition(int* arr, int low, int high)
{
    int mid = low + (high - low) / 2;//Determines the subscript of the intermediate element
	if (arr[low] > arr[high])
	{
		swap(arr, low, high);//Exchange data at the left and right ends to keep the left end small
	}
	if (arr[mid] > arr[high])
	{
		swap(arr, high, mid);//Exchange data at the middle right end to ensure that the middle is small
	}
	if (arr[mid] > arr[low])
	{
		swap(arr, mid, low);//Exchange the data of the left and middle ends to ensure that the left end is larger than the middle one, so that the middle of the three numbers will run to the far left
	}

	int pivotkey = arr[low];//Pivot key is a keyword. Just find one here. For convenience, we take the first element of the array
    int tem = pivotkey;//Backup keyword

	while (low < high)//When low and high are equal, it means that low and high point to the subscript of the keyword at the same time
	{
		while (low < high && arr[high] >= pivotkey)//Start from the right to the left of the array to find if there is anything smaller than the keyword. If there is, jump out of the loop and exchange with the number on the left of the keyword to ensure that the small numbers are on the left of the keyword.
		{
			high--;
		}
		arr[low] = arr[high];//Assignment rather than exchange
		while (low < high && arr[low] <= pivotkey)Start from the left to the right of the array to find out if there is any larger than the keyword. If there is, jump out of the loop and exchange with the number on the right of the keyword to ensure that the large numbers are on the right of the keyword.
		{
			low++;
		}
		arr[high] = arr[low];//Assignment rather than exchange
	}
    arr[low] = tem;//Return the value of the keyword to its location
	return low;//Return keyword subscripts, low and high
}

void QSort(int* arr, int low,int high)
{
	int pivot;
	while (low < high)//if becomes while
	{
		pivot = Partition(arr, low, high);
		QSort(arr, low, pivot - 1);
		low = pivot + 1;//When low is used up, it will not be used anyway, and it will become the original qsort (arr, pivot+1, high); pivot+1, continue to sort recursively
	}
}

int main()
{
	int arr[] = { 26,1,7,56,34,23,77,87,22,43,16,66 };

	QSort(arr, 0,(sizeof(arr) / sizeof(arr[0])-1));

	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
}

Operation effect

III epilogue

In fact, many library functions of computer language have quick sort function. Although they are different, the effect and speed are the same. If you are interested in the quick sort library function qsort of C language, you can read another explanation about qsort by the blogger, which is very detailed. Finally, you are welcome to leave a message if you don't understand it~

✨ Those who like and feel useful might as well give praise and attention~ ❤️

✨ Your attention is the biggest motivation for bloggers to create ~!!! Thanks for reading!!!!

Keywords: C Algorithm data structure quick sort

Added by BobcatM on Thu, 06 Jan 2022 07:03:58 +0200