排序算法四:交换排序之冒泡排序
声明:引用请注明出处http://blog.csdn.net/finish_dream/article/details/70207823
引言
系列博文的前三篇讲述了插入排序的三种不同类型,本文讲述第二大类的排序算法,交换排序。
排序相关的基本概念
排序:将一组杂乱无章的数据按一定的规律顺次排列起来。
- 数据表(data list):它是待排序对象的有限集合。
- 排序码(key):通常对象有多个属性域,即多个数据成员组成,其中有一个属性域,可用来区分对象,作为排序依据。该域即为排序
码,每个数据表用哪个属性域作为排序码,要视具体的应用需要而定。
分类
- 内排序:指在排序期间数据对象全部存放在内存的排序;
- 外排序:指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。
排序的分析
排序算法的稳定性
如果在对象序列中有两个对象r[i]和r[j] ,它们的排序码k[i]==k[j] 。如果排序前后,对象r[i]和r[j] 的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的。
排序算法的评价
时间开销
- 排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。
- 算法运行时间代价的大略估算一般都按平均情况进行估算。对于那些受对象排序码序列初始排列及对象个数影响较大的,需要按最好情况和最坏情况进行估算。
空间开销
算法执行时所需的附加存储。
交换排序(Swap Sorting)
基本思想
两两比较待排序记录(数据表)的关键字(排序码),发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。主要包括冒泡排序和快速排序。
分类
- 冒泡排序
- 快速排序
冒泡排序
算法思想及步骤
冒泡排序是第一个接触也最容易理解的排序算法,因为就像泡泡一样,最轻的率先“冒”出来占据第一的位置,随后是剩下的最轻的再冒出来,占据第二的位置,就这样一步步冒出来,也就完成了排序。
- 对象个数n。最多作最多作n-1趟, i= 0, 2, …, n-1 。
- 第i趟中从后向前j= n-1, n-2, ……, i,顺次两两比较。
- 比较如果发生逆序,则交换V[j-1] 和V[j]。
总之就是每一趟都是将剩余中最大或最小的数据项排在前面已经“冒”出来的数据表后面,遍历完毕也就实现了排序。
C#代码
/// <summary>
/// 交换x,y数值
/// </summary>
/// <param name="x">元素1</param>
/// <param name="y">元素2</param>
private static void Swap(ref int x, ref int y)
{
int tmp = x;
x = y;
y = tmp;
}
/// <summary>
/// 冒泡排序
/// </summary>
/// <param name="array">待排序数组</param>
/// <returns></returns>
public static int[] BubbleSort(int[] array)
{
if (array.Length > 0)
{
int num = array.Length; //数组元素个数
for (int i = 0; i < num - 1; i++)
{
for (int j = 0; j < num - 1; j++)
{
if (array[j] > array[j + 1])
{
Swap(ref array[j], ref array[j + 1]);
}
}
}
return array;
}
else
{
throw new Exception("待排序数组大小不能小于0");
}
}
算法分析
最好情况:正序排列,比较次数(KCN):n−1 ; 移动次数(RMN):为0。则对应的时间复杂度为O(n)。
完全正序排列的话,只需一趟就能判定是否有序,如果遍历j之后发现没有发生逆序就说明已经有序,所以,共比较了n−1次,移动0次。
最坏情况:逆序排序,比较次数(KCN):∑n−1i=1(n−i)=n(n−1)2;移动次数(RMN):3∑n−1i=1(n−i)=3n(n−1)2。
完全逆序排序的话,第i都要比较n−i次,而每次比较都要移动3次数据项来交换记录位置。因此总的时间复杂度为O(n2)。
它需要一个附加空间,是一个稳定的排序算法。
完整代码被我放在了Github上,感兴趣的可以下下来看一下https://github.com/Finish-Dream/DSAlgorithm