内部排序算法之快速排序

快速排序是一种性能较好的算法,有最好的平均性能。由冒泡排序算法改进,采用分治思想:

1.将整个区间划分两个子区间p1, p2和元素k, 使得p1区间的所有元素均小于k, p2区间的所有元素均大于或等于k(这里k成为枢轴元素),

2.再对p1和p2两个区间分别重复步骤1, 如此递归

3.由于步骤1是就地排序,直到最后每个区间的元素个数为1, 这样整个区间就有序了。

实现步骤1的函数 

int Partion(int *p, int low, int high) 

这个函数根据选择的枢轴元素不同, 实现也不同,常见的有:

1.第一个元素选为枢轴元素

int Partion(int *p, int low, int high)
{
  while(high>low)
  {
    while(high>low && p[high]>p[low]) //#1
    {
      --high;
    }
    swap(p+high, p+low);

    for(high>low && p[high]>=p[low])  //注意这里和#1处必须保证至少有一个地方取等号, 否则遇到相等的元素时会出现死循环, 函数不能退出。
    {
      ++low;
    }
    swap(p+high, p+low);
  }
  return low;
}
2.最后一个元素选为枢轴元素
int Partion(int *p, int low, int high)
{
  int i, j = low;
  for(i=low; i<high-1; ++i)
  {
    if(p[i]<=p[high])
    {
       if(i!=j) // 避免不必要的交换
       {
         swap(p+i, p+j);
       }
       ++j;
    }
  }
  swap(p+j, p+high);
  return j;
}

当序列有序的时候, 不管是选第1个还是最后一个元素为枢轴元素, 都会划分一个长度为1, 一个长度为N-2的两个子区间,子区间长度相差较大,所有子区间组成的树不平衡,造成排序时间复杂度为O(n^2),效率较低。可以采用随机化的方法选择枢轴元素:

int partion(int *p, int low, int high)
{
    int k = random() ;
    swap(p+k, p+low);  // 或者swap(p+k, p+high); 
   // 随机选择一个元素与第一个元素或者最后一个元素交换, 作为枢轴元素

   // 
   // 接下来与第一个或者最后一个元素作为枢轴元素相同 
....
}

 这样效率可以达到O(n*logn)。

通常快速排序具有最好的平均性能,时间复杂度为O(n*logn), 常数因子较其他同类算法(时间复杂度为O(n*logn)的算法)小。可是当区间元素有序(正序或者逆序)的时候,快速排序就蜕变成时间复杂度为O(n^2)的算法了。

代码实现

1.递归实现

void static qsort(int *p, int low, int high)
{
	if(low < high)
	{
		int pivot = partion(p, low, high);
		qsort(p, low, pivot-1);
		qsort(p, pivot+1, high);
	}
}

 

2. 非递归实现

void qsort(int *p, int low, int high)
	if(low < high)
	{
		Stack stack;
		init_stack(&stack);
		int mid = partion(p, low, high);
		if(mid-1 >= 0)
		{
			push_stack(&stack, low);
			push_stack(&stack, mid-1);
		}
		if(mid+1 <= high)
		{
			push_stack(&stack, mid+1);
			push_stack(&stack, high);
		}
		while(!empty_statck(&stack))
		{
			int m, n;
			if(pop_stack(&stack, &n) && pop_stack(&stack, &m))
			{
				mid = partion(p, m, n);
				if(mid-1 >= m)
				{
					push_stack(&stack, m);
					push_stack(&stack, mid-1);
				}
				if(mid+1 <= n)
				{
					push_stack(&stack, mid+1);
					push_stack(&stack, n);
				}
			}
		}
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值