思路
两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
补充
交换函数
参考
冒泡排序初级版
/* 对顺序表 L 做交换顺序(冒泡排序初级版) */
void BubbleSort0( 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);
}
Print(*L); //test
}
}
举例说明上述算法。
未排序时候 (9,1,5,8,3,7,4,6,2)
i = 1, (1,9,5,8,3,7,4,6,2)
i = 2, (1,2,9,8,5,7,4,6,3)
i = 3, (1,2,3,9,8,7,5,6,4)
i = 4, (1,2,3,4,9,8,7,6,5)
i = 5, (1,2,3,4,5,9,8,7,6)
i = 6, (1,2,3,4,5,6,9,8,7)
i = 7, (1,2,3,4,5,6,7,9,8)
i = 8, (1,2,3,4,5,6,7,8,9)
i = 9, (1,2,3,4,5,6,7,8,9)
冒泡排序
/* 对顺序表 L 做冒泡排序 */
void BubbleSort( SqList *L )
{
int i, j;
for(i = 1; i < L->length; i++)
{
for(j = L->length - 2; j >= i; j--)
{
if(L->r[j] > L->r[j+1])
swap( L, j, j+1 );
}
Print( *L ); //test
}
}
举例说明上述算法。
未排序时候 (9,1,5,8,3,7,4,6,2)
i = 1, (1,9,
2,5,8,3,7,4,6)
i = 2, (1,
2,9,
3,5,8,
4,7,6)
i = 3, (1,2,
3,9,
4,5,8,
6,7)
i = 4, (1,2,3,
4,9,5,
6,8,7)
i = 5, (1,2,3,4,
5,9,6,
7,8)
i = 6, (1,2,3,4,5,
6,9,7,8)
i = 7, (1,2,3,4,5,6,
7,9,8)
i = 8, (1,2,3,4,5,6,7,
8,9)
i = 9, (1,2,3,4,5,6,7,8,
9)
红色标记是上浮的数字,可见,在每一轮从后向前相邻数据比较,小的数字就会上浮。
优化
试想一下,如果我们待排序的序列式{2,1,3,4,5,6,7,8,9},也就是说,除了第一和第二的关键字需要交换外,别的都已经是正常的顺序。当 i = 1 时,交换了 2 和 1,此时序列已经有序,但是算法仍然不依不饶的将 i= 2 到 9 以及每个循环都执行了一遍, 尽管没有交换数据,但是之后的大量比较还是大大的多余了。
也就是说,我们可以增加一个flag来实现这一算法的改进。
/* 对顺序表 L 做改进冒泡算法 */
void BubbleSort2( SqList *L )
{
int i, j;
int flag = TRUE; /* flag 用来作为标记 */
for(i = 1; i < L->length && flag; i++)
{
/* 若 flag 为 false,则说明没有进入交换的 if 语句中,退出循环 */
flag = FALSE; /* 初始为 false */
for(j = L->length - 2; j >= i; j--)
{
if(L->r[j] > L->r[j+1])
{
swap( L, j, j+1 );
flag = TRUE; /* 如果有数据交换,则 flag 为 true */
}
}
Print( *L ); //test
}
}
避免了因已经有序的情况下的无意义循环判断。
复杂度分析
最好情况 n-1 次比较
最坏情况 需要比较 n(n-1)/2 次,并做等数量级的记录移动。
所以,总的时间复杂度为 O(n^2)。
线性表结构:
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;
}
参考
《大话数据结构》