快速排序--递归实现&非递归实现(c语言)

快速排序算法是一种利用了分治思想的排序算法,基本思想是在数组中找到一个“主元”,将所有小于“主元”的元素放在它的左边,将所有大于“主元”的元素放在它的右边,然后以“主元”为分界,将原来的数组分成两个,然后在这两个数组中重复这个过程,直到最后整个数组都是有序的。

本文首先引述了《算法导论》中的算法描述,然后给出了递归和非递归两种版本的实现。

1、算法描述

下面是《算法导论》中对于快速排序算法的描述:

 上面的描述已经很清楚了,下面是通俗的描述,方便对照理解。

1、实际上这个过程中“主元”的位置不是一开始就固定的,选择数组的最后一个元素作为“主元”,然后从数组左边向右进行遍历,一直到数组倒数第二个元素。
2、如果遇到了比“主元”小的元素,就尽可能的向左移动,如果遇到了比“主元”大的元素,则不进行操作。
3、遍历结束后整个数组一定有一个位置,这个位置左侧的所有元素都比“主元”小,那么就把“主元”和这个位置的元素进行交换,交换后还可以保证“主元”右侧的元素都比“主元”大。
4、然后将“主元”作为分界,对“主元”左侧和右侧的两个数组分别进行同样的排序即可,直到整个数组排序完成。

2、递归实现

从上面的过程可以看出来,快速排序是一个典型的递归过程,首先给出递归的实现。

#include<stdlib.h>
#include<stdio.h>

void quicksort(float * arr, int p, int r)
{
	if (p < r)
	{
		static float ex = 0;
		int i = p - 1;
		float pivot = arr[r];
		for (int j = p; j < r; ++j)
		{
			if (arr[j] < pivot)
			{
				i++;
				ex = arr[i];
				arr[i] = arr[j];
				arr[j] = ex;
			}
		}
		arr[r] = arr[i + 1];
		arr[i + 1] = pivot;

		quicksort(arr, p, i);
		quicksort(arr, i + 2, r);
	}
}

3、非递归实现

然后给出非递归的版本,非递归的版本实现主要借助了栈来实现。

void quicksort_non_recurrence(float * arr, int p, int r)
{
	if (p < r)
	{
		int *stack = (int*)malloc(sizeof(int) * (r - p + 1));
		int pointer = -1;
		stack[++pointer] = p;
		stack[++pointer] = r;

		float ex = 0;
		int left, right = 0;

		while (pointer != -1)
		{
			right = stack[pointer--];
			left = stack[pointer--];
			int i = left - 1;
			float pivot = arr[right];
			for (int j = left; j < right; ++j)
			{
				if (arr[j] < pivot)
				{
					i++;
					ex = arr[i];
					arr[i] = arr[j];
					arr[j] = ex;
				}
			}
			arr[right] = arr[i + 1];
			arr[i + 1] = pivot;

			if (left < i)
			{
				stack[++pointer] = left;
				stack[++pointer] = i;
			}

			if (i + 2 < right)
			{
				stack[++pointer] = i + 2;
				stack[++pointer] = right;
			}
		}
		free(stack);
	}
}


void main()
{
	float arr[] = { 2,5,3,6,1,0 };

	quicksort_non_recurrence(arr, 0, 5);
	for (int i = 0; i < 6; ++i)
	{
		printf("%f\n", arr[i]);
	}
}

上面代码中借助栈实现的时候,在这行代码中 int *stack = (int*)malloc(sizeof(int) * (r - p + 1)),申请的内存为(r-p+1)个int,实际上这里的栈是一个int数组,长度等于待排序的数组长度,记为n。

之所以栈的总空间为n个int,是因为栈里需要存储所有等待排序的子数组的左右下标,当n为偶数的时候,极端情况下,这个栈里会存储n个下标,当n为奇数时,这个栈里会存储n-1个下标,因此申请存储n个int的空间就足够了。具体过程可以借助树型结构来分析,极端情况下,会把原来的数组每两个相邻元素分成一个子数组,不断的放进栈里,直到最后两个元素下标入栈,因此需要的最大下标数量就等于n。

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
快速排序非递归版可以使用数组模拟栈的操作,也可以使用指针实现。以下是使用指针实现C语言代码: ```c #include <stdio.h> void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } void quickSort(int arr[], int left, int right) { int stack[right - left + 1]; int top = -1; stack[++top] = left; stack[++top] = right; while (top >= 0) { right = stack[top--]; left = stack[top--]; int pivot = arr[right]; int i = left - 1; for (int j = left; j <= right - 1; j++) { if (arr[j] < pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[right]); int pivotIndex = i + 1; if (pivotIndex - 1 > left) { stack[++top] = left; stack[++top] = pivotIndex - 1; } if (pivotIndex + 1 < right) { stack[++top] = pivotIndex + 1; stack[++top] = right; } } } void printArray(int arr[], int size) { for (int i = 0; i < size; i++) { printf("%d ", arr[i]); } printf("\n"); } int main() { int arr[] = {5, 9, 1, 3, 10, 4, 8, 6, 2, 7}; int size = sizeof(arr) / sizeof(arr[0]); quickSort(arr, 0, size - 1); printf("Sorted array: "); printArray(arr, size); return 0; } ``` 这个实现中,我们使用一个指针数组 `stack` 来模拟栈的操作,`top` 指针表示当前栈顶元素的位置。我们首先将左右边界压入栈中,然后在 while 循环中进行以下操作: - 弹出栈顶的右边界和左边界 - 选择最后一个元素作为 pivot,进行快速排序的划分操作 - 将 pivot 移动到正确的位置上 - 根据 pivot 的位置将左右两个子数组的边界压入栈中 这样我们可以使用 O(1) 的空间复杂度来实现快速排序非递归版。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值