冒泡排序的思想
以n个人站队为例,从第1个开始,依次比较相邻的两个是否逆序对(高在前,矮在后),若逆序就交换这两人,即第1个和第2个比,若逆序就交换两人,接着第2个和第3个比,若逆序就交换两人,接着第3个和第4个比,若逆序就交换两人,.....直到n-1和n比较,经过一轮比较后,则把最高的人排到最后,即将最高的人像冒泡一样逐步冒到相应的位置。原n个人的排序问题,转换为n-1个人的排序问题。第二轮从第1个开始,依次比较相邻的两个人是否逆序对,若逆序就交换两人,直到n-2和n-1比较。如此,进行n-1轮后,队列为有序的队列。
从上述分析中可以看出,每进行轮的比较之后,n 个数的排序规模就转化为n-1个数的排序规模。
列如有6个元素需要排序:
第一趟排序:
第二趟排序:
第三趟排序:
第四趟排序:
第五趟排序:
五趟结束后,6个整数就已经排序完成。排序过程中,大数慢慢地往后,相当于气泡上升,所以叫冒泡排序。
归纳上述排序过程,具体实现步骤如下:
①读人数据存放在a数组中。
②比较相邻的前后两个数据,如果前面数据大于后面的数据,就将两个数据交换。
③对数组的第0个数据到n-1个数据进行一次遍历后,最大的一个数据就“冒”到数组第n-1个位置。
④n=n-1,如果n不为0就重复前面二步,否则排序完成。
程序实现方法:用两层循环完成算法,外层循环i控制每轮要进行多少次的比较,第1轮比较n一1次,第2轮比较n-2次,....最后一轮比较1次。
内层循环j控制每轮i次比较相邻两个元素是否逆序,若逆序就交换这两个元素。
【程序实现】
#include<iostream>
using namespace std;
const int MAXN=10001;
int main()
{
int n,i,j;
float temp,a[MAXN];
cin>>n;
for(i=0;i<n;i++)
cin>>a[i]; //输入n个数
for(i=n-1;i>=1;i--)
{
for(j=0;j<i;j++) //每轮进行i次的比较
{
if(a[j]<a[j+1]) //相邻两个元素比较,若逆序就交换
swap(a[j],a[j+1]); //交换
}
}
for(i=0;i<n;i++) //输出结果
cout<<a[i]<<" ";
return 0;
}
改进的冒泡排序:
对于有些数据,我们发现,不一定要n-1次才能排完。例如15 2 3 4 6,我们发现只需-趟排序就可以将整个序列排完,于是,我们可以设置一个布尔变量,
判断是否有进行交换,如果没有交换,说明已经排序完成,进而减少几趟排序。
bool ok;
for(int i = n-1;i>=1;i--){
ok = true;
for(int j=1;j<=i;j++){
if(a[j]>a[j+1]){
swap(a[j],a[j+1]);
ok=false;
}
}
if(ok == true)break; //没有交换就退出
}
【车厢重组】
在一个旧式的火车站旁边有一座桥,其桥面可以绕河中心的桥墩水平旋转。一个车站的职工发现桥的长度最多能容纳两节车厢,如果将桥旋转180度,则可以把相邻两节车厢的位置交换,用这种方法可以重新排列车厢的顺序。于是他就负责用这座桥将进站的车厢按车厢号从小到大排列。他退休后,火车站决定将这一工作自动化,其中一项重要的工作是编一个程序,输入初始的车厢顺序,计算最少用多少步就能将车厢排序。
【输入】
有两行数据,第一行是车厢总数N(不大于10000),第二行是N个不同的数表示初始的车厢顺序。
【输出】
一个数据,是最少的旋转次数。
【输入样例】
4
4 3 2 1
【输出样例】
6
因为这个题就是一道基础题,话不多说,直接两层循环搞定
上代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int main()
{
int n,ans=0;
cin >> n;
int a[n];
for(int i = 0;i < n;i ++)
cin >> a[i];
for(int i = n-1;i >= 0;i --)
for(int j = 0;j < i;j ++)
{
if(a[j]>a[j+1])
{
swap(a[j],a[j+1]);
ans ++;
}
}
cout << ans;
return 0;
}