起泡排序

来源:互联网 发布:如何在mac切换输入法 编辑:程序博客网 时间:2024/04/27 11:06

代码来源:《数据结构(c++语言版)(第三版)》,邓俊辉编著,ISBN: 978-7-302-33064-6

起泡排序,顾名思义,一个向量像气泡浮起那样排序:

  1. 在一段向量里,进行一次扫描交换,若检测出逆序对,则交换两个元素;
  2. 当一次扫描交换完成后,最大元素一定被排在最后一个;
  3. 结束标志前移,再进行一次扫描排序,知道检测出没有逆序对。
void bubblesort1A ( int A[], int n ) { //起泡排序算法(版本1A):0 <= n   bool sorted = false; //整体排序标志,首先假定尚未排序   while ( !sorted ) { //在尚未确认已全局排序之前,逐趟进行扫描交换      sorted = true; //假定已经排序      for ( int i = 1; i < n; i++ ) { //自左向右逐对检查当前范围A[0, n)内的各相邻元素         if ( A[i - 1] > A[i] ) { //一旦A[i - 1]与A[i]逆序,则            swap ( A[i - 1], A[i] ); //交换之,并            sorted = false; //因整体排序不能保证,需要清除排序标志         }      }      n--; //至此末元素必然就位,故可以缩短待排序序列的有效长度   }} //借助布尔型标志位sorted,可及时提前退出,而不致总是蛮力地做n - 1趟扫描交换

同样,我们可以将其集成化,以模版形式表现
template <typename T> //向量的起泡排序void Vector<T>::bubbleSort ( Rank lo, Rank hi ) //assert: 0 <= lo < hi <= size{ while ( !bubble ( lo, hi-- ) ); } //逐趟做扫描交换,直至全序template <typename T> bool Vector<T>::bubble ( Rank lo, Rank hi ) { //一趟扫描交换   bool sorted = true; //整体有序标志   while ( ++lo < hi ) //自左向右,逐一检查各对相邻元素      if ( _elem[lo - 1] > _elem[lo] ) { //若逆序,则         sorted = false; //意味着尚未整体有序,并需要         swap ( _elem[lo - 1], _elem[lo] ); //通过交换使局部有序      }   return sorted; //返回有序标志}

代码中,通过返回标志sorted来表示排序任务是否完成,即某次扫描后没有任何逆序对。

但是注意到,当乱序元素仅存在向量的前r项,后(r, n)项已经有序,此时再次进行扫描算法,后面有序片段同样会进行扫描,做无用功。考虑对此处进行改进。

template <typename T> //向量的起泡排序void Vector<T>::bubbleSort ( Rank lo, Rank hi ) //assert: 0 <= lo < hi <= size{ while ( lo < (hi = bubble(lo, hi) ) ); } //逐趟做扫描交换,直至全序template <typename T> Rank Vector<T>::bubble ( Rank lo, Rank hi ) { //一趟扫描交换   Rank last = lo; //整体有序标志   while ( ++lo < hi ) //自左向右,逐一检查各对相邻元素      if ( _elem[lo - 1] > _elem[lo] ) { //若逆序,则         last = lo; //意味着尚未整体有序,并需要         swap ( _elem[lo - 1], _elem[lo] ); //通过交换使局部有序      }   return last; //返回有序标志}

代码中,定义rank型变量last。若出现上述情况时,last会调整到有序段的开头,作为标志,并返回到外部while循环中,保证在下次循环中,扫描到此标志处就不在继续扫描,从而实现代码优化。

但是,对于最坏情况,无论什么优化,起泡排序的复杂度都是O(n^2)。


0 0
原创粉丝点击