一、选择排序(以升序为例)
1.算法思想
在整个区间中找出排序码最小的元素,如果这个元素不是这组序列中的第一个元素,那么将它和第一个元素进行交换,使得最小的元素就在第一个位置,然后缩小区间,循环执行上述操作,只到区间中只剩下一个元素。
注意:选择排序和冒泡排序有相似之处,以升序为例,都是将最小的数放在最前面。但是不同之处在于冒泡排序是对于两个相邻数进行比较和交换,而选择排序是对于整体进行排序。
2.算法的具体步骤
(1)在区间中找到关键码最小的元素。
(2)如果不是待排序区间的第一个元素,则和带排序区间第一个元素交换。
(3)缩小待排序区间。
3.图解举例
4.代码实现
void SelectSort(int* arr, int size)
{
if (arr == NULL || size <= 0)
return;
for (int i = 1; i < size; i++)
{
int minindex = i;//i下标位置的元素是最小的
int start = i - 1;//从未排序的最小区间的下标开始
while (minindex < size)
{
if (arr[minindex] < arr[start])
{
swap(arr[minindex], arr[start]);
++minindex;
}
}
}
}
5.其他
(1)时间复杂度:O(n^2)
(2)空间复杂度:O(1)
(3)稳定性:不稳定
6.动态图
二、堆排序(以升序为例)
1.算法思想
- 堆数据结构是一种数组对象,它可以被视为一棵完全二叉树结构。
- 堆排序就是利用堆这种数据结构实现的一种排序算法,堆是完全二叉树的一种。
堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
- 堆有以下几个特点:
(1)最大堆:每一个父亲节点的值都大于两个孩子节点的值。
(2)最小堆:每一个父亲节点的值都小于两个孩子节点的值。
- 堆有以下几个特点:
2.算法的具体步骤
堆排序的基本思想就是利用了这种结构,如果我们需要升序:
(1)将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
(2)将堆顶元素与末尾元素交换,将最大元素”沉”到数组末端;
(3)重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
3.图解举例
4.代码实现
//堆排序
void AjustDown(int* arr, int pos, int size)//向下调整
{
int parent = pos;
int child = parent * 2 + 1;//得到的是左子树
while (child <= size)
{
if (child<size&&arr[child + 1]>arr[child])
{
child++;
}
if (arr[parent] < arr[child])
{
swap(arr[parent], arr[child]);
arr[parent] = arr[child];
child = child * 2 + 1;
}
else
{
break;
}
}
}
void AjustDown_t(int* arr, int size)//选择离叶子结点最近的父结点
//该函数的作用是:从离叶子结点最近的父节点开始使用向下调整法一直调整,直到找到最大的元素
{
int parent = (size - 2) / 2;
while (parent >= 0)
{
AjustDown(arr, parent, size-1);
parent--;
}
}
void HeapSort(int* arr, int size)//堆排序
{
//使得对按照向下调整的方法排序
AjustDown_t(arr, size);
while (size > 1)
{
//进行交换
int tmp = arr[0];
arr[0] = arr[size - 1];
arr[size - 1] = tmp;
size--;
//重新调整堆结构
AjustDown_t(arr, size);
}
}
5.其他
(1)时间复杂度:O(NlogN)
因为堆中元素的个数是N,所以堆的高度是logN,那么比较次数就是2logN,交换的次数是N次.
(2)空间复杂度:O(1)
(3)稳定性:不稳定