排序算法主要有
- 冒泡排序(时间复杂度为O(n^2))
- 选择排序(时间复杂度为O(n^2),单比冒泡排序稍微好点,主要是交换次数少)
- 直接插入排序(时间复杂度为O(n^2),比选择排序稍微好点)
(以上都是O(n^2)的排序,下边排序的复杂度都低于O(n^2)) - 希尔排序(插入排序的改进)
- 堆排序(选择排序的改进)
- 归并排序
- 快速排序(交换排序的改进)
1.冒泡排序
冒泡排序是一种交换排序,基本思想就是相邻两位两两比较,如果反序则交换顺序,一直循环直到没有反序为止。如果升序排序的话,也就是每次把当前最小的升到前边当到对应位置。
最简单的排序思路
从第一个位置开始,用第一个位置的数和后边位置比较,如果反序则交换,一次下来确定了第一个位置的数,然后到第二个位置,依次遍历完,即完成排序。
这个算法的效率很低
标准的冒泡排序
void BubbleSort(SqList *L)
{
int i,j;
for(i=1;i<L->length;i++)
{
for(j=L->length-1;j>=i;j--)
{
if(L->r[j]>L->[j+1])
swap(L,j,j+1);
}
}
}
冒泡排序的优化
当一个序列经过几次交换后就已经有序了,不需要进行接下来的循环,这时我们可以加入一个标志位,判断是否已经有序可以提前退出。
void BubbleSort2(SqList *L)
{
int i,j;
bool flag = true;
for(i=1;i<L->length && flag;i++)// for循环退出条件是全部遍历完或者某次比较中没有需要交换顺序的数
{
flag = false;
for(j=L->length-1;j>=i;j--)
{
if(L->r[j]>L->[j+1])
{
swap(L,j,j+1);
flag = true; // 如果有交换数据则需要将标志位设置为true
}
}
}
}
性能分析:
优化后的冒泡排序最好情况下的时间复杂度为O(n)
最差情况时间复杂度为O(n^2);
稳定性:稳定
2.简单选择排序
思路:每次循环找到从当前位置到结束的最小数的下标,然后交换当前位置和记录的最小数位置的数;当前位置从开始一直循环到结束。
void SelectSort(SqList *L)
{
int i,j,min;
for(i=1;i<L->length;i++)
{
min = i;
// 寻找最小数下标
for(j=i+1;j<=L->length;j++)
{
if(L->r[min]>L->r[j])
min = j;
}
// 交换位置
if(min!=i)
{
swap(L,min,i);
}
}
}
性能分析:
复杂度和冒泡排序一样,但是减少了交换次数,所以性能略优于冒泡。
最好情况时间复杂度:O(n^2)
最差情况时间复杂度:O(n^2)
稳定性:不稳定
3.直接插入排序
思路:比较当前数和前边数的大小,找到合适的位置插入当前数,从第二个数开始一直这样插入,直到插完整个序列的数。
void InsertSort(SqList *L)
{
int i,j;
for(i=2;i<=L->length;i++)// 从第二个数开始依次插入
{
if(L->r[i]<L->r[i-1])
{
L->[0] = L->r[i];// 将当前数记录在r[0]位置
// 循环和前边数比较,确定应该插入的位置,并将该位置后边的数都后移一位
for(j=i-1; L->r[j]>L->r[0];j--)
L->[j+1] = L->r[j];
L->r[j+1] = L->r[0];// 将该数插入对应位置
}
}
}
性能分析:
直接插入排序性能略微好于冒泡和选择排序
最好情况时间复杂度:O(n)
最差情况时间复杂度:O(n^2)
稳定性:稳定