冒泡排序
原理:就是遍历一次,然后将最大的数据给移动到序列尾部,这个遍历的过程是从头开始,一个个的比较前面的比后面的大,就交换位置,从后面的开始继续往后比较,一组遍历下来之后,最大的数据就移动到了尾部,然后控制下一次的遍历,遍历到倒数第二个元素的时候就不在往后比较了,当最后只有一个数据的时候就将数据按照升序排好了。
原理图示:
一次遍历走下来的整个过程和结果
然后按照这样的遍历方式一直遍历下去,每一次遍历都是将一个未排序的最大值移动到最后位置,所以每一遍历一次,最后位置就要向前移动一个位置。
代码实现
void BubbleSort(int* arr, int size)
{
int i = 0;
for (; i < size - 1; i++)
{
int j = 0;
for (; j < size - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
在这里有一个重点问题,就是这里的循环截止的条件到底是什么?
如果我们看过很多人写的冒泡排序之后就会发现,有俩个版本的冒泡,就是在写循环结束的条件到底要不要-1,俩个代码实现形式上不一样,但是本质还是一样的。
另一种的冒泡:
void BubbleSort(int* arr, int size)
{
int i = 0;
for (; i < size; i++)
{
int j = 1;
for (; j < size - i; j++)
{
if (arr[j] > arr[j - 1])
{
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}
}
它们的区别就再于用于内部比较交换的具体实现,如果你是用start和start + 1进行比较的,那么你的循环结束条件就需要-1,但是你要是用start和start - 1进行比较的,那么你的循环结束条件就不需要-1。
在遍历的图示中,在第五次遍历之后,序列已经有序了,但是我们的代码并没有有序就可以退出循环的代码,于是系统依旧会继续遍历下去,这样就造成了一定的时间的浪费,于是我们可以在遍历的时候进行一点优化,达到序列已经有序就跳出循环。
怎么优化代码就是一个新的问题了,也就是说怎么判断序列是否已经有序?
我们理解了冒泡的原理之后,不难发现,每一次的冒泡都进行数据的交换,也就是说,当这一次的遍历中没有数据进行交换的,那么序列就已经是有序的了,就可以退出循环体。
这样的话,我们优化代码的思路就很清晰了,只需要在给一个变量,用来监视遍历中有没有进行交换数据的动作即可。
代码实现:
void BubbleSort(int* arr, int size)
{
int i = 0;
for (; i < size - 1; i++)
{
int j = 0;
int end = 0;
for (; j < size - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
end = 1;
}
}
if (end == 0)
return;
}
}
代码这样一写,当我们的数据有序了以后,就不会退出函数,使得时间效率有所提升。
冒泡的核心就是一个个数据之间的比较、交换,将最大或者最小的元素移动到尾部,然后继续下一次的遍历