怎么做到快速排序
-
在数组中选一个基准数(通常为数组第一个);
-
将数组中小于基准数的数据移到基准数左边,大于基准数的移到右边;
-
对于基准数左、右两边的数组,不断重复以上两个过程,直到每个子集只有一个元素,即为全部有序。
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);
}