快速排序是先通过在数组中选择一个数字作为枢轴,用这个数字将整个数组分为两个部分,左边的这些数字小于枢轴数字,右边的这些数字大于枢轴数字。而开始时候选择的枢轴数字已经到了合适的位置,下来的步骤就是对左边和右边分别重复上述步骤。
先选择最左边的数字,将其作为枢轴,与最右边的数字进行比较如果是比它大的就将下标减1,如果比它小,就将此数字覆盖到最开始选择的最左边的下标的位置,并且记录右边的这个下标。然后右边的下标中的位置空出来了,从左边开始选择比其大的数字将其覆盖到右边空闲的位置,记录下标,如果较其小就加1。如此循环直至两下标相等,则该位置就是选择的枢轴数字的位置,将枢轴数字覆盖到该下标处,一次快速排序结束。
快速排序达到整体有序的方法有递归和循环。通过递归来从至下,将每一个分支都进行插入排序。其实现下来的流程如同一棵二叉树,左根遍历进行排序。循环排序也是同递归类似,就是每分为排一次,分别判断两个子组是否能还有两个数字及两个数字以上的数据,如果有的话就将其压入栈中。根据栈的先进后出,将其赋值给左值右值,然后再继续下去,判断栈是否为空,否则继续进行排序入栈等操作。
int quick(int *arr, int left, int right)
{
if ((left == 0 && right == 0) || arr == NULL)
{
return -1;
}
int tmp = *(arr+left);
while(left < right)
{
while(tmp<=arr[right] && left<right)//在右边寻找比tmp大的值,寻找到就结束
{
right--;
}
arr[left] = arr[right];
while(tmp>=arr[left] && left<right)//在左边寻找到比tmp小的值,找到就截至
{
left++;
}
arr[right] = arr[left];
}
arr[right] = tmp;
return right;
}
递归类实现排序
void quick_recurisive(int *array, int left, int right)
{
int base = 0;
if (left < right)
{
base = quick(array, left, right);
quick_recurisive(array, base+1, right);
quick_recurisive(array, left, base-1);
}
}
循环用栈实现排序
bool quick_stack(Sta *stack, int *arr, int left, int right)
{
if (stack == NULL || left == right)
{
return false;
}
int base = 0;
push(stack, right);
push(stack ,left);
while(!is_empty_stack(stack)) // 栈为空时就撤
{
int base = quick(arr, left, right);
if (base+1 != right && base != right)
{
push(stack, base+1);
push(stack, right);
}
if (base-1 != left && base != left)
{
push(stack, left);
push(stack, base-1);
}
pop(stack, &right);//you
pop(stack, &left); //zuo
}
return true;
}
快速排序的平均时间为T(n)=kn(ln(n-1)),k是一个常数。快速排序每次比较都需要进栈出栈,可以想到,快速排序在第一次走的时候是一棵树的最左边的一斜行,这行的深度就是快速排序中所用到的最大的空间数量,其空间复杂度为O(log<2>n)
快速排序的优化:
1.选择合适的枢轴,通过三者取中,拿出数组最左边,最右边,中间的三个数的中位数,与第一个进行交换,然后再进行快速排序
2.插入排序在数字基本有序的时候效率很高,所以在快速排序的数组分化成一定规模的时候选择内嵌入插入排序来提高效率