目录
1.排序的概念及常见排序算法
1.1排序的概念
排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性 :假定在待排序的记录序列中,存在多个具有相同的关键字(相同的数据)的记录,若经过排序,这些记录的相对次序保持不变 ,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不断地在内外存之间移动数据的排序。
1.2常见的排序算法
2.常见O(N^2)排序算法的实现
2.1插入排序
2.1.1基本思想
**把待排序的元素按大小关系逐个插入到一个已经排好序的有序序列中,直到所以的元素插入完为止,得到一个新的有序序列。**类比于平时玩扑克牌时理牌的思想。
2.1.2直接插入排序
当插入第i(i>=1)个元素时,前面的array[0],array[1],...,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],...的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移。
2.1.2.1直接插入排序的特性
(1)元素集合越接近有序,直接插入排序算法的时间效率越高(比较的次数越少),最好情况为有序的情况,时间复杂度会优化为O(N)。
(2)时间复杂度:O(N^2)。
(3)空间复杂度:O(1)。
(4)稳定性:稳定。
2.1.2.2直接插入排序算法实现
cpp
void InsertSort(int* a, int n)
{
for (int i = 0; i < n - 1; i++)// end最后一个位置为n-2
{
int end = i;
int tmp = a[end + 1]; //先保存end+1位置的值,以免移动时被覆盖
//[0, end]有序,end+1位置的值插入然后保持有序
while (end >= 0) //如果是循环条件不满足跳出的循环,则表示tmp比所以值都小,此时的end为-1
{
if (a[end] > tmp)
{
a[end + 1] = a[end];
end--;
}
else
{
//a[end + 1] = tmp; 这行代码放到循环外是为了兼容tmp为最小值不满足循环条件跳出循
//环的情况
break;
}
}
a[end + 1] = tmp;
}
}
2.2选择排序
2.2.1基本思想
每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
2.2.2直接选择排序
1.在元素集合 array[i]--array[n-1] 中选择关键码最大 ( 小 ) 的数据元素。
2.若它不是这组元素中的最后一个 ( 第一个 ) 元素,则将它与这组元素中的最后一个(第一个)元素交换。
3.在剩余的 array[i]--array[n-2] ( array[i+1]--array[n-1] )集合中,重复上述步骤,直到集合剩余 1 个元素。
2.2.2.1直接选择排序的特性
-
直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用。
-
时间复杂度:O(N^2)
-
空间复杂度:O(1)
-
稳定性:不稳定
2.2.2.2直接选择排序算法实现
该算法实现每次遍历从数组中找出最大的数和最小的数,分别放在最后和最前面。
cpp
void SelectSort(int* a, int n)
{
int begin = 0, end = n - 1;
while (begin < end)
{
int mini = begin, maxi = begin;
for (int i = begin + 1; i <= end; ++i)
{
if (a[i] > a[maxi])
{
maxi = i;
}
if (a[i] < a[mini])
{
mini = i;
}
}
Swap(&a[begin], &a[mini]);
if (begin == maxi) //如果第一个位置是最大的数,修正maxi
{
maxi = mini;
}
Swap(&a[end], &a[maxi]);
++begin;
--end;
}
}
2.3冒泡排序
2.3.1基本思想
从开始比较两个相邻的元素,把大的元素放在后面,再依次和该元素后面元素一一比较,单趟结束之后把最大的数冒到最后。
2.3.2冒泡排序的特性总结
- 冒泡排序是一种非常容易理解的排序。
- 时间复杂度:O(N^2)。
- 空间复杂度:O(1)。
- 稳定性:稳定。