交换排序基本思想: 所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置 交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动
前面在C语言博客专栏中我们已经接触过冒泡排序的思路了,冒泡排序是一种最基础的交换排序。之所以叫做冒泡排序,因为每一个元素都可以像小气泡一样,根据自身大小一点一点向数组的一侧移动。

//1)冒泡排序
void BubbleSort(int* arr, int n)
{
int exchange = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
exchange = 1;
Swap(&arr[j], &arr[j + 1]);
}
}
if (exchange == 0)
{
break;
}
}
}冒泡排序的特性总结
快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
//2)快速排序
void QuickSort(int* arr, int left, int right)
{
if (left >= right)
{
return;
}
//找基准值keyi
int keyi = _QuickSort(arr, left, right);
//左序列[left,keyi - 1] 右序列[keyi + 1,right]
QuickSort(arr, left, keyi - 1);
QuickSort(arr, keyi + 1, right);
}将区间中的元素进行划分的 _QuickSort 方法主要有以下几种实现方式:
算法思路: 1)创建左右指针,确定基准值 2)从右向左找出比基准值小的数据,从左向右找出比基准值大的数据,左右指针数据交换,进入下次循环
//找基准值 -- hoare版本
int _QuickSort1(int* arr, int left, int right)
{
int keyi = left;
left++;
while (left <= right)
{
//right:从右往左找比基准值要小的
while (left <= right && arr[right] > arr[keyi])
{
--right;
}
//left:从左往右找比基准值要大的
while (left <= right && arr[left] < arr[keyi])
{
++left;
}
//left和right交换
if (left <= right)
{
Swap(&arr[left], &arr[right]);
left++;
right--;
}
}
//right的位置就是基准值的位置
Swap(&arr[keyi], &arr[right]);//交换值
return right;
}思路: 创建左右指针。首先从右向左找出比基准小的数据,找到后立即放入左边坑中,当前位置变为新的"坑",然后从左向右找出比基准大的数据,找到后立即放入右边坑中,当前位置变为新的"坑",结束循环后将最开始存储的分界值放入当前的"坑"中,返回当前"坑"下标(即分界值下标)

int _QuickSort2(int* arr, int left, int right)
{
int hole = left;
int key = arr[hole];
while (left < right)
{
while (left < right && arr[right] > key)
{
--right;
}
arr[hole] = arr[right];
hole = right;
while (left < right && arr[left] < key)
{
++left;
}
arr[hole] = arr[left];
hole = left;
}
arr[hole] = key;
return hole;
}创建前后指针,从左往右找比基准值小的进行交换,使得小的都排在基准值的左边。
cur从左往右找比基准值要小的数据 1)cur指向的数据比基准值要小,++prev,cur和prev交换值,++cur 2)cur指向的数据不比基准值要小,++cur

//找基准值 -- lomuto前后指针
int _QuickSort3(int* arr, int left, int right)
{
int prev = left, cur = left + 1;
int keyi = left;
while (cur <= right)
{
//cur数据和基准值比较
if (arr[cur] < arr[keyi] && ++prev != cur)
{
Swap(&arr[cur], &arr[prev]);
}
++cur;
}
Swap(&arr[keyi], &arr[prev]);
return prev;
}快速排序特性总结:
非递归版本的快速排序需要借助数据结构:栈
//非递归版本快速排序
// 交换两个元素
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
// 分区操作:返回基准值最终位置
int partition(int arr[], int left, int right) {
// 选择最右侧元素作为基准值
int pivot = arr[right];
// i 指向小于基准值区域的最后一个元素
int i = left - 1;
for (int j = left; j < right; j++) {
// 若当前元素小于等于基准值,加入左侧区域
if (arr[j] <= pivot) {
i++;
swap(&arr[i], &arr[j]);
}
}
// 将基准值放到正确位置(i+1 是基准值的最终索引)
swap(&arr[i + 1], &arr[right]);
return i + 1;
}
// 非递归快速排序
void quickSort(int arr[], int n) {
if (n <= 1) return;
// 用数组模拟栈,存储区间的左右边界(每个区间占两个位置)
int* stack = (int*)malloc(2 * n * sizeof(int));
int top = -1; // 栈顶指针
// 初始区间 [0, n-1] 入栈
stack[++top] = 0;
stack[++top] = n - 1;
// 栈不为空时循环处理
while (top >= 0) {
// 弹出右边界和左边界(注意栈的先入后出特性)
int right = stack[top--];
int left = stack[top--];
// 分区操作,获取基准值位置
int pivotIndex = partition(arr, left, right);
// 左子区间 [left, pivotIndex-1] 入栈(若有效)
if (pivotIndex - 1 > left) {
stack[++top] = left;
stack[++top] = pivotIndex - 1;
}
// 右子区间 [pivotIndex+1, right] 入栈(若有效)
if (pivotIndex + 1 < right) {
stack[++top] = pivotIndex + 1;
stack[++top] = right;
}
}
free(stack); // 释放栈内存
}