常见的排序算法之选择排序
选择排序是排序算法中比较简单的排序,选择排序又可以细分为直接选择排序和堆排序。
基本思想:
每一趟(第i趟,i=0,1,...,n-2)在后面n-i个待排序的数据元素集合中选出关键码最小的数据元素,作为有序元素序列的第i个元素。待到第n-2趟做完,待排序元素集合中只剩下一个元素,排序结束。
直接选择排序:
· 在元素集合array[i]-array[n-1]中选择关键码最大(小)的数据元素
· 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
· 在剩余的array[i]-array[n-2](array[i+1]-array[n-1])集合中,重复上述步骤,直至集合剩余一个元素
下面我们举个例子,直观的看一下直接选择排序是怎么排序的:
上代码:
//选择排序(每次排最大的和最小的)
//时间复杂度:O(n^2)
//不稳定
void SelectSort(int array[], int size)
{
int i;
int maxPos,minPos;//下标
int minSpace = 0;
int maxSpace = size-1;
while(minSpace < maxSpace)
{
minPos = minSpace;
maxPos = minSpace;
for(i=minSpace+1; i<=maxSpace; i++)
{
if(array[i] < array[minPos])
{
minPos = i;
}
if(array[i] > array[maxPos])
{
maxPos = i;
}
}
Swap(array+minSpace, array+minPos);
if(minSpace == maxPos)
{
maxPos = minPos;
}//不要漏掉这一点
Swap(array+maxSpace, array+maxPos);
minSpace++;
maxSpace--;
}
}
直接选择排序的时间复杂度是O(n^2),空间复杂度是O(1),它是一种不稳定的排序算法。
堆排序:
· 创建堆:升序--->大堆 降序--->小堆
· 执行 如下步骤,直到数组为空
· 把堆顶array[0]元素和当前最堆的最后一个元素交换
· 堆元素个数减1
· 由于第一步后根节点不再满足最堆定义,向下调整根节点
上代码:
//堆排序(升序,建大堆)
//向下调整
void AdjustDown(int array[], int size, int root)
{
int left;
int right,maxChild;
while(1){
left = root*2+1;
right = root*2+2;
if(left >= size)
{
return;
}
maxChild = left;
if(right<size && array[right]>array[left])
{
maxChild = right;
}
if(array[maxChild] <= array[root])
{
return;
}
Swap(array+maxChild, array+root);
root = maxChild;
}
}
void HeapSort(int array[], int size)
{
int i = 0;
int j = 0;
//建堆
//从最后一个叶子节点的双亲节点开始向下调整
for(i=(size-2)/2; i>=0; i--)
{
AdjustDown(array, size, i);
}
//排序
for(j=size-1; j>=0; j--)
{
Swap(array+j, array);
AdjustDown(array, j, 0);
}
}
把一颗完全二叉树调整为堆,以及每次将堆顶元素交换后进行调整的时间复杂度为O(log2(n)),所以堆排序的时间复杂度为:O(n*log2(n)),空间复杂度为O(1)。堆排序是一种不稳定的排序算法。