冒泡排序
冒泡排序是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
基本思路:
从第一个元素开始比较相邻的两个元素,如果第一个比第一个大或小,就互换它们的位置,这样先比较完一次,然后抛弃最大(或最小)的继续比较,直到排序完成。
下面以从小到大排序为例:
比较相邻的两个数,如果第一个比第二个大,就交换他们的位置;第一轮比较下来,最从左往右比较最大的数会逐渐向左边移动, 若将其竖直起来看,就会发现最大数像气泡一般浮了上来
冒泡排序在实现的细节上可以有很多种变化,这里我分别就三种不同的冒泡说起:
本篇头文件等信息为:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define MAXSIZE 10 /* 用于要排序数组个数最大值, 可根据需要修改*/
#define TRUE 1
#define FALSE -1
typedef int Status;
结构体统一为:
typedef struct
{
int r[MAXSIZE+1];/* 用于存储要排序数组,r[0]用作哨兵或临时变量 */
int length;/* 用于记录顺序表的长度 */
}SqList;
交换函数:
/*交换L中数组r的下标为i和j的值*/
void swap(SqList *L, int i, int j)
{
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
- 冒泡排序初级版:
/* 简化版 */
void bubble_sort1(SqList *L)
{
int i,j;
for(i=1; i<L->length; i++)
{
for(j=i+1; j<L->length; j++)
{
if(L->r[i]>L->r[j])
swap(L, i, j);/*交换L->r[i]与L->r[j]的值*/
}
}
}
这段代码严格意义上来说不算是标准的冒泡排序,因为它不满足两两相邻数比较。
这段代码侧重用每次比较序列的第一个数去与后面剩下的数进行比较,如果后面的数比第一个数小,则二者互相交换,将较小的数放在第一个。
它的思路就是让每一个关键字,都和子序列第一个关键字进行比较,不断将第一个关键字替换成较小的数,循环一轮过后第一个关键字一定变成最小值。
但这种排序每次循环虽说都起到了排序的作用,但是排序好每个关键字所需的对应位置的时候,对其余关键字是没有什么帮助的,甚至有时还会起反作用。也就是说,这个算法的效率是非常低的。如下图:
观察后可以发现,在排序好1和2的位置之后,对其余关键字的排序没有什么帮助(数字3反而还被换到了最后一位)
2. 冒泡排序:
void bubble_sort2(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->r[j+1])//小的往前递
swap(L, j, j+1);
}
}
/*
for(i=1; i<L->length; i++)
{
for(j=1; j<L->length+1-i; j++)
{
if(L->r[j] > L->r[j+1])//大的往后递
swap(L, j, j+1);
}
}
*/
}
这个排序是对相邻的两个关键字不断进行比较,然后根据所需条件判断是否交换位置,如下图:
在不断循环的过程中,例如第一次循环,除了将关键字1放到第一的位置,我们还将关键字2从第九位置提到了第三的位置,图中较小的数如同气泡般慢慢浮到上面
- 冒泡排序优化:
/*优化冒泡算法*/
void bubble_sort3(SqList *L)
{
int i,j;
Status flag = TRUE;/*剔除多余冗杂循环*/
for(i=1; i<L->length && flag; i++)
{ flag = FALSE;
for(j=L->length-1; j>=i; j--)
{
if(L->r[j] > L->r[j+1])//小的往前递
{
swap(L, j, j+1);
flag = TRUE;
}
}
}
}
这段代码是对冒泡排序的优化处理,假设数据循环有n次,当我们循环到第i次的时候,整个序列就已经有序,后续就没有交换操作了,尽管此时序列已经有序,但是算法仍不依不饶地将后面的n-i次循环全部执行玩不腻,尽管没有交换数据,但是之后的大量比较还是大大地多余了。
此时加入一个中间的判断变量flag,判断序列是否进行交换操作(相当于判断序列是否已经有序,如果序列有序了就不会执行交换操作),来控制循环是否跳出。
代码改动的关键就是这个中间判断变量,增加了flag是否为True的判断。经过这样的改进,冒泡排序在性能上就有了一些提升,可以避免因已经有序的情况下的无意义循环判断。