排序算法——快速排序

怎么做到快速排序

  1. 在数组中选一个基准数(通常为数组第一个);

  2. 将数组中小于基准数的数据移到基准数左边,大于基准数的移到右边;

  3. 对于基准数左、右两边的数组,不断重复以上两个过程,直到每个子集只有一个元素,即为全部有序。

​ left和right分别为待排序序列的区间左右下标,先选取一个数据作为基准,right从后向前找比基准小的数据,找到后存储到left位置(而不是交换当前left和right位置的数据),然后left从前向后找比基准大的数据,找到后存储到right位置。直到left和right相遇,将基准数据存储到left位置。

​ 由以上过程就可以根据基准数据将整个序列分成左右两部分。然后分别对左部分和右部分执行以上过程。直到左右部分没有数据或者只剩一个数据。
在这里插入图片描述
如果left下标或者right下标,在与基准比较后,没有移动,则直接移动left或right继续比较,而不是切换另一边进行比较。
在这里插入图片描述
快速排序
时间复杂度: O(nlogn)
空间复杂度: O(logn)
稳定性 : 不稳定

快速排序的代码实现

递归实现

int OneQuick(int *arr, int left, int right)
{
	int i = left;
	int j = right;
	int tmp = arr[i];//Pivot 基准定义为 left 最左边数字

	while(i < j)
	{
		while(i < j && arr[j] >= tmp) j--;//先对right比较 
		//大于基准则j--继续比较
		
		arr[i] = arr[j];//否则将 right 存贮在 left 的位置
		//而不是交换当前left和right位置的数据

		while(i < j && arr[i] <= tmp) i++;//与上面同理
		arr[j] = arr[i];
	}
	//i == j 
	arr[i] = tmp;//将 Pivot 的值存在left 与 right 下标交汇的地方
	//这时候 该下标位置固定即排序完成 

	return i;
}

void Quick(int *arr, int left, int right)
{
	int mod = OneQuick(arr, left, right);

	if(mod - left > 1)//mod > 0
	{
		Quick(arr, left, mod - 1);//递归,新的组[left(0),mod-1]
	}
	if(right - mod > 1)//mod < len-1
	{
		Quick(arr, mod + 1, right);//递归,[mod+1,right(len-1)]
	}
}

void QuickSort(int *arr, int len)
{
	Quick(arr, 0, len-1);
}

非递归实现

栈实现
通过入栈出栈方式,将需要排序的组Pop出栈,同时排序完成会生成两个新的组,并将两个新的组入栈,同时在再一次出栈排序又会形成两个新的组,继而通过栈的方式实现了类似递归的方式。

/////////////////////////////快排的非递归实现//////////////////////////
//栈实现
//通过入栈出栈方式,将需要排序的组Pop出栈,同时排序完成会生成两个新的组
//并将两个新的组入栈,同时在再一次出栈排序又会形成两个新的组
//继而通过栈的方式实现了类似递归的方式
typedef struct 
{
	int left;
	int right;
}PairData;

typedef struct 
{
	PairData *data;
	int  top;
	int  size;
}Stack;

void InitStack(Stack *st, int init_size)
{
	if(st == NULL)  exit(0);

	init_size = init_size > 0 ? init_size : 10;

	st->data = (PairData*)malloc(sizeof(PairData) * init_size);
	if(st->data == NULL)  exit(0);

	st->top = 0;
	st->size = init_size;
}

int Empty(Stack *st)
{
	if(st == NULL)  exit(0);

	return st->top == 0;
}

PairData  Pop(Stack *st)
{
	if(st == NULL)  exit(0);

	if(Empty(st))  exit(0);

	st->top--;

	return st->data[st->top];
}

void Push(Stack *st, PairData value)
{
	if(st == NULL) exit(0);

	if(st->top == st->size) exit(0);

	st->data[st->top++] = value;
}

void Destroy(Stack *st)
{
	if(st == NULL)  exit(0);

	free(st->data);
	st->data = NULL;
	st->top = st->size = 0;
}

void Quick2(int *arr, int left, int right)
{
	Stack st;
	int stack_size = 2 * ((int)(log10(right-left+1) / log10(2)) + 1);
	//计算 栈的大小
	
	InitStack(&st, stack_size);

	PairData value = {left, right};
	Push(&st, value);

	while(!Empty(&st))
	{
		value = Pop(&st);
		int mod = OneQuick(arr, value.left, value.right);//一次排序
		if(mod - value.left > 1)//一次排序后 left 组
		{
			PairData left_pair = {value.left, mod-1};
			//left == left 还是原来的left right == mod-1
			Push(&st, left_pair);//入栈 等待Pop 进行排序处理
		}
		if(value.right - mod > 1)//与上面同理
		{
			PairData right_pair = {mod+1, value.right};
			Push(&st, right_pair);
		}
	}

	Destroy(&st);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值