1.直接插入排序
直接插入排序的基本思想是将整个待排序表看成左右两个部分,其中左边为有序区,右边为无序区,排序过程就是把无序区的数据插入到有序区,以构成新的有序区。
即将R[i]插入到有序序列R[1..i-1],使记录的有序序列从R[1..i-1]变为R[1..i]。
代码实现如下:
void insertSort(int a[], int size)
{
int temp;
for (int i = 1; i < size; i++)
{
temp = a[i];
int j = i-1;
while (a[j] > temp)
{
a[j+1] = a[j];
j--;
}
a[j+1] = temp;
}
}
直接插入排序是稳定的排序,最小时间复杂度为O(n),最大时间复杂度为O(n²)。
2.折半插入排序
折半插入排序与直接插入排序相比,采用二分查找的方式确定插入位置,减少了关键字比较的次数。
代码实现如下:
void binSort(int a[], int size)
{
int temp;
for (int i = 1; i < size; i++)
{
temp = a[i];
int l = 0, r = i-1;
while (r > l)
{
temp = a[i];
int mid = (l+r)/2;
if (temp > a[mid])
l = mid+1;
else
r = mid-1;
}
for (int j = i-1; j >= r+1; j--)
a[j+1] = a[j];
a[r+1] = temp;
}
}
时间复杂度同样为O(n²)。
3.希尔排序
希尔排序的基本思想是:将待排序列划分为若干组,在每组内进行直接差入排序,当每组序列基本有序后,再对整个序列进行直接插入排序。
希尔排序的关键是如何分组,我这里采用间隔方法分组,分组方法为:给定一个步长d,将下标相差为d的倍数的元素放一组,得到d组。d的典型取值为d1 = n/2, d2 = d1/2, d3 =
d2/2, ... , 1,当d = 1时,整个序列在一组内执行直接插入排序,此时只需要较少的比较和移动次数。
代码实现如下:
void shellSort(int a[], int size)
{
int temp;
int dh = size/2;
while (dh > 0)
{
for (int i = dh; i < n; i++)
{
temp = a[i];
int j = i - dh;
while (j >= 0 && a[j] > temp)
{
a[j+dh] = a[j];
j = j -dh;
}
a[j+dh] = temp;
}
dh = dh/2;
}
}
希尔排序每一趟都是在上一趟的基础上进行的,各趟的时间复杂度为O(n),所需趟数为log2(n),故整个排序的时间复杂度为O(nlog2(n))。该算法是不稳定算法。
4.冒泡排序
冒泡排序的基本思想是:从一端开始,逐个比较相邻的两个元素,发现倒序即交换。典型的做法是从后往前逐个比较相邻的两个元素,发现倒序即交换。
代码实现如下:
void bubbleSort(int a[], int size)
{
for (int i = 0; i < size-1; i++)
for (int j = size-1; j > i; j--)
if (a[j] > a[j-1])
{
int temp = a[j];
a[j] = a[j-1];
a[j-1] = temp;
}
}
如果在某一趟排序过程中,没有进行任何交换,那么数据已经有序,就可以结束排序,其时间复杂度可以达到O(n)。为实现这一要求,在每趟排序中设置是否交换的标志,这样
可以得到改进的冒泡排序如下:
void bubbleSort(int a[], int size)
{
int i = 0;
bool exchanged = true;
do
{
exchanged = false;
for (int j = size-1; j > i; j--)
if (a[j] > a[j-1])
{
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
exchanged = true;
}
i++;
}while (i < size-1 && exchanged = true);
}
5.快速排序
快速排序的基本思想是:首先选定一个元素作为中间元素,然后将数表中所有元素与该中间元素相比较,将表中比中间元素小的元素调到表的前面,比中间元素大的调到后面,
再将中间数放在两部分之间作为一个分界点,由此得到一个划分。对左右两部分分别进行快速排序,直到每个子表仅有一个元素或为空表。
这里以第一个数为中间数,代码实现如下:
void quickSort(int a[], int l, int r)
{
if (l < r)
{
int i = l, j = r, x = a[l];
while (i < j)
{
while(i < j && a[j]>= x) // 从右向左找第一个小于x的数
j--;
if(i < j)
a[i++] = a[j];
while(i < j && a[i]< x) // 从左向右找第一个大于等于x的数
i++;
if(i < j)
a[j--] = a[i];
}
a[i] = x;
quickSort(a, l, i - 1); // 递归调用
quickSort(a, i + 1, r);
}
}
快速排序显然是不稳定排序。快速排序完成一次排序共需log2(n)趟,每一趟划分所需时间可认为是cn(c为常数)。因而可认为快速排序的平均时间复杂度为O(knlog2(n))。
6.直接选择排序
直接选择排序很简单:通过在待排序子表中比较一遍得到最大(小)元素,再将该元素放在子表的最后(前)面。
void selectSort(int a[], int size)
{
for (int i = 0; i < size-1; i++)
{
int min = i;
for (int j = i+1; j < size; j++)
{
if (a[j] < a[min])
min = j;
}
if (a[i] != a[min])
{
temp = a[min];
a[min] = a[i];
a[i] = temp;
}
}
}
直接选择排序是不稳定排序,时间复杂度为O(n²)。