1. 直接选择排序
直接选择排序:每一趟都从数据元素中选出最小(或最大)的一个元素,并将其存放在序列的起始位置(或末端位置),直到将所有数据元素排完。
具体方法:
- 首先遍历找到序列中最大或最小的元素(结合自己的排序选择元素);
- 将找到的元素与序列第一个或最后一个元素进行交换;
- 重复上述过程,直至序列只剩下一个元素。
我们看一下排序简要过程:
原序列:7 4 5 9 8 2
上述过程的代码片:
首先我们先实现一个交换函数:
void Swap(int *a, int* b)
{
int x = *a;
*a = *b;
*b = x;
}
直接选择排序:
void DirectSelectionSort(int* a, int n)
{
int end = n - 1;
int begin = 0;
int min, max;
while (begin <= end)
{
max = begin;
min = begin;
for (int i = begin + 1; i <= end; ++i)
{
if (a[i] < a[min])
{
min = i;
}
if (a[i] > a[max])
{
max = i;
}
}
Swap (&a[min], &a[begin]);
if (max == begin)
{
max = min;
}
Swap (&a[max], &a[end]);
++begin;
--end;
}
}
总结
效率不高
稳定性:不稳定
时间复杂度:O(N2)
空间复杂度:O(1)
2.堆排序
堆排序:指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是一种选择排序,通过堆来进行选择数据。 升序建大堆,降序建小堆
具体操作(向下调整):
从最后一个父亲结点反方向直到根节点a[0],依次对其中的每一个节点a[i]执行向下调整;
- 若该结点小于或等于其最小的孩子,则本轮向下调整结束,否则执行下一步骤;
- 将该节点与其最小孩子交换;交换完后,继续以该节点为参考对象,重复执行以上步骤。
由于在数组中下标从0开始,所以在堆中i的左子结点为2 * i+1,右子结点为2 * i+2。
// 向下调整----降序建小堆
void AdjustDown(int* a, size_t n, size_t parent)
{
int child = parent * 2 + 1;
while (child < n)
{
// 选出小的那个孩子,用child记录
if (child + 1 < n && a[child + 1] < a[child])
++child;
// 孩子小于父亲,则交换
if (a[child] < a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else return;
}
}
// 向下调整----升序建大堆
void AdjustDown(int* a, size_t n, size_t parent)
{
int child = parent * 2 + 1;
while (child < n)
{
// 选出大的那个孩子,用child记录
if (child + 1 < n && a[child + 1] > a[child])
++child;
// 孩子大于父亲,则交换
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else return;
}
}
堆排序的实现:(升序建大堆,降序建小堆)不影响这块代码
void HeapSort(int* a, size_t n) // 堆排序
{
for (int i = (n - 2) / 2; i >= 0; --i)
{
AdjustDown(a, n, i);
}
int end = n - 1;
while (end > 0)
{
Swap(&a[end], &a[0]);
AdjustDown(a, end, 0);
--end;
}
}
打印堆:
void PrintHeap(int* a, size_t n)// 打印堆
{
for (int i = 0; i <= n - 1; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
}
总结
稳定性:不稳定
时间复杂度:O(N*logN)
空间复杂度:O(1)