【C语言】【数据结构初阶】 快排变慢排?怎么个事儿?

一.为何“快排”变“慢排”

我们知道,快排是一种很好的排序算法。但是在极少数的一些情况下,“快速排序”好像名不副实了。比如:1,2,1,2,1,2,1。。。。。。这样的数列

并且:递归深度太深,有栈溢出的风险。

这样,我们就得到了一个很可惜的结论:快排不是万金油。

但是,这是指的递归版本的快排,我们可以写非递归方式的快速排序,来看看是否能解决这个问题。

二.更改思路

想要改成非递归的版本,那么循环是否可以呢?

这里涉及到了左右区间分别递归,想要用循环实现,还是不大容易的。

//快速排序
void QuickSort(int* a, int left,int right)
{
	if (left >= right)
	{
		return;
	}
	int keyi = Partion(a, left, right);
	QuickSort(a, left, keyi - 1);
	QuickSort(a, keyi + 1, right);
}

那么,我们还有其它方式来解决这个问题吗?

答案是当然有。

我们可以用栈模拟

栈中存储的是需要排序的区间。栈是后入先出的。

如果是C++,那我们可以直接用STL里的,但是由于我们这里选择使用C语言来实现,所以我们需要先写一个栈。

下面是我们简单实现的一个栈。

#include
#include
#include
#include

typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;  //栈中数据数量
	int capacity; //栈的容量
}ST;

//检查空间是否足够,不够则扩容
void CheckCapacity(ST* ps)
{
	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newcapacity);
		if (tmp == NULL)
		{
			printf("realloc failed!\n");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
}

//初始化
void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

//销毁
void StackDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}

//插入数据
void StackPush(ST* ps, STDataType x)
{
	assert(ps);

	CheckCapacity(ps);

	ps->a[ps->top] = x;
	ps->top++;
}

//删除数据
void StackPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}

//取出栈顶数据
STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	return ps->a[ps->top - 1];
}

//计算栈中数据数量
int StackSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

//判断栈是否为空
bool StackEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

三.具体实现

我们可以使用栈来模拟递归过程:

每次从栈中取出一段区间,单趟分割处理左右子区间入栈。

#include"sort.h"
#include"Stack.h"

void Swap(int* p, int* q)
{
	int tmp = *p;
	*p = *q;
	*q = tmp;
}

int PartSort1(int* a, int left, int right)
{
	int keyi = left;

	while (left < right)
	{
		while (a[right] >= a[keyi] && left < right)
		{
			right--;
		}
		while (a[left] <= a[keyi] && left < right)
		{
			left++;
		}

		Swap(&a[left], &a[right]);
	}

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

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

	int keyi = PartSort1(a, left, right);

	QuickSort(a, left, keyi - 1);
	QuickSort(a, keyi + 1, right);
}




void QSortNonR(int* a, int begin, int end)
{
	ST st;
	StackInit(&st);

	StackPush(&st, end);
	StackPush(&st, begin);

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

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

		int keyi = PartSort1(a, left, right);

		if (keyi + 1 < right)
		{
			StackPush(&st, right);
			StackPush(&st, keyi + 1);
		}

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

	StackDestroy(&st);

}

四.测试运行

【C语言】【数据结构初阶】 快排变慢排?怎么个事儿?_第1张图片

 

你可能感兴趣的:(数据结构,C语言,数据结构,排序算法,算法)