选择排序
1.选择排序
普通方法
- 每次从无序区间里选出最小的数,然后插入到无序区间的begin,(数组右边是有序,左边是无序),begin加加,这时begin以前的都是升序的,重复前面操作直到begin和end相遇,至此所有记录有序。
void SelectSort1(int* a, size_t n)
{
int begin = 0;
int end = n-1;
int min = 0;
while (begin < end)//O(n)
{
min = begin;
for (size_t i = begin; i <= end; i++)//n到1
{
if (a[min] > a[i])
{
min = i;//选择出最小的
}
}
swap(a[begin], a[min]);
++begin;
}
}
优化版本:
- 每次选出两个数,一个min,一个max,min和begin交换,max和end交换,区间两边都减小,重复前面操作直到begin和end相遇。
- 注意:防止min和max两个位置互相交换,因为如果max是begin活着min是end,就会使的min和max的值混了,发生错误。
void SelectSort2(int* a, size_t n)
{
int begin = 0;
int end = n-1;
int min = 0;
int max = 0;
while (begin<end)//O(1/n)
{
min = begin;
max = begin;
for (size_t i = begin; i <= end; i++) //相为2的等差数列
{
if (a[min]>a[i]) //在无序区间里选出最小的
{
min = i;
}
if (a[max] < a[i]) //在无序区间里选出最大的
{
max = i;
}
}
swap(a[max], a[end]);
if (end == min)// 防止max和min互相交换,看下图
{
a[min] = a[max];
}
swap(a[min], a[begin]);
++begin;
--end;
}
}
时间复杂度
每一个单趟执行的次数依次是从n到1,总共循环n次,因此是一个等差数列,时间复杂度为O(n^2)。
2.堆排序
- 升序——建大堆:建大堆是因为把堆顶最大的和堆尾交换后,只用对堆顶进行一次向下调整就行,其他子树还是大堆,注意调整的范围要减减,;如果是小堆,那么堆顶是最小得,那么要对后面所有的数重新建小堆,就复杂了。
- 降序——建小堆
代码实现
void AdjustDown(int *a, size_t i,size_t end)
{
int parent = i;
int child = i * 2 + 1;
while (child<=end)
{
if ((child < end) && a[child] < a[child + 1])
{
child++;
}
if (a[parent] < a[child])
{
swap(a[parent], a[child]);
parent = child;
child = child * 2 + 1;
}
else
{
break;
}
}
}
void HeapSort(int *a, size_t n)
{
for (int i = (n-2)/2; i >=0; i--)
{
AdjustDown(a, i,n-1);
}
for (int end = n - 1;end>0;end--)
{
swap(a[end], a[0]);
AdjustDown(a, 0, end - 1);
}
}
时间复杂度
时间复杂度:O(n*lgn)