快速排序(递归版和非递归版)

快速排序 

基本思想:通过一趟排序将要排序的数据分割成独立的两部分,分割点左边都是比它小的数,右边都是比它大的数。

然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

动态效果示意图:

详细的图解往往比大堆的文字更有说明力,所以直接上图:

上图中,演示了快速排序的处理过程:

初始状态为一组无序的数组:2、4、5、1、3。

经过以上操作步骤后,完成了第一次的排序,得到新的数组:1、2、5、4、3。

新的数组中,以2为分割点,左边都是比2小的数,右边都是比2大的数。

因为2已经在数组中找到了合适的位置,所以不用再动。

2左边的数组只有一个元素1,所以显然不用再排序,位置也被确定。(注:这种情况时,left指针和right指针显然是重合的。因此在代码中,我们可以通过设置判定条件left必须小于right,如果不满足,则不用排序了)。

而对于2右边的数组5、4、3,设置left指向5,right指向3,开始继续重复图中的一、二、三、四步骤,对新的数组进行排序。

复杂度和稳定性情况:

  • 最好的时间复杂度:O(nlog n)
  • 最坏的时间复杂度:O(n²)
  • 平均的时间复杂度:O(nlog n)
  • 空间复杂度:O(log n)
  • 稳定性:不稳定

C++实现快排(递归版) 

// 快速排序
void QuickSort(vector<int> &a, int left, int right)
{
    // 递归边界条件
    if (left >= right)
        return;
    if (left < 0 || right >= a.size())
        return;
    // 以最左边的数(left)为基准
    int base = a[left];
    int i = left, j = right, tmp;
    while (i < j) {
        // 从序列右端开始,向左遍历,直到找到小于base的数
        while (a[j] >= base && i < j)
            j--;
 
        // 从序列左端开始,向右遍历,直到找到大于base的数
        while (a[i] <= base && i < j)
            i++;
        if (i < j)
        {
            int tmp = a[i];
            a[i] = a[j];
            a[j] = tmp;
        }
    }
    // 基准数归位
    a[left] = a[i];
    a[i] = base;

    // 对“基准标号“左侧的一组数值进行递归的切割,以至于将这些数值完整的排序
    QuickSort(a, left, i - 1);
 
    // 对“基准标号“右侧的一组数值进行递归的切割,以至于将这些数值完整的排序
    QuickSort(a, i + 1, right);
}
 
int main()
{
    int arr[] = { 6, 4, 8, 9, 2, 3, 1 };
    vector<int> test(arr, arr + sizeof(arr) / sizeof(arr[0]));
    cout << "排序前" << endl;
    for (int i = 0; i < test.size(); i++){
        cout << test[i] << " ";
    }
    cout << endl;
    vector<int> result = test;
    QuickSort(result, 0, result.size() - 1);
    cout << "排序后" << endl;
    for (int i = 0; i < result.size(); i++){
        cout << result[i] << " ";
    }
    cout << endl;
    return 0;
}

C++实现快排(非递归版) 

借助一个栈,边划分边排序

int Divide(vector<int> &a, int left, int right)
{
	int base = a[left];

	while(left < right)
	{
		while(left < right && a[right] >= base)
			right--;
		a[left] = a[right];
		
		while(left < right && a[left] <= base)
			left++;
		a[right] = a[left];
	}
	a[left] = base;
	return left;
}
void QuickSort(vector<int> &a, int left, int right)
{
	stack<int> s;
	if(left < right)
	{
		int base = Divide(a, left, right);

		if(left < base-1)
		{
			s.push(left);
			s.push(base-1);
		}

		if(base+1 < right)
		{
			s.push(base+1);
			s.push(right);
		}

		while(!s.empty())
		{
			int r = s.top();
			s.pop();
			int l = s.top();
			s.pop();

			int b = Divide(a, l, r);

			if(l < b-1)
			{
				s.push(l);
				s.push(b-1);
			}

			if(r > b+1)
			{
				s.push(b+1);
				s.push(r);
			}
		}
	}

}

int main()
{
	int a[] = {5,6,3,2,8,9,0};
	int len = sizeof(a)/sizeof(a[0]);
	vector<int> v(a,a+len);
	QuickSort(v, 0, v.size()-1);
	for(int i = 0; i < v.size(); ++i)
	{
		cout<<v[i]<<" ";
	}
	cout<<endl;
	return 0;
}

其他排序算法: 

  1. 堆排
  2. 直接插入排序
  3. 希尔排序(优化版)
  4. 直接选择排序
  5. 冒泡排序及其优化
  6. 归并排序
  7. 基数排序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值