常见排序
在实际生活中,排序的运用很多,排序就是将一组杂乱无章的数据升序或者降序排成有序的序列。常见的排序算法有。
不同的排序算法适用于不同的场景下,衡量一个排序算法的标准不仅有空间复杂度,空间复杂度,还有稳定性。一个稳定的排序算法,相同的排序码在排序前后相对位置是不会发生变化的。
当然,排序也会根据数据量的情况,分为:
1.内部排序:数据可以加载到内存中进行排序。
2.外部排序:数据元素太多不能一次性加载到内存中,根据排序的情况不能再内存和外村中移动数据的排序。
插入排序
算法思想:每一步把一个元素key根据其排序码插入到它前面的一组已经排好序的序列中,直到所有元素排好序。
具体执行步骤:
(1)先认为第一个元素是已序的,第二个元素。
(2)去第二个元素,从后向前在已序的序列中比较。
(3)如果该元素比(已排序)比新元素大,将该元素移动到下一个位置。
(3)重复步骤三,直到找到比已排序元素小或者等于的元素。
(4)插入新元素到该位置。
(5)重复步骤(2)
算法性能
时间复杂度:
最优的情况下:就是数据元素已经是升序的,时间复杂度O(N);
最差的情况:数据序列是降序的,时间复杂度O(N^2);
空间复杂度:O(1)
稳定性:稳定。
适用的场景:当数据是已序的或者接近有序的,并且数据量比较小。
代码实现:
//最差的情况是降序拍,时间复杂度O(N^2)
//最好的情况是升序的,时间复杂度是O(N)
//平均时间复杂度O(N^2)
//稳定的排序算法。
//空间复杂度O(1)
void InsertSort(int *array,int size)
{
for (int i=1;i<size;i++)
{
int end = array[i];
int j = i - 1;
while (j >= 0 && array[j] > end)//找到带 c插入元素位置
{
array[j + 1] = array[j];
j--;
}
array[j + 1] = end;
}
}
我们可以用二分查找来提高查找插入位置的位置,来对插入排序进行优化,简称二分插入排序。
实现代码:
void BinaryInsertSort(int*array, int size)
{
for (int i = 1; i < size; ++i)
{
int left = 0;
int right = i - 1;
int end = array[i];
while (left<= right)
{
int mid = left + ((right - left) >> 1);
if (array[mid] < end)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
for (int j = i - 1; j >= left; --j)
{
array[j + 1] = array[j];
}
array[left] = end;
}
}
希尔排序 (减增量排序)
从本质上来说,希尔排序是对直接插入排序的一种优化,为了避免直接插入排序出现最差的情况,希尔排序将数据元素进行了分组,先进行预排序,使数据逐渐接近有序,再使用插入排序。
基本思想:先将待排序序列分割成若干个子序列(子序列由相隔某个“增量”的元素组成),分别对这些子序列进行直接插入排序,然后减小“增量”,分组排序子序列,使序列 基本有序,最后再对全体元素进行一次直接插入排序。
适用场景:希尔排序是对插入排序的一种优化,当数据元素比较多时,适合希尔排序。
时间复杂度:当N比较大的时候,时间复杂度在O(N^1.25)-1.6O(N……1.25)之间
空间复杂度:O(1)
稳定性:不稳定
代码实现:
void ShellSort(int*array, int size)
{
assert(array);
int gap = 1;
while (gap < size)
{
gap = gap * 2 + 1;
}
while (gap>=0)
{
for (int i = gap; i < size; ++i)
{
int key = array[i];
int j = i - gap;
while (j>0&&key<array[j])
{
array[j + 1] = array[j];
j = j - gap;
}
array[j + gap] = key;
}
gap = gap / 3 + 1;
}