选择排序
算法思想:以升序为例,在整个区间中找出排序码最小的元素,如果这个元素不是这组序列中的第一个元素,那么将它和第一个元素进行交换,使得最小的元素就在第一个位置,然后缩小区间,循环执行上述操作,只到区间中只剩下一个元素。
具体步骤(升序):
- 在区间中找到关键码最小的元素。
- 如果不是待排序区间的第一个元素,则和带排序区间第一个元素交换。
- 缩小待排序区间。
代码实现:
void ChangeSort(int *array, int size)
{
assert(array);
for (int i = 1; i < size; ++i)
{
int minindex = i;//未排序的最小元素下标
int start = i - 1;//未排序区间第一个元素下标
while (minindex<size)
{
if (array[minindex] < array[start])
swap(array[minindex], array[start]);
++minindex;
}
}
}
算法性能:
时间复杂度:最好的情况是已经有序,交换次数为0,最坏的情况是逆序,交换次数是n-1,比较次数与关键字的初始状态无关。总的比较次数为N=n*(n-1)/2,所以时间复杂度为O(N^2)
空间复杂度:O(1)
稳定性:不稳定
堆排序
基本思想:堆排序就是利用堆这种数据结构实现的一种排序算法,堆是完全二叉树的一种。堆的特点是:
- 最大堆:每一个父节点的值都大于两个子节点
- 最小堆:每一个父节点的值都小于两个子节点
堆排序的基本思想就是利用了这种结构,如果我们需要升序:
1.把所有[a1,a2,a3…an]建成大堆。
2.把堆顶的元素(即数组中最大的元素和堆中最后一个元素交换),此时分为两个区域,一个[a1,a2,an–1]无序区和[an]有序区。
3.因为交换了元素,有可能会违反了堆的性质,因此无序区的元素进行调整,满足堆的性质。
4.重复步骤2,直到有序区的元素有n-1个。
代码实现:
void AdJustDown(int *array, int size, int n)
{
int parent = n;
int child = parent*+1;
while (child<n)
{
if ((child + 1 < size) && array[child] < array[child + 1])
{
++child;
}
if (array[child] > array[parent])
{
swap(array[child], array[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void HeapSort(int *array, int size)
{
assert(array);
for (int i=(size-2)>>1;i>=0;++i)
{
AdJustDown(array,size,i);//创建大堆,将所有数据都重新排序
}
for (int i = size - 1; i >= 0; ++i)
{
swap(array[0], array[size]);//交换堆顶元素和已序序列第一个元素
AdJustDown(array, i, 0);//缩小区间,调整堆结构
}
}
算法性能:
- 时间复杂度:因为堆中元素的个数是N,所以堆的高度是logN,那么比较次数就是2logN,交换的次数是N次,所以平均时间复杂度是O(NlogN)
- 空间复杂度:O(1)
- 稳定性:不稳定
验证结果: