递归
1、先在待排序序列中选择一个基准数据,一般常用的就是第一个数据
2、i,j : i从前向后 j从后向前 当i < j时,进入循环
(1)从后向前找第一个比基准小的数据(i<j),找到后就将其放到i位置
(2)从前向后找第一个比基准大的数据(i<j),找到后就将其放到j位置
3、将基准的值存储到i位置
4、基准将数据序列划分成左右两部分,当左右两部分的数据量大于1时,递归处理左右两部分。
// 在start位置 end位置 和中间位置找到中位数,将其换到start位置
void GetModNum(int *arr, int start, int end)
{
int mod = (end - start + 1) / 2 + start;
if (arr[mod] > arr[end])
{
Swap(&arr[mod], &arr[end]);
}
if (arr[start] > arr[end])
{
Swap(&arr[start], &arr[end]);
}
if (arr[start] > arr[mod])
{
Swap(&arr[start], &arr[mod]);
}
}
int Quick(int *arr, int start, int end)
{
//GetModNum(arr, start, end);
int tmp = arr[start];
while (start < end) // 大循环,将待排序序列全部访问一遍
{
//小循环, 从后向前找第一个比基准小的数据,存储到start位置
while (start < end)
{
if (arr[end] < tmp) break;
end--;
}
arr[start] = arr[end];
//小循环, 从前向后找第一个比基准大的数据,存储到end位置
while (start < end)
{
if (arr[start] > tmp) break;
start++;
}
arr[end] = arr[start];
}
arr[start] = tmp;
return start;
}
// arr是整个序列的起始地址,start是本次快排处理的数据的起始位置,end是本次快排处理的数据的结束位置
void OneQuick(int *arr, int start, int end)
{
int mod = Quick(arr, start, end);
if (mod - start > 1) // 判断其mod的左边超过1个数据,则进入递归处理mod的左边
{
OneQuick(arr, start, mod - 1);
}
if (end - mod > 1)
{
OneQuick(arr, mod + 1, end);
}
}
void QuickSort(int *arr, int len)
{
OneQuick(arr, 0, len - 1);
}
非递归
非递归实现快速排序 – 栈 或 队列 -> 存储数据序列的起始位置和结束位置这一对数据
1、初始化栈或者队列 , 初始化空间的大小为O(logn) * 2 * sizeof(int)
2、将初始的起始位置(0)和结束位置(len-1)入栈或者入队列
3、循环 退出条件是:栈为空或者队列为空
(1) 出栈或者出队列,获取到本次要处理的序列的起始位置和结束位置
(2)执行一次快排操作,得到到mod位置
(3)判断mod的右边是否还有超过1个的数据, 如果有,将右边的起始位置和结束位置入栈或者入队列
(4)判断mod的左边是否还有超过1个的数据, 如果有,将左边的起始位置和结束位置入栈或者入队列
*/
typedef struct Peer
{
unsigned int start;
unsigned int end;
}Peer;
typedef struct Stack
{
Peer *data;
int top;
}Stack;
void QuickSortNoR(int *arr, int len)
{
int size = (int)(log((double)len) / log((double)2)) + 1;
Stack st;
st.data = (Peer *)malloc(sizeof(Peer) * size);
assert(st.data != NULL);
st.top = 0;
Peer peer;
peer.start = 0;
peer.end = len - 1;
st.data[st.top++] = peer;
while (st.top != 0)
{
peer = st.data[--st.top];
int mod = Quick(arr, peer.start, peer.end);
if (peer.end - mod > 1)
{
Peer new_peer = { mod + 1, peer.end };
st.data[st.top++] = new_peer;
}
if (mod - peer.start > 1)
{
Peer new_peer = { peer.start, mod - 1 };
st.data[st.top++] = new_peer;
}
}
free(st.data);
}
快排的优化:
1、对选择基准的方式的优化: 随机选择 三位(第一位,最后一位,中间一位)取中(中位数)
2、数据量越小,数据越有序,直接插入排序的效率越高 当快排的数据量小于一定值后,直接用直接插入排序
3、对重复数据: 每次划分将与key相等的元素集中到key的周围,处理左边或右边时,这些数据不再参与
4、多线程并行处理
快速排序详解
本文详细介绍了快速排序算法的递归和非递归实现过程,包括基准数据的选择、序列划分及优化策略,如中位数选取、小规模数据直接插入排序、重复数据处理和多线程并行处理。
1万+





