写在前面
目录
1 插入排序
1.1 直接插入排序
基本思想:
注意事项:
具体代码:
void InsertSort(int* a, int sz)//最好情况是O(N)
{
for (int i = 0; i < sz - 1; i++)
{
int end = i;
int tmp = a[end + 1];
while (end >= 0)
{
if (a[end] > tmp)//降序就变成<
{
a[end + 1] = a[end];
end--;
}
else
{
break;
}
}
a[end + 1] = tmp;
}
}
1.2 希尔排序
基本思想:
注意事项:
具体代码:
void ShellSort(int* a, int sz)
{
int gap = sz;
while (gap)
{
gap /= 2;
for (int i = 0; i < sz - gap; i++)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (a[end] > tmp)
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = tmp;
}
}
}
我们可以测试一下直接插入排序与希尔排序的性能对比:
由上图可知当排10W个数据时希尔排序的效率时直接插入排序的几百倍,数据越多,它们之间的差距只会越来越大。
2 选择排序
2.1 直接选择排序
基本思想:
直接选择排序的思想很简单,代码写起来也比较容易,这里就直接上具体代码:
void SelectSort1(int* a, int sz)
{
int i = 0;
int j = 0;
for (i = 0; i < sz; i++)
{
int k = i;
for (j = i + 1; j < sz; j++)
{
if (a[k] > a[j])
{
k = j;
}
}
Swap(&a[i], &a[k]);
}
}
这里还可以用双下标的方法优化一下直接选择排序,让其效率比第一种要高一些,但是时间复杂度还是O(N^2),具体代码:
void SelectSort2(int* a, int sz)
{
int begin = 0;
int end = sz - 1;
while (begin < end)
{
int mini = begin;
int maxi = begin;
for (int i = begin; i <= end; i++)
{
if (a[i] < a[mini])
{
mini = i;
}
if (a[i] > a[maxi])
{
maxi = i;
}
}
Swap(&a[begin], &a[mini]);
if (a[begin] == a[maxi])
{
maxi = mini;
}
Swap(&a[end], &a[maxi]);
begin++;
end--;
}
}
2.2 堆排序
具体代码(以建大堆为例):
void AdjustDown(int* a, int sz, int root)
{
int parent = root;
int child = parent * 2 + 1;
while (child < sz)
{
if (a[child + 1] > a[child] && child + 1 < sz)
{
child++;
}
if (a[parent] < a[child])
{
Swap(&a[parent], &a[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
但如果左右子树并不是大堆(小堆)那应该怎么办呢?
我们的处理方法是从倒数第二排的非叶子结点(也就是最后一个元素的父亲)开始建堆,直到第一个元素为止,具体代码如下:
for (int i = (sz - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(a, sz, i);
}
这样就完成了建堆,那么建堆的时间复杂度是多少呢?
这里我们可以来计算一下:
然后用错位相减法就可以得出:t(n)=2^h-h-1; 由于是完全二叉树h=log(i+N) (以2为底),
带入得t(n)=N-log(N+1) 当N区域无穷大得时候 t(n)=N; 故其建堆的时间复杂度为O(N).
具体代码:
我们来看看这四种排序的效率对比:
由图可以直观看出堆排序和希尔排序的效率比较高,直接插入和直接选择的效率较低。
好了,今天的分享就到这里了,如果对你有帮助的话能不能支持一下博主呢?