冒泡排序
它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
代码如下:
void BubbleSort(int* a, int n)
{
assert(a);
for (int end = n-1; end > 0; --end)
{
for (int i = 1; i <= end ; ++i)
{
if (a[i-1] > a[i])
{
swap(a[i-1], a[i]);
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
冒泡排序的优化
我们已经知道当走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成,所以我们可以设置一个标志位来判断是否已经排序完毕。
void BubbleSort(int* a, int n)
{
assert(a);
for (int end = n-1; end > 0; --end)
{
bool exchange = false;
for (int i = 1; i <= end ; ++i)
{
if (a[i-1] > a[i])
{
swap(a[i-1], a[i]);
exchange = true;
}
}
if (exchange == false)
break;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
稳定性
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,我想你是不会再无聊地把他们俩交换一下的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
插入排序
直接插入排序
直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的纪录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的纪录插入完为止,得到一个新的有序序列。
在这里要注意直接插入排序的前提,是插入到一个已经排好序的有序序列中,这表明,我们在插入一个数之前,必须保证被插入的序列是有序序列。
所以我们在插入之前,要先构造一个有序序列, 所以从第一个参数开始,我们一个一个插入,并且都保证插入后序列为有序序列即可。
所以插入顺序应如下图所示:
那么应该怎么描述以上的过程呢?
其实有很多中方法:
第一种,swap
for(int i = 1;i < n;i++)
for(int j = i;j > 0 && a[j-1] > a[j];j--)
swap(a[i],a[j]);
- 1
- 2
- 3
- 1
- 2
- 3
但是,这种方法调用swap函数,速度较慢,我们可以使用临时变量来替代swap函数:
int tmp = a[j];
a[j] = a[j-1];
a[j-1] = tmp;
- 1
- 2
- 3
- 1
- 2
- 3
上面的代码又会在内循环中不停地给变量tmp赋相同的值,所以将临时变量tmp定义提出来。
最终优化过的完整代码如下:
void InsertSort(int* a, size_t n)
{
assert(a);
for (int i = 0; i < n-1; ++i)
{
int end = i;
int tmp = a[end+1];
while (end >= 0 && a[end] > tmp)
{
a[end+1] = a[end];
--end;
}
a[end+1] = tmp;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
稳定性
直接插入排序是稳定排序,即相同的数据元素在排序前后不会改变二者之间的相对顺序。