一、选择排序
基本思想:每一趟(第i趟,i=0,1,…,n-2)在后面n-i个待排序的数据元素集合中选出关键码最小的数据元素,作为有序元素序列的第i个元素。待到第n-2趟做完,待排序元素集合中只剩下1个元素,排序结束。
1、直接选择排序
算法步骤:
1、在元素集合array[i]–array[n-1]中选择关键码最小的数据元素;
2、若它不是这组元素中的第一个元素,则将它与这组元素中的第一个元素交换。
3、在剩余的array[i+1]–array[n-1]集合中,重复12步骤,直到集合剩余1个元素。
图形解释:
代码实现:
void SelectSort(int*array, int size)
{
int begin = 0;
int end = size - 1;
while (begin < end)
{
int min = begin;
int max = end;
for (int i = begin; i < end; i++)
{
if (array[i] < array[min])
min = i;//找到最小的下标
if (array[i]>array[max])
max = i;//找到最大的下标
}
swap(array[begin], array[min]);//
if (min == end)//最大的下标已经被换走了,重新赋值
min = max;
swap(array[end], array[max]);
begin++;
end--;
}
}
算法性能分析
(1)时间复杂度:O(N^2)
(2)空间复杂度:O(1)
(3)稳定性:不稳定
2、堆排序
利用大小堆对元素进行排序,这里以大堆为例:每一次将对顶元素与堆最后一个元素交换位置,然后将剩下n-1个元素进行重新建堆,然后重复此操作,直到只剩下堆顶一个元素为止,这样就完成了一次排序;
算法步骤:
执行以下循环结构:
a、把堆顶array[0]元素和当前最堆的最后一个元素交换;
b、最大堆元素个数减1
c、由于第1步后根节点不再满足最堆定义,向下调整跟结点。
代码实现:
//堆排序(以大堆为例)
//向下调整堆
void AdjustDown(int *array, int size, int parent)
{
//默认左孩子最小
int child = parent * 2 + 1;
while (child < size)
{
if (child + 1 < size&&array[child] < array[child + 1])
child++;
else if (array[child]>array[parent])
{
swap(array[child], array[parent]);
parent = child;
child = 2 * parent + 1;
}
else
break;
}
}
void HeapSort(int *array, int size)
{
//创建堆
for (int root = ((size - 2) >> 1); root >= 0; root--)
AdjustDown(array, size, root);
int end = size - 1;
//交换堆顶元素与堆尾元素
while (end > 0)
{
swap(array[0], array[end]);
AdjustDown(array, end, 0);
--end;
}
}
算法性能分析:
(1)时间复杂度:O(n*lgN)
(2)空间复杂度:O(1)
(3)稳定性:不稳定
二、归并排序
基本思想:将待排序的元素序列分成两个长度相等的子序列,为每一个子序列排序,然后将他们合并成一个序列。合并两个子序列的过程称为两路归并。
在介绍归并排序之前,首先让我们先来看看如何将两个有序数组合并,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果其中有一个数列为空,那直接将另一个数列的数据依次取出即可。
void MergeArray(int *a, int left,int mid,int right, int *c)
{
int i = left;
int j = mid ;
int k = left;
//元素比较,
while (i < mid&&j < right)
{
if (a[i] <=a[j])
c[k++] = a[i++];
else
c[k++] = a[j++];
}
//当有剩余元素时,直接全部取出即可
while (i < mid)
c[k++] = a[i++];
while (j <right)
c[k++] = a[j++];
memcpy(a + left, c + left, (right - left)*sizeof(int));
}
归并排序的步骤:
(1)第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
(2)第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
(3)第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
(4)重复步骤3直到某一指针超出序列尾将另一序列剩下的所有元素直接复制到合并序列尾
代码实现:
void _Mergesort(int *array,int left,int end, int *tmp)
{
if(left+1 < end)
{
int mid = left + ((end - left) >> 1);
_Mergesort(array, left, mid, tmp);//左边有序
_Mergesort(array, mid , end, tmp);//右边有序
MergeArray(array, left,mid, end, tmp);//合并两个有序数列
}
}
void MergeSort(int *array, int size)
{
//assert(array);
int *p = new int[size];
if (p == NULL)
return;
_Mergesort(array, 0, size, p);
delete[] p;
}
算法性能分析:
(1)时间复杂度:O(log N)
(2)空间复杂度:O(N)
(3)稳定性:稳定