它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
冒泡排序对 {\displaystyle n} n个项目需要O( {\displaystyle n^{2}} n^{2})的比较次数,且可以原地排序。尽管这个算法是最简单了解和实现的排序算法之一,但它对于包含大量的元素的数列排序是很没有效率的。
冒泡排序是与插入排序拥有相等的运行时间,但是两种算法在需要的交换次数却很大地不同。在最坏的情况,冒泡排序需要 {\displaystyle O(n^{2})} O(n^{2})次交换,而插入排序只要最多 {\displaystyle O(n)} O(n)交换。冒泡排序的实现(类似下面)通常会对已经排序好的数列拙劣地运行( {\displaystyle O(n^{2})} O(n^{2})),而插入排序在这个例子只需要 {\displaystyle O(n)} O(n)个运算。因此很多现代的算法教科书避免使用冒泡排序,而用插入排序取代之。冒泡排序如果能在内部循环第一次运行时,使用一个旗标来表示有无需要交换的可能,也可以把最优情况下的复杂度降低到 {\displaystyle O(n)} O(n)。在这个情况,已经排序好的数列就无交换的需要。若在每次走访数列时,把走访顺序反过来,也可以稍微地改进效率。有时候称为鸡尾酒排序,因为算法会从数列的一端到另一端之间穿梭往返。
冒泡排序算法的运作如下:
1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
3、针对所有的元素重复以上的步骤,除了最后一个。
4、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#include <conio.h>
using namespace std;
const int SIZE = 10000;
void fBubbleSort(int *pData, int size);
int main()
{
int number;
int fDate[SIZE] = { 0 };
cout << "请输入需要进行排序的个数:";
cin >> number;
for (int i = 0; i < number; i++)
cin >> fDate[i];
cout << "————————————————" << endl;
fBubbleSort(fDate, number);
cout << "答案是:" << endl;
for (int i = 0; i < number; ++i)
cout << fDate[i] << ‘ ‘;
_getch();
return 0;
}
void fBubbleSort(int *pData, int size)
{
for (int i = 0; i < size - 1; i++)
{
int number;
for (int j = 0; j < size - 1 - i; j++)
{
if (pData[j] > pData[j + 1])
{
int temp = pData[j];
pData[j] = pData[j + 1];
pData[j + 1] = temp;
}
printf("交换的是第%d和第%d位:", j + 1, j + 2);
for (int i = 0; i < size; ++i)
cout << pData[i] << ‘ ‘;
cout << endl;
}
cout << "————————————————" << endl;
}
}
最近在网上看到了一个大佬的冒泡排序,他用比较直接的方式讲述了冒泡排序的定义写法和更为减少时间复杂度的写法。
在代码开始前,先写一个用于交换的函数,这个在整个冒泡排序中很重要
自定义交换函数Swap
:
Swap
函数是为了交换不同地址间的数据。在最初的两者数据交换时,我们一般是用int a,b,c;
的方式,进行赋值运算的交换,但是这种方法在自定义函数中并不适用。交换的值并没有传到主函数里面。所以在这里我采用这样的方法。
void swap(int& a, int& b)
{
int swap = a;
a = b;
b = swap;
}
下面是根据定义写出的冒泡排序。
定义代码:
void BubbleSort1(int a[], int n)
{
int i, j;
for (i = 0; i < n; i++)
for (j = 1; j < n - i; j++)
if (a[j - 1] > a[j])
Swap(a[j - 1], a[j]);
}
经典的双for
循环,i
用于判断对象,j
用于遍历被判断对象。内for
的语句进行判断,然后用Swap
函数进行数组数据间地址的交换。
下面对其进行优化,设置一个标志,如果这一趟发生了交换,则为true,否则为false。明显如果有一趟没有发生交换,说明排序已经完成。这一用法可以很好的减少时间复杂度。如果遇到1 2 4 3 5
的情况则只需冒泡三次即可成功。但是如果像上面代码,则需要进行五次循环。
改进代码:
void BubbleSort2(int a[], int n)
{
int j, k;
bool flag;
k = n;
flag = true;
while (flag) //没有交换则停止
{
flag = false;
for (j = 1; j < k; j++)
if (a[j - 1] > a[j])
{
Swap(a[j - 1], a[j]);
flag = true;
}
k--;
}
}
再做进一步的优化。如果有100个数的数组,仅前面10个无序,后面90个都已排好序且都大于前面10个数字,那么在第一趟遍历后,最后发生交换的位置必定小于10,且这个位置之后的数据必定已经有序了,记录下这位置,第二次只要从数组头部遍历到这个位置就可以了。
void BubbleSort3(int a[], int n)
{
int j, k;
int flag;
flag = n;
while (flag > 0)
{
k = flag;
flag = 0;
for (j = 1; j < k; j++)
if (a[j - 1] > a[j])
{
Swap(a[j - 1], a[j]);
flag = j;
}
}
}
作者:MoreWindows
来源:CSDN
原文:https://blog.csdn.net/MoreWindows/article/details/6657829
---------------------
作者:ThdLee
来源:简书
原文:https://www.jianshu.com/p/5c422f4fb062
原文:https://www.cnblogs.com/JingWenxing/p/9949669.html