排序(7)——非递归快排

前面我们已经写了快排用递归的方法实现,在数据量大的时候,有可能会栈溢出。这里我们尝试一下改为非递归

区分:

  • 数据结构的栈——利用的是内存中的堆空间
  • 内存的栈——利用就是内存中的栈空间——函数创建函数栈帧
  • 堆的空间是远远大于栈的空间

递归 -> 非递归

  1. 循环  一般递归可以改为非递归的话,就说明这个题目用循环来写会更顺。有些题目不好改为非递归,比如二叉树的前序遍历。
  2. 借助栈。 

基本思路

注意栈后进先出的特性。

  • 首先入栈单趟排序的区间,然后出栈确定left和right,单趟排序确定keyi。接下来根据新的keyi再次入栈单趟排序的区间。
  • 对于区间,先入end,再入begin。先出begin,再出end。对于子问题,先入右序列,再入左序列。先出左序列,再出右序列。(对应于递归先递归左边再递归右边。)
  • 递归:把子问题放到函数栈帧(借助栈的空间)
  • 非递归:把子问题放到数据结构的栈(借助堆的空间)
  • 不是递归胜似递归。

代码实现

  • 入栈的条件left < right。
  • 栈不为空就继续,栈为空就结束。
  • 对于区间,先入end,再入begin。先出begin,再出end。对于子问题,先入右序列,再入左序列。先出左序列,再出右序列。
  • 一定要记得赋值完left和right后要出栈
void QuickSortNonR(int* a, int begin, int end)
{
	ST s;
	STInit(&s);
	STPush(&s, end); //先进end
	STPush(&s, begin); //再进begin

	while (!STempty(&s))
	{
		int left = STTop(&s); //取begin为left
		STPop(&s); //begin出栈
		int right = STTop(&s); //取end为right
		STPop(&s); //end出栈

		int keyi = PartSort3(a, left, right); //单趟排序取新keyi
		// [left, keyi-1] keyi [keyi+1, right]
        //如果子区间不是left==right或者无数据

        if (keyi + 1 < right)
        //处理右区间
		{
			STPush(&s, right); //先入end
			STPush(&s, keyi + 1); //再入begin
		}

		if (left < keyi - 1) 
        //处理左区间
		{
			STPush(&s, keyi - 1); //先入end 
			STPush(&s, left); //再入begin
		}
		
	}

	STDestroy(&s);
}

图解分析

 

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值