上次讲了选择排序和堆排序:数据结构排序——选择排序与堆排序
今天就来快排和冒泡
文章目录
1.快排
1.1基本介绍
1.2不同的分区方法及代码实现
1.2.1Hoare版
void Swap(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
int GetMid(int* a,int left, int right)//找中间的
{
// a[left] a[mid] a[right]
int mid = (left + right) / 2;
if (a[left] < a[mid])
{
if (a[mid] < a[right])
{
return mid;
}
else if (a[left] > a[right]) // mid是最大值
{
return left;
}
else
{
return right;
}
}
else // a[left] > a[mid]
{
if (a[left] < a[right])
{
return left;
}
else if (a[mid] < a[right])
{
return right;
}
else
{
return mid;
}
}
}
//一次排序
int OneSort1(int* a, int left, int right)//使keyi位置的元素处于正确的位置上
{
int mid = GetMid(a, left, right);
Swap(&a[mid], &a[left]);//现在left处是三者的中间值了
//左边第一个为key,右边先走才能保证相遇处比啊a[keyi]小
int keyi = left;
while (left < right)
{
while (a[right] >= a[keyi] && left < right)//右边先走
{
right--;
}
while (a[left] <= a[keyi] && left < right)//左侧找大的
{
left++;
}
Swap(&a[left], &a[right]);//找到一个大和一个小的就交换
}
Swap(&a[keyi], &a[left]);//把keyi放相遇位置
return left;//返回相遇的索引
}
void QuickSort(int* a, int begin, int end)//升序
{
if (begin >= end)
{
return;
}
// [begin, keyi-1] keyi [keyi+1, end]
int keyi = OneSort1(a, begin, end);//找到keyi索引,才能分左右
QuickSort(a, begin, keyi - 1);//左侧
QuickSort(a, keyi + 1, end);//右侧
}
int main()
{
int a[] = { 6,1,2,7,9,3,4,5,10,8 };
printf("排序前:");
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
{
printf("%d ", a[i]);
}
printf("\n");
QuickSort(a, 0,sizeof(a) / sizeof(int)-1);
printf("排序后:");
for (int i = 0; i < sizeof(a) / sizeof(int); i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
1.2.2挖坑版
int OneSort2(int* a, int left, int right)//挖坑
{
int mid = GetMid(a, left, right);
Swap(&a[mid], &a[left]);//现在left处是三者的中间值了
int key = a[left];//保存基准元素
int hole = left;//储存坑下标,不能直接赋值为0
while (left < right)
{
while (a[right] >= key && left < right)//右边先走,没有等号两侧出现相同值会死循环
{
right--;
}//找到了就去赋值到第一个“坑”
a[hole] = a[right];
hole = right;//更新坑
while (a[left] <= key && left < right)//左侧找大的
{
left++;
}
a[hole] = a[left];
hole = left;
}
Swap(&key, &a[left]);//把keyi放相遇位置
return left;//返回相遇的索引
}
1.2.3 前后指针版
int OneSort3(int* a, int left, int right)//挖坑
{
int mid = GetMid(a, left, right);
Swap(&a[mid], &a[left]);
int keyi = left;
int pre = left;
int cur = left + 1;
while (cur <= right)
{
if (a[cur] < a[keyi])
{
pre++;
Swap(&a[cur], &a[pre]);
}
cur++;
}
Swap(&a[pre], &a[keyi]);
return pre;
}
1.3快排的优化
1.3.1三数取中选key
代码在Hoare版已经展示过了
int GetMid(int* a,int left, int right)//找中间的
{
// a[left] a[mid] a[right]
int mid = (left + right) / 2;
if (a[left] < a[mid])
{
if (a[mid] < a[right])
{
return mid;
}
else if (a[left] > a[right]) // mid是最大值
{
return left;
}
else
{
return right;
}
}
else // a[left] > a[mid]
{
if (a[left] < a[right])
{
return left;
}
else if (a[mid] < a[right])
{
return right;
}
else
{
return mid;
}
}
}
1.3.2递归到小的子区间时,可以考虑使用插入排序
void InsertSort(int* a, int n)
{
for (int i = 0; i < n - 1; i++)
{
int end = i;
int tmp = a[end + 1];
while (end >= 0)
{
if (a[end] > tmp)
{
a[end + 1] = a[end];
}
else
{
break;
}
end--;
}
a[end + 1] = tmp;
}
}
int OneSort3(int* a, int left, int right)//挖坑
{
int mid = GetMid(a, left, right);
Swap(&a[mid], &a[left]);
int keyi = left;
int pre = left;
int cur = left + 1;
while (cur <= right)
{
if (a[cur] < a[keyi])
{
pre++;
Swap(&a[cur], &a[pre]);
}
cur++;
}
Swap(&a[pre], &a[keyi]);
return pre;
}
void QuickSort(int* a, int begin, int end)//升序
{
if (begin >= end)
{
return;
}
if ((end - begin + 1) > 10)
{
// [begin, keyi-1] keyi [keyi+1, end]
int keyi = OneSort3(a, begin, end);
QuickSort(a, begin, keyi - 1);
QuickSort(a, keyi + 1, end);
}
else
{
//用插入排序
InsertSort(a + begin, end - begin + 1);
}
}
1.3.3大量重复数据采用三路划分
基本步骤:
void QuickSort(int* a, int left, int right)
{
if (left >= right)
{
return;
}
int begin = left;
int end = right;
int mid = GetMid(a, left, right);
Swap(&a[mid], &a[left]);
int cur = left + 1;
int key = a[left];//储存一下,后面比较来用,用a[left]会被替代
while (cur <= right)
{
if (a[cur] < key)
{
Swap(&a[cur], &a[left]);
cur++;
left++;
}
else if (a[cur] == key)
{
cur++;
}
else
{
Swap(&a[cur], &a[right]);
right--;
}
}
QuickSort(a, begin, left - 1);
QuickSort(a, right + 1, end);
}
1.4快排非递归
void QuickSortNonR(int* a, int begin, int end)//利用栈,先想好先排左侧再排右侧
{
ST st;
STInit(&st);
STPush(&st,end);//把各个区间的两侧的索引(整形)插入进Stack中
STPush(&st,begin);//栈(后进先出),先排左侧所以后入左
while (!STEmpty(&st))
{
int left = STTop(&st);
STPop(&st);
int right = STTop(&st);
STPop(&st);
int keyi = OneSort1(a, left, right);//得到基准元素下标
// [begin, keyi-1] keyi [keyi+1, end]
if (keyi + 1 < right)//等于说明就一个,没必要
{
STPush(&st, right);
STPush(&st, keyi);
}
if (left < keyi-1)
{
STPush(&st, keyi-1);
STPush(&st, left);
}
}
STDestroy(&st);
}
2.冒泡排序
void BobbleSort(int* a, int n)
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (a[j] > a[j + 1])
{
Swap(&a[j], &a[j + 1]);
}
}
}
}
好啦,这次内容就到这里啦,下次带来归并排序,感谢大家支持!!!