前言
上篇博客我们介绍了选择排序中的直接选择排序以及交换排序中的快速排序的hoare
版本的方法,这篇博客将会介绍交换排序中选择排序的挖坑法、lomuto
前后指针法以及非递归的方法,最后再介绍归并排序
交换排序
挖坑法
思路:
创建左右指针。首先从右向左找出比基准小的数据,找到后立即放入左边坑中,当前位置变为新的"坑",然后从左向右找出比基准大的数据,找到后立即放入右边坑中,当前位置变为新的"坑",结束循环后将最开始存储的分界值放入当的"坑"中,返回当前"坑"下标(即分界值下标)
int _QuickSort(int* arr, int left, int right)
{
int hole = left;
int key = arr[hole];
while (left < right)
{
while (left < right && arr[left] < key)
{
left++;
}
arr[hole] = arr[left];
hole = left;
while (left < right && arr[right] > key)
{
right--;
}
arr[hole] = arr[right];
hole = right;
}
arr[hole] = key;
return hole;
}
void QuickSort(int* arr, int left, int right)
{
if (left >= right)
{
return;
}
int keyi = _QuickSort(arr, left, right);
QuickSort(arr, left, keyi - 1);
QuickSort(arr, keyi + 1, right);
}
lomuto前后指针
思路:
创建前后指针,从左往右找比基准值小的进行交换,使得小的都排在基准值的左边。
int _QuickSort(int* arr, int left, int right)
{
int prev = left;
int cur = left + 1;
int keyi = left;
while (cur <= right)
{
while (arr[cur] < arr[keyi] && ++prev != cur)
{
swap(&arr[prev], &arr[cur]);
}
cur++;
}
swap(&arr[prev], &arr[keyi]);
return keyi;
}
void QuickSort(int* arr, int left, int right)
{
if (left >= right)
{
return;
}
int keyi = _QuickSort(arr, left, right);
QuickSort(arr, left, keyi - 1);
QuickSort(arr, keyi + 1, right);
}
非递归方法
非递归版本的快速排序需要借助数据结构:栈
思路:
将数组的左右下标入栈,取栈顶元素后出栈,接着借助lomuto
前后指针法找基准值,划分左右区间,接着将左右区间入栈,以此循环,直到栈为空。
void QuickSortNonR(int* arr, int left, int right)
{
ST st;
STInit(&st);
STPush(&st,right);
STPush(&st,left);
while (!StackEmpty(&st))
{
int begin = StackTop(&st);
STPop(&st);
int end = StackTop(&st);
STPop(&st);
int prev = begin;
int cur = prev + 1;
int keyi = prev;
while (cur <= end)
{
while (arr[keyi] > arr[cur] && ++prev != cur)
{
swap(&arr[prev], &arr[cur]);
}
cur++;
}
swap(&arr[keyi], &arr[prev]);
keyi = prev;
if (keyi + 1 < end)
{
STPush(&st, end);
STPush(&st, keyi + 1);
}
if (keyi - 1 > begin)
{
STPush(&st, keyi - 1);
STPush(&st,begin);
}
}
STDestory(&st);
}
归并排序
归并排序算法思想:
归并排序是建立在归并操作上的⼀种有效的排序算法,该算法是采用分治法的⼀个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成⼀个有序表,称为⼆路归并。
void _MergeSort(int* arr, int left, int right, int* tmp)
{
if (left >= right)
{
return;
}
//分解
int mid = (left + right) / 2;
_MergeSort(arr, left, mid, tmp);
_MergeSort(arr, mid + 1, right, tmp);
//合并
int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int index = begin1;
while (begin1 <= end1 && begin2 <= end2)
{
if (arr[begin1] < arr[begin2])
{
tmp[index++] = arr[begin1++];
}
else
{
tmp[index++] = arr[begin2++];
}
}
while (begin1 <= end1)
{
tmp[index++] = arr[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = arr[begin2++];
}
for (int i = left; i <= right; i++)
{
arr[i] = tmp[i];
}
}
void MergeSort(int* arr, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
perror("malloc fail!");
exit(1);
}
_MergeSort(arr, 0, n-1, tmp);
free(tmp);
}