文章目录
一、递归算法快速排序分析
二、非递归算法实现快速排序
2.1 需求分析
我们采用递归算法来实现快速排序时,我们递归的到底是什么?很简单,我们通过递归,就是再次调用该函数的功能,也就是单趟排序。那么我们如果不用递归,该如何保证能像递归一样,一直调用单趟排序这个功能呢?
答案就是:循环 |
答案就是:使用数据结构里面的栈 |
2.2 图解分析(如何利用栈)
三、快排(非递归)代码
这里我会把数据结构的栈也放出来,三数取中也加在里面
//交换函数
void Swap(int* p1, int* p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
//三数取中
int GetMinIndex(int* arr, int left, int right)
{
int mid = (left + right) >> 1;
if (arr[left] < arr[mid])
{
if (arr[mid] < arr[right])
{
return mid;
}
if (arr[left] < arr[right] && arr[right] < arr[mid])
{
return right;
}
return left;
}
else//arr[left] >= arr[mid]
{
if (arr[left] < arr[right])
{
return left;
}
if (arr[mid] < arr[right] && arr[right] < arr[left])
{
return right;
}
return mid;
}
}
//快排非递归
void QuickSort(int* arr, int n)
{
ST st;
StackInit(&st);
//把左右区间压栈,先压右边
StackPush(&st, n - 1);
//后压左边
StackPush(&st, 0);
//只要栈不为空,就继续分割排序
while (!StackEmpty(&st))
{
//从栈里面取出左右区间
int left = StackTop(&st);
StackPop(&st);
int right = StackTop(&st);
StackPop(&st);
int index = GetMinIndex(arr, left, right);
//因为我们下面的逻辑都是把第一个数作为key,
//为了避免改动代码,这里我们直接交换就可以
Swap(&arr[left], &arr[index]);
//开始单趟排序
int begin = left;
int end = right;
int pivot = begin;
int key = arr[begin];
while (begin < end)
{
//end开始找小
while (begin < end && arr[end] >= key)
{
end--;
}
arr[pivot] = arr[end];
pivot = end;
//begin开始找大
while (begin < end && arr[begin] <= key)
{
begin++;
}
arr[pivot] = arr[begin];
pivot = begin;
}
pivot = begin;
arr[pivot] = key;
//区间分为[left,pivot-1]pivot[pivot+1,right]
//利用循环继续分割区间
//先入右子区间
if (pivot + 1 < right)
{
//说明右子区间不止一个数
//先入右边边界
StackPush(&st, right);
//再入左边边界
StackPush(&st, pivot+1);
}
//再入左子区间
if (left < pivot-1)
{
//说明左子区间不止一个数
//先入右边边界
StackPush(&st, pivot-1);
//再入左边边界
StackPush(&st, left);
}
}
StackDestory(&st);
}
#pragma once
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>
typedef int STDateType;
typedef struct Stack
{
STDateType* a;
STDateType top;
int capacity;
}ST;
//初始化栈
void StackInit(ST* ps);
//销毁栈
void StackDestory(ST* ps);
//入栈
void StackPush(ST* ps, STDateType x);
//出栈
void StackPop(ST* ps);
//取出栈顶元素
STDateType StackTop(ST* ps);
//获取当前栈大小
int StackSize(ST* ps);
//判断栈是否为空
bool StackEmpty(ST* ps);
#include"Stact.h"
//初始化
void StackInit(ST* ps)
{
ps->a = (STDateType*)malloc(sizeof(STDateType) * 4);
ps->top = 0;
ps->capacity = 4;
}
//销毁栈
void StackDestory(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
//入栈
void StackPush(ST* ps, STDateType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
STDateType* tmp = (STDateType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDateType));
if (tmp == NULL)
{
printf("realloc fail\n");
exit (-1);
}
else
{
ps->a = tmp;
ps -> capacity *= 2;
}
}
ps->a[ps->top] = x;
ps->top++;
}
//出栈
void StackPop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
ps->top--;
}
//获取栈顶元素
STDateType StackTop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
//获取栈元素个数
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
//判断栈是否为空
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
如果写C++代码,那么这里的栈可以直接用STL里面的栈,很方便。